Home | History | Annotate | Line # | Download | only in nvmectl
logpage.c revision 1.2.2.1
      1  1.2.2.1  pgoyette /*	$NetBSD: logpage.c,v 1.2.2.1 2017/03/20 06:57:02 pgoyette Exp $	*/
      2      1.1    nonaka 
      3      1.1    nonaka /*-
      4      1.1    nonaka  * Copyright (c) 2013 EMC Corp.
      5      1.1    nonaka  * All rights reserved.
      6      1.1    nonaka  *
      7      1.1    nonaka  * Copyright (C) 2012-2013 Intel Corporation
      8      1.1    nonaka  * All rights reserved.
      9      1.1    nonaka  *
     10      1.1    nonaka  * Redistribution and use in source and binary forms, with or without
     11      1.1    nonaka  * modification, are permitted provided that the following conditions
     12      1.1    nonaka  * are met:
     13      1.1    nonaka  * 1. Redistributions of source code must retain the above copyright
     14      1.1    nonaka  *    notice, this list of conditions and the following disclaimer.
     15      1.1    nonaka  * 2. Redistributions in binary form must reproduce the above copyright
     16      1.1    nonaka  *    notice, this list of conditions and the following disclaimer in the
     17      1.1    nonaka  *    documentation and/or other materials provided with the distribution.
     18      1.1    nonaka  *
     19      1.1    nonaka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     20      1.1    nonaka  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21      1.1    nonaka  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22      1.1    nonaka  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     23      1.1    nonaka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24      1.1    nonaka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25      1.1    nonaka  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26      1.1    nonaka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27      1.1    nonaka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28      1.1    nonaka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29      1.1    nonaka  * SUCH DAMAGE.
     30      1.1    nonaka  */
     31      1.1    nonaka 
     32      1.1    nonaka #include <sys/cdefs.h>
     33      1.1    nonaka #ifndef lint
     34  1.2.2.1  pgoyette __RCSID("$NetBSD: logpage.c,v 1.2.2.1 2017/03/20 06:57:02 pgoyette Exp $");
     35      1.1    nonaka #if 0
     36      1.1    nonaka __FBSDID("$FreeBSD: head/sbin/nvmecontrol/logpage.c 285796 2015-07-22 16:10:29Z jimharris $");
     37      1.1    nonaka #endif
     38      1.1    nonaka #endif
     39      1.1    nonaka 
     40      1.1    nonaka #include <sys/param.h>
     41      1.1    nonaka #include <sys/ioccom.h>
     42      1.1    nonaka 
     43      1.1    nonaka #include <ctype.h>
     44      1.1    nonaka #include <err.h>
     45      1.1    nonaka #include <fcntl.h>
     46      1.1    nonaka #include <stdbool.h>
     47      1.1    nonaka #include <stddef.h>
     48      1.1    nonaka #include <stdio.h>
     49      1.1    nonaka #include <stdlib.h>
     50      1.1    nonaka #include <string.h>
     51      1.1    nonaka #include <unistd.h>
     52      1.1    nonaka 
     53      1.1    nonaka #include "nvmectl.h"
     54  1.2.2.1  pgoyette #include "bn.h"
     55      1.1    nonaka 
     56      1.1    nonaka #define DEFAULT_SIZE	(4096)
     57      1.1    nonaka #define MAX_FW_SLOTS	(7)
     58      1.1    nonaka 
     59      1.1    nonaka typedef void (*print_fn_t)(void *buf, uint32_t size);
     60      1.1    nonaka 
     61      1.1    nonaka static void *
     62      1.1    nonaka get_log_buffer(uint32_t size)
     63      1.1    nonaka {
     64      1.1    nonaka 	void	*buf;
     65      1.1    nonaka 
     66      1.1    nonaka 	if ((buf = malloc(size)) == NULL)
     67      1.1    nonaka 		errx(1, "unable to malloc %u bytes", size);
     68      1.1    nonaka 
     69      1.1    nonaka 	memset(buf, 0, size);
     70      1.1    nonaka 	return (buf);
     71      1.1    nonaka }
     72      1.1    nonaka 
     73      1.1    nonaka void
     74      1.1    nonaka read_logpage(int fd, uint8_t log_page, int nsid, void *payload,
     75      1.1    nonaka     uint32_t payload_size)
     76      1.1    nonaka {
     77      1.1    nonaka 	struct nvme_pt_command	pt;
     78      1.1    nonaka 
     79      1.1    nonaka 	memset(&pt, 0, sizeof(pt));
     80      1.1    nonaka 	pt.cmd.opcode = NVM_ADMIN_GET_LOG_PG;
     81      1.1    nonaka 	pt.cmd.nsid = nsid;
     82      1.1    nonaka 	pt.cmd.cdw10 = ((payload_size/sizeof(uint32_t)) - 1) << 16;
     83      1.1    nonaka 	pt.cmd.cdw10 |= log_page;
     84      1.1    nonaka 	pt.buf = payload;
     85      1.1    nonaka 	pt.len = payload_size;
     86      1.1    nonaka 	pt.is_read = 1;
     87      1.1    nonaka 
     88      1.1    nonaka 	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
     89      1.1    nonaka 		err(1, "get log page request failed");
     90      1.1    nonaka 
     91      1.1    nonaka 	if (nvme_completion_is_error(&pt.cpl))
     92      1.1    nonaka 		errx(1, "get log page request returned error");
     93      1.1    nonaka }
     94      1.1    nonaka 
     95      1.1    nonaka static void
     96      1.1    nonaka print_log_error(void *buf, uint32_t size)
     97      1.1    nonaka {
     98      1.1    nonaka 	int					i, nentries;
     99      1.1    nonaka 	struct nvme_error_information_entry	*entry = buf;
    100      1.1    nonaka 
    101      1.1    nonaka 	printf("Error Information Log\n");
    102      1.1    nonaka 	printf("=====================\n");
    103      1.1    nonaka 
    104      1.1    nonaka 	if (entry->error_count == 0) {
    105      1.1    nonaka 		printf("No error entries found\n");
    106      1.1    nonaka 		return;
    107      1.1    nonaka 	}
    108      1.1    nonaka 
    109      1.1    nonaka 	nentries = size/sizeof(struct nvme_error_information_entry);
    110      1.1    nonaka 	for (i = 0; i < nentries; i++, entry++) {
    111      1.1    nonaka 		if (entry->error_count == 0)
    112      1.1    nonaka 			break;
    113      1.1    nonaka 
    114      1.1    nonaka 		printf("Entry %02d\n", i + 1);
    115      1.1    nonaka 		printf("=========\n");
    116      1.1    nonaka 		printf(" Error count:           %ju\n", entry->error_count);
    117      1.1    nonaka 		printf(" Submission queue ID:   %u\n", entry->sqid);
    118      1.1    nonaka 		printf(" Command ID:            %u\n", entry->cid);
    119      1.1    nonaka 		/* TODO: Export nvme_status_string structures from kernel? */
    120      1.1    nonaka 		printf(" Status:\n");
    121      1.1    nonaka 		printf("  Phase tag:            %d\n",
    122      1.1    nonaka 		    (uint16_t)__SHIFTOUT(entry->status, NVME_CQE_PHASE));
    123      1.1    nonaka 		printf("  Status code:          %d\n",
    124      1.1    nonaka 		    (uint16_t)__SHIFTOUT(entry->status, NVME_CQE_SC_MASK));
    125      1.1    nonaka 		printf("  Status code type:     %d\n",
    126      1.1    nonaka 		    (uint16_t)__SHIFTOUT(entry->status, NVME_CQE_SCT_MASK));
    127      1.1    nonaka 		printf("  More:                 %d\n",
    128      1.1    nonaka 		    (uint16_t)__SHIFTOUT(entry->status, NVME_CQE_M));
    129      1.1    nonaka 		printf("  DNR:                  %d\n",
    130      1.1    nonaka 		    (uint16_t)__SHIFTOUT(entry->status, NVME_CQE_DNR));
    131      1.1    nonaka 		printf(" Error location:        %u\n", entry->error_location);
    132      1.1    nonaka 		printf(" LBA:                   %ju\n", entry->lba);
    133      1.1    nonaka 		printf(" Namespace ID:          %u\n", entry->nsid);
    134      1.1    nonaka 		printf(" Vendor specific info:  %u\n", entry->vendor_specific);
    135      1.1    nonaka 		printf(" Command specific info: %ju\n",
    136      1.1    nonaka 		    entry->command_specific);
    137      1.1    nonaka 	}
    138      1.1    nonaka }
    139      1.1    nonaka 
    140  1.2.2.1  pgoyette #define	METRIX_PREFIX_BUFSIZ	17
    141  1.2.2.1  pgoyette #define	NO_METRIX_PREFIX_BUFSIZ	42
    142  1.2.2.1  pgoyette 
    143  1.2.2.1  pgoyette static void
    144  1.2.2.1  pgoyette print_bignum(const char *title, uint64_t v[2], const char *suffix)
    145  1.2.2.1  pgoyette {
    146  1.2.2.1  pgoyette 	char buf[64];
    147  1.2.2.1  pgoyette 	uint8_t tmp[16];
    148  1.2.2.1  pgoyette 	uint64_t l = le64toh(v[0]);
    149  1.2.2.1  pgoyette 	uint64_t h = le64toh(v[1]);
    150  1.2.2.1  pgoyette 
    151  1.2.2.1  pgoyette 	tmp[ 0] = (h >> 56) & 0xff;
    152  1.2.2.1  pgoyette 	tmp[ 1] = (h >> 48) & 0xff;
    153  1.2.2.1  pgoyette 	tmp[ 2] = (h >> 40) & 0xff;
    154  1.2.2.1  pgoyette 	tmp[ 3] = (h >> 32) & 0xff;
    155  1.2.2.1  pgoyette 	tmp[ 4] = (h >> 24) & 0xff;
    156  1.2.2.1  pgoyette 	tmp[ 5] = (h >> 16) & 0xff;
    157  1.2.2.1  pgoyette 	tmp[ 6] = (h >> 8) & 0xff;
    158  1.2.2.1  pgoyette 	tmp[ 7] = h & 0xff;
    159  1.2.2.1  pgoyette 	tmp[ 8] = (l >> 56) & 0xff;
    160  1.2.2.1  pgoyette 	tmp[ 9] = (l >> 48) & 0xff;
    161  1.2.2.1  pgoyette 	tmp[10] = (l >> 40) & 0xff;
    162  1.2.2.1  pgoyette 	tmp[11] = (l >> 32) & 0xff;
    163  1.2.2.1  pgoyette 	tmp[12] = (l >> 24) & 0xff;
    164  1.2.2.1  pgoyette 	tmp[13] = (l >> 16) & 0xff;
    165  1.2.2.1  pgoyette 	tmp[14] = (l >> 8) & 0xff;
    166  1.2.2.1  pgoyette 	tmp[15] = l & 0xff;
    167  1.2.2.1  pgoyette 
    168  1.2.2.1  pgoyette 	buf[0] = '\0';
    169  1.2.2.1  pgoyette 	BIGNUM *bn = BN_bin2bn(tmp, __arraycount(tmp), NULL);
    170  1.2.2.1  pgoyette 	if (bn != NULL) {
    171  1.2.2.1  pgoyette 		humanize_bignum(buf, METRIX_PREFIX_BUFSIZ + strlen(suffix),
    172  1.2.2.1  pgoyette 		    bn, suffix, HN_AUTOSCALE, HN_DECIMAL);
    173  1.2.2.1  pgoyette 		BN_free(bn);
    174  1.2.2.1  pgoyette 	}
    175  1.2.2.1  pgoyette 	if (buf[0] == '\0')
    176  1.2.2.1  pgoyette 		snprintf(buf, sizeof(buf), "0x%016jx%016jx", h, l);
    177  1.2.2.1  pgoyette 	printf("%-31s %s\n", title, buf);
    178  1.2.2.1  pgoyette }
    179  1.2.2.1  pgoyette 
    180      1.1    nonaka static void
    181      1.1    nonaka print_log_health(void *buf, uint32_t size __unused)
    182      1.1    nonaka {
    183      1.1    nonaka 	struct nvme_health_information_page *health = buf;
    184      1.1    nonaka 	float composite_temperature = health->composite_temperature;
    185      1.1    nonaka 
    186      1.1    nonaka 	printf("SMART/Health Information Log\n");
    187      1.1    nonaka 	printf("============================\n");
    188      1.1    nonaka 
    189      1.1    nonaka 	printf("Critical Warning State:         0x%02x\n",
    190      1.1    nonaka 	    health->critical_warning);
    191      1.1    nonaka 	printf(" Available spare:               %d\n",
    192      1.1    nonaka 	    (uint8_t)__SHIFTOUT(health->critical_warning,
    193      1.1    nonaka 	      NVME_HEALTH_PAGE_CW_AVAIL_SPARE));
    194      1.1    nonaka 	printf(" Temperature:                   %d\n",
    195      1.1    nonaka 	    (uint8_t)__SHIFTOUT(health->critical_warning,
    196      1.1    nonaka 	      NVME_HEALTH_PAGE_CW_TEMPERTURE));
    197      1.1    nonaka 	printf(" Device reliability:            %d\n",
    198      1.1    nonaka 	    (uint8_t)__SHIFTOUT(health->critical_warning,
    199      1.1    nonaka 	      NVME_HEALTH_PAGE_CW_DEVICE_RELIABLITY));
    200      1.1    nonaka 	printf(" Read only:                     %d\n",
    201      1.1    nonaka 	    (uint8_t)__SHIFTOUT(health->critical_warning,
    202      1.1    nonaka 	      NVME_HEALTH_PAGE_CW_READ_ONLY));
    203      1.1    nonaka 	printf(" Volatile memory backup:        %d\n",
    204      1.1    nonaka 	    (uint8_t)__SHIFTOUT(health->critical_warning,
    205      1.1    nonaka 	      NVME_HEALTH_PAGE_CW_VOLATILE_MEMORY_BACKUP));
    206      1.1    nonaka 	printf("Temperature:                    %u K, %2.2f C, %3.2f F\n",
    207      1.1    nonaka 	    health->composite_temperature,
    208      1.1    nonaka 	    composite_temperature - (float)273.15,
    209      1.1    nonaka 	    (composite_temperature * (float)9/5) - (float)459.67);
    210      1.1    nonaka 	printf("Available spare:                %u\n",
    211      1.1    nonaka 	    health->available_spare);
    212      1.1    nonaka 	printf("Available spare threshold:      %u\n",
    213      1.1    nonaka 	    health->available_spare_threshold);
    214      1.1    nonaka 	printf("Percentage used:                %u\n",
    215      1.1    nonaka 	    health->percentage_used);
    216      1.1    nonaka 
    217  1.2.2.1  pgoyette 	print_bignum("Data units (512 byte) read:",
    218  1.2.2.1  pgoyette 	    health->data_units_read, "");
    219  1.2.2.1  pgoyette 	print_bignum("Data units (512 byte) written:",
    220  1.2.2.1  pgoyette 	    health->data_units_written, "");
    221  1.2.2.1  pgoyette 	print_bignum("Host read commands:",
    222  1.2.2.1  pgoyette 	    health->host_read_commands, "");
    223  1.2.2.1  pgoyette 	print_bignum("Host write commands:",
    224  1.2.2.1  pgoyette 	    health->host_write_commands, "");
    225  1.2.2.1  pgoyette 	print_bignum("Controller busy time (minutes):",
    226  1.2.2.1  pgoyette 	    health->controller_busy_time, "");
    227  1.2.2.1  pgoyette 	print_bignum("Power cycles:",
    228  1.2.2.1  pgoyette 	    health->power_cycles, "");
    229  1.2.2.1  pgoyette 	print_bignum("Power on hours:",
    230  1.2.2.1  pgoyette 	    health->power_on_hours, "");
    231  1.2.2.1  pgoyette 	print_bignum("Unsafe shutdowns:",
    232  1.2.2.1  pgoyette 	    health->unsafe_shutdowns, "");
    233  1.2.2.1  pgoyette 	print_bignum("Media errors:",
    234  1.2.2.1  pgoyette 	    health->media_errors, "");
    235  1.2.2.1  pgoyette 	print_bignum("No. error info log entries:",
    236  1.2.2.1  pgoyette 	    health->num_error_info_log_entries, "");
    237      1.1    nonaka }
    238      1.1    nonaka 
    239      1.1    nonaka static void
    240      1.1    nonaka print_log_firmware(void *buf, uint32_t size __unused)
    241      1.1    nonaka {
    242      1.1    nonaka 	u_int				i;
    243      1.1    nonaka 	const char			*status;
    244      1.1    nonaka 	struct nvme_firmware_page	*fw = buf;
    245      1.1    nonaka 
    246      1.1    nonaka 	printf("Firmware Slot Log\n");
    247      1.1    nonaka 	printf("=================\n");
    248      1.1    nonaka 
    249      1.1    nonaka 	for (i = 0; i < MAX_FW_SLOTS; i++) {
    250      1.1    nonaka 		printf("Slot %d: ", i + 1);
    251      1.1    nonaka 		if (__SHIFTOUT(fw->afi, NVME_FW_PAGE_AFI_SLOT) == i + 1)
    252      1.1    nonaka 			status = "  Active";
    253      1.1    nonaka 		else
    254      1.1    nonaka 			status = "Inactive";
    255      1.1    nonaka 
    256      1.1    nonaka 		if (fw->revision[i] == 0LLU)
    257      1.1    nonaka 			printf("Empty\n");
    258      1.1    nonaka 		else
    259      1.1    nonaka 			if (isprint(*(uint8_t *)&fw->revision[i]))
    260      1.1    nonaka 				printf("[%s] %.8s\n", status,
    261      1.1    nonaka 				    (char *)&fw->revision[i]);
    262      1.1    nonaka 			else
    263      1.1    nonaka 				printf("[%s] %016jx\n", status,
    264      1.1    nonaka 				    fw->revision[i]);
    265      1.1    nonaka 	}
    266      1.1    nonaka }
    267      1.1    nonaka 
    268      1.1    nonaka static struct logpage_function {
    269      1.1    nonaka 	uint8_t		log_page;
    270      1.1    nonaka 	print_fn_t	fn;
    271      1.1    nonaka } logfuncs[] = {
    272      1.1    nonaka 	{NVME_LOG_ERROR,		print_log_error		},
    273      1.1    nonaka 	{NVME_LOG_HEALTH_INFORMATION,	print_log_health	},
    274      1.1    nonaka 	{NVME_LOG_FIRMWARE_SLOT,	print_log_firmware	},
    275      1.1    nonaka 	{0,				NULL			},
    276      1.1    nonaka };
    277      1.1    nonaka 
    278      1.2     joerg __dead static void
    279      1.1    nonaka logpage_usage(void)
    280      1.1    nonaka {
    281      1.1    nonaka 	fprintf(stderr, "usage:\n");
    282      1.1    nonaka 	fprintf(stderr, LOGPAGE_USAGE);
    283      1.1    nonaka 	exit(1);
    284      1.1    nonaka }
    285      1.1    nonaka 
    286      1.1    nonaka void
    287      1.1    nonaka logpage(int argc, char *argv[])
    288      1.1    nonaka {
    289      1.1    nonaka 	int				fd, nsid;
    290      1.1    nonaka 	int				log_page = 0, pageflag = false;
    291      1.1    nonaka 	int				hexflag = false, ns_specified;
    292      1.1    nonaka 	int				ch;
    293      1.1    nonaka 	char				*p;
    294      1.1    nonaka 	char				cname[64];
    295      1.1    nonaka 	uint32_t			size;
    296      1.1    nonaka 	void				*buf;
    297      1.1    nonaka 	struct logpage_function		*f;
    298      1.1    nonaka 	struct nvm_identify_controller	cdata;
    299      1.1    nonaka 	print_fn_t			print_fn;
    300      1.1    nonaka 
    301      1.1    nonaka 	while ((ch = getopt(argc, argv, "p:x")) != -1) {
    302      1.1    nonaka 		switch (ch) {
    303      1.1    nonaka 		case 'p':
    304      1.1    nonaka 			/* TODO: Add human-readable ASCII page IDs */
    305      1.1    nonaka 			log_page = strtol(optarg, &p, 0);
    306      1.1    nonaka 			if (p != NULL && *p != '\0') {
    307      1.1    nonaka 				fprintf(stderr,
    308      1.1    nonaka 				    "\"%s\" not valid log page id.\n",
    309      1.1    nonaka 				    optarg);
    310      1.1    nonaka 				logpage_usage();
    311      1.1    nonaka 			/* TODO: Define valid log page id ranges in nvme.h? */
    312      1.1    nonaka 			} else if (log_page == 0 ||
    313      1.1    nonaka 				   (log_page >= 0x04 && log_page <= 0x7F) ||
    314      1.1    nonaka 				   (log_page >= 0x80 && log_page <= 0xBF)) {
    315      1.1    nonaka 				fprintf(stderr,
    316      1.1    nonaka 				    "\"%s\" not valid log page id.\n",
    317      1.1    nonaka 				    optarg);
    318      1.1    nonaka 				logpage_usage();
    319      1.1    nonaka 			}
    320      1.1    nonaka 			pageflag = true;
    321      1.1    nonaka 			break;
    322      1.1    nonaka 		case 'x':
    323      1.1    nonaka 			hexflag = true;
    324      1.1    nonaka 			break;
    325      1.1    nonaka 		}
    326      1.1    nonaka 	}
    327      1.1    nonaka 
    328      1.1    nonaka 	if (!pageflag) {
    329      1.1    nonaka 		printf("Missing page_id (-p).\n");
    330      1.1    nonaka 		logpage_usage();
    331      1.1    nonaka 	}
    332      1.1    nonaka 
    333      1.1    nonaka 	/* Check that a controller and/or namespace was specified. */
    334      1.1    nonaka 	if (optind >= argc)
    335      1.1    nonaka 		logpage_usage();
    336      1.1    nonaka 
    337      1.1    nonaka 	if (strstr(argv[optind], NVME_NS_PREFIX) != NULL) {
    338      1.1    nonaka 		ns_specified = true;
    339      1.1    nonaka 		parse_ns_str(argv[optind], cname, &nsid);
    340      1.1    nonaka 		open_dev(cname, &fd, 1, 1);
    341      1.1    nonaka 	} else {
    342      1.1    nonaka 		ns_specified = false;
    343      1.1    nonaka 		nsid = 0xffffffff;
    344      1.1    nonaka 		open_dev(argv[optind], &fd, 1, 1);
    345      1.1    nonaka 	}
    346      1.1    nonaka 
    347      1.1    nonaka 	read_controller_data(fd, &cdata);
    348      1.1    nonaka 
    349      1.1    nonaka 	/*
    350      1.1    nonaka 	 * The log page attribtues indicate whether or not the controller
    351      1.1    nonaka 	 * supports the SMART/Health information log page on a per
    352      1.1    nonaka 	 * namespace basis.
    353      1.1    nonaka 	 */
    354      1.1    nonaka 	if (ns_specified) {
    355      1.1    nonaka 		if (log_page != NVME_LOG_HEALTH_INFORMATION)
    356      1.1    nonaka 			errx(1, "log page %d valid only at controller level",
    357      1.1    nonaka 			    log_page);
    358      1.1    nonaka 		if (!(cdata.lpa & NVME_ID_CTRLR_LPA_NS_SMART))
    359      1.1    nonaka 			errx(1,
    360      1.1    nonaka 			    "controller does not support per namespace "
    361      1.1    nonaka 			    "smart/health information");
    362      1.1    nonaka 	}
    363      1.1    nonaka 
    364      1.1    nonaka 	print_fn = print_hex;
    365      1.1    nonaka 	if (!hexflag) {
    366      1.1    nonaka 		/*
    367      1.1    nonaka 		 * See if there is a pretty print function for the
    368      1.1    nonaka 		 *  specified log page.  If one isn't found, we
    369      1.1    nonaka 		 *  just revert to the default (print_hex).
    370      1.1    nonaka 		 */
    371      1.1    nonaka 		f = logfuncs;
    372      1.1    nonaka 		while (f->log_page > 0) {
    373      1.1    nonaka 			if (log_page == f->log_page) {
    374      1.1    nonaka 				print_fn = f->fn;
    375      1.1    nonaka 				break;
    376      1.1    nonaka 			}
    377      1.1    nonaka 			f++;
    378      1.1    nonaka 		}
    379      1.1    nonaka 	}
    380      1.1    nonaka 
    381      1.1    nonaka 	/* Read the log page */
    382      1.1    nonaka 	switch (log_page) {
    383      1.1    nonaka 	case NVME_LOG_ERROR:
    384      1.1    nonaka 		size = sizeof(struct nvme_error_information_entry);
    385      1.1    nonaka 		size *= (cdata.elpe + 1);
    386      1.1    nonaka 		break;
    387      1.1    nonaka 	case NVME_LOG_HEALTH_INFORMATION:
    388      1.1    nonaka 		size = sizeof(struct nvme_health_information_page);
    389      1.1    nonaka 		break;
    390      1.1    nonaka 	case NVME_LOG_FIRMWARE_SLOT:
    391      1.1    nonaka 		size = sizeof(struct nvme_firmware_page);
    392      1.1    nonaka 		break;
    393      1.1    nonaka 	default:
    394      1.1    nonaka 		size = DEFAULT_SIZE;
    395      1.1    nonaka 		break;
    396      1.1    nonaka 	}
    397      1.1    nonaka 
    398      1.1    nonaka 	buf = get_log_buffer(size);
    399      1.1    nonaka 	read_logpage(fd, log_page, nsid, buf, size);
    400      1.1    nonaka 	print_fn(buf, size);
    401      1.1    nonaka 
    402      1.1    nonaka 	close(fd);
    403      1.1    nonaka 	exit(0);
    404      1.1    nonaka }
    405