block: remove ->driverfs_dev
[cascardo/linux.git] / drivers / nvdimm / bus.c
index 19f822d..5e4e5c7 100644 (file)
@@ -40,6 +40,8 @@ static int to_nd_device_type(struct device *dev)
                return ND_DEVICE_REGION_PMEM;
        else if (is_nd_blk(dev))
                return ND_DEVICE_REGION_BLK;
+       else if (is_nd_dax(dev))
+               return ND_DEVICE_DAX_PMEM;
        else if (is_nd_pmem(dev->parent) || is_nd_blk(dev->parent))
                return nd_region_to_nstype(to_nd_region(dev->parent));
 
@@ -122,9 +124,10 @@ static int nvdimm_bus_remove(struct device *dev)
        struct nd_device_driver *nd_drv = to_nd_device_driver(dev->driver);
        struct module *provider = to_bus_provider(dev);
        struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
-       int rc;
+       int rc = 0;
 
-       rc = nd_drv->remove(dev);
+       if (nd_drv->remove)
+               rc = nd_drv->remove(dev);
        nd_region_disable(nvdimm_bus, dev);
 
        dev_dbg(&nvdimm_bus->dev, "%s.remove(%s) = %d\n", dev->driver->name,
@@ -246,6 +249,8 @@ static void nd_async_device_unregister(void *d, async_cookie_t cookie)
 
 void __nd_device_register(struct device *dev)
 {
+       if (!dev)
+               return;
        dev->bus = &nvdimm_bus_type;
        get_device(dev);
        async_schedule_domain(nd_async_device_register, dev,
@@ -292,8 +297,8 @@ int __nd_driver_register(struct nd_device_driver *nd_drv, struct module *owner,
                return -EINVAL;
        }
 
-       if (!nd_drv->probe || !nd_drv->remove) {
-               pr_debug("->probe() and ->remove() must be specified\n");
+       if (!nd_drv->probe) {
+               pr_debug("%s ->probe() must be specified\n", mod_name);
                return -EINVAL;
        }
 
@@ -307,7 +312,7 @@ EXPORT_SYMBOL(__nd_driver_register);
 
 int nvdimm_revalidate_disk(struct gendisk *disk)
 {
-       struct device *dev = disk->driverfs_dev;
+       struct device *dev = disk_to_dev(disk)->parent;
        struct nd_region *nd_region = to_nd_region(dev->parent);
        const char *pol = nd_region->ro ? "only" : "write";
 
@@ -439,6 +444,12 @@ static const struct nd_cmd_desc __nd_cmd_dimm_descs[] = {
                .out_num = 3,
                .out_sizes = { 4, 4, UINT_MAX, },
        },
+       [ND_CMD_CALL] = {
+               .in_num = 2,
+               .in_sizes = { sizeof(struct nd_cmd_pkg), UINT_MAX, },
+               .out_num = 1,
+               .out_sizes = { UINT_MAX, },
+       },
 };
 
 const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd)
@@ -473,6 +484,12 @@ static const struct nd_cmd_desc __nd_cmd_bus_descs[] = {
                .out_num = 3,
                .out_sizes = { 4, 4, 8, },
        },
+       [ND_CMD_CALL] = {
+               .in_num = 2,
+               .in_sizes = { sizeof(struct nd_cmd_pkg), UINT_MAX, },
+               .out_num = 1,
+               .out_sizes = { UINT_MAX, },
+       },
 };
 
 const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd)
@@ -500,6 +517,10 @@ u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd,
                struct nd_cmd_vendor_hdr *hdr = buf;
 
                return hdr->in_length;
+       } else if (cmd == ND_CMD_CALL) {
+               struct nd_cmd_pkg *pkg = buf;
+
+               return pkg->nd_size_in;
        }
 
        return UINT_MAX;
@@ -522,6 +543,12 @@ u32 nd_cmd_out_size(struct nvdimm *nvdimm, int cmd,
                return out_field[1];
        else if (!nvdimm && cmd == ND_CMD_ARS_STATUS && idx == 2)
                return out_field[1] - 8;
+       else if (cmd == ND_CMD_CALL) {
+               struct nd_cmd_pkg *pkg = (struct nd_cmd_pkg *) in_field;
+
+               return pkg->nd_size_out;
+       }
+
 
        return UINT_MAX;
 }
@@ -588,25 +615,31 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
        unsigned int cmd = _IOC_NR(ioctl_cmd);
        void __user *p = (void __user *) arg;
        struct device *dev = &nvdimm_bus->dev;
+       struct nd_cmd_pkg pkg;
        const char *cmd_name, *dimm_name;
-       unsigned long dsm_mask;
+       unsigned long cmd_mask;
        void *buf;
        int rc, i;
 
        if (nvdimm) {
                desc = nd_cmd_dimm_desc(cmd);
                cmd_name = nvdimm_cmd_name(cmd);
-               dsm_mask = nvdimm->dsm_mask ? *(nvdimm->dsm_mask) : 0;
+               cmd_mask = nvdimm->cmd_mask;
                dimm_name = dev_name(&nvdimm->dev);
        } else {
                desc = nd_cmd_bus_desc(cmd);
                cmd_name = nvdimm_bus_cmd_name(cmd);
-               dsm_mask = nd_desc->dsm_mask;
+               cmd_mask = nd_desc->cmd_mask;
                dimm_name = "bus";
        }
 
+       if (cmd == ND_CMD_CALL) {
+               if (copy_from_user(&pkg, p, sizeof(pkg)))
+                       return -EFAULT;
+       }
+
        if (!desc || (desc->out_num + desc->in_num == 0) ||
-                       !test_bit(cmd, &dsm_mask))
+                       !test_bit(cmd, &cmd_mask))
                return -ENOTTY;
 
        /* fail write commands (when read-only) */
@@ -616,6 +649,7 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
                case ND_CMD_SET_CONFIG_DATA:
                case ND_CMD_ARS_START:
                case ND_CMD_CLEAR_ERROR:
+               case ND_CMD_CALL:
                        dev_dbg(&nvdimm_bus->dev, "'%s' command while read-only.\n",
                                        nvdimm ? nvdimm_cmd_name(cmd)
                                        : nvdimm_bus_cmd_name(cmd));
@@ -643,6 +677,16 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
                in_len += in_size;
        }
 
+       if (cmd == ND_CMD_CALL) {
+               dev_dbg(dev, "%s:%s, idx: %llu, in: %zu, out: %zu, len %zu\n",
+                               __func__, dimm_name, pkg.nd_command,
+                               in_len, out_len, buf_len);
+
+               for (i = 0; i < ARRAY_SIZE(pkg.nd_reserved2); i++)
+                       if (pkg.nd_reserved2[i])
+                               return -EINVAL;
+       }
+
        /* process an output envelope */
        for (i = 0; i < desc->out_num; i++) {
                u32 out_size = nd_cmd_out_size(nvdimm, cmd, desc, i,
@@ -783,6 +827,9 @@ int __init nvdimm_bus_init(void)
 {
        int rc;
 
+       BUILD_BUG_ON(sizeof(struct nd_smart_payload) != 128);
+       BUILD_BUG_ON(sizeof(struct nd_smart_threshold_payload) != 8);
+
        rc = bus_register(&nvdimm_bus_type);
        if (rc)
                return rc;