diff --git a/CHANGELOG.md b/CHANGELOG.md index 36f844f8e..920930334 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -130,6 +130,11 @@ The functions `spdk_reactor_enable_framework_monitor_context_switch()` and `spdk_framework_enable_context_switch_monitor()` and `spdk_framework_context_switch_monitor_enabled()`, respectively. +### bdev + +Added spdk_bdev_io_get_nvme_fused_status function for translating bdev_io status to NVMe status +code for fused compare-and-write operation. + ## v19.10: ### rpc diff --git a/include/spdk/bdev.h b/include/spdk/bdev.h index 477a0e324..1729b9ded 100644 --- a/include/spdk/bdev.h +++ b/include/spdk/bdev.h @@ -1139,6 +1139,9 @@ int spdk_bdev_comparev_blocks_with_md(struct spdk_bdev_desc *desc, struct spdk_i * data and may not be able to directly transfer out of the buffers provided. In * this case, the request may fail. * + * spdk_bdev_io_get_nvme_fused_status() function should be called in callback function + * to get status for the individual operation. + * * \ingroup bdev_io_submit_functions * * \param desc Block device descriptor. @@ -1559,6 +1562,20 @@ void spdk_bdev_get_device_stat(struct spdk_bdev *bdev, struct spdk_bdev_io_stat void spdk_bdev_io_get_nvme_status(const struct spdk_bdev_io *bdev_io, uint32_t *cdw0, int *sct, int *sc); +/** + * Get the status of bdev_io as an NVMe status codes and command specific + * completion queue value for fused operations such as compare-and-write. + * + * \param bdev_io I/O to get the status from. + * \param cdw0 Command specific completion queue value + * \param first_sct Status Code Type return value for the first operation, as defined by the NVMe specification. + * \param first_sc Status Code return value for the first operation, as defined by the NVMe specification. + * \param second_sct Status Code Type return value for the second operation, as defined by the NVMe specification. + * \param second_sc Status Code return value for the second operation, as defined by the NVMe specification. + */ +void spdk_bdev_io_get_nvme_fused_status(const struct spdk_bdev_io *bdev_io, uint32_t *cdw0, + int *first_sct, int *first_sc, int *second_sct, int *second_sc); + /** * Get the status of bdev_io as a SCSI status code. * diff --git a/include/spdk/bdev_module.h b/include/spdk/bdev_module.h index e9bb8f166..9b74ad9d3 100644 --- a/include/spdk/bdev_module.h +++ b/include/spdk/bdev_module.h @@ -222,6 +222,7 @@ struct spdk_bdev_fn_table { /** bdev I/O completion status */ enum spdk_bdev_io_status { + SPDK_BDEV_IO_STATUS_FIRST_FUSED_FAILED = -6, SPDK_BDEV_IO_STATUS_MISCOMPARE = -5, /* * NOMEM should be returned when a bdev module cannot start an I/O because of diff --git a/lib/bdev/bdev.c b/lib/bdev/bdev.c index 23eba9865..99bb4e15d 100644 --- a/lib/bdev/bdev.c +++ b/lib/bdev/bdev.c @@ -3691,7 +3691,7 @@ bdev_compare_and_write_do_compare(void *_bdev_io) if (rc == -ENOMEM) { bdev_queue_io_wait_with_cb(bdev_io, bdev_compare_and_write_do_compare); } else if (rc != 0) { - bdev_io->internal.status = SPDK_BDEV_IO_STATUS_FAILED; + bdev_io->internal.status = SPDK_BDEV_IO_STATUS_FIRST_FUSED_FAILED; bdev_io->internal.cb(bdev_io, false, bdev_io->internal.caller_ctx); } } @@ -4639,6 +4639,54 @@ spdk_bdev_io_get_nvme_status(const struct spdk_bdev_io *bdev_io, uint32_t *cdw0, *cdw0 = bdev_io->internal.error.nvme.cdw0; } +void +spdk_bdev_io_get_nvme_fused_status(const struct spdk_bdev_io *bdev_io, uint32_t *cdw0, + int *first_sct, int *first_sc, int *second_sct, int *second_sc) +{ + assert(first_sct != NULL); + assert(first_sc != NULL); + assert(second_sct != NULL); + assert(second_sc != NULL); + assert(cdw0 != NULL); + + if (bdev_io->internal.status == SPDK_BDEV_IO_STATUS_NVME_ERROR) { + if (bdev_io->internal.error.nvme.sct == SPDK_NVME_SCT_MEDIA_ERROR && + bdev_io->internal.error.nvme.sc == SPDK_NVME_SC_COMPARE_FAILURE) { + *first_sct = bdev_io->internal.error.nvme.sct; + *first_sc = bdev_io->internal.error.nvme.sc; + *second_sct = SPDK_NVME_SCT_GENERIC; + *second_sc = SPDK_NVME_SC_ABORTED_FAILED_FUSED; + } else { + *first_sct = SPDK_NVME_SCT_GENERIC; + *first_sc = SPDK_NVME_SC_SUCCESS; + *second_sct = bdev_io->internal.error.nvme.sct; + *second_sc = bdev_io->internal.error.nvme.sc; + } + } else if (bdev_io->internal.status == SPDK_BDEV_IO_STATUS_SUCCESS) { + *first_sct = SPDK_NVME_SCT_GENERIC; + *first_sc = SPDK_NVME_SC_SUCCESS; + *second_sct = SPDK_NVME_SCT_GENERIC; + *second_sc = SPDK_NVME_SC_SUCCESS; + } else if (bdev_io->internal.status == SPDK_BDEV_IO_STATUS_FIRST_FUSED_FAILED) { + *first_sct = SPDK_NVME_SCT_GENERIC; + *first_sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR; + *second_sct = SPDK_NVME_SCT_GENERIC; + *second_sc = SPDK_NVME_SC_ABORTED_FAILED_FUSED; + } else if (bdev_io->internal.status == SPDK_BDEV_IO_STATUS_MISCOMPARE) { + *first_sct = SPDK_NVME_SCT_MEDIA_ERROR; + *first_sc = SPDK_NVME_SC_COMPARE_FAILURE; + *second_sct = SPDK_NVME_SCT_GENERIC; + *second_sc = SPDK_NVME_SC_ABORTED_FAILED_FUSED; + } else { + *first_sct = SPDK_NVME_SCT_GENERIC; + *first_sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR; + *second_sct = SPDK_NVME_SCT_GENERIC; + *second_sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR; + } + + *cdw0 = bdev_io->internal.error.nvme.cdw0; +} + struct spdk_thread * spdk_bdev_io_get_thread(struct spdk_bdev_io *bdev_io) {