diff options
Diffstat (limited to 'sys/dev/nvme/nvme_qpair.c')
-rw-r--r-- | sys/dev/nvme/nvme_qpair.c | 239 |
1 files changed, 223 insertions, 16 deletions
diff --git a/sys/dev/nvme/nvme_qpair.c b/sys/dev/nvme/nvme_qpair.c index 70cf363..1e76447 100644 --- a/sys/dev/nvme/nvme_qpair.c +++ b/sys/dev/nvme/nvme_qpair.c @@ -37,6 +37,215 @@ __FBSDID("$FreeBSD$"); static void _nvme_qpair_submit_request(struct nvme_qpair *qpair, struct nvme_request *req); +struct nvme_opcode_string { + + uint16_t opc; + const char * str; +}; + +static struct nvme_opcode_string admin_opcode[] = { + { NVME_OPC_DELETE_IO_SQ, "DELETE IO SQ" }, + { NVME_OPC_CREATE_IO_SQ, "CREATE IO SQ" }, + { NVME_OPC_GET_LOG_PAGE, "GET LOG PAGE" }, + { NVME_OPC_DELETE_IO_CQ, "DELETE IO CQ" }, + { NVME_OPC_CREATE_IO_CQ, "CREATE IO CQ" }, + { NVME_OPC_IDENTIFY, "IDENTIFY" }, + { NVME_OPC_ABORT, "ABORT" }, + { NVME_OPC_SET_FEATURES, "SET FEATURES" }, + { NVME_OPC_GET_FEATURES, "GET FEATURES" }, + { NVME_OPC_ASYNC_EVENT_REQUEST, "ASYNC EVENT REQUEST" }, + { NVME_OPC_FIRMWARE_ACTIVATE, "FIRMWARE ACTIVATE" }, + { NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD, "FIRMWARE IMAGE DOWNLOAD" }, + { NVME_OPC_FORMAT_NVM, "FORMAT NVM" }, + { NVME_OPC_SECURITY_SEND, "SECURITY SEND" }, + { NVME_OPC_SECURITY_RECEIVE, "SECURITY RECEIVE" }, + { 0xFFFF, "ADMIN COMMAND" } +}; + +static struct nvme_opcode_string io_opcode[] = { + { NVME_OPC_FLUSH, "FLUSH" }, + { NVME_OPC_WRITE, "WRITE" }, + { NVME_OPC_READ, "READ" }, + { NVME_OPC_WRITE_UNCORRECTABLE, "WRITE UNCORRECTABLE" }, + { NVME_OPC_COMPARE, "COMPARE" }, + { NVME_OPC_DATASET_MANAGEMENT, "DATASET MANAGEMENT" }, + { 0xFFFF, "IO COMMAND" } +}; + +static const char * +get_admin_opcode_string(uint16_t opc) +{ + struct nvme_opcode_string *entry; + + entry = admin_opcode; + + while (entry->opc != 0xFFFF) { + if (entry->opc == opc) + return (entry->str); + entry++; + } + return (entry->str); +} + +static const char * +get_io_opcode_string(uint16_t opc) +{ + struct nvme_opcode_string *entry; + + entry = io_opcode; + + while (entry->opc != 0xFFFF) { + if (entry->opc == opc) + return (entry->str); + entry++; + } + return (entry->str); +} + + +static void +nvme_admin_qpair_print_command(struct nvme_qpair *qpair, + struct nvme_command *cmd) +{ + + nvme_printf(qpair->ctrlr, "%s (%02x) sqid:%d cid:%d nsid:%x " + "cdw10:%08x cdw11:%08x\n", + get_admin_opcode_string(cmd->opc), cmd->opc, qpair->id, cmd->cid, + cmd->nsid, cmd->cdw10, cmd->cdw11); +} + +static void +nvme_io_qpair_print_command(struct nvme_qpair *qpair, + struct nvme_command *cmd) +{ + + switch (cmd->opc) { + case NVME_OPC_WRITE: + case NVME_OPC_READ: + case NVME_OPC_WRITE_UNCORRECTABLE: + case NVME_OPC_COMPARE: + nvme_printf(qpair->ctrlr, "%s sqid:%d cid:%d nsid:%d " + "lba:%lu len:%d\n", + get_io_opcode_string(cmd->opc), qpair->id, cmd->cid, + cmd->nsid, ((uint64_t)cmd->cdw11 << 32) | cmd->cdw10, + (cmd->cdw12 & 0xFFFF) + 1); + break; + case NVME_OPC_FLUSH: + case NVME_OPC_DATASET_MANAGEMENT: + nvme_printf(qpair->ctrlr, "%s sqid:%d cid:%d nsid:%d\n", + get_io_opcode_string(cmd->opc), qpair->id, cmd->cid, + cmd->nsid); + break; + default: + nvme_printf(qpair->ctrlr, "%s (%02x) sqid:%d cid:%d nsid:%d\n", + get_io_opcode_string(cmd->opc), cmd->opc, qpair->id, + cmd->cid, cmd->nsid); + break; + } +} + +static void +nvme_qpair_print_command(struct nvme_qpair *qpair, struct nvme_command *cmd) +{ + if (qpair->id == 0) + nvme_admin_qpair_print_command(qpair, cmd); + else + nvme_io_qpair_print_command(qpair, cmd); +} + +struct nvme_status_string { + + uint16_t sc; + const char * str; +}; + +static struct nvme_status_string generic_status[] = { + { NVME_SC_SUCCESS, "SUCCESS" }, + { NVME_SC_INVALID_OPCODE, "INVALID OPCODE" }, + { NVME_SC_INVALID_FIELD, "INVALID_FIELD" }, + { NVME_SC_COMMAND_ID_CONFLICT, "COMMAND ID CONFLICT" }, + { NVME_SC_DATA_TRANSFER_ERROR, "DATA TRANSFER ERROR" }, + { NVME_SC_ABORTED_POWER_LOSS, "ABORTED - POWER LOSS" }, + { NVME_SC_INTERNAL_DEVICE_ERROR, "INTERNAL DEVICE ERROR" }, + { NVME_SC_ABORTED_BY_REQUEST, "ABORTED - BY REQUEST" }, + { NVME_SC_ABORTED_SQ_DELETION, "ABORTED - SQ DELETION" }, + { NVME_SC_ABORTED_FAILED_FUSED, "ABORTED - FAILED FUSED" }, + { NVME_SC_ABORTED_MISSING_FUSED, "ABORTED - MISSING FUSED" }, + { NVME_SC_INVALID_NAMESPACE_OR_FORMAT, "INVALID NAMESPACE OR FORMAT" }, + { NVME_SC_COMMAND_SEQUENCE_ERROR, "COMMAND SEQUENCE ERROR" }, + { NVME_SC_LBA_OUT_OF_RANGE, "LBA OUT OF RANGE" }, + { NVME_SC_CAPACITY_EXCEEDED, "CAPACITY EXCEEDED" }, + { NVME_SC_NAMESPACE_NOT_READY, "NAMESPACE NOT READY" }, + { 0xFFFF, "GENERIC" } +}; + +static struct nvme_status_string command_specific_status[] = { + { NVME_SC_COMPLETION_QUEUE_INVALID, "INVALID COMPLETION QUEUE" }, + { NVME_SC_INVALID_QUEUE_IDENTIFIER, "INVALID QUEUE IDENTIFIER" }, + { NVME_SC_MAXIMUM_QUEUE_SIZE_EXCEEDED, "MAX QUEUE SIZE EXCEEDED" }, + { NVME_SC_ABORT_COMMAND_LIMIT_EXCEEDED, "ABORT CMD LIMIT EXCEEDED" }, + { NVME_SC_ASYNC_EVENT_REQUEST_LIMIT_EXCEEDED, "ASYNC LIMIT EXCEEDED" }, + { NVME_SC_INVALID_FIRMWARE_SLOT, "INVALID FIRMWARE SLOT" }, + { NVME_SC_INVALID_FIRMWARE_IMAGE, "INVALID FIRMWARE IMAGE" }, + { NVME_SC_INVALID_INTERRUPT_VECTOR, "INVALID INTERRUPT VECTOR" }, + { NVME_SC_INVALID_LOG_PAGE, "INVALID LOG PAGE" }, + { NVME_SC_INVALID_FORMAT, "INVALID FORMAT" }, + { NVME_SC_FIRMWARE_REQUIRES_RESET, "FIRMWARE REQUIRES RESET" }, + { NVME_SC_CONFLICTING_ATTRIBUTES, "CONFLICTING ATTRIBUTES" }, + { NVME_SC_INVALID_PROTECTION_INFO, "INVALID PROTECTION INFO" }, + { NVME_SC_ATTEMPTED_WRITE_TO_RO_PAGE, "WRITE TO RO PAGE" }, + { 0xFFFF, "COMMAND SPECIFIC" } +}; + +static struct nvme_status_string media_error_status[] = { + { NVME_SC_WRITE_FAULTS, "WRITE FAULTS" }, + { NVME_SC_UNRECOVERED_READ_ERROR, "UNRECOVERED READ ERROR" }, + { NVME_SC_GUARD_CHECK_ERROR, "GUARD CHECK ERROR" }, + { NVME_SC_APPLICATION_TAG_CHECK_ERROR, "APPLICATION TAG CHECK ERROR" }, + { NVME_SC_REFERENCE_TAG_CHECK_ERROR, "REFERENCE TAG CHECK ERROR" }, + { NVME_SC_COMPARE_FAILURE, "COMPARE FAILURE" }, + { NVME_SC_ACCESS_DENIED, "ACCESS DENIED" }, + { 0xFFFF, "MEDIA ERROR" } +}; + +static const char * +get_status_string(uint16_t sct, uint16_t sc) +{ + struct nvme_status_string *entry; + + switch (sct) { + case NVME_SCT_GENERIC: + entry = generic_status; + break; + case NVME_SCT_COMMAND_SPECIFIC: + entry = command_specific_status; + break; + case NVME_SCT_MEDIA_ERROR: + entry = media_error_status; + break; + case NVME_SCT_VENDOR_SPECIFIC: + return ("VENDOR SPECIFIC"); + default: + return ("RESERVED"); + } + + while (entry->sc != 0xFFFF) { + if (entry->sc == sc) + return (entry->str); + entry++; + } + return (entry->str); +} + +static void +nvme_qpair_print_completion(struct nvme_qpair *qpair, + struct nvme_completion *cpl) +{ + nvme_printf(qpair->ctrlr, "%s (%02x/%02x) sqid:%d cid:%d cdw0:%x\n", + get_status_string(cpl->status.sct, cpl->status.sc), + cpl->status.sct, cpl->status.sc, cpl->sqid, cpl->cid, cpl->cdw0); +} + static boolean_t nvme_completion_is_retry(const struct nvme_completion *cpl) { @@ -108,8 +317,8 @@ nvme_qpair_complete_tracker(struct nvme_qpair *qpair, struct nvme_tracker *tr, req->retries < nvme_retry_count; if (error && print_on_error) { - nvme_dump_completion(cpl); - nvme_dump_command(&req->cmd); + nvme_qpair_print_command(qpair, &req->cmd); + nvme_qpair_print_completion(qpair, cpl); } qpair->act_tr[cpl->cid] = NULL; @@ -184,8 +393,8 @@ nvme_qpair_manual_complete_request(struct nvme_qpair *qpair, error = nvme_completion_is_error(&cpl); if (error && print_on_error) { - nvme_dump_completion(&cpl); - nvme_dump_command(&req->cmd); + nvme_qpair_print_command(qpair, &req->cmd); + nvme_qpair_print_completion(qpair, &cpl); } if (req->cb_fn) @@ -223,7 +432,8 @@ nvme_qpair_process_completions(struct nvme_qpair *qpair) nvme_qpair_complete_tracker(qpair, tr, cpl, TRUE); qpair->sq_head = cpl->sqhd; } else { - printf("cpl does not map to outstanding cmd\n"); + nvme_printf(qpair->ctrlr, + "cpl does not map to outstanding cmd\n"); nvme_dump_completion(cpl); KASSERT(0, ("received completion for unknown cmd\n")); } @@ -423,7 +633,8 @@ nvme_abort_complete(void *arg, const struct nvme_completion *status) * abort it for some reason. Construct a fake completion * status, and then complete the I/O's tracker manually. */ - printf("abort command failed, aborting command manually\n"); + nvme_printf(tr->qpair->ctrlr, + "abort command failed, aborting command manually\n"); nvme_qpair_manual_complete_tracker(tr->qpair, tr, NVME_SCT_GENERIC, NVME_SC_ABORTED_BY_REQUEST, 0, TRUE); } @@ -597,7 +808,7 @@ nvme_admin_qpair_enable(struct nvme_qpair *qpair) * command was issued no longer applies. */ TAILQ_FOREACH_SAFE(tr, &qpair->outstanding_tr, tailq, tr_temp) { - device_printf(qpair->ctrlr->dev, + nvme_printf(qpair->ctrlr, "aborting outstanding admin command\n"); nvme_qpair_manual_complete_tracker(qpair, tr, NVME_SCT_GENERIC, NVME_SC_ABORTED_BY_REQUEST, 1 /* do not retry */, TRUE); @@ -620,8 +831,7 @@ nvme_io_qpair_enable(struct nvme_qpair *qpair) * reached its limit. */ TAILQ_FOREACH_SAFE(tr, &qpair->outstanding_tr, tailq, tr_temp) { - device_printf(qpair->ctrlr->dev, - "aborting outstanding i/o\n"); + nvme_printf(qpair->ctrlr, "aborting outstanding i/o\n"); nvme_qpair_manual_complete_tracker(qpair, tr, NVME_SCT_GENERIC, NVME_SC_ABORTED_BY_REQUEST, 0, TRUE); } @@ -636,9 +846,8 @@ nvme_io_qpair_enable(struct nvme_qpair *qpair) while (!STAILQ_EMPTY(&temp)) { req = STAILQ_FIRST(&temp); STAILQ_REMOVE_HEAD(&temp, stailq); - device_printf(qpair->ctrlr->dev, - "resubmitting queued i/o\n"); - nvme_dump_command(&req->cmd); + nvme_printf(qpair->ctrlr, "resubmitting queued i/o\n"); + nvme_qpair_print_command(qpair, &req->cmd); _nvme_qpair_submit_request(qpair, req); } @@ -683,8 +892,7 @@ nvme_qpair_fail(struct nvme_qpair *qpair) while (!STAILQ_EMPTY(&qpair->queued_req)) { req = STAILQ_FIRST(&qpair->queued_req); STAILQ_REMOVE_HEAD(&qpair->queued_req, stailq); - device_printf(qpair->ctrlr->dev, - "failing queued i/o\n"); + nvme_printf(qpair->ctrlr, "failing queued i/o\n"); mtx_unlock(&qpair->lock); nvme_qpair_manual_complete_request(qpair, req, NVME_SCT_GENERIC, NVME_SC_ABORTED_BY_REQUEST, TRUE); @@ -698,8 +906,7 @@ nvme_qpair_fail(struct nvme_qpair *qpair) * Do not remove the tracker. The abort_tracker path will * do that for us. */ - device_printf(qpair->ctrlr->dev, - "failing outstanding i/o\n"); + nvme_printf(qpair->ctrlr, "failing outstanding i/o\n"); mtx_unlock(&qpair->lock); nvme_qpair_manual_complete_tracker(qpair, tr, NVME_SCT_GENERIC, NVME_SC_ABORTED_BY_REQUEST, 1 /* do not retry */, TRUE); |