| /* |
| * Copyright (c) 2022 Intel Corporation |
| * SPDX-License-Identifier: Apache-2.0 |
| * |
| * Derived from FreeBSD original driver made by Jim Harris |
| * with contributions from Alexander Motin and Wojciech Macek |
| */ |
| |
| #ifndef ZEPHYR_DRIVERS_DISK_NVME_NVME_COMMAND_H_ |
| #define ZEPHYR_DRIVERS_DISK_NVME_NVME_COMMAND_H_ |
| |
| #include <zephyr/sys/slist.h> |
| #include <zephyr/sys/byteorder.h> |
| |
| struct nvme_command { |
| /* dword 0 */ |
| struct _cdw0 { |
| uint8_t opc; /* opcode */ |
| uint8_t fuse : 2; /* fused operation */ |
| uint8_t rsvd : 4; /* reserved */ |
| uint8_t psdt : 2; /* PRP or SGL for Data Transfer */ |
| uint16_t cid; /* command identifier */ |
| } cdw0; |
| |
| /* dword 1 */ |
| uint32_t nsid; /* namespace identifier */ |
| |
| /* dword 2-3 */ |
| uint32_t cdw2; |
| uint32_t cdw3; |
| |
| /* dword 4-5 */ |
| uint64_t mptr; /* metadata pointer */ |
| |
| /* dword 6-7 and 8-9 */ |
| struct _dptr { |
| uint64_t prp1; /* prp entry 1 */ |
| uint64_t prp2; /* prp entry 2 */ |
| } dptr; /* data pointer */ |
| |
| /* dword 10 */ |
| union { |
| uint32_t cdw10; /* command-specific */ |
| uint32_t ndt; /* Number of Dwords in Data transfer */ |
| }; |
| |
| /* dword 11 */ |
| union { |
| uint32_t cdw11; /* command-specific */ |
| uint32_t ndm; /* Number of Dwords in Metadata transfer */ |
| }; |
| |
| /* dword 12-15 */ |
| uint32_t cdw12; /* command-specific */ |
| uint32_t cdw13; /* command-specific */ |
| uint32_t cdw14; /* command-specific */ |
| uint32_t cdw15; /* command-specific */ |
| }; |
| |
| struct nvme_completion { |
| /* dword 0 */ |
| uint32_t cdw0; /* command-specific */ |
| |
| /* dword 1 */ |
| uint32_t rsvd; |
| |
| /* dword 2 */ |
| uint16_t sqhd; /* submission queue head pointer */ |
| uint16_t sqid; /* submission queue identifier */ |
| |
| /* dword 3 */ |
| uint16_t cid; /* command identifier */ |
| uint16_t status; |
| } __aligned(8); |
| |
| struct nvme_completion_poll_status { |
| int status; |
| struct nvme_completion cpl; |
| struct k_sem sem; |
| }; |
| |
| /* status code types */ |
| enum nvme_status_code_type { |
| NVME_SCT_GENERIC = 0x0, |
| NVME_SCT_COMMAND_SPECIFIC = 0x1, |
| NVME_SCT_MEDIA_ERROR = 0x2, |
| NVME_SCT_PATH_RELATED = 0x3, |
| /* 0x3-0x6 - reserved */ |
| NVME_SCT_VENDOR_SPECIFIC = 0x7, |
| }; |
| |
| /* generic command status codes */ |
| enum nvme_generic_command_status_code { |
| NVME_SC_SUCCESS = 0x00, |
| NVME_SC_INVALID_OPCODE = 0x01, |
| NVME_SC_INVALID_FIELD = 0x02, |
| NVME_SC_COMMAND_ID_CONFLICT = 0x03, |
| NVME_SC_DATA_TRANSFER_ERROR = 0x04, |
| NVME_SC_ABORTED_POWER_LOSS = 0x05, |
| NVME_SC_INTERNAL_DEVICE_ERROR = 0x06, |
| NVME_SC_ABORTED_BY_REQUEST = 0x07, |
| NVME_SC_ABORTED_SQ_DELETION = 0x08, |
| NVME_SC_ABORTED_FAILED_FUSED = 0x09, |
| NVME_SC_ABORTED_MISSING_FUSED = 0x0a, |
| NVME_SC_INVALID_NAMESPACE_OR_FORMAT = 0x0b, |
| NVME_SC_COMMAND_SEQUENCE_ERROR = 0x0c, |
| NVME_SC_INVALID_SGL_SEGMENT_DESCR = 0x0d, |
| NVME_SC_INVALID_NUMBER_OF_SGL_DESCR = 0x0e, |
| NVME_SC_DATA_SGL_LENGTH_INVALID = 0x0f, |
| NVME_SC_METADATA_SGL_LENGTH_INVALID = 0x10, |
| NVME_SC_SGL_DESCRIPTOR_TYPE_INVALID = 0x11, |
| NVME_SC_INVALID_USE_OF_CMB = 0x12, |
| NVME_SC_PRP_OFFSET_INVALID = 0x13, |
| NVME_SC_ATOMIC_WRITE_UNIT_EXCEEDED = 0x14, |
| NVME_SC_OPERATION_DENIED = 0x15, |
| NVME_SC_SGL_OFFSET_INVALID = 0x16, |
| /* 0x17 - reserved */ |
| NVME_SC_HOST_ID_INCONSISTENT_FORMAT = 0x18, |
| NVME_SC_KEEP_ALIVE_TIMEOUT_EXPIRED = 0x19, |
| NVME_SC_KEEP_ALIVE_TIMEOUT_INVALID = 0x1a, |
| NVME_SC_ABORTED_DUE_TO_PREEMPT = 0x1b, |
| NVME_SC_SANITIZE_FAILED = 0x1c, |
| NVME_SC_SANITIZE_IN_PROGRESS = 0x1d, |
| NVME_SC_SGL_DATA_BLOCK_GRAN_INVALID = 0x1e, |
| NVME_SC_NOT_SUPPORTED_IN_CMB = 0x1f, |
| NVME_SC_NAMESPACE_IS_WRITE_PROTECTED = 0x20, |
| NVME_SC_COMMAND_INTERRUPTED = 0x21, |
| NVME_SC_TRANSIENT_TRANSPORT_ERROR = 0x22, |
| |
| NVME_SC_LBA_OUT_OF_RANGE = 0x80, |
| NVME_SC_CAPACITY_EXCEEDED = 0x81, |
| NVME_SC_NAMESPACE_NOT_READY = 0x82, |
| NVME_SC_RESERVATION_CONFLICT = 0x83, |
| NVME_SC_FORMAT_IN_PROGRESS = 0x84, |
| }; |
| |
| /* command specific status codes */ |
| enum nvme_command_specific_status_code { |
| NVME_SC_COMPLETION_QUEUE_INVALID = 0x00, |
| NVME_SC_INVALID_QUEUE_IDENTIFIER = 0x01, |
| NVME_SC_MAXIMUM_QUEUE_SIZE_EXCEEDED = 0x02, |
| NVME_SC_ABORT_COMMAND_LIMIT_EXCEEDED = 0x03, |
| /* 0x04 - reserved */ |
| NVME_SC_ASYNC_EVENT_REQUEST_LIMIT_EXCEEDED = 0x05, |
| NVME_SC_INVALID_FIRMWARE_SLOT = 0x06, |
| NVME_SC_INVALID_FIRMWARE_IMAGE = 0x07, |
| NVME_SC_INVALID_INTERRUPT_VECTOR = 0x08, |
| NVME_SC_INVALID_LOG_PAGE = 0x09, |
| NVME_SC_INVALID_FORMAT = 0x0a, |
| NVME_SC_FIRMWARE_REQUIRES_RESET = 0x0b, |
| NVME_SC_INVALID_QUEUE_DELETION = 0x0c, |
| NVME_SC_FEATURE_NOT_SAVEABLE = 0x0d, |
| NVME_SC_FEATURE_NOT_CHANGEABLE = 0x0e, |
| NVME_SC_FEATURE_NOT_NS_SPECIFIC = 0x0f, |
| NVME_SC_FW_ACT_REQUIRES_NVMS_RESET = 0x10, |
| NVME_SC_FW_ACT_REQUIRES_RESET = 0x11, |
| NVME_SC_FW_ACT_REQUIRES_TIME = 0x12, |
| NVME_SC_FW_ACT_PROHIBITED = 0x13, |
| NVME_SC_OVERLAPPING_RANGE = 0x14, |
| NVME_SC_NS_INSUFFICIENT_CAPACITY = 0x15, |
| NVME_SC_NS_ID_UNAVAILABLE = 0x16, |
| /* 0x17 - reserved */ |
| NVME_SC_NS_ALREADY_ATTACHED = 0x18, |
| NVME_SC_NS_IS_PRIVATE = 0x19, |
| NVME_SC_NS_NOT_ATTACHED = 0x1a, |
| NVME_SC_THIN_PROV_NOT_SUPPORTED = 0x1b, |
| NVME_SC_CTRLR_LIST_INVALID = 0x1c, |
| NVME_SC_SELF_TEST_IN_PROGRESS = 0x1d, |
| NVME_SC_BOOT_PART_WRITE_PROHIB = 0x1e, |
| NVME_SC_INVALID_CTRLR_ID = 0x1f, |
| NVME_SC_INVALID_SEC_CTRLR_STATE = 0x20, |
| NVME_SC_INVALID_NUM_OF_CTRLR_RESRC = 0x21, |
| NVME_SC_INVALID_RESOURCE_ID = 0x22, |
| NVME_SC_SANITIZE_PROHIBITED_WPMRE = 0x23, |
| NVME_SC_ANA_GROUP_ID_INVALID = 0x24, |
| NVME_SC_ANA_ATTACH_FAILED = 0x25, |
| |
| NVME_SC_CONFLICTING_ATTRIBUTES = 0x80, |
| NVME_SC_INVALID_PROTECTION_INFO = 0x81, |
| NVME_SC_ATTEMPTED_WRITE_TO_RO_PAGE = 0x82, |
| }; |
| |
| /* media error status codes */ |
| enum nvme_media_error_status_code { |
| NVME_SC_WRITE_FAULTS = 0x80, |
| NVME_SC_UNRECOVERED_READ_ERROR = 0x81, |
| NVME_SC_GUARD_CHECK_ERROR = 0x82, |
| NVME_SC_APPLICATION_TAG_CHECK_ERROR = 0x83, |
| NVME_SC_REFERENCE_TAG_CHECK_ERROR = 0x84, |
| NVME_SC_COMPARE_FAILURE = 0x85, |
| NVME_SC_ACCESS_DENIED = 0x86, |
| NVME_SC_DEALLOCATED_OR_UNWRITTEN = 0x87, |
| }; |
| |
| /* path related status codes */ |
| enum nvme_path_related_status_code { |
| NVME_SC_INTERNAL_PATH_ERROR = 0x00, |
| NVME_SC_ASYMMETRIC_ACCESS_PERSISTENT_LOSS = 0x01, |
| NVME_SC_ASYMMETRIC_ACCESS_INACCESSIBLE = 0x02, |
| NVME_SC_ASYMMETRIC_ACCESS_TRANSITION = 0x03, |
| NVME_SC_CONTROLLER_PATHING_ERROR = 0x60, |
| NVME_SC_HOST_PATHING_ERROR = 0x70, |
| NVME_SC_COMMAND_ABORTED_BY_HOST = 0x71, |
| }; |
| |
| /* admin opcodes */ |
| enum nvme_admin_opcode { |
| NVME_OPC_DELETE_IO_SQ = 0x00, |
| NVME_OPC_CREATE_IO_SQ = 0x01, |
| NVME_OPC_GET_LOG_PAGE = 0x02, |
| /* 0x03 - reserved */ |
| NVME_OPC_DELETE_IO_CQ = 0x04, |
| NVME_OPC_CREATE_IO_CQ = 0x05, |
| NVME_OPC_IDENTIFY = 0x06, |
| /* 0x07 - reserved */ |
| NVME_OPC_ABORT = 0x08, |
| NVME_OPC_SET_FEATURES = 0x09, |
| NVME_OPC_GET_FEATURES = 0x0a, |
| /* 0x0b - reserved */ |
| NVME_OPC_ASYNC_EVENT_REQUEST = 0x0c, |
| NVME_OPC_NAMESPACE_MANAGEMENT = 0x0d, |
| /* 0x0e-0x0f - reserved */ |
| NVME_OPC_FIRMWARE_ACTIVATE = 0x10, |
| NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD = 0x11, |
| /* 0x12-0x13 - reserved */ |
| NVME_OPC_DEVICE_SELF_TEST = 0x14, |
| NVME_OPC_NAMESPACE_ATTACHMENT = 0x15, |
| /* 0x16-0x17 - reserved */ |
| NVME_OPC_KEEP_ALIVE = 0x18, |
| NVME_OPC_DIRECTIVE_SEND = 0x19, |
| NVME_OPC_DIRECTIVE_RECEIVE = 0x1a, |
| /* 0x1b - reserved */ |
| NVME_OPC_VIRTUALIZATION_MANAGEMENT = 0x1c, |
| NVME_OPC_NVME_MI_SEND = 0x1d, |
| NVME_OPC_NVME_MI_RECEIVE = 0x1e, |
| /* 0x1f-0x7b - reserved */ |
| NVME_OPC_DOORBELL_BUFFER_CONFIG = 0x7c, |
| |
| NVME_OPC_FORMAT_NVM = 0x80, |
| NVME_OPC_SECURITY_SEND = 0x81, |
| NVME_OPC_SECURITY_RECEIVE = 0x82, |
| /* 0x83 - reserved */ |
| NVME_OPC_SANITIZE = 0x84, |
| /* 0x85 - reserved */ |
| NVME_OPC_GET_LBA_STATUS = 0x86, |
| }; |
| |
| /* nvme nvm opcodes */ |
| enum nvme_nvm_opcode { |
| NVME_OPC_FLUSH = 0x00, |
| NVME_OPC_WRITE = 0x01, |
| NVME_OPC_READ = 0x02, |
| /* 0x03 - reserved */ |
| NVME_OPC_WRITE_UNCORRECTABLE = 0x04, |
| NVME_OPC_COMPARE = 0x05, |
| /* 0x06-0x07 - reserved */ |
| NVME_OPC_WRITE_ZEROES = 0x08, |
| NVME_OPC_DATASET_MANAGEMENT = 0x09, |
| /* 0x0a-0x0b - reserved */ |
| NVME_OPC_VERIFY = 0x0c, |
| NVME_OPC_RESERVATION_REGISTER = 0x0d, |
| NVME_OPC_RESERVATION_REPORT = 0x0e, |
| /* 0x0f-0x10 - reserved */ |
| NVME_OPC_RESERVATION_ACQUIRE = 0x11, |
| /* 0x12-0x14 - reserved */ |
| NVME_OPC_RESERVATION_RELEASE = 0x15, |
| }; |
| |
| enum nvme_feature { |
| /* 0x00 - reserved */ |
| NVME_FEAT_ARBITRATION = 0x01, |
| NVME_FEAT_POWER_MANAGEMENT = 0x02, |
| NVME_FEAT_LBA_RANGE_TYPE = 0x03, |
| NVME_FEAT_TEMPERATURE_THRESHOLD = 0x04, |
| NVME_FEAT_ERROR_RECOVERY = 0x05, |
| NVME_FEAT_VOLATILE_WRITE_CACHE = 0x06, |
| NVME_FEAT_NUMBER_OF_QUEUES = 0x07, |
| NVME_FEAT_INTERRUPT_COALESCING = 0x08, |
| NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION = 0x09, |
| NVME_FEAT_WRITE_ATOMICITY = 0x0A, |
| NVME_FEAT_ASYNC_EVENT_CONFIGURATION = 0x0B, |
| NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION = 0x0C, |
| NVME_FEAT_HOST_MEMORY_BUFFER = 0x0D, |
| NVME_FEAT_TIMESTAMP = 0x0E, |
| NVME_FEAT_KEEP_ALIVE_TIMER = 0x0F, |
| NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT = 0x10, |
| NVME_FEAT_NON_OP_POWER_STATE_CONFIG = 0x11, |
| NVME_FEAT_READ_RECOVERY_LEVEL_CONFIG = 0x12, |
| NVME_FEAT_PREDICTABLE_LATENCY_MODE_CONFIG = 0x13, |
| NVME_FEAT_PREDICTABLE_LATENCY_MODE_WINDOW = 0x14, |
| NVME_FEAT_LBA_STATUS_INFORMATION_ATTRIBUTES = 0x15, |
| NVME_FEAT_HOST_BEHAVIOR_SUPPORT = 0x16, |
| NVME_FEAT_SANITIZE_CONFIG = 0x17, |
| NVME_FEAT_ENDURANCE_GROUP_EVENT_CONFIGURATION = 0x18, |
| /* 0x19-0x77 - reserved */ |
| /* 0x78-0x7f - NVMe Management Interface */ |
| NVME_FEAT_SOFTWARE_PROGRESS_MARKER = 0x80, |
| NVME_FEAT_HOST_IDENTIFIER = 0x81, |
| NVME_FEAT_RESERVATION_NOTIFICATION_MASK = 0x82, |
| NVME_FEAT_RESERVATION_PERSISTENCE = 0x83, |
| NVME_FEAT_NAMESPACE_WRITE_PROTECTION_CONFIG = 0x84, |
| /* 0x85-0xBF - command set specific (reserved) */ |
| /* 0xC0-0xFF - vendor specific */ |
| }; |
| |
| #if !defined(CONFIG_DCACHE_LINE_SIZE) || (CONFIG_DCACHE_LINE_SIZE == 0) |
| #define CACHE_LINE_SIZE (64) |
| #else |
| #define CACHE_LINE_SIZE CONFIG_DCACHE_LINE_SIZE |
| #endif |
| |
| #define NVME_PBAO_MASK (CONFIG_MMU_PAGE_SIZE - 1) |
| |
| #define NVME_PRP_NEXT_PAGE(_addr) \ |
| ((_addr & ~NVME_PBAO_MASK) + CONFIG_MMU_PAGE_SIZE) |
| |
| struct nvme_prp_list { |
| uintptr_t prp[CONFIG_MMU_PAGE_SIZE / sizeof(uintptr_t)] |
| __aligned(CONFIG_MMU_PAGE_SIZE); |
| sys_dnode_t node; |
| }; |
| |
| struct nvme_cmd_qpair { |
| struct nvme_controller *ctrlr; |
| uint32_t id; |
| |
| uint32_t num_entries; |
| |
| uint32_t sq_tdbl_off; |
| uint32_t cq_hdbl_off; |
| |
| uint32_t phase; |
| uint32_t sq_head; |
| uint32_t sq_tail; |
| uint32_t cq_head; |
| |
| int64_t num_cmds; |
| int64_t num_intr_handler_calls; |
| int64_t num_retries; |
| int64_t num_failures; |
| int64_t num_ignored; |
| |
| struct nvme_command *cmd; |
| struct nvme_completion *cpl; |
| |
| uintptr_t cmd_bus_addr; |
| uintptr_t cpl_bus_addr; |
| |
| uint16_t vector; |
| } __aligned(CACHE_LINE_SIZE); |
| |
| typedef void (*nvme_cb_fn_t)(void *, const struct nvme_completion *); |
| |
| enum nvme_request_type { |
| NVME_REQUEST_NULL = 1, |
| NVME_REQUEST_VADDR = 2, |
| }; |
| |
| struct nvme_request { |
| struct nvme_command cmd; |
| struct nvme_cmd_qpair *qpair; |
| |
| uint32_t type; |
| uint32_t req_start; |
| int32_t retries; |
| |
| void *payload; |
| uint32_t payload_size; |
| nvme_cb_fn_t cb_fn; |
| void *cb_arg; |
| |
| struct nvme_prp_list *prp_list; |
| |
| sys_dnode_t node; |
| }; |
| |
| void nvme_cmd_init(void); |
| |
| void nvme_completion_poll_cb(void *arg, const struct nvme_completion *cpl); |
| |
| #ifdef CONFIG_NVME_LOG_LEVEL_DBG |
| void nvme_completion_print(const struct nvme_completion *cpl); |
| #else |
| #define nvme_completion_print(...) |
| #endif /* CONFIG_NVME_LOG_LEVEL_DBG */ |
| |
| void nvme_cmd_request_free(struct nvme_request *request); |
| |
| struct nvme_request *nvme_cmd_request_alloc(void); |
| |
| int nvme_cmd_qpair_setup(struct nvme_cmd_qpair *qpair, |
| struct nvme_controller *ctrlr, |
| uint32_t id); |
| |
| void nvme_cmd_qpair_reset(struct nvme_cmd_qpair *qpair); |
| |
| int nvme_cmd_qpair_submit_request(struct nvme_cmd_qpair *qpair, |
| struct nvme_request *request); |
| |
| int nvme_cmd_identify_controller(struct nvme_controller *ctrlr, |
| void *payload, |
| nvme_cb_fn_t cb_fn, |
| void *cb_arg); |
| |
| int nvme_ctrlr_cmd_identify_controller(struct nvme_controller *ctrlr, |
| nvme_cb_fn_t cb_fn, void *cb_arg); |
| |
| int nvme_ctrlr_cmd_identify_namespace(struct nvme_controller *ctrlr, |
| uint32_t nsid, void *payload, |
| nvme_cb_fn_t cb_fn, void *cb_arg); |
| |
| int nvme_ctrlr_cmd_create_io_cq(struct nvme_controller *ctrlr, |
| struct nvme_cmd_qpair *io_queue, |
| nvme_cb_fn_t cb_fn, void *cb_arg); |
| |
| int nvme_ctrlr_cmd_create_io_sq(struct nvme_controller *ctrlr, |
| struct nvme_cmd_qpair *io_queue, |
| nvme_cb_fn_t cb_fn, void *cb_arg); |
| |
| int nvme_ctrlr_cmd_delete_io_cq(struct nvme_controller *ctrlr, |
| struct nvme_cmd_qpair *io_queue, |
| nvme_cb_fn_t cb_fn, void *cb_arg); |
| |
| int nvme_ctrlr_cmd_delete_io_sq(struct nvme_controller *ctrlr, |
| struct nvme_cmd_qpair *io_queue, |
| nvme_cb_fn_t cb_fn, void *cb_arg); |
| |
| int nvme_ctrlr_cmd_set_feature(struct nvme_controller *ctrlr, |
| uint8_t feature, uint32_t cdw11, |
| uint32_t cdw12, uint32_t cdw13, |
| uint32_t cdw14, uint32_t cdw15, |
| void *payload, uint32_t payload_size, |
| nvme_cb_fn_t cb_fn, void *cb_arg); |
| |
| int nvme_ctrlr_cmd_get_feature(struct nvme_controller *ctrlr, |
| uint8_t feature, uint32_t cdw11, |
| void *payload, uint32_t payload_size, |
| nvme_cb_fn_t cb_fn, void *cb_arg); |
| |
| int nvme_ctrlr_cmd_set_num_queues(struct nvme_controller *ctrlr, |
| uint32_t num_queues, |
| nvme_cb_fn_t cb_fn, void *cb_arg); |
| |
| static inline |
| struct nvme_request *nvme_allocate_request(nvme_cb_fn_t cb_fn, void *cb_arg) |
| { |
| struct nvme_request *request; |
| |
| request = nvme_cmd_request_alloc(); |
| if (request != NULL) { |
| request->cb_fn = cb_fn; |
| request->cb_arg = cb_arg; |
| } |
| |
| return request; |
| } |
| |
| static inline |
| struct nvme_request *nvme_allocate_request_vaddr(void *payload, |
| uint32_t payload_size, |
| nvme_cb_fn_t cb_fn, |
| void *cb_arg) |
| { |
| struct nvme_request *request; |
| |
| request = nvme_allocate_request(cb_fn, cb_arg); |
| if (request != NULL) { |
| request->type = NVME_REQUEST_VADDR; |
| request->payload = payload; |
| request->payload_size = payload_size; |
| } |
| |
| return request; |
| } |
| |
| |
| static inline |
| struct nvme_request *nvme_allocate_request_null(nvme_cb_fn_t cb_fn, |
| void *cb_arg) |
| { |
| struct nvme_request *request; |
| |
| request = nvme_allocate_request(cb_fn, cb_arg); |
| if (request != NULL) { |
| request->type = NVME_REQUEST_NULL; |
| } |
| |
| return request; |
| } |
| |
| /* |
| * Command building helper functions |
| * These functions assume allocator zeros out cmd structure |
| */ |
| static inline |
| void nvme_namespace_flush_cmd(struct nvme_command *cmd, uint32_t nsid) |
| { |
| cmd->cdw0.opc = NVME_OPC_FLUSH; |
| cmd->nsid = sys_cpu_to_le32(nsid); |
| } |
| |
| static inline |
| void nvme_namespace_rw_cmd(struct nvme_command *cmd, uint32_t rwcmd, |
| uint32_t nsid, uint64_t lba, uint32_t count) |
| { |
| cmd->cdw0.opc = rwcmd; |
| cmd->nsid = sys_cpu_to_le32(nsid); |
| cmd->cdw10 = sys_cpu_to_le32(lba & 0xffffffffu); |
| cmd->cdw11 = sys_cpu_to_le32(lba >> 32); |
| cmd->cdw12 = sys_cpu_to_le32(count-1); |
| } |
| |
| static inline |
| void nvme_namespace_write_cmd(struct nvme_command *cmd, uint32_t nsid, |
| uint64_t lba, uint32_t count) |
| { |
| nvme_namespace_rw_cmd(cmd, NVME_OPC_WRITE, nsid, lba, count); |
| } |
| |
| static inline |
| void nvme_namespace_read_cmd(struct nvme_command *cmd, uint32_t nsid, |
| uint64_t lba, uint32_t count) |
| { |
| nvme_namespace_rw_cmd(cmd, NVME_OPC_READ, nsid, lba, count); |
| } |
| |
| static inline void nvme_completion_swapbytes(struct nvme_completion *cpl) |
| { |
| #if _BYTE_ORDER != _LITTLE_ENDIAN |
| cpl->cdw0 = sys_le32_to_cpu(cpl->cdw0); |
| /* omit rsvd1 */ |
| cpl->sqhd = sys_le16_to_cpu(cpl->sqhd); |
| cpl->sqid = sys_le16_to_cpu(cpl->sqid); |
| /* omit cid */ |
| cpl->status = sys_le16_to_cpu(s->status); |
| #else |
| ARG_UNUSED(cpl); |
| #endif |
| } |
| |
| static inline |
| void nvme_completion_poll(struct nvme_completion_poll_status *status) |
| { |
| k_sem_take(&status->sem, K_FOREVER); |
| } |
| |
| #define NVME_CPL_STATUS_POLL_INIT(cpl_status) \ |
| { \ |
| .status = 0, \ |
| .sem = Z_SEM_INITIALIZER(cpl_status.sem, 0, 1), \ |
| } |
| |
| static inline |
| void nvme_cpl_status_poll_init(struct nvme_completion_poll_status *status) |
| { |
| status->status = 0; |
| k_sem_init(&status->sem, 0, 1); |
| } |
| |
| #define nvme_completion_is_error(cpl) \ |
| ((NVME_STATUS_GET_SC((cpl)->status) != 0) | \ |
| (NVME_STATUS_GET_SCT((cpl)->status) != 0)) |
| |
| static inline |
| bool nvme_cpl_status_is_error(struct nvme_completion_poll_status *status) |
| { |
| return ((status->status != 0) || |
| nvme_completion_is_error(&status->cpl)); |
| } |
| |
| #endif /* ZEPHYR_DRIVERS_DISK_NVME_NVME_COMMAND_H_ */ |