From 3fa5467a0641863f5846236136e924a845dfbe7b Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Sun, 11 Mar 2018 05:09:02 +0000 Subject: [PATCH] Add new identify data structures fields from NVMe 1.3a. Some of them are already supported by existing hardware, so reporting them `nvmecontrol identify` can be useful. --- sbin/nvmecontrol/identify.c | 132 ++++++++++++++++++++++++---- sys/dev/nvme/nvme.h | 169 ++++++++++++++++++++++++++++++++++-- 2 files changed, 281 insertions(+), 20 deletions(-) diff --git a/sbin/nvmecontrol/identify.c b/sbin/nvmecontrol/identify.c index aa88a8a2836d..978b91db440f 100644 --- a/sbin/nvmecontrol/identify.c +++ b/sbin/nvmecontrol/identify.c @@ -95,25 +95,35 @@ print_controller(struct nvme_controller_data *cdata) printf("Controller Capabilities/Features\n"); printf("================================\n"); - printf("Vendor ID: %04x\n", cdata->vid); - printf("Subsystem Vendor ID: %04x\n", cdata->ssvid); + printf("Vendor ID: %04x\n", cdata->vid); + printf("Subsystem Vendor ID: %04x\n", cdata->ssvid); nvme_strvis(str, cdata->sn, sizeof(str), NVME_SERIAL_NUMBER_LENGTH); - printf("Serial Number: %s\n", str); + printf("Serial Number: %s\n", str); nvme_strvis(str, cdata->mn, sizeof(str), NVME_MODEL_NUMBER_LENGTH); - printf("Model Number: %s\n", str); + printf("Model Number: %s\n", str); nvme_strvis(str, cdata->fr, sizeof(str), NVME_FIRMWARE_REVISION_LENGTH); - printf("Firmware Version: %s\n", str); - printf("Recommended Arb Burst: %d\n", cdata->rab); - printf("IEEE OUI Identifier: %02x %02x %02x\n", + printf("Firmware Version: %s\n", str); + printf("Recommended Arb Burst: %d\n", cdata->rab); + printf("IEEE OUI Identifier: %02x %02x %02x\n", cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]); - printf("Multi-Interface Cap: %02x\n", cdata->mic); + printf("Multi-Path I/O Capabilities: %s%s%s%s\n", + (cdata->mic == 0) ? "Not Supported" : "", + ((cdata->mic >> NVME_CTRLR_DATA_MIC_SRIOVVF_SHIFT) & + NVME_CTRLR_DATA_MIC_SRIOVVF_MASK) ? "SR-IOV VF, " : "", + ((cdata->mic >> NVME_CTRLR_DATA_MIC_MCTRLRS_SHIFT) & + NVME_CTRLR_DATA_MIC_MCTRLRS_MASK) ? "Multiple controllers, " : "", + ((cdata->mic >> NVME_CTRLR_DATA_MIC_MPORTS_SHIFT) & + NVME_CTRLR_DATA_MIC_MPORTS_MASK) ? "Multiple ports" : ""); /* TODO: Use CAP.MPSMIN to determine true memory page size. */ - printf("Max Data Transfer Size: "); + printf("Max Data Transfer Size: "); if (cdata->mdts == 0) printf("Unlimited\n"); else printf("%d\n", PAGE_SIZE * (1 << cdata->mdts)); - printf("Controller ID: 0x%02x\n", cdata->ctrlr_id); + printf("Controller ID: 0x%02x\n", cdata->ctrlr_id); + printf("Version: %d.%d.%d\n", + (cdata->ver >> 16) & 0xffff, (cdata->ver >> 8) & 0xff, + cdata->ver & 0xff); printf("\n"); printf("Admin Command Set Attributes\n"); @@ -126,6 +136,21 @@ print_controller(struct nvme_controller_data *cdata) fw ? "Supported" : "Not Supported"); printf("Namespace Managment: %s\n", nsmgmt ? "Supported" : "Not Supported"); + printf("Device Self-test: %sSupported\n", + ((oacs >> NVME_CTRLR_DATA_OACS_SELFTEST_SHIFT) & + NVME_CTRLR_DATA_OACS_SELFTEST_MASK) ? "" : "Not "); + printf("Directives: %sSupported\n", + ((oacs >> NVME_CTRLR_DATA_OACS_DIRECTIVES_SHIFT) & + NVME_CTRLR_DATA_OACS_DIRECTIVES_MASK) ? "" : "Not "); + printf("NVMe-MI Send/Receive: %sSupported\n", + ((oacs >> NVME_CTRLR_DATA_OACS_NVMEMI_SHIFT) & + NVME_CTRLR_DATA_OACS_NVMEMI_MASK) ? "" : "Not "); + printf("Virtualization Management: %sSupported\n", + ((oacs >> NVME_CTRLR_DATA_OACS_VM_SHIFT) & + NVME_CTRLR_DATA_OACS_VM_MASK) ? "" : "Not "); + printf("Doorbell Buffer Config %sSupported\n", + ((oacs >> NVME_CTRLR_DATA_OACS_DBBUFFER_SHIFT) & + NVME_CTRLR_DATA_OACS_DBBUFFER_MASK) ? "" : "Not "); printf("Abort Command Limit: %d\n", cdata->acl+1); printf("Async Event Request Limit: %d\n", cdata->aerl+1); printf("Number of Firmware Slots: "); @@ -159,6 +184,18 @@ print_controller(struct nvme_controller_data *cdata) write_unc ? "Supported" : "Not Supported"); printf("Dataset Management Command: %s\n", dsm ? "Supported" : "Not Supported"); + printf("Write Zeroes Command: %sSupported\n", + ((oncs >> NVME_CTRLR_DATA_ONCS_WRZERO_SHIFT) & + NVME_CTRLR_DATA_ONCS_WRZERO_MASK) ? "" : "Not "); + printf("Save Features: %sSupported\n", + ((oncs >> NVME_CTRLR_DATA_ONCS_SAVEFEAT_SHIFT) & + NVME_CTRLR_DATA_ONCS_SAVEFEAT_MASK) ? "" : "Not "); + printf("Reservations: %sSupported\n", + ((oncs >> NVME_CTRLR_DATA_ONCS_RESERV_SHIFT) & + NVME_CTRLR_DATA_ONCS_RESERV_MASK) ? "" : "Not "); + printf("Timestamp feature: %sSupported\n", + ((oncs >> NVME_CTRLR_DATA_ONCS_TIMESTAMP_SHIFT) & + NVME_CTRLR_DATA_ONCS_TIMESTAMP_MASK) ? "" : "Not "); printf("Volatile Write Cache: %s\n", vwc_present ? "Present" : "Not Present"); @@ -177,8 +214,8 @@ static void print_namespace(struct nvme_namespace_data *nsdata) { uint32_t i; - uint32_t lbaf, lbads, ms; - uint8_t thin_prov; + uint32_t lbaf, lbads, ms, rp; + uint8_t thin_prov, ptype; uint8_t flbas_fmt; thin_prov = (nsdata->nsfeat >> NVME_NS_DATA_NSFEAT_THIN_PROV_SHIFT) & @@ -200,14 +237,79 @@ print_namespace(struct nvme_namespace_data *nsdata) thin_prov ? "Supported" : "Not Supported"); printf("Number of LBA Formats: %d\n", nsdata->nlbaf+1); printf("Current LBA Format: LBA Format #%02d\n", flbas_fmt); + printf("Data Protection Caps: %s%s%s%s%s%s\n", + (nsdata->dpc == 0) ? "Not Supported" : "", + ((nsdata->dpc >> NVME_NS_DATA_DPC_MD_END_SHIFT) & + NVME_NS_DATA_DPC_MD_END_MASK) ? "Last Bytes, " : "", + ((nsdata->dpc >> NVME_NS_DATA_DPC_MD_START_SHIFT) & + NVME_NS_DATA_DPC_MD_START_MASK) ? "First Bytes, " : "", + ((nsdata->dpc >> NVME_NS_DATA_DPC_PIT3_SHIFT) & + NVME_NS_DATA_DPC_PIT3_MASK) ? "Type 3, " : "", + ((nsdata->dpc >> NVME_NS_DATA_DPC_PIT2_SHIFT) & + NVME_NS_DATA_DPC_PIT2_MASK) ? "Type 2, " : "", + ((nsdata->dpc >> NVME_NS_DATA_DPC_PIT2_MASK) & + NVME_NS_DATA_DPC_PIT1_MASK) ? "Type 1" : ""); + printf("Data Protection Settings: "); + ptype = (nsdata->dps >> NVME_NS_DATA_DPS_PIT_SHIFT) & + NVME_NS_DATA_DPS_PIT_MASK; + if (ptype) { + printf("Type %d, %s Bytes\n", ptype, + ((nsdata->dps >> NVME_NS_DATA_DPS_MD_START_SHIFT) & + NVME_NS_DATA_DPS_MD_START_MASK) ? "First" : "Last"); + } else { + printf("Not Enabled\n"); + } + printf("Multi-Path I/O Capabilities: %s%s\n", + (nsdata->nmic == 0) ? "Not Supported" : "", + ((nsdata->nmic >> NVME_NS_DATA_NMIC_MAY_BE_SHARED_SHIFT) & + NVME_NS_DATA_NMIC_MAY_BE_SHARED_MASK) ? "May be shared" : ""); + printf("Reservation Capabilities: %s%s%s%s%s%s%s%s%s\n", + (nsdata->rescap == 0) ? "Not Supported" : "", + ((nsdata->rescap >> NVME_NS_DATA_RESCAP_IEKEY13_SHIFT) & + NVME_NS_DATA_RESCAP_IEKEY13_MASK) ? "IEKEY13, " : "", + ((nsdata->rescap >> NVME_NS_DATA_RESCAP_EX_AC_AR_SHIFT) & + NVME_NS_DATA_RESCAP_EX_AC_AR_MASK) ? "EX_AC_AR, " : "", + ((nsdata->rescap >> NVME_NS_DATA_RESCAP_WR_EX_AR_SHIFT) & + NVME_NS_DATA_RESCAP_WR_EX_AR_MASK) ? "WR_EX_AR, " : "", + ((nsdata->rescap >> NVME_NS_DATA_RESCAP_EX_AC_RO_SHIFT) & + NVME_NS_DATA_RESCAP_EX_AC_RO_MASK) ? "EX_AC_RO, " : "", + ((nsdata->rescap >> NVME_NS_DATA_RESCAP_WR_EX_RO_SHIFT) & + NVME_NS_DATA_RESCAP_WR_EX_RO_MASK) ? "WR_EX_RO, " : "", + ((nsdata->rescap >> NVME_NS_DATA_RESCAP_EX_AC_SHIFT) & + NVME_NS_DATA_RESCAP_EX_AC_MASK) ? "EX_AC, " : "", + ((nsdata->rescap >> NVME_NS_DATA_RESCAP_WR_EX_SHIFT) & + NVME_NS_DATA_RESCAP_WR_EX_MASK) ? "WR_EX, " : "", + ((nsdata->rescap >> NVME_NS_DATA_RESCAP_PTPL_SHIFT) & + NVME_NS_DATA_RESCAP_PTPL_MASK) ? "PTPL" : ""); + printf("Format Progress Indicator: "); + if ((nsdata->fpi >> NVME_NS_DATA_FPI_SUPP_SHIFT) & + NVME_NS_DATA_FPI_SUPP_MASK) { + printf("%u%% remains\n", + (nsdata->fpi >> NVME_NS_DATA_FPI_PERC_SHIFT) & + NVME_NS_DATA_FPI_PERC_MASK); + } else + printf("Not Supported\n"); + printf("Optimal I/O Boundary (LBAs): %u\n", nsdata->noiob); + printf("Globally Unique Identifier: "); + for (i = 0; i < sizeof(nsdata->nguid); i++) + printf("%02x", nsdata->nguid[i]); + printf("\n"); + printf("IEEE EUI64: "); + for (i = 0; i < sizeof(nsdata->eui64); i++) + printf("%02x", nsdata->eui64[i]); + printf("\n"); for (i = 0; i <= nsdata->nlbaf; i++) { lbaf = nsdata->lbaf[i]; lbads = (lbaf >> NVME_NS_DATA_LBAF_LBADS_SHIFT) & NVME_NS_DATA_LBAF_LBADS_MASK; ms = (lbaf >> NVME_NS_DATA_LBAF_MS_SHIFT) & NVME_NS_DATA_LBAF_MS_MASK; - printf("LBA Format #%02d: Data Size: %5d Metadata Size: %5d\n", - i, 1 << lbads, ms); + rp = (lbaf >> NVME_NS_DATA_LBAF_RP_SHIFT) & + NVME_NS_DATA_LBAF_RP_MASK; + printf("LBA Format #%02d: Data Size: %5d Metadata Size: %5d" + " Performance: %s\n", + i, 1 << lbads, ms, (rp == 0) ? "Best" : + (rp == 1) ? "Better" : (rp == 2) ? "Good" : "Degraded"); } } @@ -252,7 +354,7 @@ identify_ctrlr(int argc, char *argv[]) hexlength = sizeof(struct nvme_controller_data); else hexlength = offsetof(struct nvme_controller_data, - reserved5); + reserved8); print_hex(&cdata, hexlength); exit(0); } diff --git a/sys/dev/nvme/nvme.h b/sys/dev/nvme/nvme.h index 5c0f6241ac4a..15147c542e6f 100644 --- a/sys/dev/nvme/nvme.h +++ b/sys/dev/nvme/nvme.h @@ -153,6 +153,17 @@ #define NVME_PWR_ST_APS_SHIFT (6) #define NVME_PWR_ST_APS_MASK (0x3) +/** Controller Multi-path I/O and Namespace Sharing Capabilities */ +/* More then one port */ +#define NVME_CTRLR_DATA_MIC_MPORTS_SHIFT (0) +#define NVME_CTRLR_DATA_MIC_MPORTS_MASK (0x1) +/* More then one controller */ +#define NVME_CTRLR_DATA_MIC_MCTRLRS_SHIFT (1) +#define NVME_CTRLR_DATA_MIC_MCTRLRS_MASK (0x1) +/* SR-IOV Virtual Function */ +#define NVME_CTRLR_DATA_MIC_SRIOVVF_SHIFT (2) +#define NVME_CTRLR_DATA_MIC_SRIOVVF_MASK (0x1) + /** OACS - optional admin command support */ /* supports security send/receive commands */ #define NVME_CTRLR_DATA_OACS_SECURITY_SHIFT (0) @@ -166,6 +177,21 @@ /* supports namespace management commands */ #define NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT (3) #define NVME_CTRLR_DATA_OACS_NSMGMT_MASK (0x1) +/* supports Device Self-test command */ +#define NVME_CTRLR_DATA_OACS_SELFTEST_SHIFT (4) +#define NVME_CTRLR_DATA_OACS_SELFTEST_MASK (0x1) +/* supports Directives */ +#define NVME_CTRLR_DATA_OACS_DIRECTIVES_SHIFT (5) +#define NVME_CTRLR_DATA_OACS_DIRECTIVES_MASK (0x1) +/* supports NVMe-MI Send/Receive */ +#define NVME_CTRLR_DATA_OACS_NVMEMI_SHIFT (6) +#define NVME_CTRLR_DATA_OACS_NVMEMI_MASK (0x1) +/* supports Virtualization Management */ +#define NVME_CTRLR_DATA_OACS_VM_SHIFT (7) +#define NVME_CTRLR_DATA_OACS_VM_MASK (0x1) +/* supports Doorbell Buffer Config */ +#define NVME_CTRLR_DATA_OACS_DBBUFFER_SHIFT (8) +#define NVME_CTRLR_DATA_OACS_DBBUFFER_MASK (0x1) /** firmware updates */ /* first slot is read-only */ @@ -209,6 +235,14 @@ #define NVME_CTRLR_DATA_ONCS_WRITE_UNC_MASK (0x1) #define NVME_CTRLR_DATA_ONCS_DSM_SHIFT (2) #define NVME_CTRLR_DATA_ONCS_DSM_MASK (0x1) +#define NVME_CTRLR_DATA_ONCS_WRZERO_SHIFT (3) +#define NVME_CTRLR_DATA_ONCS_WRZERO_MASK (0x1) +#define NVME_CTRLR_DATA_ONCS_SAVEFEAT_SHIFT (4) +#define NVME_CTRLR_DATA_ONCS_SAVEFEAT_MASK (0x1) +#define NVME_CTRLR_DATA_ONCS_RESERV_SHIFT (5) +#define NVME_CTRLR_DATA_ONCS_RESERV_MASK (0x1) +#define NVME_CTRLR_DATA_ONCS_TIMESTAMP_SHIFT (6) +#define NVME_CTRLR_DATA_ONCS_TIMESTAMP_MASK (0x1) /** volatile write cache */ #define NVME_CTRLR_DATA_VWC_PRESENT_SHIFT (0) @@ -218,6 +252,15 @@ /* thin provisioning */ #define NVME_NS_DATA_NSFEAT_THIN_PROV_SHIFT (0) #define NVME_NS_DATA_NSFEAT_THIN_PROV_MASK (0x1) +/* NAWUN, NAWUPF, and NACWU fields are valid */ +#define NVME_NS_DATA_NSFEAT_NA_FIELDS_SHIFT (1) +#define NVME_NS_DATA_NSFEAT_NA_FIELDS_MASK (0x1) +/* Deallocated or Unwritten Logical Block errors supported */ +#define NVME_NS_DATA_NSFEAT_DEALLOC_SHIFT (2) +#define NVME_NS_DATA_NSFEAT_DEALLOC_MASK (0x1) +/* NGUID and EUI64 fields are not reusable */ +#define NVME_NS_DATA_NSFEAT_NO_ID_REUSE_SHIFT (3) +#define NVME_NS_DATA_NSFEAT_NO_ID_REUSE_MASK (0x1) /** formatted lba size */ #define NVME_NS_DATA_FLBAS_FORMAT_SHIFT (0) @@ -259,6 +302,45 @@ #define NVME_NS_DATA_DPS_MD_START_SHIFT (3) #define NVME_NS_DATA_DPS_MD_START_MASK (0x1) +/** Namespace Multi-path I/O and Namespace Sharing Capabilities */ +/* the namespace may be attached to two or more controllers */ +#define NVME_NS_DATA_NMIC_MAY_BE_SHARED_SHIFT (0) +#define NVME_NS_DATA_NMIC_MAY_BE_SHARED_MASK (0x1) + +/** Reservation Capabilities */ +/* Persist Through Power Loss */ +#define NVME_NS_DATA_RESCAP_PTPL_SHIFT (0) +#define NVME_NS_DATA_RESCAP_PTPL_MASK (0x1) +/* supports the Write Exclusive */ +#define NVME_NS_DATA_RESCAP_WR_EX_SHIFT (1) +#define NVME_NS_DATA_RESCAP_WR_EX_MASK (0x1) +/* supports the Exclusive Access */ +#define NVME_NS_DATA_RESCAP_EX_AC_SHIFT (2) +#define NVME_NS_DATA_RESCAP_EX_AC_MASK (0x1) +/* supports the Write Exclusive – Registrants Only */ +#define NVME_NS_DATA_RESCAP_WR_EX_RO_SHIFT (3) +#define NVME_NS_DATA_RESCAP_WR_EX_RO_MASK (0x1) +/* supports the Exclusive Access - Registrants Only */ +#define NVME_NS_DATA_RESCAP_EX_AC_RO_SHIFT (4) +#define NVME_NS_DATA_RESCAP_EX_AC_RO_MASK (0x1) +/* supports the Write Exclusive – All Registrants */ +#define NVME_NS_DATA_RESCAP_WR_EX_AR_SHIFT (5) +#define NVME_NS_DATA_RESCAP_WR_EX_AR_MASK (0x1) +/* supports the Exclusive Access - All Registrants */ +#define NVME_NS_DATA_RESCAP_EX_AC_AR_SHIFT (6) +#define NVME_NS_DATA_RESCAP_EX_AC_AR_MASK (0x1) +/* Ignore Existing Key is used as defined in revision 1.3 or later */ +#define NVME_NS_DATA_RESCAP_IEKEY13_SHIFT (7) +#define NVME_NS_DATA_RESCAP_IEKEY13_MASK (0x1) + +/** Format Progress Indicator */ +/* percentage of the Format NVM command that remains to be completed */ +#define NVME_NS_DATA_FPI_PERC_SHIFT (0) +#define NVME_NS_DATA_FPI_PERC_MASK (0x7f) +/* namespace supports the Format Progress Indicator */ +#define NVME_NS_DATA_FPI_SUPP_SHIFT (7) +#define NVME_NS_DATA_FPI_SUPP_MASK (0x1) + /** lba format support */ /* metadata size */ #define NVME_NS_DATA_LBAF_MS_SHIFT (0) @@ -719,11 +801,34 @@ struct nvme_controller_data { /** volatile write cache */ uint8_t vwc; - /* TODO: flesh out remaining nvm command set attributes */ - uint8_t reserved5[178]; + /** Atomic Write Unit Normal */ + uint16_t awun; - /* bytes 704-2047: i/o command set attributes */ - uint8_t reserved6[1344]; + /** Atomic Write Unit Power Fail */ + uint16_t awupf; + + /** NVM Vendor Specific Command Configuration */ + uint8_t nvscc; + uint8_t reserved5; + + /** Atomic Compare & Write Unit */ + uint16_t acwu; + uint16_t reserved6; + + /** SGL Support */ + uint32_t sgls; + + /* bytes 540-767: Reserved */ + uint8_t reserved7[228]; + + /** NVM Subsystem NVMe Qualified Name */ + uint8_t subnqn[256]; + + /* bytes 1024-1791: Reserved */ + uint8_t reserved8[768]; + + /* bytes 1792-2047: NVMe over Fabrics specification */ + uint8_t reserved9[256]; /* bytes 2048-3071: power state descriptors */ struct nvme_power_state power_state[32]; @@ -763,7 +868,50 @@ struct nvme_namespace_data { /** end-to-end data protection type settings */ uint8_t dps; - uint8_t reserved5[98]; + /** Namespace Multi-path I/O and Namespace Sharing Capabilities */ + uint8_t nmic; + + /** Reservation Capabilities */ + uint8_t rescap; + + /** Format Progress Indicator */ + uint8_t fpi; + + /** Deallocate Logical Block Features */ + uint8_t dlfeat; + + /** Namespace Atomic Write Unit Normal */ + uint16_t nawun; + + /** Namespace Atomic Write Unit Power Fail */ + uint16_t nawupf; + + /** Namespace Atomic Compare & Write Unit */ + uint16_t nacwu; + + /** Namespace Atomic Boundary Size Normal */ + uint16_t nabsn; + + /** Namespace Atomic Boundary Offset */ + uint16_t nabo; + + /** Namespace Atomic Boundary Size Power Fail */ + uint16_t nabspf; + + /** Namespace Optimal IO Boundary */ + uint16_t noiob; + + /** NVM Capacity */ + uint8_t nvmcap[16]; + + /* bytes 64-103: Reserved */ + uint8_t reserved5[40]; + + /** Namespace Globally Unique Identifier */ + uint8_t nguid[16]; + + /** IEEE Extended Unique Identifier */ + uint8_t eui64[8]; /** lba format support */ uint32_t lbaf[16]; @@ -1154,6 +1302,10 @@ void nvme_controller_data_swapbytes(struct nvme_controller_data *s) s->nn = le32toh(s->nn); s->oncs = le16toh(s->oncs); s->fuses = le16toh(s->fuses); + s->awun = le16toh(s->awun); + s->awupf = le16toh(s->awupf); + s->acwu = le16toh(s->acwu); + s->sgls = le32toh(s->sgls); for (i = 0; i < 32; i++) nvme_power_state_swapbytes(&s->power_state[i]); } @@ -1166,6 +1318,13 @@ void nvme_namespace_data_swapbytes(struct nvme_namespace_data *s) s->nsze = le64toh(s->nsze); s->ncap = le64toh(s->ncap); s->nuse = le64toh(s->nuse); + s->nawun = le16toh(s->nawun); + s->nawupf = le16toh(s->nawupf); + s->nacwu = le16toh(s->nacwu); + s->nabsn = le16toh(s->nabsn); + s->nabo = le16toh(s->nabo); + s->nabspf = le16toh(s->nabspf); + s->noiob = le16toh(s->noiob); for (i = 0; i < 16; i++) s->lbaf[i] = le32toh(s->lbaf[i]); }