1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 #include "nvme.h" 36 37 static void 38 print_ascii_string(const void *buf, size_t size) 39 { 40 const uint8_t *str = buf; 41 42 /* Trim trailing spaces */ 43 while (size > 0 && str[size - 1] == ' ') { 44 size--; 45 } 46 47 while (size--) { 48 if (*str >= 0x20 && *str <= 0x7E) { 49 printf("%c", *str); 50 } else { 51 printf("."); 52 } 53 str++; 54 } 55 } 56 57 static void 58 print_controller(struct nvme_ctrlr *ctrlr, const struct spdk_pci_addr *addr) 59 { 60 const struct spdk_nvme_ctrlr_data *cdata; 61 char fmtaddr[32] = {}; 62 63 cdata = nvme_ctrlr_get_data(ctrlr); 64 spdk_pci_addr_fmt(fmtaddr, sizeof(fmtaddr), addr); 65 66 printf("=====================================================\n"); 67 printf("NVMe Controller at %s\n", fmtaddr); 68 printf("=====================================================\n"); 69 printf("Vendor ID: %04x\n", cdata->vid); 70 printf("Subsystem Vendor ID: %04x\n", cdata->ssvid); 71 printf("Serial Number: "); 72 print_ascii_string(cdata->sn, sizeof(cdata->sn)); 73 printf("\n"); 74 printf("Model Number: "); 75 print_ascii_string(cdata->mn, sizeof(cdata->mn)); 76 printf("\n"); 77 printf("Firmware Version: "); 78 print_ascii_string(cdata->fr, sizeof(cdata->fr)); 79 printf("\n"); 80 printf("Recommended Arb Burst: %d\n", cdata->rab); 81 printf("IEEE OUI Identifier: %02x %02x %02x\n", 82 cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]); 83 printf("Multi-path I/O\n"); 84 printf(" May have multiple subsystem ports: %s\n", cdata->cmic.multi_port ? "Yes" : "No"); 85 printf(" May be connected to multiple hosts: %s\n", cdata->cmic.multi_host ? "Yes" : "No"); 86 printf(" Associated with SR-IOV VF: %s\n", cdata->cmic.sr_iov ? "Yes" : "No"); 87 printf("Max Number of Namespaces: %d\n", cdata->nn); 88 if (cdata->ver.raw != 0) { 89 printf("NVMe Specification Version (Identify): %u.%u", 90 cdata->ver.bits.mjr, cdata->ver.bits.mnr); 91 if (cdata->ver.bits.ter) { 92 printf(".%u", cdata->ver.bits.ter); 93 } 94 printf("\n"); 95 } 96 printf("Optional Asynchronous Events Supported\n"); 97 printf(" Namespace Attribute Notices: %s\n", 98 cdata->oaes.ns_attribute_notices ? "Supported" : "Not Supported"); 99 printf(" Firmware Activation Notices: %s\n", 100 cdata->oaes.fw_activation_notices ? "Supported" : "Not Supported"); 101 printf("128-bit Host Identifier: %s\n", 102 cdata->ctratt.host_id_exhid_supported ? "Supported" : "Not Supported"); 103 } 104 105 static void 106 attach_cb(void *cb_ctx, const struct spdk_pci_addr *addr, 107 struct nvme_ctrlr *ctrlr) 108 { 109 (void)cb_ctx; 110 111 print_controller(ctrlr, addr); 112 nvme_detach(ctrlr); 113 } 114 115 int 116 main(int argc, const char **argv) 117 { 118 struct spdk_env_opts opts; 119 struct spdk_pci_addr addr; 120 struct nvme_ctrlr *ctrlr; 121 int rc; 122 123 spdk_env_opts_init(&opts); 124 opts.name = "identify"; 125 126 if (spdk_env_init(&opts) != 0) { 127 fprintf(stderr, "%s: unable to initialize SPDK env\n", argv[0]); 128 return 1; 129 } 130 131 if (argc == 2) { 132 rc = spdk_pci_addr_parse(&addr, argv[1]); 133 if (rc != 0) { 134 fprintf(stderr, "%s: failed to parse the address\n", argv[0]); 135 return 1; 136 } 137 138 ctrlr = nvme_connect(&addr); 139 if (!ctrlr) { 140 fprintf(stderr, "%s: failed to connect to controller at %s\n", 141 argv[0], argv[1]); 142 return 1; 143 } 144 145 print_controller(ctrlr, &addr); 146 nvme_detach(ctrlr); 147 } else if (argc == 1) { 148 rc = nvme_probe(attach_cb, NULL); 149 if (rc != 0) { 150 fprintf(stderr, "%s: nvme probe failed\n", argv[0]); 151 return 1; 152 } 153 } else { 154 fprintf(stderr, "Usage: %s [PCI_BDF_ADDRESS]\n", argv[0]); 155 return 1; 156 } 157 158 return 0; 159 } 160