Skip to content

Commit a12f1dd

Browse files
authored
Merge pull request #502 from CodeConstruct/pr/mi-status
Add encoding for MI/NVMe status values
2 parents b483bbd + 6cd5403 commit a12f1dd

5 files changed

Lines changed: 127 additions & 7 deletions

File tree

src/libnvme-mi.map

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ LIBNVME_MI_1_2 {
88
nvme_mi_admin_sanitize_nvm;
99
nvme_mi_admin_fw_download;
1010
nvme_mi_admin_fw_commit;
11+
nvme_mi_status_to_string;
1112
};
1213

1314
LIBNVME_MI_1_1 {

src/nvme/mi.c

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <stdlib.h>
1212
#include <stdio.h>
1313

14+
#include <ccan/array_size/array_size.h>
1415
#include <ccan/endian/endian.h>
1516

1617
#include "log.h"
@@ -315,13 +316,12 @@ static int nvme_mi_admin_parse_status(struct nvme_mi_resp *resp, __u32 *result)
315316
resp_hdr = (struct nvme_mi_msg_resp *)resp->hdr;
316317

317318
/* If we have a MI error, we can't be sure there's an admin header
318-
* following; return just the MI status
319-
*
320-
* TODO: this may alias the cdw3 result values, see
321-
* https://github.com/linux-nvme/libnvme/issues/456
319+
* following; return just the MI status, with the status type
320+
* indicator of MI.
322321
*/
323322
if (resp_hdr->status)
324-
return resp_hdr->status;
323+
return resp_hdr->status |
324+
(NVME_STATUS_TYPE_MI << NVME_STATUS_TYPE_SHIFT);
325325

326326
/* We shouldn't hit this, as we'd have an error reported earlier.
327327
* However, for pointer safety, ensure we have a full admin header
@@ -1283,3 +1283,37 @@ nvme_mi_ctrl_t nvme_mi_next_ctrl(nvme_mi_ep_t ep, nvme_mi_ctrl_t c)
12831283
{
12841284
return c ? list_next(&ep->controllers, c, ep_entry) : NULL;
12851285
}
1286+
1287+
1288+
static const char *const mi_status[] = {
1289+
[NVME_MI_RESP_MPR] = "More Processing Required: The command message is in progress and requires more time to complete processing",
1290+
[NVME_MI_RESP_INTERNAL_ERR] = "Internal Error: The request message could not be processed due to a vendor-specific error",
1291+
[NVME_MI_RESP_INVALID_OPCODE] = "Invalid Command Opcode",
1292+
[NVME_MI_RESP_INVALID_PARAM] = "Invalid Parameter",
1293+
[NVME_MI_RESP_INVALID_CMD_SIZE] = "Invalid Command Size: The size of the message body of the request was different than expected",
1294+
[NVME_MI_RESP_INVALID_INPUT_SIZE] = "Invalid Command Input Data Size: The command requires data and contains too much or too little data",
1295+
[NVME_MI_RESP_ACCESS_DENIED] = "Access Denied. Processing prohibited due to a vendor-specific mechanism of the Command and Feature lockdown function",
1296+
[NVME_MI_RESP_VPD_UPDATES_EXCEEDED] = "VPD Updates Exceeded",
1297+
[NVME_MI_RESP_PCIE_INACCESSIBLE] = "PCIe Inaccessible. The PCIe functionality is not available at this time",
1298+
[NVME_MI_RESP_MEB_SANITIZED] = "Management Endpoint Buffer Cleared Due to Sanitize",
1299+
[NVME_MI_RESP_ENC_SERV_FAILURE] = "Enclosure Services Failure",
1300+
[NVME_MI_RESP_ENC_SERV_XFER_FAILURE] = "Enclosure Services Transfer Failure: Communication with the Enclosure Services Process has failed",
1301+
[NVME_MI_RESP_ENC_FAILURE] = "An unrecoverable enclosure failure has been detected by the Enclosuer Services Process",
1302+
[NVME_MI_RESP_ENC_XFER_REFUSED] = "Enclosure Services Transfer Refused: The NVM Subsystem or Enclosure Services Process indicated an error or an invalid format in communication",
1303+
[NVME_MI_RESP_ENC_FUNC_UNSUP] = "Unsupported Enclosure Function: An SES Send command has been attempted to a simple Subenclosure",
1304+
[NVME_MI_RESP_ENC_SERV_UNAVAIL] = "Enclosure Services Unavailable: The NVM Subsystem or Enclosure Services Process has encountered an error but may become available again",
1305+
[NVME_MI_RESP_ENC_DEGRADED] = "Enclosure Degraded: A noncritical failure has been detected by the Enclosure Services Process",
1306+
[NVME_MI_RESP_SANITIZE_IN_PROGRESS] = "Sanitize In Progress: The requested command is prohibited while a sanitize operation is in progress",
1307+
};
1308+
1309+
/* kept in mi.c while we have a split libnvme/libnvme-mi; consider moving
1310+
* to utils.c (with nvme_status_to_string) if we ever merge. */
1311+
const char *nvme_mi_status_to_string(int status)
1312+
{
1313+
const char *s = "Unknown status";
1314+
1315+
if (status < ARRAY_SIZE(mi_status) && mi_status[status])
1316+
s = mi_status[status];
1317+
1318+
return s;
1319+
}

src/nvme/mi.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,20 @@ struct nvme_mi_admin_resp_hdr {
367367
__le32 cdw0, cdw1, cdw3;
368368
} __attribute__((packed));
369369

370+
/**
371+
* nvme_mi_status_to_string() - return a string representation of the MI
372+
* status.
373+
* @status: MI response status
374+
*
375+
* Gives a string description of @status, as per section 4.1.2 of the NVMe-MI
376+
* spec. The status value should be of type NVME_STATUS_MI, and extracted
377+
* from the return value using nvme_status_get_value().
378+
*
379+
* Returned string is const, and should not be free()ed.
380+
*
381+
* Returns: A string representing the status value
382+
*/
383+
const char *nvme_mi_status_to_string(int status);
370384

371385
/**
372386
* nvme_mi_create_root() - Create top-level MI (root) handle.

src/nvme/types.h

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6141,6 +6141,75 @@ static inline __u16 nvme_status_code(__u16 status_field)
61416141
return NVME_GET(status_field, SC);
61426142
}
61436143

6144+
/**
6145+
* enum nvme_status_type - type encoding for NVMe return values, when
6146+
* represented as an int.
6147+
*
6148+
* The nvme_* api returns an int, with negative values indicating an internal
6149+
* or syscall error, zero signifying success, positive values representing
6150+
* the NVMe status.
6151+
*
6152+
* That latter case (the NVMe status) may represent status values from
6153+
* different parts of the transport/controller/etc, and are at most 16 bits of
6154+
* data. So, we use the most-significant 3 bits of the signed int to indicate
6155+
* which type of status this is.
6156+
*
6157+
* @NVME_STATUS_TYPE_SHIFT: shift value for status bits
6158+
* @NVME_STATUS_TYPE_MASK: mask value for status bits
6159+
*
6160+
* @NVME_STATUS_TYPE_NVME: NVMe command status value, typically from CDW3
6161+
* @NVME_STATUS_TYPE_MI: NVMe-MI header status
6162+
*/
6163+
enum nvme_status_type {
6164+
NVME_STATUS_TYPE_SHIFT = 27,
6165+
NVME_STATUS_TYPE_MASK = 0x7,
6166+
6167+
NVME_STATUS_TYPE_NVME = 0,
6168+
NVME_STATUS_TYPE_MI = 1,
6169+
};
6170+
6171+
/**
6172+
* nvme_status_get_type() - extract the type from a nvme_* return value
6173+
* @status: the (non-negative) return value from the NVMe API
6174+
*
6175+
* Returns: the type component of the status.
6176+
*/
6177+
static inline __u32 nvme_status_get_type(int status)
6178+
{
6179+
return NVME_GET(status, STATUS_TYPE);
6180+
}
6181+
6182+
/**
6183+
* nvme_status_get_value() - extract the status value from a nvme_* return
6184+
* value
6185+
* @status: the (non-negative) return value from the NVMe API
6186+
*
6187+
* Returns: the value component of the status; the set of values will depend
6188+
* on the status type.
6189+
*/
6190+
static inline __u32 nvme_status_get_value(int status)
6191+
{
6192+
return status & ~(NVME_STATUS_TYPE_MASK << NVME_STATUS_TYPE_SHIFT);
6193+
}
6194+
6195+
/**
6196+
* nvme_status_equals() - helper to check a status against a type and value
6197+
* @status: the (non-negative) return value from the NVMe API
6198+
* @type: the status type
6199+
* @value: the status value
6200+
*
6201+
* Returns: true if @status is of the specified type and value
6202+
*/
6203+
static inline __u32 nvme_status_equals(int status, enum nvme_status_type type,
6204+
unsigned int value)
6205+
{
6206+
if (status < 0)
6207+
return false;
6208+
6209+
return nvme_status_get_type(status) == type &&
6210+
nvme_status_get_value(status) == value;
6211+
}
6212+
61446213
/**
61456214
* enum nvme_admin_opcode - Known NVMe admin opcodes
61466215
* @nvme_admin_delete_sq: Delete I/O Submission Queue

test/mi-mctp.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,8 @@ static void test_admin_resp_err(nvme_mi_ep_t ep, struct test_peer *peer)
308308
peer->tx_buf_len = 8;
309309

310310
rc = nvme_mi_admin_identify_ctrl(ctrl, &id);
311-
assert(rc == 0x2);
311+
assert(nvme_status_get_type(rc) == NVME_STATUS_TYPE_MI);
312+
assert(nvme_status_get_value(rc) == NVME_MI_RESP_INTERNAL_ERR);
312313
}
313314

314315
/* test: all 4-byte aligned response sizes - should be decoded into the
@@ -332,7 +333,8 @@ static void test_admin_resp_sizes(nvme_mi_ep_t ep, struct test_peer *peer)
332333
for (i = 8; i <= 4096 + 8; i+=4) {
333334
peer->tx_buf_len = i;
334335
rc = nvme_mi_admin_identify_ctrl(ctrl, &id);
335-
assert(rc == 2);
336+
assert(nvme_status_get_type(rc) == NVME_STATUS_TYPE_MI);
337+
assert(nvme_status_get_value(rc) == NVME_MI_RESP_INTERNAL_ERR);
336338
}
337339

338340
nvme_mi_close_ctrl(ctrl);

0 commit comments

Comments
 (0)