diff options
Diffstat (limited to 'nvme-status.c')
-rw-r--r-- | nvme-status.c | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/nvme-status.c b/nvme-status.c new file mode 100644 index 0000000..1b060dc --- /dev/null +++ b/nvme-status.c @@ -0,0 +1,167 @@ +#include <linux/types.h> +#include <stdbool.h> +#include <errno.h> + +#include "nvme.h" +#include "nvme-status.h" + +static inline __u8 nvme_generic_status_to_errno(__u16 status) +{ + switch (status) { + case NVME_SC_INVALID_OPCODE: + case NVME_SC_INVALID_FIELD: + case NVME_SC_INVALID_NS: + case NVME_SC_SGL_INVALID_LAST: + case NVME_SC_SGL_INVALID_COUNT: + case NVME_SC_SGL_INVALID_DATA: + case NVME_SC_SGL_INVALID_METADATA: + case NVME_SC_SGL_INVALID_TYPE: + case NVME_SC_SGL_INVALID_OFFSET: + case NVME_SC_CMB_INVALID_USE: + case NVME_SC_PRP_INVALID_OFFSET: + return EINVAL; + case NVME_SC_CMDID_CONFLICT: + return EADDRINUSE; + case NVME_SC_DATA_XFER_ERROR: + case NVME_SC_INTERNAL: + case NVME_SC_SANITIZE_FAILED: + return EIO; + case NVME_SC_POWER_LOSS: + case NVME_SC_ABORT_REQ: + case NVME_SC_ABORT_QUEUE: + case NVME_SC_FUSED_FAIL: + case NVME_SC_FUSED_MISSING: + return EWOULDBLOCK; + case NVME_SC_CMD_SEQ_ERROR: + return EILSEQ; + case NVME_SC_SANITIZE_IN_PROGRESS: + case NVME_SC_FORMAT_IN_PROGRESS: + return EINPROGRESS; + case NVME_SC_NS_WRITE_PROTECTED: + case NVME_SC_NS_NOT_READY: + case NVME_SC_RESERVATION_CONFLICT: + return EACCES; + case NVME_SC_LBA_RANGE: + return EREMOTEIO; + case NVME_SC_CAP_EXCEEDED: + return ENOSPC; + case NVME_SC_OPERATION_DENIED: + return EPERM; + } + + return EIO; +} + +static inline __u8 nvme_cmd_specific_status_to_errno(__u16 status) +{ + switch (status) { + case NVME_SC_CQ_INVALID: + case NVME_SC_QID_INVALID: + case NVME_SC_QUEUE_SIZE: + case NVME_SC_FIRMWARE_SLOT: + case NVME_SC_FIRMWARE_IMAGE: + case NVME_SC_INVALID_VECTOR: + case NVME_SC_INVALID_LOG_PAGE: + case NVME_SC_INVALID_FORMAT: + case NVME_SC_INVALID_QUEUE: + case NVME_SC_NS_INSUFFICIENT_CAP: + case NVME_SC_NS_ID_UNAVAILABLE: + case NVME_SC_CTRL_LIST_INVALID: + case NVME_SC_BAD_ATTRIBUTES: + case NVME_SC_INVALID_PI: + case NVME_SC_INVALID_CTRL_ID: + case NVME_SC_INVALID_SECONDARY_CTRL_STATE: + case NVME_SC_INVALID_NUM_CTRL_RESOURCE: + case NVME_SC_INVALID_RESOURCE_ID: + case NVME_SC_ANA_INVALID_GROUP_ID: + return EINVAL; + case NVME_SC_ABORT_LIMIT: + case NVME_SC_ASYNC_LIMIT: + return EDQUOT; + case NVME_SC_FW_NEEDS_CONV_RESET: + case NVME_SC_FW_NEEDS_SUBSYS_RESET: + case NVME_SC_FW_NEEDS_MAX_TIME: + return ERESTART; + case NVME_SC_FEATURE_NOT_SAVEABLE: + case NVME_SC_FEATURE_NOT_CHANGEABLE: + case NVME_SC_FEATURE_NOT_PER_NS: + case NVME_SC_FW_ACTIVATE_PROHIBITED: + case NVME_SC_NS_IS_PRIVATE: + case NVME_SC_BP_WRITE_PROHIBITED: + case NVME_SC_READ_ONLY: + case NVME_SC_PMR_SAN_PROHIBITED: + return EPERM; + case NVME_SC_OVERLAPPING_RANGE: + case NVME_SC_NS_NOT_ATTACHED: + return ENOSPC; + case NVME_SC_NS_ALREADY_ATTACHED: + return EALREADY; + case NVME_SC_THIN_PROV_NOT_SUPP: + case NVME_SC_ONCS_NOT_SUPPORTED: + return EOPNOTSUPP; + case NVME_SC_DEVICE_SELF_TEST_IN_PROGRESS: + return EINPROGRESS; + } + + return EIO; +} + +static inline __u8 nvme_fabrics_status_to_errno(__u16 status) +{ + switch (status) { + case NVME_SC_CONNECT_FORMAT: + case NVME_SC_CONNECT_INVALID_PARAM: + return EINVAL; + case NVME_SC_CONNECT_CTRL_BUSY: + return EBUSY; + case NVME_SC_CONNECT_RESTART_DISC: + return ERESTART; + case NVME_SC_CONNECT_INVALID_HOST: + return ECONNREFUSED; + case NVME_SC_DISCOVERY_RESTART: + return EAGAIN; + case NVME_SC_AUTH_REQUIRED: + return EPERM; + } + + return EIO; +} + +/* + * nvme_status_to_errno - It converts given status to errno mapped + * @status: >= 0 for nvme status field in completion queue entry, + * < 0 for linux internal errors + * @fabrics: true if given status is for fabrics + * + * Notes: This function will convert a given status to an errno mapped + */ +__u8 nvme_status_to_errno(int status, bool fabrics) +{ + __u8 sct; + + if (!status) + return 0; + + if (status < 0) + return ECOMM; + + /* + * The actual status code is enough with masking 0xff, but we need to + * cover status code type which is 3bits with 0x7ff. + */ + status &= 0x7ff; + + sct = nvme_status_type(status); + if (sct == NVME_SCT_GENERIC) + return nvme_generic_status_to_errno(status); + else if (sct == NVME_SCT_CMD_SPECIFIC && !fabrics) + return nvme_cmd_specific_status_to_errno(status); + else if (sct == NVME_SCT_CMD_SPECIFIC && fabrics) + return nvme_fabrics_status_to_errno(status); + + /* + * Media, integrity related status, and the others will be mapped to + * EIO. + */ + return EIO; +} |