]> www.infradead.org Git - nvme.git/commitdiff
nvmet: Implement arbitration feature support
authorDamien Le Moal <dlemoal@kernel.org>
Sat, 4 Jan 2025 04:59:49 +0000 (13:59 +0900)
committerKeith Busch <kbusch@kernel.org>
Sat, 11 Jan 2025 03:30:49 +0000 (19:30 -0800)
NVMe base specification v2.1 mandates support for the arbitration
feature (NVME_FEAT_ARBITRATION). Introduce the data structure
struct nvmet_feat_arbitration to define the high, medium and low
priority weight fields and the arbitration burst field of this feature
and implement the functions nvmet_get_feat_arbitration() and
nvmet_set_feat_arbitration() functions to get and set these fields.

Since there is no generic way to implement support for the arbitration
feature, these functions respectively use the controller get_feature()
and set_feature() operations to process the feature with the help of
the controller driver. If the controller driver does not implement these
operations and a get feature command or a set feature command for this
feature is received, the command is failed with an invalid field error.

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
drivers/nvme/target/nvmet.h

index 8b8ec33330b238067f35873bafb773391354410a..3ddd8e44e148c19866eb3e35aa9502df3ca24ee5 100644 (file)
@@ -1324,6 +1324,25 @@ static u16 nvmet_set_feat_irq_config(struct nvmet_req *req)
        return ctrl->ops->set_feature(ctrl, NVME_FEAT_IRQ_CONFIG, &irqcfg);
 }
 
+static u16 nvmet_set_feat_arbitration(struct nvmet_req *req)
+{
+       struct nvmet_ctrl *ctrl = req->sq->ctrl;
+       u32 cdw11 = le32_to_cpu(req->cmd->common.cdw11);
+       struct nvmet_feat_arbitration arb = {
+               .hpw = (cdw11 >> 24) & 0xff,
+               .mpw = (cdw11 >> 16) & 0xff,
+               .lpw = (cdw11 >> 8) & 0xff,
+               .ab = cdw11 & 0x3,
+       };
+
+       if (!ctrl->ops->set_feature) {
+               req->error_loc = offsetof(struct nvme_common_command, cdw10);
+               return NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
+       }
+
+       return ctrl->ops->set_feature(ctrl, NVME_FEAT_ARBITRATION, &arb);
+}
+
 void nvmet_execute_set_features(struct nvmet_req *req)
 {
        struct nvmet_subsys *subsys = nvmet_req_subsys(req);
@@ -1337,6 +1356,9 @@ void nvmet_execute_set_features(struct nvmet_req *req)
                return;
 
        switch (cdw10 & 0xff) {
+       case NVME_FEAT_ARBITRATION:
+               status = nvmet_set_feat_arbitration(req);
+               break;
        case NVME_FEAT_NUM_QUEUES:
                ncqr = (cdw11 >> 16) & 0xffff;
                nsqr = cdw11 & 0xffff;
@@ -1446,6 +1468,30 @@ static u16 nvmet_get_feat_irq_config(struct nvmet_req *req)
        return NVME_SC_SUCCESS;
 }
 
+static u16 nvmet_get_feat_arbitration(struct nvmet_req *req)
+{
+       struct nvmet_ctrl *ctrl = req->sq->ctrl;
+       struct nvmet_feat_arbitration arb = { };
+       u16 status;
+
+       if (!ctrl->ops->get_feature) {
+               req->error_loc = offsetof(struct nvme_common_command, cdw10);
+               return NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
+       }
+
+       status = ctrl->ops->get_feature(ctrl, NVME_FEAT_ARBITRATION, &arb);
+       if (status != NVME_SC_SUCCESS)
+               return status;
+
+       nvmet_set_result(req,
+                        ((u32)arb.hpw << 24) |
+                        ((u32)arb.mpw << 16) |
+                        ((u32)arb.lpw << 8) |
+                        (arb.ab & 0x3));
+
+       return NVME_SC_SUCCESS;
+}
+
 void nvmet_get_feat_kato(struct nvmet_req *req)
 {
        nvmet_set_result(req, req->sq->ctrl->kato * 1000);
@@ -1472,8 +1518,6 @@ void nvmet_execute_get_features(struct nvmet_req *req)
         * need to come up with some fake values for these.
         */
 #if 0
-       case NVME_FEAT_ARBITRATION:
-               break;
        case NVME_FEAT_POWER_MGMT:
                break;
        case NVME_FEAT_TEMP_THRESH:
@@ -1483,6 +1527,9 @@ void nvmet_execute_get_features(struct nvmet_req *req)
        case NVME_FEAT_WRITE_ATOMIC:
                break;
 #endif
+       case NVME_FEAT_ARBITRATION:
+               status = nvmet_get_feat_arbitration(req);
+               break;
        case NVME_FEAT_IRQ_COALESCE:
                status = nvmet_get_feat_irq_coalesce(req);
                break;
index 999a4ebf597efae0517fdef2f38a42f48d65b02c..f4df458df9dbbfd7e711361d3a5a910bd1270c05 100644 (file)
@@ -921,4 +921,11 @@ struct nvmet_feat_irq_config {
        bool            cd;
 };
 
+struct nvmet_feat_arbitration {
+       u8              hpw;
+       u8              mpw;
+       u8              lpw;
+       u8              ab;
+};
+
 #endif /* _NVMET_H */