[PATCH v3 13/19] nvme: Have NVMe pr_ops return a blk_status_t

Mike Christie
2022-10-26T23:22:18Z

If register or reserve hit a reservation conflict upper layers like LIO
need to pass that error to the initiator. To do this it has to know the
device/driver type so it can convert the return code because that's
currently a NVMe specific value. Instead of having the upper layers
figure out the device/driver type and call a NVMe conversion function this
has NVMe do the conversion and return a blk_status_t which the upper
layer knows how to handle.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
drivers/nvme/host/core.c | 2 +-
drivers/nvme/host/nvme.h | 1 +
drivers/nvme/host/pr.c | 54 ++++++++++++++++++++++++++--------------
3 files changed, 38 insertions(+), 19 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 2de9c42094a6..1fd152a90ed4 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -248,7 +248,7 @@ static void nvme_delete_ctrl_sync(struct nvme_ctrl *ctrl)
nvme_put_ctrl(ctrl);
}

-static blk_status_t nvme_error_status(u16 status)
+blk_status_t nvme_error_status(u16 status)
{
switch (status & 0x7ff) {
case NVME_SC_SUCCESS:
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index e82be1f1373d..d60da2b8c1c6 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -855,6 +855,7 @@ int nvme_ns_head_chr_uring_cmd(struct io_uring_cmd *ioucmd,
unsigned int issue_flags);
int nvme_getgeo(struct block_device *bdev, struct hd_geometry *geo);
int nvme_dev_uring_cmd(struct io_uring_cmd *ioucmd, unsigned int issue_flags);
+blk_status_t nvme_error_status(u16 status);

extern const struct attribute_group *nvme_ns_id_attr_groups[];
extern const struct pr_ops nvme_pr_ops;
diff --git a/drivers/nvme/host/pr.c b/drivers/nvme/host/pr.c
index 854a26ce55fe..818955c570e3 100644
--- a/drivers/nvme/host/pr.c
+++ b/drivers/nvme/host/pr.c
@@ -43,7 +43,8 @@ static enum pr_type block_pr_type_from_nvme(enum nvme_pr_type type)
}

static int nvme_send_ns_head_pr_command(struct block_device *bdev,
- struct nvme_command *c, u8 *data, unsigned int data_len)
+ struct nvme_command *c, u8 *data, unsigned int data_len,
+ blk_status_t *blk_stat)
{
struct nvme_ns_head *head = bdev->bd_disk->private_data;
int srcu_idx = srcu_read_lock(&head->srcu);
@@ -53,20 +54,28 @@ static int nvme_send_ns_head_pr_command(struct block_device *bdev,
if (ns) {
c->common.nsid = cpu_to_le32(ns->head->ns_id);
ret = nvme_submit_sync_cmd(ns->queue, c, data, data_len);
+ if (blk_stat && ret >= 0)
+ *blk_stat = nvme_error_status(ret);
}
srcu_read_unlock(&head->srcu, srcu_idx);
return ret;
}

static int nvme_send_ns_pr_command(struct nvme_ns *ns, struct nvme_command *c,
- u8 *data, unsigned int data_len)
+ u8 *data, unsigned int data_len, blk_status_t *blk_stat)
{
+ int ret;
+
c->common.nsid = cpu_to_le32(ns->head->ns_id);
- return nvme_submit_sync_cmd(ns->queue, c, data, data_len);
+ ret = nvme_submit_sync_cmd(ns->queue, c, data, data_len);
+ if (blk_stat && ret >= 0)
+ *blk_stat = nvme_error_status(ret);
+ return ret;
}

static int nvme_pr_command(struct block_device *bdev, u32 cdw10,
- u64 key, u64 sa_key, u8 op)
+ u64 key, u64 sa_key, u8 op,
+ blk_status_t *blk_stat)
{
struct nvme_command c = { };
u8 data[16] = { 0, };
@@ -80,9 +89,9 @@ static int nvme_pr_command(struct block_device *bdev, u32 cdw10,
if (IS_ENABLED(CONFIG_NVME_MULTIPATH) &&
bdev->bd_disk->fops == &nvme_ns_head_ops)
return nvme_send_ns_head_pr_command(bdev, &c, data,
- sizeof(data));
- return nvme_send_ns_pr_command(bdev->bd_disk->private_data, &c, data,
- sizeof(data));
+ sizeof(data), blk_stat);
+ return nvme_send_ns_pr_command(bdev->bd_disk->private_data, &c,
+ data, sizeof(data), blk_stat);
}

