Home | History | Annotate | Line # | Download | only in nvmectl
identify.c revision 1.2.8.1
      1  1.2.8.1  martin /*	$NetBSD: identify.c,v 1.2.8.1 2018/04/19 15:37:56 martin Exp $	*/
      2      1.1  nonaka 
      3      1.1  nonaka /*-
      4  1.2.8.1  martin  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
      5  1.2.8.1  martin  *
      6      1.1  nonaka  * Copyright (C) 2012-2013 Intel Corporation
      7      1.1  nonaka  * All rights reserved.
      8      1.1  nonaka  *
      9      1.1  nonaka  * Redistribution and use in source and binary forms, with or without
     10      1.1  nonaka  * modification, are permitted provided that the following conditions
     11      1.1  nonaka  * are met:
     12      1.1  nonaka  * 1. Redistributions of source code must retain the above copyright
     13      1.1  nonaka  *    notice, this list of conditions and the following disclaimer.
     14      1.1  nonaka  * 2. Redistributions in binary form must reproduce the above copyright
     15      1.1  nonaka  *    notice, this list of conditions and the following disclaimer in the
     16      1.1  nonaka  *    documentation and/or other materials provided with the distribution.
     17      1.1  nonaka  *
     18      1.1  nonaka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     19      1.1  nonaka  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     20      1.1  nonaka  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     21      1.1  nonaka  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     22      1.1  nonaka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     23      1.1  nonaka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     24      1.1  nonaka  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     25      1.1  nonaka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     26      1.1  nonaka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     27      1.1  nonaka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     28      1.1  nonaka  * SUCH DAMAGE.
     29      1.1  nonaka  */
     30      1.1  nonaka 
     31      1.1  nonaka #include <sys/cdefs.h>
     32      1.1  nonaka #ifndef lint
     33  1.2.8.1  martin __RCSID("$NetBSD: identify.c,v 1.2.8.1 2018/04/19 15:37:56 martin Exp $");
     34      1.1  nonaka #if 0
     35  1.2.8.1  martin __FBSDID("$FreeBSD: head/sbin/nvmecontrol/identify.c 329824 2018-02-22 13:32:31Z wma $");
     36      1.1  nonaka #endif
     37      1.1  nonaka #endif
     38      1.1  nonaka 
     39      1.1  nonaka #include <sys/param.h>
     40      1.1  nonaka 
     41      1.1  nonaka #include <ctype.h>
     42      1.1  nonaka #include <err.h>
     43      1.1  nonaka #include <fcntl.h>
     44      1.1  nonaka #include <stddef.h>
     45      1.1  nonaka #include <stdio.h>
     46      1.1  nonaka #include <stdlib.h>
     47      1.1  nonaka #include <string.h>
     48      1.1  nonaka #include <unistd.h>
     49      1.1  nonaka 
     50      1.1  nonaka #include "nvmectl.h"
     51      1.1  nonaka 
     52      1.1  nonaka static void
     53      1.1  nonaka print_controller(struct nvm_identify_controller *cdata)
     54      1.1  nonaka {
     55      1.1  nonaka 	uint8_t str[128];
     56      1.1  nonaka 
     57      1.1  nonaka 	printf("Controller Capabilities/Features\n");
     58      1.1  nonaka 	printf("================================\n");
     59      1.1  nonaka 	printf("Vendor ID:                  %04x\n", cdata->vid);
     60      1.1  nonaka 	printf("Subsystem Vendor ID:        %04x\n", cdata->ssvid);
     61      1.1  nonaka 	nvme_strvis(str, sizeof(str), cdata->sn, sizeof(cdata->sn));
     62      1.1  nonaka 	printf("Serial Number:              %s\n", str);
     63      1.1  nonaka 	nvme_strvis(str, sizeof(str), cdata->mn, sizeof(cdata->mn));
     64      1.1  nonaka 	printf("Model Number:               %s\n", str);
     65      1.1  nonaka 	nvme_strvis(str, sizeof(str), cdata->fr, sizeof(cdata->fr));
     66      1.1  nonaka 	printf("Firmware Version:           %s\n", str);
     67      1.1  nonaka 	printf("Recommended Arb Burst:      %d\n", cdata->rab);
     68      1.1  nonaka 	printf("IEEE OUI Identifier:        %02x %02x %02x\n",
     69      1.1  nonaka 		cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]);
     70      1.1  nonaka 	printf("Multi-Interface Cap:        %02x\n", cdata->cmic);
     71      1.1  nonaka 	/* TODO: Use CAP.MPSMIN to determine true memory page size. */
     72      1.1  nonaka 	printf("Max Data Transfer Size:     ");
     73      1.1  nonaka 	if (cdata->mdts == 0)
     74      1.1  nonaka 		printf("Unlimited\n");
     75      1.1  nonaka 	else
     76      1.1  nonaka 		printf("%ld\n", sysconf(_SC_PAGESIZE) * (1 << cdata->mdts));
     77  1.2.8.1  martin 	printf("Controller ID:              0x%02x\n", cdata->cntlid);
     78      1.1  nonaka 	printf("\n");
     79      1.1  nonaka 
     80      1.1  nonaka 	printf("Admin Command Set Attributes\n");
     81      1.1  nonaka 	printf("============================\n");
     82      1.1  nonaka 	printf("Security Send/Receive:       %s\n",
     83      1.1  nonaka 		(cdata->oacs & NVME_ID_CTRLR_OACS_SECURITY) ?
     84      1.1  nonaka 		"Supported" : "Not Supported");
     85      1.1  nonaka 	printf("Format NVM:                  %s\n",
     86      1.1  nonaka 		(cdata->oacs & NVME_ID_CTRLR_OACS_FORMAT) ?
     87      1.1  nonaka 		"Supported" : "Not Supported");
     88      1.1  nonaka 	printf("Firmware Activate/Download:  %s\n",
     89      1.1  nonaka 		(cdata->oacs & NVME_ID_CTRLR_OACS_FW) ?
     90      1.1  nonaka 		"Supported" : "Not Supported");
     91  1.2.8.1  martin 	printf("Namespace Managment:         %s\n",
     92  1.2.8.1  martin 		(cdata->oacs & NVME_ID_CTRLR_OACS_NS) ?
     93  1.2.8.1  martin 		"Supported" : "Not Supported");
     94      1.1  nonaka 	printf("Abort Command Limit:         %d\n", cdata->acl+1);
     95      1.1  nonaka 	printf("Async Event Request Limit:   %d\n", cdata->aerl+1);
     96      1.1  nonaka 	printf("Number of Firmware Slots:    ");
     97      1.1  nonaka 	if (cdata->oacs & NVME_ID_CTRLR_OACS_FW)
     98      1.1  nonaka 		printf("%d\n",
     99      1.1  nonaka 		    (uint8_t)__SHIFTOUT(cdata->frmw, NVME_ID_CTRLR_FRMW_NSLOT));
    100      1.1  nonaka 	else
    101      1.1  nonaka 		printf("N/A\n");
    102      1.1  nonaka 	printf("Firmware Slot 1 Read-Only:   ");
    103      1.1  nonaka 	if (cdata->oacs & NVME_ID_CTRLR_OACS_FW)
    104      1.1  nonaka 		printf("%s\n", (cdata->frmw & NVME_ID_CTRLR_FRMW_SLOT1_RO) ?
    105      1.1  nonaka 		    "Yes" : "No");
    106      1.1  nonaka 	else
    107      1.1  nonaka 		printf("N/A\n");
    108      1.1  nonaka 	printf("Per-Namespace SMART Log:     %s\n",
    109      1.1  nonaka 		(cdata->lpa & NVME_ID_CTRLR_LPA_NS_SMART) ? "Yes" : "No");
    110      1.1  nonaka 	printf("Error Log Page Entries:      %d\n", cdata->elpe+1);
    111      1.1  nonaka 	printf("Number of Power States:      %d\n", cdata->npss+1);
    112      1.1  nonaka 	printf("\n");
    113      1.1  nonaka 
    114      1.1  nonaka 	printf("NVM Command Set Attributes\n");
    115      1.1  nonaka 	printf("==========================\n");
    116      1.1  nonaka 	printf("Submission Queue Entry Size\n");
    117      1.1  nonaka 	printf("  Max:                       %d\n",
    118      1.1  nonaka 	    1 << __SHIFTOUT(cdata->sqes, NVME_ID_CTRLR_SQES_MAX));
    119      1.1  nonaka 	printf("  Min:                       %d\n",
    120      1.1  nonaka 	    1 << __SHIFTOUT(cdata->sqes, NVME_ID_CTRLR_SQES_MIN));
    121      1.1  nonaka 	printf("Completion Queue Entry Size\n");
    122      1.1  nonaka 	printf("  Max:                       %d\n",
    123      1.1  nonaka 	    1 << __SHIFTOUT(cdata->cqes, NVME_ID_CTRLR_CQES_MAX));
    124      1.1  nonaka 	printf("  Min:                       %d\n",
    125      1.1  nonaka 	    1 << __SHIFTOUT(cdata->cqes, NVME_ID_CTRLR_CQES_MIN));
    126      1.1  nonaka 	printf("Number of Namespaces:        %d\n", cdata->nn);
    127      1.1  nonaka 	printf("Compare Command:             %s\n",
    128      1.1  nonaka 		(cdata->oncs & NVME_ID_CTRLR_ONCS_COMPARE) ?
    129      1.1  nonaka 		"Supported" : "Not Supported");
    130      1.1  nonaka 	printf("Write Uncorrectable Command: %s\n",
    131      1.1  nonaka 		(cdata->oncs & NVME_ID_CTRLR_ONCS_WRITE_UNC) ?
    132      1.1  nonaka 		"Supported" : "Not Supported");
    133      1.1  nonaka 	printf("Dataset Management Command:  %s\n",
    134      1.1  nonaka 		(cdata->oncs & NVME_ID_CTRLR_ONCS_DSM) ?
    135      1.1  nonaka 		"Supported" : "Not Supported");
    136      1.1  nonaka 	printf("Write Zeroes Command:        %s\n",
    137      1.1  nonaka 		(cdata->oncs & NVME_ID_CTRLR_ONCS_WRITE_ZERO) ?
    138      1.1  nonaka 		"Supported" : "Not Supported");
    139      1.1  nonaka 	printf("Set Features Command:        %s\n",
    140      1.1  nonaka 		(cdata->oncs & NVME_ID_CTRLR_ONCS_SET_FEATURES) ?
    141      1.1  nonaka 		"Supported" : "Not Supported");
    142      1.1  nonaka 	printf("Reservation:                 %s\n",
    143      1.1  nonaka 		(cdata->oncs & NVME_ID_CTRLR_ONCS_RESERVATION) ?
    144      1.1  nonaka 		"Supported" : "Not Supported");
    145      1.1  nonaka 	printf("Volatile Write Cache:        %s\n",
    146      1.1  nonaka 		(cdata->vwc & NVME_ID_CTRLR_VWC_PRESENT) ?
    147      1.1  nonaka 		"Present" : "Not Present");
    148  1.2.8.1  martin 
    149  1.2.8.1  martin 	if (cdata->oacs & NVME_ID_CTRLR_OACS_NS) {
    150  1.2.8.1  martin 		printf("\n");
    151  1.2.8.1  martin 		printf("Namespace Drive Attributes\n");
    152  1.2.8.1  martin 		printf("==========================\n");
    153  1.2.8.1  martin 		print_bignum("NVM total cap:               ",
    154  1.2.8.1  martin 		    cdata->untncap.tnvmcap, "");
    155  1.2.8.1  martin 		print_bignum("NVM unallocated cap:         ",
    156  1.2.8.1  martin 		    cdata->untncap.unvmcap, "");
    157  1.2.8.1  martin 	}
    158      1.1  nonaka }
    159      1.1  nonaka 
    160      1.1  nonaka static void
    161      1.1  nonaka print_namespace(struct nvm_identify_namespace *nsdata)
    162      1.1  nonaka {
    163      1.1  nonaka 	uint32_t	i;
    164      1.1  nonaka 
    165      1.1  nonaka 	printf("Size (in LBAs):              %lld (%lldM)\n",
    166      1.1  nonaka 		(long long)nsdata->nsze,
    167      1.1  nonaka 		(long long)nsdata->nsze / 1024 / 1024);
    168      1.1  nonaka 	printf("Capacity (in LBAs):          %lld (%lldM)\n",
    169      1.1  nonaka 		(long long)nsdata->ncap,
    170      1.1  nonaka 		(long long)nsdata->ncap / 1024 / 1024);
    171      1.1  nonaka 	printf("Utilization (in LBAs):       %lld (%lldM)\n",
    172      1.1  nonaka 		(long long)nsdata->nuse,
    173      1.1  nonaka 		(long long)nsdata->nuse / 1024 / 1024);
    174      1.1  nonaka 	printf("Thin Provisioning:           %s\n",
    175      1.1  nonaka 		(nsdata->nsfeat & NVME_ID_NS_NSFEAT_THIN_PROV) ?
    176      1.1  nonaka 		"Supported" : "Not Supported");
    177      1.1  nonaka 	printf("Number of LBA Formats:       %d\n", nsdata->nlbaf+1);
    178      1.1  nonaka 	printf("Current LBA Format:          LBA Format #%02d\n",
    179      1.1  nonaka 		NVME_ID_NS_FLBAS(nsdata->flbas));
    180      1.1  nonaka 	for (i = 0; i <= nsdata->nlbaf; i++)
    181      1.1  nonaka 		printf("LBA Format #%02d: Data Size: %5d  Metadata Size: %5d\n",
    182      1.1  nonaka 		    i, 1 << nsdata->lbaf[i].lbads, nsdata->lbaf[i].ms);
    183      1.1  nonaka }
    184      1.1  nonaka 
    185      1.2   joerg __dead static void
    186      1.1  nonaka identify_usage(void)
    187      1.1  nonaka {
    188      1.1  nonaka 	fprintf(stderr, "usage:\n");
    189  1.2.8.1  martin 	fprintf(stderr, "\t%s " IDENTIFY_USAGE, getprogname());
    190      1.1  nonaka 	exit(1);
    191      1.1  nonaka }
    192      1.1  nonaka 
    193      1.2   joerg __dead static void
    194      1.1  nonaka identify_ctrlr(int argc, char *argv[])
    195      1.1  nonaka {
    196      1.1  nonaka 	struct nvm_identify_controller	cdata;
    197      1.1  nonaka 	int				ch, fd, hexflag = 0, hexlength;
    198      1.1  nonaka 	int				verboseflag = 0;
    199      1.1  nonaka 
    200      1.1  nonaka 	while ((ch = getopt(argc, argv, "vx")) != -1) {
    201      1.1  nonaka 		switch (ch) {
    202      1.1  nonaka 		case 'v':
    203      1.1  nonaka 			verboseflag = 1;
    204      1.1  nonaka 			break;
    205      1.1  nonaka 		case 'x':
    206      1.1  nonaka 			hexflag = 1;
    207      1.1  nonaka 			break;
    208      1.1  nonaka 		default:
    209      1.1  nonaka 			identify_usage();
    210      1.1  nonaka 		}
    211      1.1  nonaka 	}
    212      1.1  nonaka 
    213      1.1  nonaka 	/* Check that a controller was specified. */
    214      1.1  nonaka 	if (optind >= argc)
    215      1.1  nonaka 		identify_usage();
    216      1.1  nonaka 
    217      1.1  nonaka 	open_dev(argv[optind], &fd, 1, 1);
    218      1.1  nonaka 	read_controller_data(fd, &cdata);
    219      1.1  nonaka 	close(fd);
    220      1.1  nonaka 
    221      1.1  nonaka 	if (hexflag == 1) {
    222      1.1  nonaka 		if (verboseflag == 1)
    223      1.1  nonaka 			hexlength = sizeof(struct nvm_identify_controller);
    224      1.1  nonaka 		else
    225      1.1  nonaka 			hexlength = offsetof(struct nvm_identify_controller,
    226      1.1  nonaka 			    _reserved7);
    227      1.1  nonaka 		print_hex(&cdata, hexlength);
    228      1.1  nonaka 		exit(0);
    229      1.1  nonaka 	}
    230      1.1  nonaka 
    231      1.1  nonaka 	if (verboseflag == 1) {
    232      1.1  nonaka 		fprintf(stderr, "-v not currently supported without -x\n");
    233      1.1  nonaka 		identify_usage();
    234      1.1  nonaka 	}
    235      1.1  nonaka 
    236      1.1  nonaka 	print_controller(&cdata);
    237      1.1  nonaka 	exit(0);
    238      1.1  nonaka }
    239      1.1  nonaka 
    240      1.2   joerg __dead static void
    241      1.1  nonaka identify_ns(int argc, char *argv[])
    242      1.1  nonaka {
    243      1.1  nonaka 	struct nvm_identify_namespace	nsdata;
    244      1.1  nonaka 	char				path[64];
    245      1.1  nonaka 	int				ch, fd, hexflag = 0, hexlength, nsid;
    246      1.1  nonaka 	int				verboseflag = 0;
    247      1.1  nonaka 
    248      1.1  nonaka 	while ((ch = getopt(argc, argv, "vx")) != -1) {
    249      1.1  nonaka 		switch (ch) {
    250      1.1  nonaka 		case 'v':
    251      1.1  nonaka 			verboseflag = 1;
    252      1.1  nonaka 			break;
    253      1.1  nonaka 		case 'x':
    254      1.1  nonaka 			hexflag = 1;
    255      1.1  nonaka 			break;
    256      1.1  nonaka 		default:
    257      1.1  nonaka 			identify_usage();
    258      1.1  nonaka 		}
    259      1.1  nonaka 	}
    260      1.1  nonaka 
    261      1.1  nonaka 	/* Check that a namespace was specified. */
    262      1.1  nonaka 	if (optind >= argc)
    263      1.1  nonaka 		identify_usage();
    264      1.1  nonaka 
    265      1.1  nonaka 	/*
    266      1.1  nonaka 	 * Check if the specified device node exists before continuing.
    267      1.1  nonaka 	 *  This is a cleaner check for cases where the correct controller
    268      1.1  nonaka 	 *  is specified, but an invalid namespace on that controller.
    269      1.1  nonaka 	 */
    270      1.1  nonaka 	open_dev(argv[optind], &fd, 1, 1);
    271      1.1  nonaka 	close(fd);
    272      1.1  nonaka 
    273      1.1  nonaka 	/*
    274      1.1  nonaka 	 * We send IDENTIFY commands to the controller, not the namespace,
    275      1.1  nonaka 	 *  since it is an admin cmd.  The namespace ID will be specified in
    276      1.1  nonaka 	 *  the IDENTIFY command itself.  So parse the namespace's device node
    277      1.1  nonaka 	 *  string to get the controller substring and namespace ID.
    278      1.1  nonaka 	 */
    279      1.1  nonaka 	parse_ns_str(argv[optind], path, &nsid);
    280      1.1  nonaka 	open_dev(path, &fd, 1, 1);
    281      1.1  nonaka 	read_namespace_data(fd, nsid, &nsdata);
    282      1.1  nonaka 	close(fd);
    283      1.1  nonaka 
    284      1.1  nonaka 	if (hexflag == 1) {
    285      1.1  nonaka 		if (verboseflag == 1)
    286      1.1  nonaka 			hexlength = sizeof(struct nvm_identify_namespace);
    287      1.1  nonaka 		else
    288      1.1  nonaka 			hexlength = offsetof(struct nvm_identify_namespace,
    289      1.1  nonaka 			    _reserved2);
    290      1.1  nonaka 		print_hex(&nsdata, hexlength);
    291      1.1  nonaka 		exit(0);
    292      1.1  nonaka 	}
    293      1.1  nonaka 
    294      1.1  nonaka 	if (verboseflag == 1) {
    295      1.1  nonaka 		fprintf(stderr, "-v not currently supported without -x\n");
    296      1.1  nonaka 		identify_usage();
    297      1.1  nonaka 	}
    298      1.1  nonaka 
    299      1.1  nonaka 	print_namespace(&nsdata);
    300      1.1  nonaka 	exit(0);
    301      1.1  nonaka }
    302      1.1  nonaka 
    303      1.1  nonaka void
    304      1.1  nonaka identify(int argc, char *argv[])
    305      1.1  nonaka {
    306      1.1  nonaka 	char	*target;
    307      1.1  nonaka 
    308      1.1  nonaka 	if (argc < 2)
    309      1.1  nonaka 		identify_usage();
    310      1.1  nonaka 
    311      1.1  nonaka 	while (getopt(argc, argv, "vx") != -1) ;
    312      1.1  nonaka 
    313      1.1  nonaka 	/* Check that a controller or namespace was specified. */
    314      1.1  nonaka 	if (optind >= argc)
    315      1.1  nonaka 		identify_usage();
    316      1.1  nonaka 
    317      1.1  nonaka 	target = argv[optind];
    318      1.1  nonaka 
    319      1.1  nonaka 	optreset = 1;
    320      1.1  nonaka 	optind = 1;
    321      1.1  nonaka 
    322      1.1  nonaka 	/*
    323      1.1  nonaka 	 * If device node contains "ns", we consider it a namespace,
    324      1.1  nonaka 	 *  otherwise, consider it a controller.
    325      1.1  nonaka 	 */
    326      1.1  nonaka 	if (strstr(target, NVME_NS_PREFIX) == NULL)
    327      1.1  nonaka 		identify_ctrlr(argc, argv);
    328      1.1  nonaka 	else
    329      1.1  nonaka 		identify_ns(argc, argv);
    330      1.1  nonaka }
    331