nvme: read the subsystem NQN from Identify Controller
authorChristoph Hellwig <hch@lst.de>
Mon, 26 Jun 2017 10:39:02 +0000 (12:39 +0200)
committerJens Axboe <axboe@kernel.dk>
Wed, 28 Jun 2017 14:14:13 +0000 (08:14 -0600)
NVMe 1.2.1 or later requires controllers to provide a subsystem NQN in the
Identify controller data structures.  Use this NQN for the subsysnqn
sysfs attribute by storing it in the nvme_ctrl structure after verifying
it.  For older controllers we generate a "fake" NQN per non-normative
text in the NVMe 1.3 spec.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Keith Busch <keith.busch@intel.com>
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
drivers/nvme/host/core.c
drivers/nvme/host/fabrics.c
drivers/nvme/host/fabrics.h
drivers/nvme/host/fc.c
drivers/nvme/host/nvme.h
drivers/nvme/host/rdma.c
drivers/nvme/target/loop.c

index 9c03655ac2a90c05b418e4968778f0665a1abd17..3593abf3c806fe7b810f1e28d039a4ea58afcb0a 100644 (file)
@@ -1705,6 +1705,31 @@ static bool quirk_matches(const struct nvme_id_ctrl *id,
                string_matches(id->fr, q->fr, sizeof(id->fr));
 }
 
