xref: /freebsd/sys/dev/nvme/nvme_util.c (revision 7b3ee39e73af36f49f471f7900baeb98ac3504d0)
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
nvme_opcode_sbuf(bool admin,uint8_t opc,struct sbuf * sb)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
nvme_sc_sbuf(const struct nvme_completion * cpl,struct sbuf * sb)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
nvme_cpl_sbuf(const struct nvme_completion * cpl,struct sbuf * sb)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
nvme_strvis(uint8_t * dst,const uint8_t * src,int dstlen,int srclen)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