static int nvme_pr_register(struct block_device *bdev, u64 old,
@@ -96,7 +105,8 @@ static int nvme_pr_register(struct block_device *bdev, u64 old,
cdw10 = old ? 2 : 0;
cdw10 |= (flags & PR_FL_IGNORE_KEY) ? 1 << 3 : 0;
cdw10 |= (1 << 30) | (1 << 31); /* PTPL=1 */
- return nvme_pr_command(bdev, cdw10, old, new, nvme_cmd_resv_register);
+ return nvme_pr_command(bdev, cdw10, old, new, nvme_cmd_resv_register,
+ blk_stat);
}

static int nvme_pr_reserve(struct block_device *bdev, u64 key,
@@ -109,7 +119,8 @@ static int nvme_pr_reserve(struct block_device *bdev, u64 key,

cdw10 = nvme_pr_type_from_blk(type) << 8;
cdw10 |= ((flags & PR_FL_IGNORE_KEY) ? 1 << 3 : 0);
- return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_acquire);
+ return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_acquire,
+ blk_stat);
}

static int nvme_pr_preempt(struct block_device *bdev, u64 old, u64 new,
@@ -117,7 +128,8 @@ static int nvme_pr_preempt(struct block_device *bdev, u64 old, u64 new,
{
u32 cdw10 = nvme_pr_type_from_blk(type) << 8 | (abort ? 2 : 1);

- return nvme_pr_command(bdev, cdw10, old, new, nvme_cmd_resv_acquire);
+ return nvme_pr_command(bdev, cdw10, old, new, nvme_cmd_resv_acquire,
+ blk_stat);
}

static int nvme_pr_clear(struct block_device *bdev, u64 key,
@@ -125,7 +137,8 @@ static int nvme_pr_clear(struct block_device *bdev, u64 key,
{
u32 cdw10 = 1 | (key ? 0 : 1 << 3);

- return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_release);
+ return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_release,
+ blk_stat);
}

static int nvme_pr_release(struct block_device *bdev, u64 key, enum pr_type type,
@@ -133,11 +146,12 @@ static int nvme_pr_release(struct block_device *bdev, u64 key, enum pr_type type
{
u32 cdw10 = nvme_pr_type_from_blk(type) << 8 | (key ? 0 : 1 << 3);

- return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_release);
+ return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_release,
+ blk_stat);
}

static int nvme_pr_resv_report(struct block_device *bdev, u8 *data,
- u32 data_len, bool *eds)
+ u32 data_len, bool *eds, blk_status_t *blk_stat)
{
struct nvme_command c = { };
int ret;
@@ -148,12 +162,16 @@ static int nvme_pr_resv_report(struct block_device *bdev, u8 *data,
*eds = true;

retry:
+ if (blk_stat)
+ *blk_stat = 0;
+
if (IS_ENABLED(CONFIG_NVME_MULTIPATH) &&
bdev->bd_disk->fops == &nvme_ns_head_ops)
- ret = nvme_send_ns_head_pr_command(bdev, &c, data, data_len);
+ ret = nvme_send_ns_head_pr_command(bdev, &c, data, data_len,
+ blk_stat);
else
ret = nvme_send_ns_pr_command(bdev->bd_disk->private_data, &c,
- data, data_len);
+ data, data_len, blk_stat);
if (ret == NVME_SC_HOST_ID_INCONSIST &&
c.common.cdw11 == NVME_EXTENDED_DATA_STRUCT) {
c.common.cdw11 = 0;
@@ -184,7 +202,7 @@ static int nvme_pr_read_keys(struct block_device *bdev,
if (!data)
return -ENOMEM;

- ret = nvme_pr_resv_report(bdev, data, data_len, &eds);
+ ret = nvme_pr_resv_report(bdev, data, data_len, &eds, blk_stat);
if (ret)
goto free_data;

@@ -224,7 +242,7 @@ static int nvme_pr_read_reservation(struct block_device *bdev,
* the response buffer.
*/
ret = nvme_pr_resv_report(bdev, (u8 *)&tmp_status, sizeof(tmp_status),
- &eds);
+ &eds, blk_stat);
if (ret)
return 0;

@@ -240,7 +258,7 @@ static int nvme_pr_read_reservation(struct block_device *bdev,
if (!data)
return -ENOMEM;

- ret = nvme_pr_resv_report(bdev, data, data_len, &eds);
+ ret = nvme_pr_resv_report(bdev, data, data_len, &eds, blk_stat);
if (ret)
goto free_data;
status = (struct nvme_reservation_status *)data;
--
2.25.1