+static void nvme_init_subnqn(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
+{
+       size_t nqnlen;
+       int off;
+
+       nqnlen = strnlen(id->subnqn, NVMF_NQN_SIZE);
+       if (nqnlen > 0 && nqnlen < NVMF_NQN_SIZE) {
+               strcpy(ctrl->subnqn, id->subnqn);
+               return;
+       }
+
+       if (ctrl->vs >= NVME_VS(1, 2, 1))
+               dev_warn(ctrl->device, "missing or invalid SUBNQN field.\n");
+
+       /* Generate a "fake" NQN per Figure 254 in NVMe 1.3 + ECN 001 */
+       off = snprintf(ctrl->subnqn, NVMF_NQN_SIZE,
+                       "nqn.2014.08.org.nvmexpress:%4x%4x",
+                       le16_to_cpu(id->vid), le16_to_cpu(id->ssvid));
+       memcpy(ctrl->subnqn + off, id->sn, sizeof(id->sn));
+       off += sizeof(id->sn);
+       memcpy(ctrl->subnqn + off, id->mn, sizeof(id->mn));
+       off += sizeof(id->mn);
+       memset(ctrl->subnqn + off, 0, sizeof(ctrl->subnqn) - off);
+}
+
 /*
  * Initialize the cached copies of the Identify data and various controller
  * register in our nvme_ctrl structure.  This should be called as soon as
@@ -1740,6 +1765,8 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
                return -EIO;
        }
 
+       nvme_init_subnqn(ctrl, id);
+
        if (!ctrl->identified) {
                /*
                 * Check for quirks.  Quirk can depend on firmware version,
@@ -2135,8 +2162,7 @@ static ssize_t nvme_sysfs_show_subsysnqn(struct device *dev,
 {
        struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
 
-       return snprintf(buf, PAGE_SIZE, "%s\n",
-                       ctrl->ops->get_subsysnqn(ctrl));
+       return snprintf(buf, PAGE_SIZE, "%s\n", ctrl->subnqn);
 }
 static DEVICE_ATTR(subsysnqn, S_IRUGO, nvme_sysfs_show_subsysnqn, NULL);
 
@@ -2181,7 +2207,6 @@ static umode_t nvme_dev_attrs_are_visible(struct kobject *kobj,
                        return 0;
        }
 
-       CHECK_ATTR(ctrl, a, subsysnqn);
        CHECK_ATTR(ctrl, a, address);
 
        return a->mode;
index a59a243b81c6b339ba5a95001c146165d1648df1..7996e95383d461397e285b67baafd169a4ae9eb4 100644 (file)
@@ -125,16 +125,6 @@ int nvmf_get_address(struct nvme_ctrl *ctrl, char *buf, int size)
 }
 EXPORT_SYMBOL_GPL(nvmf_get_address);
 
-/**
- * nvmf_get_subsysnqn() - Get subsystem NQN
- * @ctrl:      Host NVMe controller instance which we got the NQN
- */
-const char *nvmf_get_subsysnqn(struct nvme_ctrl *ctrl)
-{
-       return ctrl->opts->subsysnqn;
-}
-EXPORT_SYMBOL_GPL(nvmf_get_subsysnqn);
-
 /**
  * nvmf_reg_read32() -  NVMe Fabrics "Property Get" API function.
  * @ctrl:      Host NVMe controller instance maintaining the admin
index c8b2f0127ccc7c7ddcb85310648c9455bb382b7a..bf33663218cd24c22c7f189a532062b0757eabdc 100644 (file)
@@ -139,7 +139,6 @@ int nvmf_connect_io_queue(struct nvme_ctrl *ctrl, u16 qid);
 int nvmf_register_transport(struct nvmf_transport_ops *ops);
 void nvmf_unregister_transport(struct nvmf_transport_ops *ops);
 void nvmf_free_options(struct nvmf_ctrl_options *opts);
-const char *nvmf_get_subsysnqn(struct nvme_ctrl *ctrl);
 int nvmf_get_address(struct nvme_ctrl *ctrl, char *buf, int size);
 bool nvmf_should_reconnect(struct nvme_ctrl *ctrl);
 
index 5d5ecefd8dbee3f383aa8d6ec7f3304208c05b02..158d313be84767f836142c25f2d1cf7ceb01b19e 100644 (file)
@@ -2631,7 +2631,6 @@ static const struct nvme_ctrl_ops nvme_fc_ctrl_ops = {
        .free_ctrl              = nvme_fc_nvme_ctrl_freed,
        .submit_async_event     = nvme_fc_submit_async_event,
        .delete_ctrl            = nvme_fc_del_nvme_ctrl,
-       .get_subsysnqn          = nvmf_get_subsysnqn,
        .get_address            = nvmf_get_address,
 };
 
index aa4c3576a2012b5bcaa055618e6d49a351a6a6ff..d70ff0fdd36bdf2cda89391e509df72af58e7d29 100644 (file)
@@ -138,6 +138,7 @@ struct nvme_ctrl {
        char serial[20];
        char model[40];
        char firmware_rev[8];
+       char subnqn[NVMF_NQN_SIZE];
        u16 cntlid;
 
        u32 ctrl_config;
@@ -225,7 +226,6 @@ struct nvme_ctrl_ops {
        void (*free_ctrl)(struct nvme_ctrl *ctrl);
        void (*submit_async_event)(struct nvme_ctrl *ctrl, int aer_idx);
        int (*delete_ctrl)(struct nvme_ctrl *ctrl);
-       const char *(*get_subsysnqn)(struct nvme_ctrl *ctrl);
        int (*get_address)(struct nvme_ctrl *ctrl, char *buf, int size);
 };
 
index bc0322bf7d2753f117aef4f624cf9481859f3c29..6d4119dfbdaacf5df18c41bf92d0711c2e074bbf 100644 (file)
@@ -1757,7 +1757,6 @@ static const struct nvme_ctrl_ops nvme_rdma_ctrl_ops = {
        .free_ctrl              = nvme_rdma_free_ctrl,
        .submit_async_event     = nvme_rdma_submit_async_event,
        .delete_ctrl            = nvme_rdma_del_ctrl,
-       .get_subsysnqn          = nvmf_get_subsysnqn,
        .get_address            = nvmf_get_address,
 };
 
index 86c09e2a149002bd32d7dca5de6b3dc821e573f9..5f55c683b338c7f47245e727f1d4abbf744ad991 100644 (file)
@@ -540,7 +540,6 @@ static const struct nvme_ctrl_ops nvme_loop_ctrl_ops = {
        .free_ctrl              = nvme_loop_free_ctrl,
        .submit_async_event     = nvme_loop_submit_async_event,
        .delete_ctrl            = nvme_loop_del_ctrl,
-       .get_subsysnqn          = nvmf_get_subsysnqn,
 };
 
 static int nvme_loop_create_io_queues(struct nvme_loop_ctrl *ctrl)