]> www.infradead.org Git - nvme.git/commitdiff
nvmet: Implement host identifier set feature support
authorDamien Le Moal <dlemoal@kernel.org>
Sat, 4 Jan 2025 04:59:46 +0000 (13:59 +0900)
committerKeith Busch <kbusch@kernel.org>
Sat, 11 Jan 2025 03:30:48 +0000 (19:30 -0800)
The NVMe specifications mandate support for the host identifier
set_features for controllers that also supports reservations. Satisfy
this requirement by implementing handling of the NVME_FEAT_HOST_ID
feature for the nvme_set_features command. This implementation is for
now effective only for PCI target controllers. For other controller
types, the set features command is failed with a NVME_SC_CMD_SEQ_ERROR
status as before.

As noted in the code, 128 bits host identifiers are supported since the
NVMe base specifications version 2.1 indicate in section 5.1.25.1.28.1
that "The controller may support a 64-bit Host Identifier...".

The RHII (Reservations and Host Identifier Interaction) bit of the
controller attribute (ctratt) field of the identify controller data is
also set to indicate that a host ID of "0" is supported but that the
host ID must be a non-zero value to use reservations.

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Tested-by: Rick Wertenbroek <rick.wertenbroek@gmail.com>
Tested-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Keith Busch <kbusch@kernel.org>
drivers/nvme/target/admin-cmd.c
include/linux/nvme.h

index 0c5127a1d191057ac4318a58c6d12b758d28172b..efef3acba9fbb6989a5a7fbcfd65e5febcc7ebfe 100644 (file)
@@ -659,7 +659,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
        struct nvmet_ctrl *ctrl = req->sq->ctrl;
        struct nvmet_subsys *subsys = ctrl->subsys;
        struct nvme_id_ctrl *id;
-       u32 cmd_capsule_size;
+       u32 cmd_capsule_size, ctratt;
        u16 status = 0;
 
        if (!subsys->subsys_discovered) {
@@ -707,8 +707,10 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
 
        /* XXX: figure out what to do about RTD3R/RTD3 */
        id->oaes = cpu_to_le32(NVMET_AEN_CFG_OPTIONAL);
-       id->ctratt = cpu_to_le32(NVME_CTRL_ATTR_HID_128_BIT |
-               NVME_CTRL_ATTR_TBKAS);
+       ctratt = NVME_CTRL_ATTR_HID_128_BIT | NVME_CTRL_ATTR_TBKAS;
+       if (nvmet_is_pci_ctrl(ctrl))
+               ctratt |= NVME_CTRL_ATTR_RHII;
+       id->ctratt = cpu_to_le32(ctratt);
 
        id->oacs = 0;
 
@@ -1255,6 +1257,31 @@ u16 nvmet_set_feat_async_event(struct nvmet_req *req, u32 mask)
        return 0;
 }
 
+static u16 nvmet_set_feat_host_id(struct nvmet_req *req)
+{
+       struct nvmet_ctrl *ctrl = req->sq->ctrl;
+
+       if (!nvmet_is_pci_ctrl(ctrl))
+               return NVME_SC_CMD_SEQ_ERROR | NVME_STATUS_DNR;
+
+       /*
+        * The NVMe base specifications v2.1 recommends supporting 128-bits host
+        * IDs (section 5.1.25.1.28.1). However, that same section also says
+        * that "The controller may support a 64-bit Host Identifier and/or an
+        * extended 128-bit Host Identifier". So simplify this support and do
+        * not support 64-bits host IDs to avoid needing to check that all
+        * controllers associated with the same subsystem all use the same host
+        * ID size.
+        */
+       if (!(req->cmd->common.cdw11 & cpu_to_le32(1 << 0))) {
+               req->error_loc = offsetof(struct nvme_common_command, cdw11);
+               return NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
+       }
+
+       return nvmet_copy_from_sgl(req, 0, &req->sq->ctrl->hostid,
+                                  sizeof(req->sq->ctrl->hostid));
+}
+
 void nvmet_execute_set_features(struct nvmet_req *req)
 {
        struct nvmet_subsys *subsys = nvmet_req_subsys(req);
@@ -1285,7 +1312,7 @@ void nvmet_execute_set_features(struct nvmet_req *req)
                status = nvmet_set_feat_async_event(req, NVMET_AEN_CFG_ALL);
                break;
        case NVME_FEAT_HOST_ID:
-               status = NVME_SC_CMD_SEQ_ERROR | NVME_STATUS_DNR;
+               status = nvmet_set_feat_host_id(req);
                break;
        case NVME_FEAT_WRITE_PROTECT:
                status = nvmet_set_feat_write_protect(req);
index 42fc00dc494e81e8ab1935157e444ef03a897cf5..fe3b60818fdcfbb4baabce59f7499bc1fa07e855 100644 (file)
@@ -276,6 +276,7 @@ enum nvme_ctrl_attr {
        NVME_CTRL_ATTR_HID_128_BIT      = (1 << 0),
        NVME_CTRL_ATTR_TBKAS            = (1 << 6),
        NVME_CTRL_ATTR_ELBAS            = (1 << 15),
+       NVME_CTRL_ATTR_RHII             = (1 << 18),
 };
 
 struct nvme_id_ctrl {