[PATCH v2 10/20] nvme: Add pr_ops read_keys support

Mike Christie
2022-08-09T00:07:15Z

This patch adds support for the pr_ops read_keys callout by calling the
NVMe Reservation Report helper, then parsing that info to get the
controller's registered keys. Because the callout is only used in the
kernel where the callers do not know about controller/host IDs, the
callout just returns the registered keys which is required by the SCSI PR
in READ KEYS command.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
drivers/nvme/host/core.c | 45 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 6b22a5dec122..230e5deca391 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -2223,12 +2223,57 @@ static int nvme_pr_resv_report(struct block_device *bdev, u8 *data,
return ret;
}

+static int nvme_pr_read_keys(struct block_device *bdev,
+ struct pr_keys *keys_info, u32 keys_len)
+{
+ struct nvme_reservation_status *status;
+ u32 data_len, num_ret_keys;
+ int ret, i;
+ bool eds;
+ u8 *data;
+
+ /*
+ * Assume we are using 128-bit host IDs and allocate a buffer large
+ * enough to get enough keys to fill the return keys buffer.
+ */
+ num_ret_keys = keys_len / 8;
+ data_len = sizeof(*status) +
+ num_ret_keys * sizeof(struct nvme_registered_ctrl_ext);
+ data = kzalloc(data_len, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ ret = nvme_pr_resv_report(bdev, data, data_len, &eds);
+ if (ret)
+ goto free_data;
+
+ status = (struct nvme_reservation_status *)data;
+ keys_info->generation = le32_to_cpu(status->gen);
+ keys_info->num_keys = get_unaligned_le16(&status->regctl);
+
+ num_ret_keys = min(num_ret_keys, keys_info->num_keys);
+ for (i = 0; i < num_ret_keys; i++) {
+ if (eds) {
+ keys_info->keys[i] =
+ le64_to_cpu(status->regctl_eds[i].rkey);
+ } else {
+ keys_info->keys[i] =
+ le64_to_cpu(status->regctl_ds[i].rkey);
+ }
+ }
+
+free_data:
+ kfree(data);
+ return ret;
+}
+
const struct pr_ops nvme_pr_ops = {
.pr_register = nvme_pr_register,
.pr_reserve = nvme_pr_reserve,
.pr_release = nvme_pr_release,
.pr_preempt = nvme_pr_preempt,
.pr_clear = nvme_pr_clear,
+ .pr_read_keys = nvme_pr_read_keys,
};

#ifdef CONFIG_BLK_SED_OPAL
--
2.18.2