1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2021 Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "spdk/stdinc.h" 7 #include "nvme.h" 8 9 static void 10 print_ascii_string(const void *buf, size_t size) 11 { 12 const uint8_t *str = buf; 13 14 /* Trim trailing spaces */ 15 while (size > 0 && str[size - 1] == ' ') { 16 size--; 17 } 18 19 while (size--) { 20 if (*str >= 0x20 && *str <= 0x7E) { 21 printf("%c", *str); 22 } else { 23 printf("."); 24 } 25 str++; 26 } 27 } 28 29 static void 30 print_controller(struct nvme_ctrlr *ctrlr, const struct spdk_pci_addr *addr) 31 { 32 const struct spdk_nvme_ctrlr_data *cdata; 33 char fmtaddr[32] = {}; 34 35 cdata = nvme_ctrlr_get_data(ctrlr); 36 spdk_pci_addr_fmt(fmtaddr, sizeof(fmtaddr), addr); 37 38 printf("=====================================================\n"); 39 printf("NVMe Controller at %s\n", fmtaddr); 40 printf("=====================================================\n"); 41 printf("Vendor ID: %04x\n", cdata->vid); 42 printf("Subsystem Vendor ID: %04x\n", cdata->ssvid); 43 printf("Serial Number: "); 44 print_ascii_string(cdata->sn, sizeof(cdata->sn)); 45 printf("\n"); 46 printf("Model Number: "); 47 print_ascii_string(cdata->mn, sizeof(cdata->mn)); 48 printf("\n"); 49 printf("Firmware Version: "); 50 print_ascii_string(cdata->fr, sizeof(cdata->fr)); 51 printf("\n"); 52 printf("Recommended Arb Burst: %d\n", cdata->rab); 53 printf("IEEE OUI Identifier: %02x %02x %02x\n", 54 cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]); 55 printf("Multi-path I/O\n"); 56 printf(" May have multiple subsystem ports: %s\n", cdata->cmic.multi_port ? "Yes" : "No"); 57 printf(" May have multiple controllers: %s\n", cdata->cmic.multi_ctrlr ? "Yes" : "No"); 58 printf(" Associated with SR-IOV VF: %s\n", cdata->cmic.sr_iov ? "Yes" : "No"); 59 printf("Max Number of Namespaces: %d\n", cdata->nn); 60 if (cdata->ver.raw != 0) { 61 printf("NVMe Specification Version (Identify): %u.%u", 62 cdata->ver.bits.mjr, cdata->ver.bits.mnr); 63 if (cdata->ver.bits.ter) { 64 printf(".%u", cdata->ver.bits.ter); 65 } 66 printf("\n"); 67 } 68 printf("Optional Asynchronous Events Supported\n"); 69 printf(" Namespace Attribute Notices: %s\n", 70 cdata->oaes.ns_attribute_notices ? "Supported" : "Not Supported"); 71 printf(" Firmware Activation Notices: %s\n", 72 cdata->oaes.fw_activation_notices ? "Supported" : "Not Supported"); 73 printf("128-bit Host Identifier: %s\n", 74 cdata->ctratt.host_id_exhid_supported ? "Supported" : "Not Supported"); 75 } 76 77 static void 78 attach_cb(void *cb_ctx, const struct spdk_pci_addr *addr, 79 struct nvme_ctrlr *ctrlr) 80 { 81 (void)cb_ctx; 82 83 print_controller(ctrlr, addr); 84 nvme_detach(ctrlr); 85 } 86 87 int 88 main(int argc, const char **argv) 89 { 90 struct spdk_env_opts opts; 91 struct spdk_pci_addr addr; 92 struct nvme_ctrlr *ctrlr; 93 int rc; 94 95 spdk_env_opts_init(&opts); 96 opts.name = "identify"; 97 98 if (spdk_env_init(&opts) != 0) { 99 fprintf(stderr, "%s: unable to initialize SPDK env\n", argv[0]); 100 return 1; 101 } 102 103 if (argc == 2) { 104 rc = spdk_pci_addr_parse(&addr, argv[1]); 105 if (rc != 0) { 106 fprintf(stderr, "%s: failed to parse the address\n", argv[0]); 107 return 1; 108 } 109 110 ctrlr = nvme_connect(&addr); 111 if (!ctrlr) { 112 fprintf(stderr, "%s: failed to connect to controller at %s\n", 113 argv[0], argv[1]); 114 return 1; 115 } 116 117 print_controller(ctrlr, &addr); 118 nvme_detach(ctrlr); 119 } else if (argc == 1) { 120 rc = nvme_probe(attach_cb, NULL); 121 if (rc != 0) { 122 fprintf(stderr, "%s: nvme probe failed\n", argv[0]); 123 return 1; 124 } 125 } else { 126 fprintf(stderr, "Usage: %s [PCI_BDF_ADDRESS]\n", argv[0]); 127 return 1; 128 } 129 130 return 0; 131 } 132