1*ecee5a1fSHans Rosenfeld /* 2*ecee5a1fSHans Rosenfeld * This file and its contents are supplied under the terms of the 3*ecee5a1fSHans Rosenfeld * Common Development and Distribution License ("CDDL"), version 1.0. 4*ecee5a1fSHans Rosenfeld * You may only use this file in accordance with the terms of version 5*ecee5a1fSHans Rosenfeld * 1.0 of the CDDL. 6*ecee5a1fSHans Rosenfeld * 7*ecee5a1fSHans Rosenfeld * A full copy of the text of the CDDL should have accompanied this 8*ecee5a1fSHans Rosenfeld * source. A copy of the CDDL is also available via the Internet at 9*ecee5a1fSHans Rosenfeld * http://www.illumos.org/license/CDDL. 10*ecee5a1fSHans Rosenfeld */ 11*ecee5a1fSHans Rosenfeld 12*ecee5a1fSHans Rosenfeld /* 13*ecee5a1fSHans Rosenfeld * Copyright 2016 Nexenta Systems, Inc. 14*ecee5a1fSHans Rosenfeld */ 15*ecee5a1fSHans Rosenfeld 16*ecee5a1fSHans Rosenfeld /* 17*ecee5a1fSHans Rosenfeld * functions for printing of NVMe data structures and their members 18*ecee5a1fSHans Rosenfeld */ 19*ecee5a1fSHans Rosenfeld 20*ecee5a1fSHans Rosenfeld #include <sys/byteorder.h> 21*ecee5a1fSHans Rosenfeld #include <sys/types.h> 22*ecee5a1fSHans Rosenfeld #include <inttypes.h> 23*ecee5a1fSHans Rosenfeld #include <stdio.h> 24*ecee5a1fSHans Rosenfeld #include <stdlib.h> 25*ecee5a1fSHans Rosenfeld #include <strings.h> 26*ecee5a1fSHans Rosenfeld #include <stdarg.h> 27*ecee5a1fSHans Rosenfeld #include <err.h> 28*ecee5a1fSHans Rosenfeld #include <assert.h> 29*ecee5a1fSHans Rosenfeld 30*ecee5a1fSHans Rosenfeld #include "nvmeadm.h" 31*ecee5a1fSHans Rosenfeld 32*ecee5a1fSHans Rosenfeld static int nvme_strlen(const char *, int); 33*ecee5a1fSHans Rosenfeld 34*ecee5a1fSHans Rosenfeld static void nvme_print_str(int, char *, int, const char *, int); 35*ecee5a1fSHans Rosenfeld static void nvme_print_double(int, char *, double, int, char *); 36*ecee5a1fSHans Rosenfeld static void nvme_print_uint64(int, char *, uint64_t, const char *, char *); 37*ecee5a1fSHans Rosenfeld static void nvme_print_uint128(int, char *, nvme_uint128_t, char *, int, int); 38*ecee5a1fSHans Rosenfeld static void nvme_print_bit(int, char *, int, char *, char *); 39*ecee5a1fSHans Rosenfeld 40*ecee5a1fSHans Rosenfeld #define ARRAYSIZE(x) (sizeof (x) / sizeof (*(x))) 41*ecee5a1fSHans Rosenfeld 42*ecee5a1fSHans Rosenfeld static const char *generic_status_codes[] = { 43*ecee5a1fSHans Rosenfeld "Successful Completion", 44*ecee5a1fSHans Rosenfeld "Invalid Command Opcode", 45*ecee5a1fSHans Rosenfeld "Invalid Field in Command", 46*ecee5a1fSHans Rosenfeld "Command ID Conflict", 47*ecee5a1fSHans Rosenfeld "Data Transfer Error", 48*ecee5a1fSHans Rosenfeld "Commands Aborted due to Power Loss Notification", 49*ecee5a1fSHans Rosenfeld "Internal Error", 50*ecee5a1fSHans Rosenfeld "Command Abort Requested", 51*ecee5a1fSHans Rosenfeld "Command Aborted due to SQ Deletion", 52*ecee5a1fSHans Rosenfeld "Command Aborted due to Failed Fused Command", 53*ecee5a1fSHans Rosenfeld "Command Aborted due to Missing Fused Command", 54*ecee5a1fSHans Rosenfeld "Invalid Namespace or Format", 55*ecee5a1fSHans Rosenfeld "Command Sequence Error", 56*ecee5a1fSHans Rosenfeld /* NVMe 1.1 */ 57*ecee5a1fSHans Rosenfeld "Invalid SGL Segment Descriptor", 58*ecee5a1fSHans Rosenfeld "Invalid Number of SGL Descriptors", 59*ecee5a1fSHans Rosenfeld "Data SGL Length Invalid", 60*ecee5a1fSHans Rosenfeld "Metadata SGL Length Invalid", 61*ecee5a1fSHans Rosenfeld "SGL Descriptor Type Invalid", 62*ecee5a1fSHans Rosenfeld /* NVMe 1.2 */ 63*ecee5a1fSHans Rosenfeld "Invalid Use of Controller Memory Buffer", 64*ecee5a1fSHans Rosenfeld "PRP Offset Invalid", 65*ecee5a1fSHans Rosenfeld "Atomic Write Unit Exceeded" 66*ecee5a1fSHans Rosenfeld }; 67*ecee5a1fSHans Rosenfeld 68*ecee5a1fSHans Rosenfeld static const char *specific_status_codes[] = { 69*ecee5a1fSHans Rosenfeld "Completion Queue Invalid", 70*ecee5a1fSHans Rosenfeld "Invalid Queue Identifier", 71*ecee5a1fSHans Rosenfeld "Invalid Queue Size", 72*ecee5a1fSHans Rosenfeld "Abort Command Limit Exceeded", 73*ecee5a1fSHans Rosenfeld "Reserved", 74*ecee5a1fSHans Rosenfeld "Asynchronous Event Request Limit Exceeded", 75*ecee5a1fSHans Rosenfeld "Invalid Firmware Slot", 76*ecee5a1fSHans Rosenfeld "Invalid Firmware Image", 77*ecee5a1fSHans Rosenfeld "Invalid Interrupt Vector", 78*ecee5a1fSHans Rosenfeld "Invalid Log Page", 79*ecee5a1fSHans Rosenfeld "Invalid Format", 80*ecee5a1fSHans Rosenfeld "Firmware Activation Requires Conventional Reset", 81*ecee5a1fSHans Rosenfeld "Invalid Queue Deletion", 82*ecee5a1fSHans Rosenfeld /* NVMe 1.1 */ 83*ecee5a1fSHans Rosenfeld "Feature Identifier Not Saveable", 84*ecee5a1fSHans Rosenfeld "Feature Not Changeable", 85*ecee5a1fSHans Rosenfeld "Feature Not Namespace Specific", 86*ecee5a1fSHans Rosenfeld "Firmware Activation Requires NVM Subsystem Reset", 87*ecee5a1fSHans Rosenfeld /* NVMe 1.2 */ 88*ecee5a1fSHans Rosenfeld "Firmware Activation Requires Reset", 89*ecee5a1fSHans Rosenfeld "Firmware Activation Requires Maximum Time Violation", 90*ecee5a1fSHans Rosenfeld "Firmware Activation Prohibited", 91*ecee5a1fSHans Rosenfeld "Overlapping Range", 92*ecee5a1fSHans Rosenfeld "Namespace Insufficient Capacity", 93*ecee5a1fSHans Rosenfeld "Namespace Identifier Unavailable", 94*ecee5a1fSHans Rosenfeld "Reserved", 95*ecee5a1fSHans Rosenfeld "Namespace Already Attached", 96*ecee5a1fSHans Rosenfeld "Namespace Is Private", 97*ecee5a1fSHans Rosenfeld "Namespace Not Attached", 98*ecee5a1fSHans Rosenfeld "Thin Provisioning Not Supported", 99*ecee5a1fSHans Rosenfeld "Controller List Invalid" 100*ecee5a1fSHans Rosenfeld }; 101*ecee5a1fSHans Rosenfeld 102*ecee5a1fSHans Rosenfeld static const char *generic_nvm_status_codes[] = { 103*ecee5a1fSHans Rosenfeld "LBA Out Of Range", 104*ecee5a1fSHans Rosenfeld "Capacity Exceeded", 105*ecee5a1fSHans Rosenfeld "Namespace Not Ready", 106*ecee5a1fSHans Rosenfeld /* NVMe 1.1 */ 107*ecee5a1fSHans Rosenfeld "Reservation Conflict", 108*ecee5a1fSHans Rosenfeld /* NVMe 1.2 */ 109*ecee5a1fSHans Rosenfeld "Format In Progress", 110*ecee5a1fSHans Rosenfeld }; 111*ecee5a1fSHans Rosenfeld 112*ecee5a1fSHans Rosenfeld static const char *specific_nvm_status_codes[] = { 113*ecee5a1fSHans Rosenfeld "Conflicting Attributes", 114*ecee5a1fSHans Rosenfeld "Invalid Protection Information", 115*ecee5a1fSHans Rosenfeld "Attempted Write to Read Only Range" 116*ecee5a1fSHans Rosenfeld }; 117*ecee5a1fSHans Rosenfeld 118*ecee5a1fSHans Rosenfeld static const char *media_nvm_status_codes[] = { 119*ecee5a1fSHans Rosenfeld "Write Fault", 120*ecee5a1fSHans Rosenfeld "Unrecovered Read Error", 121*ecee5a1fSHans Rosenfeld "End-to-End Guard Check Error", 122*ecee5a1fSHans Rosenfeld "End-to-End Application Tag Check Error", 123*ecee5a1fSHans Rosenfeld "End-to-End Reference Tag Check Error", 124*ecee5a1fSHans Rosenfeld "Compare Failure", 125*ecee5a1fSHans Rosenfeld "Access Denied", 126*ecee5a1fSHans Rosenfeld /* NVMe 1.2 */ 127*ecee5a1fSHans Rosenfeld "Deallocated or Unwritten Logical Block" 128*ecee5a1fSHans Rosenfeld }; 129*ecee5a1fSHans Rosenfeld 130*ecee5a1fSHans Rosenfeld static const char *status_code_types[] = { 131*ecee5a1fSHans Rosenfeld "Generic Command Status", 132*ecee5a1fSHans Rosenfeld "Command Specific Status", 133*ecee5a1fSHans Rosenfeld "Media Errors", 134*ecee5a1fSHans Rosenfeld "Reserved", 135*ecee5a1fSHans Rosenfeld "Reserved", 136*ecee5a1fSHans Rosenfeld "Reserved", 137*ecee5a1fSHans Rosenfeld "Reserved", 138*ecee5a1fSHans Rosenfeld "Vendor Specific" 139*ecee5a1fSHans Rosenfeld }; 140*ecee5a1fSHans Rosenfeld 141*ecee5a1fSHans Rosenfeld static const char *lbaf_relative_performance[] = { 142*ecee5a1fSHans Rosenfeld "Best", "Better", "Good", "Degraded" 143*ecee5a1fSHans Rosenfeld }; 144*ecee5a1fSHans Rosenfeld 145*ecee5a1fSHans Rosenfeld static const char *lba_range_types[] = { 146*ecee5a1fSHans Rosenfeld "Reserved", "Filesystem", "RAID", "Cache", "Page/Swap File" 147*ecee5a1fSHans Rosenfeld }; 148*ecee5a1fSHans Rosenfeld 149*ecee5a1fSHans Rosenfeld /* 150*ecee5a1fSHans Rosenfeld * nvme_print 151*ecee5a1fSHans Rosenfeld * 152*ecee5a1fSHans Rosenfeld * This function prints a string indented by the specified number of spaces, 153*ecee5a1fSHans Rosenfeld * optionally followed by the specified index if it is >= 0. If a format string 154*ecee5a1fSHans Rosenfeld * is specified, a single colon and the required number of spaces for alignment 155*ecee5a1fSHans Rosenfeld * are printed before the format string and any remaining arguments are passed 156*ecee5a1fSHans Rosenfeld * vprintf. 157*ecee5a1fSHans Rosenfeld * 158*ecee5a1fSHans Rosenfeld * NVME_PRINT_ALIGN was chosen so that all values will be lined up nicely even 159*ecee5a1fSHans Rosenfeld * for the longest name at its default indentation. 160*ecee5a1fSHans Rosenfeld */ 161*ecee5a1fSHans Rosenfeld 162*ecee5a1fSHans Rosenfeld #define NVME_PRINT_ALIGN 43 163*ecee5a1fSHans Rosenfeld 164*ecee5a1fSHans Rosenfeld void 165*ecee5a1fSHans Rosenfeld nvme_print(int indent, char *name, int index, const char *fmt, ...) 166*ecee5a1fSHans Rosenfeld { 167*ecee5a1fSHans Rosenfeld int align = NVME_PRINT_ALIGN - (indent + strlen(name) + 1); 168*ecee5a1fSHans Rosenfeld va_list ap; 169*ecee5a1fSHans Rosenfeld 170*ecee5a1fSHans Rosenfeld if (index >= 0) 171*ecee5a1fSHans Rosenfeld align -= snprintf(NULL, 0, " %d", index); 172*ecee5a1fSHans Rosenfeld 173*ecee5a1fSHans Rosenfeld if (align < 0) 174*ecee5a1fSHans Rosenfeld align = 0; 175*ecee5a1fSHans Rosenfeld 176*ecee5a1fSHans Rosenfeld va_start(ap, fmt); 177*ecee5a1fSHans Rosenfeld 178*ecee5a1fSHans Rosenfeld (void) printf("%*s%s", indent, "", name); 179*ecee5a1fSHans Rosenfeld 180*ecee5a1fSHans Rosenfeld if (index >= 0) 181*ecee5a1fSHans Rosenfeld (void) printf(" %d", index); 182*ecee5a1fSHans Rosenfeld 183*ecee5a1fSHans Rosenfeld if (fmt != NULL) { 184*ecee5a1fSHans Rosenfeld (void) printf(": %*s", align, ""); 185*ecee5a1fSHans Rosenfeld (void) vprintf(fmt, ap); 186*ecee5a1fSHans Rosenfeld } 187*ecee5a1fSHans Rosenfeld 188*ecee5a1fSHans Rosenfeld (void) printf("\n"); 189*ecee5a1fSHans Rosenfeld va_end(ap); 190*ecee5a1fSHans Rosenfeld } 191*ecee5a1fSHans Rosenfeld 192*ecee5a1fSHans Rosenfeld /* 193*ecee5a1fSHans Rosenfeld * nvme_strlen -- return length of string without trailing whitespace 194*ecee5a1fSHans Rosenfeld */ 195*ecee5a1fSHans Rosenfeld static int 196*ecee5a1fSHans Rosenfeld nvme_strlen(const char *str, int len) 197*ecee5a1fSHans Rosenfeld { 198*ecee5a1fSHans Rosenfeld if (len < 0) 199*ecee5a1fSHans Rosenfeld return (0); 200*ecee5a1fSHans Rosenfeld 201*ecee5a1fSHans Rosenfeld while (str[--len] == ' ') 202*ecee5a1fSHans Rosenfeld ; 203*ecee5a1fSHans Rosenfeld 204*ecee5a1fSHans Rosenfeld return (++len); 205*ecee5a1fSHans Rosenfeld } 206*ecee5a1fSHans Rosenfeld 207*ecee5a1fSHans Rosenfeld /* 208*ecee5a1fSHans Rosenfeld * nvme_print_str -- print a string up to the specified length 209*ecee5a1fSHans Rosenfeld */ 210*ecee5a1fSHans Rosenfeld static void 211*ecee5a1fSHans Rosenfeld nvme_print_str(int indent, char *name, int index, const char *value, int len) 212*ecee5a1fSHans Rosenfeld { 213*ecee5a1fSHans Rosenfeld if (len == 0) 214*ecee5a1fSHans Rosenfeld len = strlen(value); 215*ecee5a1fSHans Rosenfeld 216*ecee5a1fSHans Rosenfeld nvme_print(indent, name, index, "%.*s", nvme_strlen(value, len), value); 217*ecee5a1fSHans Rosenfeld } 218*ecee5a1fSHans Rosenfeld 219*ecee5a1fSHans Rosenfeld /* 220*ecee5a1fSHans Rosenfeld * nvme_print_double -- print a double up to a specified number of places with 221*ecee5a1fSHans Rosenfeld * optional unit 222*ecee5a1fSHans Rosenfeld */ 223*ecee5a1fSHans Rosenfeld static void 224*ecee5a1fSHans Rosenfeld nvme_print_double(int indent, char *name, double value, int places, char *unit) 225*ecee5a1fSHans Rosenfeld { 226*ecee5a1fSHans Rosenfeld if (unit == NULL) 227*ecee5a1fSHans Rosenfeld unit = ""; 228*ecee5a1fSHans Rosenfeld 229*ecee5a1fSHans Rosenfeld nvme_print(indent, name, -1, "%.*g%s", places, value, unit); 230*ecee5a1fSHans Rosenfeld } 231*ecee5a1fSHans Rosenfeld 232*ecee5a1fSHans Rosenfeld /* 233*ecee5a1fSHans Rosenfeld * nvme_print_uint64 -- print uint64_t with optional unit in decimal or another 234*ecee5a1fSHans Rosenfeld * format specified 235*ecee5a1fSHans Rosenfeld */ 236*ecee5a1fSHans Rosenfeld static void 237*ecee5a1fSHans Rosenfeld nvme_print_uint64(int indent, char *name, uint64_t value, const char *fmt, 238*ecee5a1fSHans Rosenfeld char *unit) 239*ecee5a1fSHans Rosenfeld { 240*ecee5a1fSHans Rosenfeld char *tmp_fmt; 241*ecee5a1fSHans Rosenfeld 242*ecee5a1fSHans Rosenfeld if (unit == NULL) 243*ecee5a1fSHans Rosenfeld unit = ""; 244*ecee5a1fSHans Rosenfeld 245*ecee5a1fSHans Rosenfeld if (fmt == NULL) 246*ecee5a1fSHans Rosenfeld fmt = "%"PRId64; 247*ecee5a1fSHans Rosenfeld 248*ecee5a1fSHans Rosenfeld if (asprintf(&tmp_fmt, "%s%%s", fmt) < 0) 249*ecee5a1fSHans Rosenfeld err(-1, "nvme_print_uint64()"); 250*ecee5a1fSHans Rosenfeld 251*ecee5a1fSHans Rosenfeld nvme_print(indent, name, -1, tmp_fmt, value, unit); 252*ecee5a1fSHans Rosenfeld 253*ecee5a1fSHans Rosenfeld free(tmp_fmt); 254*ecee5a1fSHans Rosenfeld } 255*ecee5a1fSHans Rosenfeld 256*ecee5a1fSHans Rosenfeld /* 257*ecee5a1fSHans Rosenfeld * nvme_print_uint128 -- print a 128bit uint with optional unit, after applying 258*ecee5a1fSHans Rosenfeld * binary and/or decimal shifting 259*ecee5a1fSHans Rosenfeld */ 260*ecee5a1fSHans Rosenfeld static void 261*ecee5a1fSHans Rosenfeld nvme_print_uint128(int indent, char *name, nvme_uint128_t value, char *unit, 262*ecee5a1fSHans Rosenfeld int scale_bits, int scale_tens) 263*ecee5a1fSHans Rosenfeld { 264*ecee5a1fSHans Rosenfeld const char hex[] = "0123456789abcdef"; 265*ecee5a1fSHans Rosenfeld uint8_t o[(128 + scale_bits) / 3]; 266*ecee5a1fSHans Rosenfeld char p[sizeof (o) * 2]; 267*ecee5a1fSHans Rosenfeld char *pp = &p[0]; 268*ecee5a1fSHans Rosenfeld int i, x; 269*ecee5a1fSHans Rosenfeld uint64_t rem = 0; 270*ecee5a1fSHans Rosenfeld 271*ecee5a1fSHans Rosenfeld if (unit == NULL) 272*ecee5a1fSHans Rosenfeld unit = ""; 273*ecee5a1fSHans Rosenfeld 274*ecee5a1fSHans Rosenfeld /* 275*ecee5a1fSHans Rosenfeld * Don't allow binary shifting by more than 64 bits to keep the 276*ecee5a1fSHans Rosenfeld * arithmetic simple. Also limit decimal shifting based on the size 277*ecee5a1fSHans Rosenfeld * of any possible remainder from binary shifting. 278*ecee5a1fSHans Rosenfeld */ 279*ecee5a1fSHans Rosenfeld assert(scale_bits <= 64); 280*ecee5a1fSHans Rosenfeld assert(scale_tens <= (64 - scale_bits) / 3); 281*ecee5a1fSHans Rosenfeld 282*ecee5a1fSHans Rosenfeld bzero(o, sizeof (o)); 283*ecee5a1fSHans Rosenfeld bzero(p, sizeof (p)); 284*ecee5a1fSHans Rosenfeld 285*ecee5a1fSHans Rosenfeld /* 286*ecee5a1fSHans Rosenfeld * Convert the two 64-bit numbers into a series of BCD digits using 287*ecee5a1fSHans Rosenfeld * a double-dabble algorithm. By using more or less iterations than 288*ecee5a1fSHans Rosenfeld * 128 we can do a binary shift in either direction. 289*ecee5a1fSHans Rosenfeld */ 290*ecee5a1fSHans Rosenfeld for (x = 0; x != 128 - scale_bits; x++) { 291*ecee5a1fSHans Rosenfeld for (i = 0; i != sizeof (o); i++) { 292*ecee5a1fSHans Rosenfeld if ((o[i] & 0xf0) > 0x40) 293*ecee5a1fSHans Rosenfeld o[i] += 0x30; 294*ecee5a1fSHans Rosenfeld 295*ecee5a1fSHans Rosenfeld if ((o[i] & 0xf) > 4) 296*ecee5a1fSHans Rosenfeld o[i] += 3; 297*ecee5a1fSHans Rosenfeld } 298*ecee5a1fSHans Rosenfeld 299*ecee5a1fSHans Rosenfeld for (i = 0; i != sizeof (o) - 1; i++) 300*ecee5a1fSHans Rosenfeld o[i] = (o[i] << 1) + (o[i+1] >> 7); 301*ecee5a1fSHans Rosenfeld 302*ecee5a1fSHans Rosenfeld o[i] = (o[i] << 1) + (value.hi >> 63); 303*ecee5a1fSHans Rosenfeld 304*ecee5a1fSHans Rosenfeld value.hi = (value.hi << 1) + (value.lo >> 63); 305*ecee5a1fSHans Rosenfeld value.lo = (value.lo << 1); 306*ecee5a1fSHans Rosenfeld } 307*ecee5a1fSHans Rosenfeld 308*ecee5a1fSHans Rosenfeld /* 309*ecee5a1fSHans Rosenfeld * If we're supposed to do a decimal left shift (* 10^x), too, 310*ecee5a1fSHans Rosenfeld * calculate the remainder of the previous binary shift operation. 311*ecee5a1fSHans Rosenfeld */ 312*ecee5a1fSHans Rosenfeld if (scale_tens > 0) { 313*ecee5a1fSHans Rosenfeld rem = value.hi >> (64 - scale_bits); 314*ecee5a1fSHans Rosenfeld 315*ecee5a1fSHans Rosenfeld for (i = 0; i != scale_tens; i++) 316*ecee5a1fSHans Rosenfeld rem *= 10; 317*ecee5a1fSHans Rosenfeld 318*ecee5a1fSHans Rosenfeld rem >>= scale_bits; 319*ecee5a1fSHans Rosenfeld } 320*ecee5a1fSHans Rosenfeld 321*ecee5a1fSHans Rosenfeld /* 322*ecee5a1fSHans Rosenfeld * Construct the decimal number for printing. Skip leading zeros. 323*ecee5a1fSHans Rosenfeld */ 324*ecee5a1fSHans Rosenfeld for (i = 0; i < sizeof (o); i++) 325*ecee5a1fSHans Rosenfeld if (o[i] != 0) 326*ecee5a1fSHans Rosenfeld break; 327*ecee5a1fSHans Rosenfeld 328*ecee5a1fSHans Rosenfeld if (i == sizeof (o)) { 329*ecee5a1fSHans Rosenfeld /* 330*ecee5a1fSHans Rosenfeld * The converted number is 0. Just print the calculated 331*ecee5a1fSHans Rosenfeld * remainder and return. 332*ecee5a1fSHans Rosenfeld */ 333*ecee5a1fSHans Rosenfeld nvme_print(indent, name, -1, "%"PRId64"%s", rem, unit); 334*ecee5a1fSHans Rosenfeld return; 335*ecee5a1fSHans Rosenfeld } else { 336*ecee5a1fSHans Rosenfeld if (o[i] > 0xf) 337*ecee5a1fSHans Rosenfeld *pp++ = hex[o[i] >> 4]; 338*ecee5a1fSHans Rosenfeld 339*ecee5a1fSHans Rosenfeld *pp++ = hex[o[i] & 0xf]; 340*ecee5a1fSHans Rosenfeld 341*ecee5a1fSHans Rosenfeld for (i++; i < sizeof (o); i++) { 342*ecee5a1fSHans Rosenfeld *pp++ = hex[o[i] >> 4]; 343*ecee5a1fSHans Rosenfeld *pp++ = hex[o[i] & 0xf]; 344*ecee5a1fSHans Rosenfeld } 345*ecee5a1fSHans Rosenfeld } 346*ecee5a1fSHans Rosenfeld 347*ecee5a1fSHans Rosenfeld /* 348*ecee5a1fSHans Rosenfeld * For negative decimal scaling, use the printf precision specifier to 349*ecee5a1fSHans Rosenfeld * truncate the results according to the requested decimal scaling. For 350*ecee5a1fSHans Rosenfeld * positive decimal scaling we print the remainder padded with 0. 351*ecee5a1fSHans Rosenfeld */ 352*ecee5a1fSHans Rosenfeld nvme_print(indent, name, -1, "%.*s%0.*"PRId64"%s", 353*ecee5a1fSHans Rosenfeld strlen(p) + scale_tens, p, 354*ecee5a1fSHans Rosenfeld scale_tens > 0 ? scale_tens : 0, rem, 355*ecee5a1fSHans Rosenfeld unit); 356*ecee5a1fSHans Rosenfeld } 357*ecee5a1fSHans Rosenfeld 358*ecee5a1fSHans Rosenfeld /* 359*ecee5a1fSHans Rosenfeld * nvme_print_bit -- print a bit with optional names for both states 360*ecee5a1fSHans Rosenfeld */ 361*ecee5a1fSHans Rosenfeld static void 362*ecee5a1fSHans Rosenfeld nvme_print_bit(int indent, char *name, int value, char *s_true, char *s_false) 363*ecee5a1fSHans Rosenfeld { 364*ecee5a1fSHans Rosenfeld if (s_true == NULL) 365*ecee5a1fSHans Rosenfeld s_true = "supported"; 366*ecee5a1fSHans Rosenfeld if (s_false == NULL) 367*ecee5a1fSHans Rosenfeld s_false = "unsupported"; 368*ecee5a1fSHans Rosenfeld 369*ecee5a1fSHans Rosenfeld nvme_print(indent, name, -1, "%s", value ? s_true : s_false); 370*ecee5a1fSHans Rosenfeld } 371*ecee5a1fSHans Rosenfeld 372*ecee5a1fSHans Rosenfeld /* 373*ecee5a1fSHans Rosenfeld * nvme_print_ctrl_summary -- print a 1-line summary of the IDENTIFY CONTROLLER 374*ecee5a1fSHans Rosenfeld * data structure 375*ecee5a1fSHans Rosenfeld */ 376*ecee5a1fSHans Rosenfeld void 377*ecee5a1fSHans Rosenfeld nvme_print_ctrl_summary(nvme_identify_ctrl_t *idctl, nvme_version_t *version) 378*ecee5a1fSHans Rosenfeld { 379*ecee5a1fSHans Rosenfeld (void) printf("model: %.*s, serial: %.*s, FW rev: %.*s, NVMe v%d.%d\n", 380*ecee5a1fSHans Rosenfeld nvme_strlen(idctl->id_model, sizeof (idctl->id_model)), 381*ecee5a1fSHans Rosenfeld idctl->id_model, 382*ecee5a1fSHans Rosenfeld nvme_strlen(idctl->id_serial, sizeof (idctl->id_serial)), 383*ecee5a1fSHans Rosenfeld idctl->id_serial, 384*ecee5a1fSHans Rosenfeld nvme_strlen(idctl->id_fwrev, sizeof (idctl->id_fwrev)), 385*ecee5a1fSHans Rosenfeld idctl->id_fwrev, 386*ecee5a1fSHans Rosenfeld version->v_major, version->v_minor); 387*ecee5a1fSHans Rosenfeld } 388*ecee5a1fSHans Rosenfeld 389*ecee5a1fSHans Rosenfeld /* 390*ecee5a1fSHans Rosenfeld * nvme_print_nsid_summary -- print a 1-line summary of the IDENTIFY NAMESPACE 391*ecee5a1fSHans Rosenfeld * data structure 392*ecee5a1fSHans Rosenfeld */ 393*ecee5a1fSHans Rosenfeld void 394*ecee5a1fSHans Rosenfeld nvme_print_nsid_summary(nvme_identify_nsid_t *idns) 395*ecee5a1fSHans Rosenfeld { 396*ecee5a1fSHans Rosenfeld int bsize = 1 << idns->id_lbaf[idns->id_flbas.lba_format].lbaf_lbads; 397*ecee5a1fSHans Rosenfeld 398*ecee5a1fSHans Rosenfeld (void) printf("Size = %"PRId64" MB, " 399*ecee5a1fSHans Rosenfeld "Capacity = %"PRId64" MB, " 400*ecee5a1fSHans Rosenfeld "Used = %"PRId64" MB\n", 401*ecee5a1fSHans Rosenfeld idns->id_nsize * bsize / 1024 / 1024, 402*ecee5a1fSHans Rosenfeld idns->id_ncap * bsize / 1024 / 1024, 403*ecee5a1fSHans Rosenfeld idns->id_nuse * bsize / 1024 / 1024); 404*ecee5a1fSHans Rosenfeld 405*ecee5a1fSHans Rosenfeld } 406*ecee5a1fSHans Rosenfeld 407*ecee5a1fSHans Rosenfeld /* 408*ecee5a1fSHans Rosenfeld * nvme_print_identify_ctrl 409*ecee5a1fSHans Rosenfeld * 410*ecee5a1fSHans Rosenfeld * This function pretty-prints the structure returned by the IDENTIFY CONTROLLER 411*ecee5a1fSHans Rosenfeld * command. 412*ecee5a1fSHans Rosenfeld */ 413*ecee5a1fSHans Rosenfeld void 414*ecee5a1fSHans Rosenfeld nvme_print_identify_ctrl(nvme_identify_ctrl_t *idctl, 415*ecee5a1fSHans Rosenfeld nvme_capabilities_t *cap, nvme_version_t *version) 416*ecee5a1fSHans Rosenfeld { 417*ecee5a1fSHans Rosenfeld int i; 418*ecee5a1fSHans Rosenfeld 419*ecee5a1fSHans Rosenfeld nvme_print(0, "Identify Controller", -1, NULL); 420*ecee5a1fSHans Rosenfeld nvme_print(2, "Controller Capabilities and Features", -1, NULL); 421*ecee5a1fSHans Rosenfeld nvme_print_str(4, "Model", -1, 422*ecee5a1fSHans Rosenfeld idctl->id_model, sizeof (idctl->id_model)); 423*ecee5a1fSHans Rosenfeld nvme_print_str(4, "Serial", -1, 424*ecee5a1fSHans Rosenfeld idctl->id_serial, sizeof (idctl->id_serial)); 425*ecee5a1fSHans Rosenfeld nvme_print_str(4, "Firmware Revision", -1, 426*ecee5a1fSHans Rosenfeld idctl->id_fwrev, sizeof (idctl->id_fwrev)); 427*ecee5a1fSHans Rosenfeld if (verbose) { 428*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "PCI vendor ID", 429*ecee5a1fSHans Rosenfeld idctl->id_vid, "0x%0.4"PRIx64, NULL); 430*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "subsystem vendor ID", 431*ecee5a1fSHans Rosenfeld idctl->id_ssvid, "0x%0.4"PRIx64, NULL); 432*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Recommended Arbitration Burst", 433*ecee5a1fSHans Rosenfeld idctl->id_rab, NULL, NULL); 434*ecee5a1fSHans Rosenfeld nvme_print(4, "Vendor IEEE OUI", -1, "%0.2X-%0.2X-%0.2X", 435*ecee5a1fSHans Rosenfeld idctl->id_oui[0], idctl->id_oui[1], idctl->id_oui[2]); 436*ecee5a1fSHans Rosenfeld } 437*ecee5a1fSHans Rosenfeld nvme_print(4, "Multi-Interface Capabilities", -1, NULL); 438*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Multiple PCI Express ports", 439*ecee5a1fSHans Rosenfeld idctl->id_mic.m_multi_pci, NULL, NULL); 440*ecee5a1fSHans Rosenfeld 441*ecee5a1fSHans Rosenfeld if (NVME_VERSION_ATLEAST(version, 1, 1)) { 442*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Multiple Controllers", 443*ecee5a1fSHans Rosenfeld idctl->id_mic.m_multi_ctrl, NULL, NULL); 444*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Is SR-IOV virtual function", 445*ecee5a1fSHans Rosenfeld idctl->id_mic.m_sr_iov, "yes", "no"); 446*ecee5a1fSHans Rosenfeld } 447*ecee5a1fSHans Rosenfeld if (idctl->id_mdts > 0) 448*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Maximum Data Transfer Size", 449*ecee5a1fSHans Rosenfeld (1 << idctl->id_mdts) * cap->mpsmin / 1024, NULL, "kB"); 450*ecee5a1fSHans Rosenfeld else 451*ecee5a1fSHans Rosenfeld nvme_print_str(4, "Maximum Data Transfer Size", -1, 452*ecee5a1fSHans Rosenfeld "unlimited", 0); 453*ecee5a1fSHans Rosenfeld 454*ecee5a1fSHans Rosenfeld if (NVME_VERSION_ATLEAST(version, 1, 1)) { 455*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Unique Controller Identifier", 456*ecee5a1fSHans Rosenfeld idctl->id_cntlid, "0x%0.4"PRIx64, NULL); 457*ecee5a1fSHans Rosenfeld } 458*ecee5a1fSHans Rosenfeld 459*ecee5a1fSHans Rosenfeld nvme_print(2, "Admin Command Set Attributes", -1, NULL); 460*ecee5a1fSHans Rosenfeld nvme_print(4, "Optional Admin Command Support", -1, NULL); 461*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Security Send & Receive", 462*ecee5a1fSHans Rosenfeld idctl->id_oacs.oa_security, NULL, NULL); 463*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Format NVM", 464*ecee5a1fSHans Rosenfeld idctl->id_oacs.oa_format, NULL, NULL); 465*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Firmware Activate & Download", 466*ecee5a1fSHans Rosenfeld idctl->id_oacs.oa_firmware, NULL, NULL); 467*ecee5a1fSHans Rosenfeld if (verbose) { 468*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Abort Command Limit", 469*ecee5a1fSHans Rosenfeld (uint16_t)idctl->id_acl + 1, NULL, NULL); 470*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Asynchronous Event Request Limit", 471*ecee5a1fSHans Rosenfeld (uint16_t)idctl->id_aerl + 1, NULL, NULL); 472*ecee5a1fSHans Rosenfeld } 473*ecee5a1fSHans Rosenfeld nvme_print(4, "Firmware Updates", -1, NULL); 474*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Firmware Slot 1", 475*ecee5a1fSHans Rosenfeld idctl->id_frmw.fw_readonly, "read-only", "writable"); 476*ecee5a1fSHans Rosenfeld nvme_print_uint64(6, "No. of Firmware Slots", 477*ecee5a1fSHans Rosenfeld idctl->id_frmw.fw_nslot, NULL, NULL); 478*ecee5a1fSHans Rosenfeld nvme_print(2, "Log Page Attributes", -1, NULL); 479*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "per Namespace SMART/Health info", 480*ecee5a1fSHans Rosenfeld idctl->id_lpa.lp_smart, NULL, NULL); 481*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Error Log Page Entries", 482*ecee5a1fSHans Rosenfeld (uint16_t)idctl->id_elpe + 1, NULL, NULL); 483*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Number of Power States", 484*ecee5a1fSHans Rosenfeld (uint16_t)idctl->id_npss + 1, NULL, NULL); 485*ecee5a1fSHans Rosenfeld if (verbose) { 486*ecee5a1fSHans Rosenfeld nvme_print_bit(4, "Admin Vendor-specific Command Format", 487*ecee5a1fSHans Rosenfeld idctl->id_avscc.av_spec, "standard", "vendor-specific"); 488*ecee5a1fSHans Rosenfeld } 489*ecee5a1fSHans Rosenfeld 490*ecee5a1fSHans Rosenfeld if (NVME_VERSION_ATLEAST(version, 1, 1)) { 491*ecee5a1fSHans Rosenfeld nvme_print_bit(4, "Autonomous Power State Transitions", 492*ecee5a1fSHans Rosenfeld idctl->id_apsta.ap_sup, NULL, NULL); 493*ecee5a1fSHans Rosenfeld } 494*ecee5a1fSHans Rosenfeld 495*ecee5a1fSHans Rosenfeld nvme_print(2, "NVM Command Set Attributes", -1, NULL); 496*ecee5a1fSHans Rosenfeld if (verbose) { 497*ecee5a1fSHans Rosenfeld nvme_print(4, "Submission Queue Entry Size", -1, 498*ecee5a1fSHans Rosenfeld "min %d, max %d", 499*ecee5a1fSHans Rosenfeld 1 << idctl->id_sqes.qes_min, 1 << idctl->id_sqes.qes_max); 500*ecee5a1fSHans Rosenfeld nvme_print(4, "Completion Queue Entry Size", -1, 501*ecee5a1fSHans Rosenfeld "min %d, max %d", 502*ecee5a1fSHans Rosenfeld 1 << idctl->id_cqes.qes_min, 1 << idctl->id_cqes.qes_max); 503*ecee5a1fSHans Rosenfeld } 504*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Number of Namespaces", 505*ecee5a1fSHans Rosenfeld idctl->id_nn, NULL, NULL); 506*ecee5a1fSHans Rosenfeld nvme_print(4, "Optional NVM Command Support", -1, NULL); 507*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Compare", 508*ecee5a1fSHans Rosenfeld idctl->id_oncs.on_compare, NULL, NULL); 509*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Write Uncorrectable", 510*ecee5a1fSHans Rosenfeld idctl->id_oncs.on_wr_unc, NULL, NULL); 511*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Dataset Management", 512*ecee5a1fSHans Rosenfeld idctl->id_oncs.on_dset_mgmt, NULL, NULL); 513*ecee5a1fSHans Rosenfeld 514*ecee5a1fSHans Rosenfeld if (NVME_VERSION_ATLEAST(version, 1, 1)) { 515*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Write Zeros", 516*ecee5a1fSHans Rosenfeld idctl->id_oncs.on_wr_zero, NULL, NULL); 517*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Save/Select in Get/Set Features", 518*ecee5a1fSHans Rosenfeld idctl->id_oncs.on_save, NULL, NULL); 519*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Reservations", 520*ecee5a1fSHans Rosenfeld idctl->id_oncs.on_reserve, NULL, NULL); 521*ecee5a1fSHans Rosenfeld } 522*ecee5a1fSHans Rosenfeld 523*ecee5a1fSHans Rosenfeld nvme_print(4, "Fused Operation Support", -1, NULL); 524*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Compare and Write", 525*ecee5a1fSHans Rosenfeld idctl->id_fuses.f_cmp_wr, NULL, NULL); 526*ecee5a1fSHans Rosenfeld nvme_print(4, "Format NVM Attributes", -1, NULL); 527*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "per Namespace Format", 528*ecee5a1fSHans Rosenfeld idctl->id_fna.fn_format == 0, NULL, NULL); 529*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "per Namespace Secure Erase", 530*ecee5a1fSHans Rosenfeld idctl->id_fna.fn_sec_erase == 0, NULL, NULL); 531*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Cryptographic Erase", 532*ecee5a1fSHans Rosenfeld idctl->id_fna.fn_crypt_erase, NULL, NULL); 533*ecee5a1fSHans Rosenfeld nvme_print_bit(4, "Volatile Write Cache", 534*ecee5a1fSHans Rosenfeld idctl->id_vwc.vwc_present, "present", "not present"); 535*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Atomic Write Unit Normal", 536*ecee5a1fSHans Rosenfeld (uint32_t)idctl->id_awun + 1, NULL, 537*ecee5a1fSHans Rosenfeld idctl->id_awun == 0 ? " block" : " blocks"); 538*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Atomic Write Unit Power Fail", 539*ecee5a1fSHans Rosenfeld (uint32_t)idctl->id_awupf + 1, NULL, 540*ecee5a1fSHans Rosenfeld idctl->id_awupf == 0 ? " block" : " blocks"); 541*ecee5a1fSHans Rosenfeld 542*ecee5a1fSHans Rosenfeld if (verbose != 0) 543*ecee5a1fSHans Rosenfeld nvme_print_bit(4, "NVM Vendor-specific Command Format", 544*ecee5a1fSHans Rosenfeld idctl->id_nvscc.nv_spec, "standard", "vendor-specific"); 545*ecee5a1fSHans Rosenfeld 546*ecee5a1fSHans Rosenfeld if (NVME_VERSION_ATLEAST(version, 1, 1)) { 547*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Atomic Compare & Write Size", 548*ecee5a1fSHans Rosenfeld (uint32_t)idctl->id_acwu + 1, NULL, 549*ecee5a1fSHans Rosenfeld idctl->id_acwu == 0 ? " block" : " blocks"); 550*ecee5a1fSHans Rosenfeld nvme_print(4, "SGL Support", -1, NULL); 551*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "SGLs in NVM commands", 552*ecee5a1fSHans Rosenfeld idctl->id_sgls.sgl_sup, NULL, NULL); 553*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "SGL Bit Bucket Descriptor", 554*ecee5a1fSHans Rosenfeld idctl->id_sgls.sgl_bucket, NULL, NULL); 555*ecee5a1fSHans Rosenfeld } 556*ecee5a1fSHans Rosenfeld 557*ecee5a1fSHans Rosenfeld for (i = 0; i != idctl->id_npss + 1; i++) { 558*ecee5a1fSHans Rosenfeld double scale = 0.01; 559*ecee5a1fSHans Rosenfeld double power = 0; 560*ecee5a1fSHans Rosenfeld int places = 2; 561*ecee5a1fSHans Rosenfeld char *unit = "W"; 562*ecee5a1fSHans Rosenfeld 563*ecee5a1fSHans Rosenfeld if (NVME_VERSION_ATLEAST(version, 1, 1) && 564*ecee5a1fSHans Rosenfeld idctl->id_psd[i].psd_mps == 1) { 565*ecee5a1fSHans Rosenfeld scale = 0.0001; 566*ecee5a1fSHans Rosenfeld places = 4; 567*ecee5a1fSHans Rosenfeld } 568*ecee5a1fSHans Rosenfeld 569*ecee5a1fSHans Rosenfeld power = (double)idctl->id_psd[i].psd_mp * scale; 570*ecee5a1fSHans Rosenfeld if (power < 1.0) { 571*ecee5a1fSHans Rosenfeld power *= 1000.0; 572*ecee5a1fSHans Rosenfeld unit = "mW"; 573*ecee5a1fSHans Rosenfeld } 574*ecee5a1fSHans Rosenfeld 575*ecee5a1fSHans Rosenfeld nvme_print(4, "Power State Descriptor", i, NULL); 576*ecee5a1fSHans Rosenfeld nvme_print_double(6, "Maximum Power", power, places, unit); 577*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Non-Operational State", 578*ecee5a1fSHans Rosenfeld idctl->id_psd[i].psd_nops, "yes", "no"); 579*ecee5a1fSHans Rosenfeld nvme_print_uint64(6, "Entry Latency", 580*ecee5a1fSHans Rosenfeld idctl->id_psd[i].psd_enlat, NULL, "us"); 581*ecee5a1fSHans Rosenfeld nvme_print_uint64(6, "Exit Latency", 582*ecee5a1fSHans Rosenfeld idctl->id_psd[i].psd_exlat, NULL, "us"); 583*ecee5a1fSHans Rosenfeld nvme_print_uint64(6, "Relative Read Throughput (0 = best)", 584*ecee5a1fSHans Rosenfeld idctl->id_psd[i].psd_rrt, NULL, NULL); 585*ecee5a1fSHans Rosenfeld nvme_print_uint64(6, "Relative Read Latency (0 = best)", 586*ecee5a1fSHans Rosenfeld idctl->id_psd[i].psd_rrl, NULL, NULL); 587*ecee5a1fSHans Rosenfeld nvme_print_uint64(6, "Relative Write Throughput (0 = best)", 588*ecee5a1fSHans Rosenfeld idctl->id_psd[i].psd_rwt, NULL, NULL); 589*ecee5a1fSHans Rosenfeld nvme_print_uint64(6, "Relative Write Latency (0 = best)", 590*ecee5a1fSHans Rosenfeld idctl->id_psd[i].psd_rwl, NULL, NULL); 591*ecee5a1fSHans Rosenfeld } 592*ecee5a1fSHans Rosenfeld } 593*ecee5a1fSHans Rosenfeld 594*ecee5a1fSHans Rosenfeld /* 595*ecee5a1fSHans Rosenfeld * nvme_print_identify_nsid 596*ecee5a1fSHans Rosenfeld * 597*ecee5a1fSHans Rosenfeld * This function pretty-prints the structure returned by the IDENTIFY NAMESPACE 598*ecee5a1fSHans Rosenfeld * command. 599*ecee5a1fSHans Rosenfeld */ 600*ecee5a1fSHans Rosenfeld void 601*ecee5a1fSHans Rosenfeld nvme_print_identify_nsid(nvme_identify_nsid_t *idns, nvme_version_t *version) 602*ecee5a1fSHans Rosenfeld { 603*ecee5a1fSHans Rosenfeld int bsize = 1 << idns->id_lbaf[idns->id_flbas.lba_format].lbaf_lbads; 604*ecee5a1fSHans Rosenfeld int i; 605*ecee5a1fSHans Rosenfeld 606*ecee5a1fSHans Rosenfeld nvme_print(0, "Identify Namespace", -1, NULL); 607*ecee5a1fSHans Rosenfeld nvme_print(2, "Namespace Capabilities and Features", -1, NULL); 608*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Namespace Size", 609*ecee5a1fSHans Rosenfeld idns->id_nsize * bsize / 1024 / 1024, NULL, "MB"); 610*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Namespace Capacity", 611*ecee5a1fSHans Rosenfeld idns->id_ncap * bsize / 1024 / 1024, NULL, "MB"); 612*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Namespace Utilization", 613*ecee5a1fSHans Rosenfeld idns->id_nuse * bsize / 1024 / 1024, NULL, "MB"); 614*ecee5a1fSHans Rosenfeld nvme_print(4, "Namespace Features", -1, NULL); 615*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Thin Provisioning", 616*ecee5a1fSHans Rosenfeld idns->id_nsfeat.f_thin, NULL, NULL); 617*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Number of LBA Formats", 618*ecee5a1fSHans Rosenfeld (uint16_t)idns->id_nlbaf + 1, NULL, NULL); 619*ecee5a1fSHans Rosenfeld nvme_print(4, "Formatted LBA Size", -1, NULL); 620*ecee5a1fSHans Rosenfeld nvme_print_uint64(6, "LBA Format", 621*ecee5a1fSHans Rosenfeld (uint16_t)idns->id_flbas.lba_format, NULL, NULL); 622*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Extended Data LBA", 623*ecee5a1fSHans Rosenfeld idns->id_flbas.lba_extlba, "yes", "no"); 624*ecee5a1fSHans Rosenfeld nvme_print(4, "Metadata Capabilities", -1, NULL); 625*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Extended Data LBA", 626*ecee5a1fSHans Rosenfeld idns->id_mc.mc_extlba, NULL, NULL); 627*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Separate Metadata", 628*ecee5a1fSHans Rosenfeld idns->id_mc.mc_separate, NULL, NULL); 629*ecee5a1fSHans Rosenfeld nvme_print(4, "End-to-End Data Protection Capabilities", -1, NULL); 630*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Protection Information Type 1", 631*ecee5a1fSHans Rosenfeld idns->id_dpc.dp_type1, NULL, NULL); 632*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Protection Information Type 2", 633*ecee5a1fSHans Rosenfeld idns->id_dpc.dp_type2, NULL, NULL); 634*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Protection Information Type 3", 635*ecee5a1fSHans Rosenfeld idns->id_dpc.dp_type3, NULL, NULL); 636*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Protection Information first", 637*ecee5a1fSHans Rosenfeld idns->id_dpc.dp_first, NULL, NULL); 638*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Protection Information last", 639*ecee5a1fSHans Rosenfeld idns->id_dpc.dp_last, NULL, NULL); 640*ecee5a1fSHans Rosenfeld nvme_print(4, "End-to-End Data Protection Settings", -1, NULL); 641*ecee5a1fSHans Rosenfeld if (idns->id_dps.dp_pinfo == 0) 642*ecee5a1fSHans Rosenfeld nvme_print_str(6, "Protection Information", -1, 643*ecee5a1fSHans Rosenfeld "disabled", 0); 644*ecee5a1fSHans Rosenfeld else 645*ecee5a1fSHans Rosenfeld nvme_print_uint64(6, "Protection Information Type", 646*ecee5a1fSHans Rosenfeld idns->id_dps.dp_pinfo, NULL, NULL); 647*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Protection Information in Metadata", 648*ecee5a1fSHans Rosenfeld idns->id_dps.dp_first, "first 8 bytes", "last 8 bytes"); 649*ecee5a1fSHans Rosenfeld 650*ecee5a1fSHans Rosenfeld if (NVME_VERSION_ATLEAST(version, 1, 1)) { 651*ecee5a1fSHans Rosenfeld nvme_print(4, "Namespace Multi-Path I/O and Namespace Sharing " 652*ecee5a1fSHans Rosenfeld "Capabilities", -1, NULL); 653*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Namespace is shared", 654*ecee5a1fSHans Rosenfeld idns->id_nmic.nm_shared, "yes", "no"); 655*ecee5a1fSHans Rosenfeld nvme_print(2, "Reservation Capabilities", -1, NULL); 656*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Persist Through Power Loss", 657*ecee5a1fSHans Rosenfeld idns->id_rescap.rc_persist, NULL, NULL); 658*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Write Exclusive", 659*ecee5a1fSHans Rosenfeld idns->id_rescap.rc_wr_excl, NULL, NULL); 660*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Exclusive Access", 661*ecee5a1fSHans Rosenfeld idns->id_rescap.rc_excl, NULL, NULL); 662*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Write Exclusive - Registrants Only", 663*ecee5a1fSHans Rosenfeld idns->id_rescap.rc_wr_excl_r, NULL, NULL); 664*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Exclusive Access - Registrants Only", 665*ecee5a1fSHans Rosenfeld idns->id_rescap.rc_excl_r, NULL, NULL); 666*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Write Exclusive - All Registrants", 667*ecee5a1fSHans Rosenfeld idns->id_rescap.rc_wr_excl_a, NULL, NULL); 668*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Exclusive Access - All Registrants", 669*ecee5a1fSHans Rosenfeld idns->id_rescap.rc_excl_a, NULL, NULL); 670*ecee5a1fSHans Rosenfeld 671*ecee5a1fSHans Rosenfeld nvme_print(4, "IEEE Extended Unique Identifier", -1, 672*ecee5a1fSHans Rosenfeld "%0.2X%0.2X%0.2X%0.2X%0.2X%0.2X%0.2X%0.2X", 673*ecee5a1fSHans Rosenfeld idns->id_eui64[0], idns->id_eui64[1], 674*ecee5a1fSHans Rosenfeld idns->id_eui64[2], idns->id_eui64[3], 675*ecee5a1fSHans Rosenfeld idns->id_eui64[4], idns->id_eui64[5], 676*ecee5a1fSHans Rosenfeld idns->id_eui64[6], idns->id_eui64[7]); 677*ecee5a1fSHans Rosenfeld } 678*ecee5a1fSHans Rosenfeld 679*ecee5a1fSHans Rosenfeld for (i = 0; i <= idns->id_nlbaf; i++) { 680*ecee5a1fSHans Rosenfeld if (verbose == 0 && idns->id_lbaf[i].lbaf_ms != 0) 681*ecee5a1fSHans Rosenfeld continue; 682*ecee5a1fSHans Rosenfeld 683*ecee5a1fSHans Rosenfeld nvme_print(4, "LBA Format", i, NULL); 684*ecee5a1fSHans Rosenfeld nvme_print_uint64(6, "Metadata Size", 685*ecee5a1fSHans Rosenfeld idns->id_lbaf[i].lbaf_ms, NULL, " bytes"); 686*ecee5a1fSHans Rosenfeld nvme_print_uint64(6, "LBA Data Size", 687*ecee5a1fSHans Rosenfeld 1 << idns->id_lbaf[i].lbaf_lbads, NULL, " bytes"); 688*ecee5a1fSHans Rosenfeld nvme_print_str(6, "Relative Performance", -1, 689*ecee5a1fSHans Rosenfeld lbaf_relative_performance[idns->id_lbaf[i].lbaf_rp], 0); 690*ecee5a1fSHans Rosenfeld } 691*ecee5a1fSHans Rosenfeld } 692*ecee5a1fSHans Rosenfeld 693*ecee5a1fSHans Rosenfeld /* 694*ecee5a1fSHans Rosenfeld * nvme_print_error_log 695*ecee5a1fSHans Rosenfeld * 696*ecee5a1fSHans Rosenfeld * This function pretty-prints all non-zero error log entries, or all entries 697*ecee5a1fSHans Rosenfeld * if verbose is set. 698*ecee5a1fSHans Rosenfeld */ 699*ecee5a1fSHans Rosenfeld void 700*ecee5a1fSHans Rosenfeld nvme_print_error_log(int nlog, nvme_error_log_entry_t *elog) 701*ecee5a1fSHans Rosenfeld { 702*ecee5a1fSHans Rosenfeld int i; 703*ecee5a1fSHans Rosenfeld 704*ecee5a1fSHans Rosenfeld nvme_print(0, "Error Log", -1, NULL); 705*ecee5a1fSHans Rosenfeld for (i = 0; i != nlog; i++) 706*ecee5a1fSHans Rosenfeld if (elog[i].el_count == 0) 707*ecee5a1fSHans Rosenfeld break; 708*ecee5a1fSHans Rosenfeld nvme_print_uint64(2, "Number of Error Log Entries", i, NULL, NULL); 709*ecee5a1fSHans Rosenfeld 710*ecee5a1fSHans Rosenfeld for (i = 0; i != nlog; i++) { 711*ecee5a1fSHans Rosenfeld int sc = elog[i].el_sf.sf_sc; 712*ecee5a1fSHans Rosenfeld const char *sc_str = ""; 713*ecee5a1fSHans Rosenfeld 714*ecee5a1fSHans Rosenfeld if (elog[i].el_count == 0 && verbose == 0) 715*ecee5a1fSHans Rosenfeld break; 716*ecee5a1fSHans Rosenfeld 717*ecee5a1fSHans Rosenfeld switch (elog[i].el_sf.sf_sct) { 718*ecee5a1fSHans Rosenfeld case 0: /* Generic Command Status */ 719*ecee5a1fSHans Rosenfeld if (sc < ARRAYSIZE(generic_status_codes)) 720*ecee5a1fSHans Rosenfeld sc_str = generic_status_codes[sc]; 721*ecee5a1fSHans Rosenfeld else if (sc >= 0x80 && 722*ecee5a1fSHans Rosenfeld sc - 0x80 < ARRAYSIZE(generic_nvm_status_codes)) 723*ecee5a1fSHans Rosenfeld sc_str = generic_nvm_status_codes[sc - 0x80]; 724*ecee5a1fSHans Rosenfeld break; 725*ecee5a1fSHans Rosenfeld case 1: /* Specific Command Status */ 726*ecee5a1fSHans Rosenfeld if (sc < ARRAYSIZE(specific_status_codes)) 727*ecee5a1fSHans Rosenfeld sc_str = specific_status_codes[sc]; 728*ecee5a1fSHans Rosenfeld else if (sc >= 0x80 && 729*ecee5a1fSHans Rosenfeld sc - 0x80 < ARRAYSIZE(specific_nvm_status_codes)) 730*ecee5a1fSHans Rosenfeld sc_str = specific_nvm_status_codes[sc - 0x80]; 731*ecee5a1fSHans Rosenfeld break; 732*ecee5a1fSHans Rosenfeld case 2: /* Media Errors */ 733*ecee5a1fSHans Rosenfeld if (sc >= 0x80 && 734*ecee5a1fSHans Rosenfeld sc - 0x80 < ARRAYSIZE(media_nvm_status_codes)) 735*ecee5a1fSHans Rosenfeld sc_str = media_nvm_status_codes[sc - 0x80]; 736*ecee5a1fSHans Rosenfeld break; 737*ecee5a1fSHans Rosenfeld case 7: /* Vendor Specific */ 738*ecee5a1fSHans Rosenfeld sc_str = "Unknown Vendor Specific"; 739*ecee5a1fSHans Rosenfeld break; 740*ecee5a1fSHans Rosenfeld default: 741*ecee5a1fSHans Rosenfeld sc_str = "Reserved"; 742*ecee5a1fSHans Rosenfeld break; 743*ecee5a1fSHans Rosenfeld } 744*ecee5a1fSHans Rosenfeld 745*ecee5a1fSHans Rosenfeld nvme_print(2, "Entry", i, NULL); 746*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Error Count", 747*ecee5a1fSHans Rosenfeld elog[i].el_count, NULL, NULL); 748*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Submission Queue ID", 749*ecee5a1fSHans Rosenfeld elog[i].el_sqid, NULL, NULL); 750*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Command ID", 751*ecee5a1fSHans Rosenfeld elog[i].el_cid, NULL, NULL); 752*ecee5a1fSHans Rosenfeld nvme_print(4, "Status Field", -1, NULL); 753*ecee5a1fSHans Rosenfeld nvme_print_uint64(6, "Phase Tag", 754*ecee5a1fSHans Rosenfeld elog[i].el_sf.sf_p, NULL, NULL); 755*ecee5a1fSHans Rosenfeld nvme_print(6, "Status Code", -1, "0x%0.2x (%s)", 756*ecee5a1fSHans Rosenfeld sc, sc_str); 757*ecee5a1fSHans Rosenfeld nvme_print(6, "Status Code Type", -1, "0x%x (%s)", 758*ecee5a1fSHans Rosenfeld elog[i].el_sf.sf_sct, 759*ecee5a1fSHans Rosenfeld status_code_types[elog[i].el_sf.sf_sct]); 760*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "More", 761*ecee5a1fSHans Rosenfeld elog[i].el_sf.sf_m, "yes", "no"); 762*ecee5a1fSHans Rosenfeld nvme_print_bit(6, "Do Not Retry", 763*ecee5a1fSHans Rosenfeld elog[i].el_sf.sf_m, "yes", "no"); 764*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Parameter Error Location byte", 765*ecee5a1fSHans Rosenfeld elog[i].el_byte, "0x%0.2"PRIx64, NULL); 766*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Parameter Error Location bit", 767*ecee5a1fSHans Rosenfeld elog[i].el_bit, NULL, NULL); 768*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Logical Block Address", 769*ecee5a1fSHans Rosenfeld elog[i].el_lba, NULL, NULL); 770*ecee5a1fSHans Rosenfeld nvme_print(4, "Namespace ID", -1, "%d", 771*ecee5a1fSHans Rosenfeld elog[i].el_nsid == 0xffffffff ? 772*ecee5a1fSHans Rosenfeld 0 : elog[i].el_nsid); 773*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, 774*ecee5a1fSHans Rosenfeld "Vendor Specifc Information Available", 775*ecee5a1fSHans Rosenfeld elog[i].el_vendor, NULL, NULL); 776*ecee5a1fSHans Rosenfeld } 777*ecee5a1fSHans Rosenfeld } 778*ecee5a1fSHans Rosenfeld 779*ecee5a1fSHans Rosenfeld /* 780*ecee5a1fSHans Rosenfeld * nvme_print_health_log 781*ecee5a1fSHans Rosenfeld * 782*ecee5a1fSHans Rosenfeld * This function pretty-prints a summary of the SMART/Health log, or all 783*ecee5a1fSHans Rosenfeld * of the log if verbose is set. 784*ecee5a1fSHans Rosenfeld */ 785*ecee5a1fSHans Rosenfeld void 786*ecee5a1fSHans Rosenfeld nvme_print_health_log(nvme_health_log_t *hlog, nvme_identify_ctrl_t *idctl) 787*ecee5a1fSHans Rosenfeld { 788*ecee5a1fSHans Rosenfeld nvme_print(0, "SMART/Health Information", -1, NULL); 789*ecee5a1fSHans Rosenfeld nvme_print(2, "Critical Warnings", -1, NULL); 790*ecee5a1fSHans Rosenfeld nvme_print_bit(4, "Available Space", 791*ecee5a1fSHans Rosenfeld hlog->hl_crit_warn.cw_avail, "low", "OK"); 792*ecee5a1fSHans Rosenfeld nvme_print_bit(4, "Temperature", 793*ecee5a1fSHans Rosenfeld hlog->hl_crit_warn.cw_temp, "too high", "OK"); 794*ecee5a1fSHans Rosenfeld nvme_print_bit(4, "Device Reliability", 795*ecee5a1fSHans Rosenfeld hlog->hl_crit_warn.cw_reliab, "degraded", "OK"); 796*ecee5a1fSHans Rosenfeld nvme_print_bit(4, "Media", 797*ecee5a1fSHans Rosenfeld hlog->hl_crit_warn.cw_readonly, "read-only", "OK"); 798*ecee5a1fSHans Rosenfeld if (idctl->id_vwc.vwc_present != 0) 799*ecee5a1fSHans Rosenfeld nvme_print_bit(4, "Volatile Memory Backup", 800*ecee5a1fSHans Rosenfeld hlog->hl_crit_warn.cw_volatile, "failed", "OK"); 801*ecee5a1fSHans Rosenfeld 802*ecee5a1fSHans Rosenfeld nvme_print_uint64(2, "Temperature", 803*ecee5a1fSHans Rosenfeld hlog->hl_temp - 273, NULL, "C"); 804*ecee5a1fSHans Rosenfeld nvme_print_uint64(2, "Available Spare Capacity", 805*ecee5a1fSHans Rosenfeld hlog->hl_avail_spare, NULL, "%"); 806*ecee5a1fSHans Rosenfeld 807*ecee5a1fSHans Rosenfeld if (verbose != 0) 808*ecee5a1fSHans Rosenfeld nvme_print_uint64(2, "Available Spare Threshold", 809*ecee5a1fSHans Rosenfeld hlog->hl_avail_spare_thr, NULL, "%"); 810*ecee5a1fSHans Rosenfeld 811*ecee5a1fSHans Rosenfeld nvme_print_uint64(2, "Device Life Used", 812*ecee5a1fSHans Rosenfeld hlog->hl_used, NULL, "%"); 813*ecee5a1fSHans Rosenfeld 814*ecee5a1fSHans Rosenfeld if (verbose == 0) 815*ecee5a1fSHans Rosenfeld return; 816*ecee5a1fSHans Rosenfeld 817*ecee5a1fSHans Rosenfeld /* 818*ecee5a1fSHans Rosenfeld * The following two fields are in 1000 512 byte units. Convert that to 819*ecee5a1fSHans Rosenfeld * GB by doing binary shifts (9 left and 30 right) and muliply by 10^3. 820*ecee5a1fSHans Rosenfeld */ 821*ecee5a1fSHans Rosenfeld nvme_print_uint128(2, "Data Read", 822*ecee5a1fSHans Rosenfeld hlog->hl_data_read, "GB", 30 - 9, 3); 823*ecee5a1fSHans Rosenfeld nvme_print_uint128(2, "Data Written", 824*ecee5a1fSHans Rosenfeld hlog->hl_data_write, "GB", 30 - 9, 3); 825*ecee5a1fSHans Rosenfeld 826*ecee5a1fSHans Rosenfeld nvme_print_uint128(2, "Read Commands", 827*ecee5a1fSHans Rosenfeld hlog->hl_host_read, NULL, 0, 0); 828*ecee5a1fSHans Rosenfeld nvme_print_uint128(2, "Write Commands", 829*ecee5a1fSHans Rosenfeld hlog->hl_host_write, NULL, 0, 0); 830*ecee5a1fSHans Rosenfeld nvme_print_uint128(2, "Controller Busy", 831*ecee5a1fSHans Rosenfeld hlog->hl_ctrl_busy, "min", 0, 0); 832*ecee5a1fSHans Rosenfeld nvme_print_uint128(2, "Power Cycles", 833*ecee5a1fSHans Rosenfeld hlog->hl_power_cycles, NULL, 0, 0); 834*ecee5a1fSHans Rosenfeld nvme_print_uint128(2, "Power On", 835*ecee5a1fSHans Rosenfeld hlog->hl_power_on_hours, "h", 0, 0); 836*ecee5a1fSHans Rosenfeld nvme_print_uint128(2, "Unsafe Shutdowns", 837*ecee5a1fSHans Rosenfeld hlog->hl_unsafe_shutdn, NULL, 0, 0); 838*ecee5a1fSHans Rosenfeld nvme_print_uint128(2, "Uncorrectable Media Errors", 839*ecee5a1fSHans Rosenfeld hlog->hl_media_errors, NULL, 0, 0); 840*ecee5a1fSHans Rosenfeld nvme_print_uint128(2, "Errors Logged", 841*ecee5a1fSHans Rosenfeld hlog->hl_errors_logged, NULL, 0, 0); 842*ecee5a1fSHans Rosenfeld } 843*ecee5a1fSHans Rosenfeld 844*ecee5a1fSHans Rosenfeld /* 845*ecee5a1fSHans Rosenfeld * nvme_print_fwslot_log 846*ecee5a1fSHans Rosenfeld * 847*ecee5a1fSHans Rosenfeld * This function pretty-prints the firmware slot information. 848*ecee5a1fSHans Rosenfeld */ 849*ecee5a1fSHans Rosenfeld void 850*ecee5a1fSHans Rosenfeld nvme_print_fwslot_log(nvme_fwslot_log_t *fwlog) 851*ecee5a1fSHans Rosenfeld { 852*ecee5a1fSHans Rosenfeld int i; 853*ecee5a1fSHans Rosenfeld 854*ecee5a1fSHans Rosenfeld nvme_print(0, "Firmware Slot Information", -1, NULL); 855*ecee5a1fSHans Rosenfeld nvme_print_uint64(2, "Active Firmware Slot", fwlog->fw_afi, NULL, NULL); 856*ecee5a1fSHans Rosenfeld 857*ecee5a1fSHans Rosenfeld for (i = 0; i != ARRAYSIZE(fwlog->fw_frs); i++) { 858*ecee5a1fSHans Rosenfeld if (fwlog->fw_frs[i][0] == '\0') 859*ecee5a1fSHans Rosenfeld break; 860*ecee5a1fSHans Rosenfeld nvme_print_str(2, "Firmware Revision for Slot", i + 1, 861*ecee5a1fSHans Rosenfeld fwlog->fw_frs[i], sizeof (fwlog->fw_frs[i])); 862*ecee5a1fSHans Rosenfeld } 863*ecee5a1fSHans Rosenfeld } 864*ecee5a1fSHans Rosenfeld 865*ecee5a1fSHans Rosenfeld /* 866*ecee5a1fSHans Rosenfeld * nvme_print_feat_* 867*ecee5a1fSHans Rosenfeld * 868*ecee5a1fSHans Rosenfeld * These functions pretty-print the data structures returned by GET FEATURES. 869*ecee5a1fSHans Rosenfeld */ 870*ecee5a1fSHans Rosenfeld void 871*ecee5a1fSHans Rosenfeld nvme_print_feat_arbitration(uint64_t res, void *b, size_t s, 872*ecee5a1fSHans Rosenfeld nvme_identify_ctrl_t *id) 873*ecee5a1fSHans Rosenfeld { 874*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(b)); 875*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(s)); 876*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(id)); 877*ecee5a1fSHans Rosenfeld nvme_arbitration_t arb; 878*ecee5a1fSHans Rosenfeld 879*ecee5a1fSHans Rosenfeld arb.r = (uint32_t)res; 880*ecee5a1fSHans Rosenfeld if (arb.b.arb_ab != 7) 881*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Arbitration Burst", 882*ecee5a1fSHans Rosenfeld 1 << arb.b.arb_ab, NULL, NULL); 883*ecee5a1fSHans Rosenfeld else 884*ecee5a1fSHans Rosenfeld nvme_print_str(4, "Arbitration Burst", 0, 885*ecee5a1fSHans Rosenfeld "no limit", 0); 886*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Low Priority Weight", 887*ecee5a1fSHans Rosenfeld (uint16_t)arb.b.arb_lpw + 1, NULL, NULL); 888*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Medium Priority Weight", 889*ecee5a1fSHans Rosenfeld (uint16_t)arb.b.arb_mpw + 1, NULL, NULL); 890*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "High Priority Weight", 891*ecee5a1fSHans Rosenfeld (uint16_t)arb.b.arb_hpw + 1, NULL, NULL); 892*ecee5a1fSHans Rosenfeld } 893*ecee5a1fSHans Rosenfeld 894*ecee5a1fSHans Rosenfeld void 895*ecee5a1fSHans Rosenfeld nvme_print_feat_power_mgmt(uint64_t res, void *b, size_t s, 896*ecee5a1fSHans Rosenfeld nvme_identify_ctrl_t *id) 897*ecee5a1fSHans Rosenfeld { 898*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(b)); 899*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(s)); 900*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(id)); 901*ecee5a1fSHans Rosenfeld nvme_power_mgmt_t pm; 902*ecee5a1fSHans Rosenfeld 903*ecee5a1fSHans Rosenfeld pm.r = (uint32_t)res; 904*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Power State", (uint8_t)pm.b.pm_ps, 905*ecee5a1fSHans Rosenfeld NULL, NULL); 906*ecee5a1fSHans Rosenfeld } 907*ecee5a1fSHans Rosenfeld 908*ecee5a1fSHans Rosenfeld void 909*ecee5a1fSHans Rosenfeld nvme_print_feat_lba_range(uint64_t res, void *buf, size_t bufsize, 910*ecee5a1fSHans Rosenfeld nvme_identify_ctrl_t *id) 911*ecee5a1fSHans Rosenfeld { 912*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(id)); 913*ecee5a1fSHans Rosenfeld 914*ecee5a1fSHans Rosenfeld nvme_lba_range_type_t lrt; 915*ecee5a1fSHans Rosenfeld nvme_lba_range_t *lr; 916*ecee5a1fSHans Rosenfeld size_t n_lr; 917*ecee5a1fSHans Rosenfeld int i; 918*ecee5a1fSHans Rosenfeld 919*ecee5a1fSHans Rosenfeld if (buf == NULL) 920*ecee5a1fSHans Rosenfeld return; 921*ecee5a1fSHans Rosenfeld 922*ecee5a1fSHans Rosenfeld lrt.r = res; 923*ecee5a1fSHans Rosenfeld lr = buf; 924*ecee5a1fSHans Rosenfeld 925*ecee5a1fSHans Rosenfeld n_lr = bufsize / sizeof (nvme_lba_range_t); 926*ecee5a1fSHans Rosenfeld if (n_lr > lrt.b.lr_num + 1) 927*ecee5a1fSHans Rosenfeld n_lr = lrt.b.lr_num + 1; 928*ecee5a1fSHans Rosenfeld 929*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Number of LBA Ranges", 930*ecee5a1fSHans Rosenfeld (uint8_t)lrt.b.lr_num + 1, NULL, NULL); 931*ecee5a1fSHans Rosenfeld 932*ecee5a1fSHans Rosenfeld for (i = 0; i != n_lr; i++) { 933*ecee5a1fSHans Rosenfeld if (verbose == 0 && lr[i].lr_nlb == 0) 934*ecee5a1fSHans Rosenfeld continue; 935*ecee5a1fSHans Rosenfeld 936*ecee5a1fSHans Rosenfeld nvme_print(4, "LBA Range", i, NULL); 937*ecee5a1fSHans Rosenfeld if (lr[i].lr_type < ARRAYSIZE(lba_range_types)) 938*ecee5a1fSHans Rosenfeld nvme_print_str(6, "Type", -1, 939*ecee5a1fSHans Rosenfeld lba_range_types[lr[i].lr_type], 0); 940*ecee5a1fSHans Rosenfeld else 941*ecee5a1fSHans Rosenfeld nvme_print_uint64(6, "Type", 942*ecee5a1fSHans Rosenfeld lr[i].lr_type, NULL, NULL); 943*ecee5a1fSHans Rosenfeld nvme_print(6, "Attributes", -1, NULL); 944*ecee5a1fSHans Rosenfeld nvme_print_bit(8, "Writable", 945*ecee5a1fSHans Rosenfeld lr[i].lr_attr.lr_write, "yes", "no"); 946*ecee5a1fSHans Rosenfeld nvme_print_bit(8, "Hidden", 947*ecee5a1fSHans Rosenfeld lr[i].lr_attr.lr_hidden, "yes", "no"); 948*ecee5a1fSHans Rosenfeld nvme_print_uint64(6, "Starting LBA", 949*ecee5a1fSHans Rosenfeld lr[i].lr_slba, NULL, NULL); 950*ecee5a1fSHans Rosenfeld nvme_print_uint64(6, "Number of Logical Blocks", 951*ecee5a1fSHans Rosenfeld lr[i].lr_nlb, NULL, NULL); 952*ecee5a1fSHans Rosenfeld nvme_print(6, "Unique Identifier", -1, 953*ecee5a1fSHans Rosenfeld "%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x" 954*ecee5a1fSHans Rosenfeld "%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", 955*ecee5a1fSHans Rosenfeld lr[i].lr_guid[0], lr[i].lr_guid[1], 956*ecee5a1fSHans Rosenfeld lr[i].lr_guid[2], lr[i].lr_guid[3], 957*ecee5a1fSHans Rosenfeld lr[i].lr_guid[4], lr[i].lr_guid[5], 958*ecee5a1fSHans Rosenfeld lr[i].lr_guid[6], lr[i].lr_guid[7], 959*ecee5a1fSHans Rosenfeld lr[i].lr_guid[8], lr[i].lr_guid[9], 960*ecee5a1fSHans Rosenfeld lr[i].lr_guid[10], lr[i].lr_guid[11], 961*ecee5a1fSHans Rosenfeld lr[i].lr_guid[12], lr[i].lr_guid[13], 962*ecee5a1fSHans Rosenfeld lr[i].lr_guid[14], lr[i].lr_guid[15]); 963*ecee5a1fSHans Rosenfeld } 964*ecee5a1fSHans Rosenfeld } 965*ecee5a1fSHans Rosenfeld 966*ecee5a1fSHans Rosenfeld void 967*ecee5a1fSHans Rosenfeld nvme_print_feat_temperature(uint64_t res, void *b, size_t s, 968*ecee5a1fSHans Rosenfeld nvme_identify_ctrl_t *id) 969*ecee5a1fSHans Rosenfeld { 970*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(b)); 971*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(s)); 972*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(id)); 973*ecee5a1fSHans Rosenfeld nvme_temp_threshold_t tt; 974*ecee5a1fSHans Rosenfeld 975*ecee5a1fSHans Rosenfeld tt.r = (uint32_t)res; 976*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Temperature Threshold", tt.b.tt_tmpth - 273, 977*ecee5a1fSHans Rosenfeld NULL, "C"); 978*ecee5a1fSHans Rosenfeld } 979*ecee5a1fSHans Rosenfeld 980*ecee5a1fSHans Rosenfeld void 981*ecee5a1fSHans Rosenfeld nvme_print_feat_error(uint64_t res, void *b, size_t s, 982*ecee5a1fSHans Rosenfeld nvme_identify_ctrl_t *id) 983*ecee5a1fSHans Rosenfeld { 984*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(b)); 985*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(s)); 986*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(id)); 987*ecee5a1fSHans Rosenfeld nvme_error_recovery_t er; 988*ecee5a1fSHans Rosenfeld 989*ecee5a1fSHans Rosenfeld er.r = (uint32_t)res; 990*ecee5a1fSHans Rosenfeld if (er.b.er_tler > 0) 991*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Time Limited Error Recovery", 992*ecee5a1fSHans Rosenfeld (uint32_t)er.b.er_tler * 100, NULL, "ms"); 993*ecee5a1fSHans Rosenfeld else 994*ecee5a1fSHans Rosenfeld nvme_print_str(4, "Time Limited Error Recovery", -1, 995*ecee5a1fSHans Rosenfeld "no time limit", 0); 996*ecee5a1fSHans Rosenfeld } 997*ecee5a1fSHans Rosenfeld 998*ecee5a1fSHans Rosenfeld void 999*ecee5a1fSHans Rosenfeld nvme_print_feat_write_cache(uint64_t res, void *b, size_t s, 1000*ecee5a1fSHans Rosenfeld nvme_identify_ctrl_t *id) 1001*ecee5a1fSHans Rosenfeld { 1002*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(b)); 1003*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(s)); 1004*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(id)); 1005*ecee5a1fSHans Rosenfeld nvme_write_cache_t wc; 1006*ecee5a1fSHans Rosenfeld 1007*ecee5a1fSHans Rosenfeld wc.r = (uint32_t)res; 1008*ecee5a1fSHans Rosenfeld nvme_print_bit(4, "Volatile Write Cache", 1009*ecee5a1fSHans Rosenfeld wc.b.wc_wce, "enabled", "disabled"); 1010*ecee5a1fSHans Rosenfeld } 1011*ecee5a1fSHans Rosenfeld 1012*ecee5a1fSHans Rosenfeld void 1013*ecee5a1fSHans Rosenfeld nvme_print_feat_nqueues(uint64_t res, void *b, size_t s, 1014*ecee5a1fSHans Rosenfeld nvme_identify_ctrl_t *id) 1015*ecee5a1fSHans Rosenfeld { 1016*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(b)); 1017*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(s)); 1018*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(id)); 1019*ecee5a1fSHans Rosenfeld nvme_nqueues_t nq; 1020*ecee5a1fSHans Rosenfeld 1021*ecee5a1fSHans Rosenfeld nq.r = (uint32_t)res; 1022*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Number of Submission Queues", 1023*ecee5a1fSHans Rosenfeld nq.b.nq_nsq + 1, NULL, NULL); 1024*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Number of Completion Queues", 1025*ecee5a1fSHans Rosenfeld nq.b.nq_ncq + 1, NULL, NULL); 1026*ecee5a1fSHans Rosenfeld } 1027*ecee5a1fSHans Rosenfeld 1028*ecee5a1fSHans Rosenfeld void 1029*ecee5a1fSHans Rosenfeld nvme_print_feat_intr_coal(uint64_t res, void *b, size_t s, 1030*ecee5a1fSHans Rosenfeld nvme_identify_ctrl_t *id) 1031*ecee5a1fSHans Rosenfeld { 1032*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(b)); 1033*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(s)); 1034*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(id)); 1035*ecee5a1fSHans Rosenfeld nvme_intr_coal_t ic; 1036*ecee5a1fSHans Rosenfeld 1037*ecee5a1fSHans Rosenfeld ic.r = (uint32_t)res; 1038*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Aggregation Threshold", 1039*ecee5a1fSHans Rosenfeld ic.b.ic_thr + 1, NULL, NULL); 1040*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Aggregation Time", 1041*ecee5a1fSHans Rosenfeld (uint16_t)ic.b.ic_time * 100, NULL, "us"); 1042*ecee5a1fSHans Rosenfeld } 1043*ecee5a1fSHans Rosenfeld void 1044*ecee5a1fSHans Rosenfeld nvme_print_feat_intr_vect(uint64_t res, void *b, size_t s, 1045*ecee5a1fSHans Rosenfeld nvme_identify_ctrl_t *id) 1046*ecee5a1fSHans Rosenfeld { 1047*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(b)); 1048*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(s)); 1049*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(id)); 1050*ecee5a1fSHans Rosenfeld nvme_intr_vect_t iv; 1051*ecee5a1fSHans Rosenfeld char *tmp; 1052*ecee5a1fSHans Rosenfeld 1053*ecee5a1fSHans Rosenfeld iv.r = (uint32_t)res; 1054*ecee5a1fSHans Rosenfeld if (asprintf(&tmp, "Vector %d Coalescing Disable", iv.b.iv_iv) < 0) 1055*ecee5a1fSHans Rosenfeld err(-1, "nvme_print_feat_common()"); 1056*ecee5a1fSHans Rosenfeld 1057*ecee5a1fSHans Rosenfeld nvme_print_bit(4, tmp, iv.b.iv_cd, "yes", "no"); 1058*ecee5a1fSHans Rosenfeld } 1059*ecee5a1fSHans Rosenfeld 1060*ecee5a1fSHans Rosenfeld void 1061*ecee5a1fSHans Rosenfeld nvme_print_feat_write_atom(uint64_t res, void *b, size_t s, 1062*ecee5a1fSHans Rosenfeld nvme_identify_ctrl_t *id) 1063*ecee5a1fSHans Rosenfeld { 1064*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(b)); 1065*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(s)); 1066*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(id)); 1067*ecee5a1fSHans Rosenfeld nvme_write_atomicity_t wa; 1068*ecee5a1fSHans Rosenfeld 1069*ecee5a1fSHans Rosenfeld wa.r = (uint32_t)res; 1070*ecee5a1fSHans Rosenfeld nvme_print_bit(4, "Disable Normal", wa.b.wa_dn, "yes", "no"); 1071*ecee5a1fSHans Rosenfeld } 1072*ecee5a1fSHans Rosenfeld 1073*ecee5a1fSHans Rosenfeld void 1074*ecee5a1fSHans Rosenfeld nvme_print_feat_async_event(uint64_t res, void *b, size_t s, 1075*ecee5a1fSHans Rosenfeld nvme_identify_ctrl_t *idctl) 1076*ecee5a1fSHans Rosenfeld { 1077*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(b)); 1078*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(s)); 1079*ecee5a1fSHans Rosenfeld nvme_async_event_conf_t aec; 1080*ecee5a1fSHans Rosenfeld 1081*ecee5a1fSHans Rosenfeld aec.r = (uint32_t)res; 1082*ecee5a1fSHans Rosenfeld nvme_print_bit(4, "Available Space below threshold", 1083*ecee5a1fSHans Rosenfeld aec.b.aec_avail, "enabled", "disabled"); 1084*ecee5a1fSHans Rosenfeld nvme_print_bit(4, "Temperature above threshold", 1085*ecee5a1fSHans Rosenfeld aec.b.aec_temp, "enabled", "disabled"); 1086*ecee5a1fSHans Rosenfeld nvme_print_bit(4, "Device Reliability compromised", 1087*ecee5a1fSHans Rosenfeld aec.b.aec_reliab, "enabled", "disabled"); 1088*ecee5a1fSHans Rosenfeld nvme_print_bit(4, "Media read-only", 1089*ecee5a1fSHans Rosenfeld aec.b.aec_readonly, "enabled", "disabled"); 1090*ecee5a1fSHans Rosenfeld if (idctl->id_vwc.vwc_present != 0) 1091*ecee5a1fSHans Rosenfeld nvme_print_bit(4, "Volatile Memory Backup failed", 1092*ecee5a1fSHans Rosenfeld aec.b.aec_volatile, "enabled", "disabled"); 1093*ecee5a1fSHans Rosenfeld } 1094*ecee5a1fSHans Rosenfeld 1095*ecee5a1fSHans Rosenfeld void 1096*ecee5a1fSHans Rosenfeld nvme_print_feat_auto_pst(uint64_t res, void *buf, size_t bufsize, 1097*ecee5a1fSHans Rosenfeld nvme_identify_ctrl_t *id) 1098*ecee5a1fSHans Rosenfeld { 1099*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(id)); 1100*ecee5a1fSHans Rosenfeld 1101*ecee5a1fSHans Rosenfeld nvme_auto_power_state_trans_t apst; 1102*ecee5a1fSHans Rosenfeld nvme_auto_power_state_t *aps; 1103*ecee5a1fSHans Rosenfeld int i; 1104*ecee5a1fSHans Rosenfeld int cnt = bufsize / sizeof (nvme_auto_power_state_t); 1105*ecee5a1fSHans Rosenfeld 1106*ecee5a1fSHans Rosenfeld if (buf == NULL) 1107*ecee5a1fSHans Rosenfeld return; 1108*ecee5a1fSHans Rosenfeld 1109*ecee5a1fSHans Rosenfeld apst.r = res; 1110*ecee5a1fSHans Rosenfeld aps = buf; 1111*ecee5a1fSHans Rosenfeld 1112*ecee5a1fSHans Rosenfeld nvme_print_bit(4, "Autonomous Power State Transition", 1113*ecee5a1fSHans Rosenfeld apst.b.apst_apste, "enabled", "disabled"); 1114*ecee5a1fSHans Rosenfeld for (i = 0; i != cnt; i++) { 1115*ecee5a1fSHans Rosenfeld if (aps[i].apst_itps == 0 && aps[i].apst_itpt == 0) 1116*ecee5a1fSHans Rosenfeld break; 1117*ecee5a1fSHans Rosenfeld 1118*ecee5a1fSHans Rosenfeld nvme_print(4, "Power State", i, NULL); 1119*ecee5a1fSHans Rosenfeld nvme_print_uint64(6, "Idle Transition Power State", 1120*ecee5a1fSHans Rosenfeld (uint16_t)aps[i].apst_itps, NULL, NULL); 1121*ecee5a1fSHans Rosenfeld nvme_print_uint64(6, "Idle Time Prior to Transition", 1122*ecee5a1fSHans Rosenfeld aps[i].apst_itpt, NULL, "ms"); 1123*ecee5a1fSHans Rosenfeld } 1124*ecee5a1fSHans Rosenfeld } 1125*ecee5a1fSHans Rosenfeld 1126*ecee5a1fSHans Rosenfeld void 1127*ecee5a1fSHans Rosenfeld nvme_print_feat_progress(uint64_t res, void *b, size_t s, 1128*ecee5a1fSHans Rosenfeld nvme_identify_ctrl_t *id) 1129*ecee5a1fSHans Rosenfeld { 1130*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(b)); 1131*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(s)); 1132*ecee5a1fSHans Rosenfeld _NOTE(ARGUNUSED(id)); 1133*ecee5a1fSHans Rosenfeld nvme_software_progress_marker_t spm; 1134*ecee5a1fSHans Rosenfeld 1135*ecee5a1fSHans Rosenfeld spm.r = (uint32_t)res; 1136*ecee5a1fSHans Rosenfeld nvme_print_uint64(4, "Pre-Boot Software Load Count", 1137*ecee5a1fSHans Rosenfeld spm.b.spm_pbslc, NULL, NULL); 1138*ecee5a1fSHans Rosenfeld } 1139