1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (C) 2013 Intel Corporation 5 * Copyright (C) 1997 Justin T. Gibbs 6 * All rights reserved. 7 * 8 * Copyright (c) 2023-2025 Chelsio Communications, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/param.h> 33 #include <sys/sbuf.h> 34 #include <dev/nvme/nvme.h> 35 36 #define OPC_ENTRY(x) [NVME_OPC_ ## x] = #x 37 38 static const char *admin_opcode[256] = { 39 OPC_ENTRY(DELETE_IO_SQ), 40 OPC_ENTRY(CREATE_IO_SQ), 41 OPC_ENTRY(GET_LOG_PAGE), 42 OPC_ENTRY(DELETE_IO_CQ), 43 OPC_ENTRY(CREATE_IO_CQ), 44 OPC_ENTRY(IDENTIFY), 45 OPC_ENTRY(ABORT), 46 OPC_ENTRY(SET_FEATURES), 47 OPC_ENTRY(GET_FEATURES), 48 OPC_ENTRY(ASYNC_EVENT_REQUEST), 49 OPC_ENTRY(NAMESPACE_MANAGEMENT), 50 OPC_ENTRY(FIRMWARE_ACTIVATE), 51 OPC_ENTRY(FIRMWARE_IMAGE_DOWNLOAD), 52 OPC_ENTRY(DEVICE_SELF_TEST), 53 OPC_ENTRY(NAMESPACE_ATTACHMENT), 54 OPC_ENTRY(KEEP_ALIVE), 55 OPC_ENTRY(DIRECTIVE_SEND), 56 OPC_ENTRY(DIRECTIVE_RECEIVE), 57 OPC_ENTRY(VIRTUALIZATION_MANAGEMENT), 58 OPC_ENTRY(NVME_MI_SEND), 59 OPC_ENTRY(NVME_MI_RECEIVE), 60 OPC_ENTRY(CAPACITY_MANAGEMENT), 61 OPC_ENTRY(LOCKDOWN), 62 OPC_ENTRY(DOORBELL_BUFFER_CONFIG), 63 OPC_ENTRY(FABRICS_COMMANDS), 64 OPC_ENTRY(FORMAT_NVM), 65 OPC_ENTRY(SECURITY_SEND), 66 OPC_ENTRY(SECURITY_RECEIVE), 67 OPC_ENTRY(SANITIZE), 68 OPC_ENTRY(GET_LBA_STATUS), 69 }; 70 71 static const char *nvm_opcode[256] = { 72 OPC_ENTRY(FLUSH), 73 OPC_ENTRY(WRITE), 74 OPC_ENTRY(READ), 75 OPC_ENTRY(WRITE_UNCORRECTABLE), 76 OPC_ENTRY(COMPARE), 77 OPC_ENTRY(WRITE_ZEROES), 78 OPC_ENTRY(DATASET_MANAGEMENT), 79 OPC_ENTRY(VERIFY), 80 OPC_ENTRY(RESERVATION_REGISTER), 81 OPC_ENTRY(RESERVATION_REPORT), 82 OPC_ENTRY(RESERVATION_ACQUIRE), 83 OPC_ENTRY(RESERVATION_RELEASE), 84 OPC_ENTRY(COPY), 85 }; 86 87 #define SC_ENTRY(x) [NVME_SC_ ## x] = #x 88 89 static const char *generic_status[256] = { 90 SC_ENTRY(SUCCESS), 91 SC_ENTRY(INVALID_OPCODE), 92 SC_ENTRY(INVALID_FIELD), 93 SC_ENTRY(COMMAND_ID_CONFLICT), 94 SC_ENTRY(DATA_TRANSFER_ERROR), 95 SC_ENTRY(ABORTED_POWER_LOSS), 96 SC_ENTRY(INTERNAL_DEVICE_ERROR), 97 SC_ENTRY(ABORTED_BY_REQUEST), 98 SC_ENTRY(ABORTED_SQ_DELETION), 99 SC_ENTRY(ABORTED_FAILED_FUSED), 100 SC_ENTRY(ABORTED_MISSING_FUSED), 101 SC_ENTRY(INVALID_NAMESPACE_OR_FORMAT), 102 SC_ENTRY(COMMAND_SEQUENCE_ERROR), 103 SC_ENTRY(INVALID_SGL_SEGMENT_DESCR), 104 SC_ENTRY(INVALID_NUMBER_OF_SGL_DESCR), 105 SC_ENTRY(DATA_SGL_LENGTH_INVALID), 106 SC_ENTRY(METADATA_SGL_LENGTH_INVALID), 107 SC_ENTRY(SGL_DESCRIPTOR_TYPE_INVALID), 108 SC_ENTRY(INVALID_USE_OF_CMB), 109 SC_ENTRY(PRP_OFFET_INVALID), 110 SC_ENTRY(ATOMIC_WRITE_UNIT_EXCEEDED), 111 SC_ENTRY(OPERATION_DENIED), 112 SC_ENTRY(SGL_OFFSET_INVALID), 113 SC_ENTRY(HOST_ID_INCONSISTENT_FORMAT), 114 SC_ENTRY(KEEP_ALIVE_TIMEOUT_EXPIRED), 115 SC_ENTRY(KEEP_ALIVE_TIMEOUT_INVALID), 116 SC_ENTRY(ABORTED_DUE_TO_PREEMPT), 117 SC_ENTRY(SANITIZE_FAILED), 118 SC_ENTRY(SANITIZE_IN_PROGRESS), 119 SC_ENTRY(SGL_DATA_BLOCK_GRAN_INVALID), 120 SC_ENTRY(NOT_SUPPORTED_IN_CMB), 121 SC_ENTRY(NAMESPACE_IS_WRITE_PROTECTED), 122 SC_ENTRY(COMMAND_INTERRUPTED), 123 SC_ENTRY(TRANSIENT_TRANSPORT_ERROR), 124 125 SC_ENTRY(LBA_OUT_OF_RANGE), 126 SC_ENTRY(CAPACITY_EXCEEDED), 127 SC_ENTRY(NAMESPACE_NOT_READY), 128 SC_ENTRY(RESERVATION_CONFLICT), 129 SC_ENTRY(FORMAT_IN_PROGRESS), 130 }; 131 132 static const char *command_specific_status[256] = { 133 SC_ENTRY(COMPLETION_QUEUE_INVALID), 134 SC_ENTRY(INVALID_QUEUE_IDENTIFIER), 135 SC_ENTRY(MAXIMUM_QUEUE_SIZE_EXCEEDED), 136 SC_ENTRY(ABORT_COMMAND_LIMIT_EXCEEDED), 137 SC_ENTRY(ASYNC_EVENT_REQUEST_LIMIT_EXCEEDED), 138 SC_ENTRY(INVALID_FIRMWARE_SLOT), 139 SC_ENTRY(INVALID_FIRMWARE_IMAGE), 140 SC_ENTRY(INVALID_INTERRUPT_VECTOR), 141 SC_ENTRY(INVALID_LOG_PAGE), 142 SC_ENTRY(INVALID_FORMAT), 143 SC_ENTRY(FIRMWARE_REQUIRES_RESET), 144 SC_ENTRY(INVALID_QUEUE_DELETION), 145 SC_ENTRY(FEATURE_NOT_SAVEABLE), 146 SC_ENTRY(FEATURE_NOT_CHANGEABLE), 147 SC_ENTRY(FEATURE_NOT_NS_SPECIFIC), 148 SC_ENTRY(FW_ACT_REQUIRES_NVMS_RESET), 149 SC_ENTRY(FW_ACT_REQUIRES_RESET), 150 SC_ENTRY(FW_ACT_REQUIRES_TIME), 151 SC_ENTRY(FW_ACT_PROHIBITED), 152 SC_ENTRY(OVERLAPPING_RANGE), 153 SC_ENTRY(NS_INSUFFICIENT_CAPACITY), 154 SC_ENTRY(NS_ID_UNAVAILABLE), 155 SC_ENTRY(NS_ALREADY_ATTACHED), 156 SC_ENTRY(NS_IS_PRIVATE), 157 SC_ENTRY(NS_NOT_ATTACHED), 158 SC_ENTRY(THIN_PROV_NOT_SUPPORTED), 159 SC_ENTRY(CTRLR_LIST_INVALID), 160 SC_ENTRY(SELF_TEST_IN_PROGRESS), 161 SC_ENTRY(BOOT_PART_WRITE_PROHIB), 162 SC_ENTRY(INVALID_CTRLR_ID), 163 SC_ENTRY(INVALID_SEC_CTRLR_STATE), 164 SC_ENTRY(INVALID_NUM_OF_CTRLR_RESRC), 165 SC_ENTRY(INVALID_RESOURCE_ID), 166 SC_ENTRY(SANITIZE_PROHIBITED_WPMRE), 167 SC_ENTRY(ANA_GROUP_ID_INVALID), 168 SC_ENTRY(ANA_ATTACH_FAILED), 169 170 SC_ENTRY(CONFLICTING_ATTRIBUTES), 171 SC_ENTRY(INVALID_PROTECTION_INFO), 172 SC_ENTRY(ATTEMPTED_WRITE_TO_RO_PAGE), 173 }; 174 175 static const char *media_error_status[256] = { 176 SC_ENTRY(WRITE_FAULTS), 177 SC_ENTRY(UNRECOVERED_READ_ERROR), 178 SC_ENTRY(GUARD_CHECK_ERROR), 179 SC_ENTRY(APPLICATION_TAG_CHECK_ERROR), 180 SC_ENTRY(REFERENCE_TAG_CHECK_ERROR), 181 SC_ENTRY(COMPARE_FAILURE), 182 SC_ENTRY(ACCESS_DENIED), 183 SC_ENTRY(DEALLOCATED_OR_UNWRITTEN), 184 }; 185 186 static const char *path_related_status[256] = { 187 SC_ENTRY(INTERNAL_PATH_ERROR), 188 SC_ENTRY(ASYMMETRIC_ACCESS_PERSISTENT_LOSS), 189 SC_ENTRY(ASYMMETRIC_ACCESS_INACCESSIBLE), 190 SC_ENTRY(ASYMMETRIC_ACCESS_TRANSITION), 191 SC_ENTRY(CONTROLLER_PATHING_ERROR), 192 SC_ENTRY(HOST_PATHING_ERROR), 193 SC_ENTRY(COMMAND_ABORTED_BY_HOST), 194 }; 195 196 void 197 nvme_opcode_sbuf(bool admin, uint8_t opc, struct sbuf *sb) 198 { 199 const char *s, *type; 200 201 if (admin) { 202 s = admin_opcode[opc]; 203 type = "ADMIN"; 204 } else { 205 s = nvm_opcode[opc]; 206 type = "NVM"; 207 } 208 if (s == NULL) 209 sbuf_printf(sb, "%s (%02x)", type, opc); 210 else 211 sbuf_printf(sb, "%s", s); 212 } 213 214 void 215 nvme_sc_sbuf(const struct nvme_completion *cpl, struct sbuf *sb) 216 { 217 const char *s, *type; 218 uint16_t status; 219 220 status = le16toh(cpl->status); 221 switch (NVME_STATUS_GET_SCT(status)) { 222 case NVME_SCT_GENERIC: 223 s = generic_status[NVME_STATUS_GET_SC(status)]; 224 type = "GENERIC"; 225 break; 226 case NVME_SCT_COMMAND_SPECIFIC: 227 s = command_specific_status[NVME_STATUS_GET_SC(status)]; 228 type = "COMMAND SPECIFIC"; 229 break; 230 case NVME_SCT_MEDIA_ERROR: 231 s = media_error_status[NVME_STATUS_GET_SC(status)]; 232 type = "MEDIA ERROR"; 233 break; 234 case NVME_SCT_PATH_RELATED: 235 s = path_related_status[NVME_STATUS_GET_SC(status)]; 236 type = "PATH RELATED"; 237 break; 238 case NVME_SCT_VENDOR_SPECIFIC: 239 s = NULL; 240 type = "VENDOR SPECIFIC"; 241 break; 242 default: 243 s = NULL; 244 type = NULL; 245 break; 246 } 247 248 if (type == NULL) 249 sbuf_printf(sb, "RESERVED (%02x/%02x)", 250 NVME_STATUS_GET_SCT(status), NVME_STATUS_GET_SC(status)); 251 else if (s == NULL) 252 sbuf_printf(sb, "%s (%02x)", type, NVME_STATUS_GET_SC(status)); 253 else 254 sbuf_printf(sb, "%s", s); 255 } 256 257 void 258 nvme_cpl_sbuf(const struct nvme_completion *cpl, struct sbuf *sb) 259 { 260 uint16_t status; 261 262 status = le16toh(cpl->status); 263 nvme_sc_sbuf(cpl, sb); 264 if (NVME_STATUS_GET_M(status) != 0) 265 sbuf_printf(sb, " M"); 266 if (NVME_STATUS_GET_DNR(status) != 0) 267 sbuf_printf(sb, " DNR"); 268 } 269 270 void 271 nvme_strvis(uint8_t *dst, const uint8_t *src, int dstlen, int srclen) 272 { 273 uint8_t *cur_pos; 274 275 /* Trim leading/trailing spaces, nulls. */ 276 while (srclen > 0 && src[0] == ' ') 277 src++, srclen--; 278 while (srclen > 0 279 && (src[srclen - 1] == ' ' || src[srclen - 1] == '\0')) 280 srclen--; 281 282 while (srclen > 0 && dstlen > 1) { 283 cur_pos = dst; 284 285 /* Show '?' for non-printable characters. */ 286 if (*src < 0x20 || *src >= 0x7F) 287 *cur_pos++ = '?'; 288 else 289 *cur_pos++ = *src; 290 src++; 291 srclen--; 292 dstlen -= cur_pos - dst; 293 dst = cur_pos; 294 } 295 *dst = '\0'; 296 } 297