xref: /illumos-gate/usr/src/cmd/diskinfo/diskinfo.c (revision ef150c2b)
1ed5fe2f8SYuri Pankov /*
2ed5fe2f8SYuri Pankov  * This file and its contents are supplied under the terms of the
3ed5fe2f8SYuri Pankov  * Common Development and Distribution License ("CDDL"), version 1.0.
4ed5fe2f8SYuri Pankov  * You may only use this file in accordance with the terms of version
5ed5fe2f8SYuri Pankov  * 1.0 of the CDDL.
6ed5fe2f8SYuri Pankov  *
7ed5fe2f8SYuri Pankov  * A full copy of the text of the CDDL should have accompanied this
8ed5fe2f8SYuri Pankov  * source.  A copy of the CDDL is also available via the Internet at
9ed5fe2f8SYuri Pankov  * http://www.illumos.org/license/CDDL.
10ed5fe2f8SYuri Pankov  */
11ed5fe2f8SYuri Pankov 
12ed5fe2f8SYuri Pankov /*
13672fc84aSRobert Mustacchi  * Copyright (c) 2018 Joyent Inc., All rights reserved.
14ca706442SAndrew Stormont  * Copyright 2021 RackTop Systems, Inc.
152b766db4SAlexander Eremin  * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
167f06aed1SRobert Mustacchi  * Copyright 2023 Oxide Computer Company
17ed5fe2f8SYuri Pankov  */
18ed5fe2f8SYuri Pankov 
19ed5fe2f8SYuri Pankov #include <sys/types.h>
20ed5fe2f8SYuri Pankov #include <sys/stat.h>
21ed5fe2f8SYuri Pankov #include <fcntl.h>
22ed5fe2f8SYuri Pankov #include <errno.h>
23ed5fe2f8SYuri Pankov #include <string.h>
24ed5fe2f8SYuri Pankov #include <stdio.h>
25ed5fe2f8SYuri Pankov #include <unistd.h>
26ed5fe2f8SYuri Pankov #include <limits.h>
27ed5fe2f8SYuri Pankov #include <assert.h>
28ed5fe2f8SYuri Pankov #include <ctype.h>
29ed5fe2f8SYuri Pankov #include <stdarg.h>
30ed5fe2f8SYuri Pankov #include <strings.h>
31e98897e3SJoshua M. Clulow #include <err.h>
32ed5fe2f8SYuri Pankov 
33ed5fe2f8SYuri Pankov #include <libdiskmgt.h>
34ed5fe2f8SYuri Pankov #include <sys/nvpair.h>
35ed5fe2f8SYuri Pankov #include <sys/param.h>
36ed5fe2f8SYuri Pankov #include <sys/ccompile.h>
37ed5fe2f8SYuri Pankov 
38ed5fe2f8SYuri Pankov #include <fm/libtopo.h>
39ed5fe2f8SYuri Pankov #include <fm/topo_hc.h>
40ed5fe2f8SYuri Pankov #include <fm/topo_list.h>
41ed5fe2f8SYuri Pankov #include <sys/fm/protocol.h>
42ed5fe2f8SYuri Pankov #include <modules/common/disk/disk.h>
43ed5fe2f8SYuri Pankov 
44ed5fe2f8SYuri Pankov typedef struct di_opts {
45ed5fe2f8SYuri Pankov 	boolean_t di_scripted;
46ed5fe2f8SYuri Pankov 	boolean_t di_parseable;
47ed5fe2f8SYuri Pankov 	boolean_t di_physical;
48ed5fe2f8SYuri Pankov 	boolean_t di_condensed;
49ed5fe2f8SYuri Pankov } di_opts_t;
50ed5fe2f8SYuri Pankov 
51ed5fe2f8SYuri Pankov typedef struct di_phys {
52ed5fe2f8SYuri Pankov 	const char *dp_dev;
53ed5fe2f8SYuri Pankov 	const char *dp_serial;
54ed5fe2f8SYuri Pankov 	const char *dp_slotname;
55ed5fe2f8SYuri Pankov 	int dp_chassis;
56ed5fe2f8SYuri Pankov 	int dp_slot;
57ed5fe2f8SYuri Pankov 	int dp_faulty;
58ed5fe2f8SYuri Pankov 	int dp_locate;
59ed5fe2f8SYuri Pankov } di_phys_t;
60ed5fe2f8SYuri Pankov 
61ed5fe2f8SYuri Pankov static void
usage(const char * execname)62ed5fe2f8SYuri Pankov usage(const char *execname)
63ed5fe2f8SYuri Pankov {
64ed5fe2f8SYuri Pankov 	(void) fprintf(stderr, "Usage: %s [-Hp] [{-c|-P}]\n", execname);
65ed5fe2f8SYuri Pankov }
66ed5fe2f8SYuri Pankov 
67ed5fe2f8SYuri Pankov static void
nvlist_query_string(nvlist_t * nvl,const char * label,char ** val)68ed5fe2f8SYuri Pankov nvlist_query_string(nvlist_t *nvl, const char *label, char **val)
69ed5fe2f8SYuri Pankov {
70ed5fe2f8SYuri Pankov 	if (nvlist_lookup_string(nvl, label, val) != 0)
71ed5fe2f8SYuri Pankov 		*val = "-";
72ed5fe2f8SYuri Pankov }
73ed5fe2f8SYuri Pankov 
74ed5fe2f8SYuri Pankov static const char *
display_string(const char * label)75ed5fe2f8SYuri Pankov display_string(const char *label)
76ed5fe2f8SYuri Pankov {
77ed5fe2f8SYuri Pankov 	return ((label) ? label : "-");
78ed5fe2f8SYuri Pankov }
79ed5fe2f8SYuri Pankov 
80ed5fe2f8SYuri Pankov static const char *
display_tristate(int val)81ed5fe2f8SYuri Pankov display_tristate(int val)
82ed5fe2f8SYuri Pankov {
83ed5fe2f8SYuri Pankov 	if (val == 0)
84ed5fe2f8SYuri Pankov 		return ("no");
85ed5fe2f8SYuri Pankov 	if (val == 1)
86ed5fe2f8SYuri Pankov 		return ("yes");
87ed5fe2f8SYuri Pankov 
88ed5fe2f8SYuri Pankov 	return ("-");
89ed5fe2f8SYuri Pankov }
90ed5fe2f8SYuri Pankov 
91ed5fe2f8SYuri Pankov static char
condensed_tristate(int val,char c)92ed5fe2f8SYuri Pankov condensed_tristate(int val, char c)
93ed5fe2f8SYuri Pankov {
94ed5fe2f8SYuri Pankov 	if (val == 0)
95ed5fe2f8SYuri Pankov 		return ('-');
96ed5fe2f8SYuri Pankov 	if (val == 1)
97ed5fe2f8SYuri Pankov 		return (c);
98ed5fe2f8SYuri Pankov 
99ed5fe2f8SYuri Pankov 	return ('?');
100ed5fe2f8SYuri Pankov }
101ed5fe2f8SYuri Pankov static int
disk_walker(topo_hdl_t * hp,tnode_t * np,void * arg)102ed5fe2f8SYuri Pankov disk_walker(topo_hdl_t *hp, tnode_t *np, void *arg)
103ed5fe2f8SYuri Pankov {
104ed5fe2f8SYuri Pankov 	di_phys_t *pp = arg;
105ed5fe2f8SYuri Pankov 	topo_faclist_t fl;
106ed5fe2f8SYuri Pankov 	topo_faclist_t *lp;
107e98897e3SJoshua M. Clulow 	int e;
108ed5fe2f8SYuri Pankov 	topo_led_state_t mode;
109ed5fe2f8SYuri Pankov 	topo_led_type_t type;
110ed5fe2f8SYuri Pankov 	char *name, *slotname, *serial;
1117f06aed1SRobert Mustacchi 	boolean_t consider_label = B_TRUE;
112ed5fe2f8SYuri Pankov 
113ed5fe2f8SYuri Pankov 	if (strcmp(topo_node_name(np), DISK) != 0)
114ed5fe2f8SYuri Pankov 		return (TOPO_WALK_NEXT);
115ed5fe2f8SYuri Pankov 
116ed5fe2f8SYuri Pankov 	if (topo_prop_get_string(np, TOPO_PGROUP_STORAGE,
117e98897e3SJoshua M. Clulow 	    TOPO_STORAGE_LOGICAL_DISK_NAME, &name, &e) != 0) {
118ed5fe2f8SYuri Pankov 		return (TOPO_WALK_NEXT);
119ed5fe2f8SYuri Pankov 	}
120ed5fe2f8SYuri Pankov 
121ed5fe2f8SYuri Pankov 	if (strcmp(name, pp->dp_dev) != 0)
122ed5fe2f8SYuri Pankov 		return (TOPO_WALK_NEXT);
123ed5fe2f8SYuri Pankov 
124ed5fe2f8SYuri Pankov 	if (topo_prop_get_string(np, TOPO_PGROUP_STORAGE,
125e98897e3SJoshua M. Clulow 	    TOPO_STORAGE_SERIAL_NUM, &serial, &e) == 0) {
126ed5fe2f8SYuri Pankov 		pp->dp_serial = serial;
127ed5fe2f8SYuri Pankov 	}
128ed5fe2f8SYuri Pankov 
1297f06aed1SRobert Mustacchi 	/*
1307f06aed1SRobert Mustacchi 	 * There are several hierarchies of nodes that we may be dealing with.
1317f06aed1SRobert Mustacchi 	 * Here are a few examples:
1327f06aed1SRobert Mustacchi 	 *
1337f06aed1SRobert Mustacchi 	 * chassis -> bay -> disk
1347f06aed1SRobert Mustacchi 	 * chassis -> bay -> nvme -> disk
1357f06aed1SRobert Mustacchi 	 * motherboard -> pcie device -> nvme -> disk
1367f06aed1SRobert Mustacchi 	 * motherboard -> slot -> nvme -> disk
1377f06aed1SRobert Mustacchi 	 * chassis -> port -> usb device -> disk
1387f06aed1SRobert Mustacchi 	 * motherboard -> pcie device -> aic -> usb device -> disk
1397f06aed1SRobert Mustacchi 	 *
1407f06aed1SRobert Mustacchi 	 * The list of possibilties can go on. We want to try and see if we can
1417f06aed1SRobert Mustacchi 	 * identify what tree this is so we can figure out what to do. To
1427f06aed1SRobert Mustacchi 	 * accomplish this we basically walk our parent nodes looking for
1437f06aed1SRobert Mustacchi 	 * information until we find everything that we expect.
1447f06aed1SRobert Mustacchi 	 */
1457f06aed1SRobert Mustacchi 	for (tnode_t *pnp = topo_node_parent(np); pnp != NULL;
1467f06aed1SRobert Mustacchi 	    pnp = topo_node_parent(pnp)) {
1477f06aed1SRobert Mustacchi 		const char *pname = topo_node_name(pnp);
1488bd37d66SRichard Lowe 
1497f06aed1SRobert Mustacchi 		/*
1507f06aed1SRobert Mustacchi 		 * First see if this is the name of something where we can
1517f06aed1SRobert Mustacchi 		 * derive the location information from and set it. We will only
1527f06aed1SRobert Mustacchi 		 * consider such information from the very first bay, slot, or
1537f06aed1SRobert Mustacchi 		 * usb-device that we encounter. If it is missing a label, a
1547f06aed1SRobert Mustacchi 		 * label higher up in the tree will not be appropriate.
1557f06aed1SRobert Mustacchi 		 */
1567f06aed1SRobert Mustacchi 		if ((strcmp(pname, BAY) == 0 || strcmp(pname, SLOT) == 0 ||
1577f06aed1SRobert Mustacchi 		    strcmp(pname, USB_DEVICE) == 0) && consider_label) {
1587f06aed1SRobert Mustacchi 			consider_label = B_FALSE;
159ed5fe2f8SYuri Pankov 
1607f06aed1SRobert Mustacchi 			if (topo_prop_get_string(pnp, TOPO_PGROUP_PROTOCOL,
1617f06aed1SRobert Mustacchi 			    TOPO_PROP_LABEL, &slotname, &e) == 0) {
1627f06aed1SRobert Mustacchi 				pp->dp_slotname = slotname;
1637f06aed1SRobert Mustacchi 			}
164ed5fe2f8SYuri Pankov 		}
165ed5fe2f8SYuri Pankov 
1667f06aed1SRobert Mustacchi 		/*
1677f06aed1SRobert Mustacchi 		 * Next, see if these are nodes where we normally have
1687f06aed1SRobert Mustacchi 		 * facilities.
1697f06aed1SRobert Mustacchi 		 */
1707f06aed1SRobert Mustacchi 		if (strcmp(pname, BAY) == 0) {
1717f06aed1SRobert Mustacchi 			if (topo_node_facility(hp, pnp, TOPO_FAC_TYPE_INDICATOR,
1727f06aed1SRobert Mustacchi 			    TOPO_FAC_TYPE_ANY, &fl, &e) == 0) {
1737f06aed1SRobert Mustacchi 				for (lp = topo_list_next(&fl.tf_list);
1747f06aed1SRobert Mustacchi 				    lp != NULL; lp = topo_list_next(lp)) {
1757f06aed1SRobert Mustacchi 					uint32_t prop;
1767f06aed1SRobert Mustacchi 
1777f06aed1SRobert Mustacchi 					if (topo_prop_get_uint32(lp->tf_node,
1787f06aed1SRobert Mustacchi 					    TOPO_PGROUP_FACILITY,
1797f06aed1SRobert Mustacchi 					    TOPO_FACILITY_TYPE, &prop, &e) !=
1807f06aed1SRobert Mustacchi 					    0) {
1817f06aed1SRobert Mustacchi 						continue;
1827f06aed1SRobert Mustacchi 					}
1837f06aed1SRobert Mustacchi 					type = (topo_led_type_t)prop;
1847f06aed1SRobert Mustacchi 
1857f06aed1SRobert Mustacchi 					if (topo_prop_get_uint32(lp->tf_node,
1867f06aed1SRobert Mustacchi 					    TOPO_PGROUP_FACILITY, TOPO_LED_MODE,
1877f06aed1SRobert Mustacchi 					    &prop, &e) != 0) {
1887f06aed1SRobert Mustacchi 						continue;
1897f06aed1SRobert Mustacchi 					}
1907f06aed1SRobert Mustacchi 					mode = (topo_led_state_t)prop;
1917f06aed1SRobert Mustacchi 
1927f06aed1SRobert Mustacchi 					switch (type) {
1937f06aed1SRobert Mustacchi 					case TOPO_LED_TYPE_SERVICE:
1947f06aed1SRobert Mustacchi 						pp->dp_faulty = mode ? 1 : 0;
1957f06aed1SRobert Mustacchi 						break;
1967f06aed1SRobert Mustacchi 					case TOPO_LED_TYPE_LOCATE:
1977f06aed1SRobert Mustacchi 						pp->dp_locate = mode ? 1 : 0;
1987f06aed1SRobert Mustacchi 						break;
1997f06aed1SRobert Mustacchi 					default:
2007f06aed1SRobert Mustacchi 						break;
2017f06aed1SRobert Mustacchi 					}
2027f06aed1SRobert Mustacchi 				}
2037f06aed1SRobert Mustacchi 			}
204672fc84aSRobert Mustacchi 		}
205ed5fe2f8SYuri Pankov 
206672fc84aSRobert Mustacchi 		/*
2077f06aed1SRobert Mustacchi 		 * Finally if this is the chassis node, we want to record its
2087f06aed1SRobert Mustacchi 		 * instance number.
209672fc84aSRobert Mustacchi 		 */
2107f06aed1SRobert Mustacchi 		if (strcmp(pname, CHASSIS) == 0) {
2117f06aed1SRobert Mustacchi 			pp->dp_chassis = topo_node_instance(pnp);
2127f06aed1SRobert Mustacchi 		}
213672fc84aSRobert Mustacchi 	}
214ed5fe2f8SYuri Pankov 
215ed5fe2f8SYuri Pankov 	return (TOPO_WALK_TERMINATE);
216ed5fe2f8SYuri Pankov }
217ed5fe2f8SYuri Pankov 
218ed5fe2f8SYuri Pankov static void
populate_physical(topo_hdl_t * hp,di_phys_t * pp)219ed5fe2f8SYuri Pankov populate_physical(topo_hdl_t *hp, di_phys_t *pp)
220ed5fe2f8SYuri Pankov {
221e98897e3SJoshua M. Clulow 	int e;
222ed5fe2f8SYuri Pankov 	topo_walk_t *wp;
223ed5fe2f8SYuri Pankov 
224ed5fe2f8SYuri Pankov 	pp->dp_faulty = pp->dp_locate = -1;
225ed5fe2f8SYuri Pankov 	pp->dp_chassis = pp->dp_slot = -1;
226ed5fe2f8SYuri Pankov 
227e98897e3SJoshua M. Clulow 	e = 0;
228e98897e3SJoshua M. Clulow 	wp = topo_walk_init(hp, FM_FMRI_SCHEME_HC, disk_walker, pp, &e);
229ed5fe2f8SYuri Pankov 	if (wp == NULL) {
230e98897e3SJoshua M. Clulow 		errx(-1, "unable to initialise topo walker: %s",
231e98897e3SJoshua M. Clulow 		    topo_strerror(e));
232ed5fe2f8SYuri Pankov 	}
233ed5fe2f8SYuri Pankov 
234e98897e3SJoshua M. Clulow 	while ((e = topo_walk_step(wp, TOPO_WALK_CHILD)) == TOPO_WALK_NEXT)
235ed5fe2f8SYuri Pankov 		;
236ed5fe2f8SYuri Pankov 
237e98897e3SJoshua M. Clulow 	if (e == TOPO_WALK_ERR)
238e98897e3SJoshua M. Clulow 		errx(-1, "topo walk failed");
239ed5fe2f8SYuri Pankov 
240ed5fe2f8SYuri Pankov 	topo_walk_fini(wp);
241ed5fe2f8SYuri Pankov }
242ed5fe2f8SYuri Pankov 
243ed5fe2f8SYuri Pankov static void
enumerate_disks(di_opts_t * opts)244ed5fe2f8SYuri Pankov enumerate_disks(di_opts_t *opts)
245ed5fe2f8SYuri Pankov {
2462b766db4SAlexander Eremin 	topo_hdl_t *hp = NULL;
247ed5fe2f8SYuri Pankov 	int filter[] = { DM_DT_FIXED, -1 };
24818c03fbaSAndy Fiddaman 	dm_descriptor_t *media;
24918c03fbaSAndy Fiddaman 	uint_t i;
25018c03fbaSAndy Fiddaman 	int e;
251ed5fe2f8SYuri Pankov 
252e98897e3SJoshua M. Clulow 	e = 0;
253e98897e3SJoshua M. Clulow 	if ((media = dm_get_descriptors(DM_MEDIA, filter, &e)) == NULL) {
254e98897e3SJoshua M. Clulow 		errno = e;
255e98897e3SJoshua M. Clulow 		err(-1, "failed to obtain media descriptors");
256ed5fe2f8SYuri Pankov 	}
257ed5fe2f8SYuri Pankov 
2582b766db4SAlexander Eremin 	/*
2592b766db4SAlexander Eremin 	 * We only need to walk topo if we're intending to display
2602b766db4SAlexander Eremin 	 * condensed or physical information. If we don't need it, we leave
2612b766db4SAlexander Eremin 	 * hp = NULL.
2622b766db4SAlexander Eremin 	 */
2632b766db4SAlexander Eremin 	if (opts->di_condensed || opts->di_physical) {
2642b766db4SAlexander Eremin 		e = 0;
2652b766db4SAlexander Eremin 		hp = topo_open(TOPO_VERSION, NULL, &e);
2662b766db4SAlexander Eremin 		if (hp == NULL) {
2672b766db4SAlexander Eremin 			errx(-1, "unable to obtain topo handle: %s",
2682b766db4SAlexander Eremin 			    topo_strerror(e));
2692b766db4SAlexander Eremin 		}
270ed5fe2f8SYuri Pankov 
2712b766db4SAlexander Eremin 		e = 0;
2722b766db4SAlexander Eremin 		(void) topo_snap_hold(hp, NULL, &e);
2732b766db4SAlexander Eremin 		if (e != 0) {
2742b766db4SAlexander Eremin 			errx(-1, "unable to hold topo snapshot: %s",
2752b766db4SAlexander Eremin 			    topo_strerror(e));
2762b766db4SAlexander Eremin 		}
277ed5fe2f8SYuri Pankov 	}
278ed5fe2f8SYuri Pankov 
279eeec3978SToomas Soome 	for (i = 0; media != NULL && media[i] != 0; i++) {
28018c03fbaSAndy Fiddaman 		dm_descriptor_t *disk, *controller;
28118c03fbaSAndy Fiddaman 		nvlist_t *mattrs, *dattrs;
28218c03fbaSAndy Fiddaman 		char *vid, *pid, *opath, *ctype, *pctype, *c;
28318c03fbaSAndy Fiddaman 		boolean_t removable, ssd;
28418c03fbaSAndy Fiddaman 		char device[MAXPATHLEN];
28518c03fbaSAndy Fiddaman 		di_phys_t phys;
28618c03fbaSAndy Fiddaman 		size_t len;
28718c03fbaSAndy Fiddaman 		uint64_t size, total;
28818c03fbaSAndy Fiddaman 		uint32_t blocksize;
28918c03fbaSAndy Fiddaman 		double total_in_GiB;
29018c03fbaSAndy Fiddaman 		char sizestr[32];
29118c03fbaSAndy Fiddaman 		char slotname[32];
29218c03fbaSAndy Fiddaman 		char statestr[8];
29318c03fbaSAndy Fiddaman 
294ed5fe2f8SYuri Pankov 		if ((disk = dm_get_associated_descriptors(media[i],
295e98897e3SJoshua M. Clulow 		    DM_DRIVE, &e)) == NULL) {
296ed5fe2f8SYuri Pankov 			continue;
297ed5fe2f8SYuri Pankov 		}
298ed5fe2f8SYuri Pankov 
299ca706442SAndrew Stormont 		/*
300ca706442SAndrew Stormont 		 * The attributes depend on us being able to get the media
301ca706442SAndrew Stormont 		 * info with DKIOCGMEDIAINFO which may not be the case for
302ca706442SAndrew Stormont 		 * disks which are failing.
303ca706442SAndrew Stormont 		 */
30418c03fbaSAndy Fiddaman 		if ((mattrs = dm_get_attributes(media[i], &e)) == NULL)
305ca706442SAndrew Stormont 			continue;
306ca706442SAndrew Stormont 
307e98897e3SJoshua M. Clulow 		e = nvlist_lookup_uint64(mattrs, DM_SIZE, &size);
308e98897e3SJoshua M. Clulow 		assert(e == 0);
309e98897e3SJoshua M. Clulow 		e = nvlist_lookup_uint32(mattrs, DM_BLOCKSIZE, &blocksize);
310e98897e3SJoshua M. Clulow 		assert(e == 0);
311ed5fe2f8SYuri Pankov 
31218c03fbaSAndy Fiddaman 		vid = pid = opath = "-";
31318c03fbaSAndy Fiddaman 		removable = B_FALSE;
31418c03fbaSAndy Fiddaman 		ssd = B_FALSE;
315ed5fe2f8SYuri Pankov 
31618c03fbaSAndy Fiddaman 		dattrs = dm_get_attributes(disk[0], &e);
31718c03fbaSAndy Fiddaman 		if (dattrs != NULL) {
31818c03fbaSAndy Fiddaman 			nvlist_query_string(dattrs, DM_VENDOR_ID, &vid);
31918c03fbaSAndy Fiddaman 			nvlist_query_string(dattrs, DM_PRODUCT_ID, &pid);
32018c03fbaSAndy Fiddaman 			nvlist_query_string(dattrs, DM_OPATH, &opath);
321ed5fe2f8SYuri Pankov 
32218c03fbaSAndy Fiddaman 			if (nvlist_lookup_boolean(dattrs, DM_REMOVABLE) == 0)
32318c03fbaSAndy Fiddaman 				removable = B_TRUE;
324ed5fe2f8SYuri Pankov 
32518c03fbaSAndy Fiddaman 			if (nvlist_lookup_boolean(dattrs, DM_SOLIDSTATE) == 0)
32618c03fbaSAndy Fiddaman 				ssd = B_TRUE;
32718c03fbaSAndy Fiddaman 		}
328ed5fe2f8SYuri Pankov 
32918c03fbaSAndy Fiddaman 		pctype = "-";
33018c03fbaSAndy Fiddaman 		ctype = NULL;
331ed5fe2f8SYuri Pankov 		if ((controller = dm_get_associated_descriptors(disk[0],
332e98897e3SJoshua M. Clulow 		    DM_CONTROLLER, &e)) != NULL) {
33318c03fbaSAndy Fiddaman 			nvlist_t *cattrs;
33418c03fbaSAndy Fiddaman 
335e98897e3SJoshua M. Clulow 			cattrs = dm_get_attributes(controller[0], &e);
33618c03fbaSAndy Fiddaman 			if (cattrs != NULL) {
33718c03fbaSAndy Fiddaman 				nvlist_query_string(cattrs, DM_CTYPE, &ctype);
33818c03fbaSAndy Fiddaman 				ctype = strdup(ctype);
33918c03fbaSAndy Fiddaman 				nvlist_free(cattrs);
34018c03fbaSAndy Fiddaman 
34118c03fbaSAndy Fiddaman 				if (ctype != NULL) {
34218c03fbaSAndy Fiddaman 					for (c = ctype; *c != '\0'; c++)
34318c03fbaSAndy Fiddaman 						*c = toupper(*c);
34418c03fbaSAndy Fiddaman 					pctype = ctype;
34518c03fbaSAndy Fiddaman 				}
34618c03fbaSAndy Fiddaman 			}
34718c03fbaSAndy Fiddaman 			dm_free_descriptors(controller);
348ed5fe2f8SYuri Pankov 		}
349ed5fe2f8SYuri Pankov 
350ed5fe2f8SYuri Pankov 		/*
351ed5fe2f8SYuri Pankov 		 * Parse full device path to only show the device name,
352ed5fe2f8SYuri Pankov 		 * i.e. c0t1d0.  Many paths will reference a particular
353ed5fe2f8SYuri Pankov 		 * slice (c0t1d0s0), so remove the slice if present.
354ed5fe2f8SYuri Pankov 		 */
355ed5fe2f8SYuri Pankov 		if ((c = strrchr(opath, '/')) != NULL)
356ed5fe2f8SYuri Pankov 			(void) strlcpy(device, c + 1, sizeof (device));
357ed5fe2f8SYuri Pankov 		else
358ed5fe2f8SYuri Pankov 			(void) strlcpy(device, opath, sizeof (device));
359ed5fe2f8SYuri Pankov 		len = strlen(device);
360ed5fe2f8SYuri Pankov 		if (device[len - 2] == 's' &&
36118c03fbaSAndy Fiddaman 		    (device[len - 1] >= '0' && device[len - 1] <= '9')) {
362ed5fe2f8SYuri Pankov 			device[len - 2] = '\0';
36318c03fbaSAndy Fiddaman 		}
364ed5fe2f8SYuri Pankov 
3652b766db4SAlexander Eremin 		if (hp != NULL) {
3662b766db4SAlexander Eremin 			bzero(&phys, sizeof (phys));
3672b766db4SAlexander Eremin 			phys.dp_dev = device;
3682b766db4SAlexander Eremin 			populate_physical(hp, &phys);
3692b766db4SAlexander Eremin 
3702b766db4SAlexander Eremin 			if (opts->di_parseable) {
3712b766db4SAlexander Eremin 				(void) snprintf(slotname, sizeof (slotname),
3722b766db4SAlexander Eremin 				    "%d,%d", phys.dp_chassis, phys.dp_slot);
3732b766db4SAlexander Eremin 			} else if (phys.dp_slotname != NULL &&
3742b766db4SAlexander Eremin 			    phys.dp_chassis != -1) {
3752b766db4SAlexander Eremin 				(void) snprintf(slotname, sizeof (slotname),
3762b766db4SAlexander Eremin 				    "[%d] %s", phys.dp_chassis,
3772b766db4SAlexander Eremin 				    phys.dp_slotname);
3782b766db4SAlexander Eremin 			} else if (phys.dp_slotname != NULL) {
3792b766db4SAlexander Eremin 				(void) snprintf(slotname, sizeof (slotname),
3802b766db4SAlexander Eremin 				    "%s", phys.dp_slotname);
3812b766db4SAlexander Eremin 			} else {
3822b766db4SAlexander Eremin 				slotname[0] = '-';
3832b766db4SAlexander Eremin 				slotname[1] = '\0';
3842b766db4SAlexander Eremin 			}
3852b766db4SAlexander Eremin 		}
386ed5fe2f8SYuri Pankov 
387ed5fe2f8SYuri Pankov 		/*
388ed5fe2f8SYuri Pankov 		 * The size is given in blocks, so multiply the number
389ed5fe2f8SYuri Pankov 		 * of blocks by the block size to get the total size,
390ed5fe2f8SYuri Pankov 		 * then convert to GiB.
391ed5fe2f8SYuri Pankov 		 */
392ed5fe2f8SYuri Pankov 		total = size * blocksize;
393ed5fe2f8SYuri Pankov 
394ed5fe2f8SYuri Pankov 		if (opts->di_parseable) {
395ed5fe2f8SYuri Pankov 			(void) snprintf(sizestr, sizeof (sizestr),
396ed5fe2f8SYuri Pankov 			    "%llu", total);
397ed5fe2f8SYuri Pankov 		} else {
398ed5fe2f8SYuri Pankov 			total_in_GiB = (double)total /
399ed5fe2f8SYuri Pankov 			    1024.0 / 1024.0 / 1024.0;
400ed5fe2f8SYuri Pankov 			(void) snprintf(sizestr, sizeof (sizestr),
401ed5fe2f8SYuri Pankov 			    "%7.2f GiB", total_in_GiB);
402ed5fe2f8SYuri Pankov 		}
403ed5fe2f8SYuri Pankov 
404ed5fe2f8SYuri Pankov 		if (opts->di_condensed) {
405ed5fe2f8SYuri Pankov 			(void) snprintf(statestr, sizeof (statestr), "%c%c%c%c",
406ed5fe2f8SYuri Pankov 			    condensed_tristate(phys.dp_faulty, 'F'),
407ed5fe2f8SYuri Pankov 			    condensed_tristate(phys.dp_locate, 'L'),
408ed5fe2f8SYuri Pankov 			    condensed_tristate(removable, 'R'),
409ed5fe2f8SYuri Pankov 			    condensed_tristate(ssd, 'S'));
410ed5fe2f8SYuri Pankov 		}
411ed5fe2f8SYuri Pankov 
412ed5fe2f8SYuri Pankov 		if (opts->di_physical) {
413ed5fe2f8SYuri Pankov 			if (opts->di_scripted) {
414ed5fe2f8SYuri Pankov 				printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
415ed5fe2f8SYuri Pankov 				    device, vid, pid,
416ed5fe2f8SYuri Pankov 				    display_string(phys.dp_serial),
417ed5fe2f8SYuri Pankov 				    display_tristate(phys.dp_faulty),
418ed5fe2f8SYuri Pankov 				    display_tristate(phys.dp_locate), slotname);
419ed5fe2f8SYuri Pankov 			} else {
420ed5fe2f8SYuri Pankov 				printf("%-22s  %-8s %-16s "
421ed5fe2f8SYuri Pankov 				    "%-20s %-3s %-3s %s\n",
422ed5fe2f8SYuri Pankov 				    device, vid, pid,
423ed5fe2f8SYuri Pankov 				    display_string(phys.dp_serial),
424ed5fe2f8SYuri Pankov 				    display_tristate(phys.dp_faulty),
425ed5fe2f8SYuri Pankov 				    display_tristate(phys.dp_locate), slotname);
426ed5fe2f8SYuri Pankov 			}
427ed5fe2f8SYuri Pankov 		} else if (opts->di_condensed) {
428ed5fe2f8SYuri Pankov 			if (opts->di_scripted) {
429ed5fe2f8SYuri Pankov 				printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
43018c03fbaSAndy Fiddaman 				    pctype, device, vid, pid,
431ed5fe2f8SYuri Pankov 				    display_string(phys.dp_serial),
432ed5fe2f8SYuri Pankov 				    sizestr, statestr, slotname);
433ed5fe2f8SYuri Pankov 			} else {
434ed5fe2f8SYuri Pankov 				printf("%-7s %-22s  %-8s %-16s "
435ed5fe2f8SYuri Pankov 				    "%-20s\n\t%-13s %-4s %s\n",
43618c03fbaSAndy Fiddaman 				    pctype, device, vid, pid,
437ed5fe2f8SYuri Pankov 				    display_string(phys.dp_serial),
438ed5fe2f8SYuri Pankov 				    sizestr, statestr, slotname);
439ed5fe2f8SYuri Pankov 			}
440ed5fe2f8SYuri Pankov 		} else {
441ed5fe2f8SYuri Pankov 			if (opts->di_scripted) {
442ed5fe2f8SYuri Pankov 				printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
44318c03fbaSAndy Fiddaman 				    pctype, device, vid, pid, sizestr,
444ed5fe2f8SYuri Pankov 				    display_tristate(removable),
445ed5fe2f8SYuri Pankov 				    display_tristate(ssd));
446ed5fe2f8SYuri Pankov 			} else {
447ed5fe2f8SYuri Pankov 				printf("%-7s %-22s  %-8s %-16s "
44818c03fbaSAndy Fiddaman 				    "%-13s %-3s %-3s\n", pctype, device,
449ed5fe2f8SYuri Pankov 				    vid, pid, sizestr,
450ed5fe2f8SYuri Pankov 				    display_tristate(removable),
451ed5fe2f8SYuri Pankov 				    display_tristate(ssd));
452ed5fe2f8SYuri Pankov 			}
453ed5fe2f8SYuri Pankov 		}
454ed5fe2f8SYuri Pankov 
455ed5fe2f8SYuri Pankov 		free(ctype);
456ed5fe2f8SYuri Pankov 		nvlist_free(dattrs);
45718c03fbaSAndy Fiddaman 		nvlist_free(mattrs);
458ed5fe2f8SYuri Pankov 		dm_free_descriptors(disk);
459ed5fe2f8SYuri Pankov 	}
460ed5fe2f8SYuri Pankov 
461ed5fe2f8SYuri Pankov 	dm_free_descriptors(media);
4622b766db4SAlexander Eremin 	if (hp != NULL) {
4632b766db4SAlexander Eremin 		topo_snap_release(hp);
4642b766db4SAlexander Eremin 		topo_close(hp);
4652b766db4SAlexander Eremin 	}
466ed5fe2f8SYuri Pankov }
467ed5fe2f8SYuri Pankov 
468ed5fe2f8SYuri Pankov int
main(int argc,char * argv[])469ed5fe2f8SYuri Pankov main(int argc, char *argv[])
470ed5fe2f8SYuri Pankov {
471*ef150c2bSRichard Lowe 	int c;
472ed5fe2f8SYuri Pankov 
473ed5fe2f8SYuri Pankov 	di_opts_t opts = {
474ed5fe2f8SYuri Pankov 		.di_condensed = B_FALSE,
475ed5fe2f8SYuri Pankov 		.di_scripted = B_FALSE,
476ed5fe2f8SYuri Pankov 		.di_physical = B_FALSE,
477ed5fe2f8SYuri Pankov 		.di_parseable = B_FALSE
478ed5fe2f8SYuri Pankov 	};
479ed5fe2f8SYuri Pankov 
480ed5fe2f8SYuri Pankov 	while ((c = getopt(argc, argv, ":cHPp")) != EOF) {
481ed5fe2f8SYuri Pankov 		switch (c) {
482ed5fe2f8SYuri Pankov 		case 'c':
483ed5fe2f8SYuri Pankov 			if (opts.di_physical) {
484ed5fe2f8SYuri Pankov 				usage(argv[0]);
485e98897e3SJoshua M. Clulow 				errx(1, "-c and -P are mutually exclusive");
486ed5fe2f8SYuri Pankov 			}
487ed5fe2f8SYuri Pankov 			opts.di_condensed = B_TRUE;
488ed5fe2f8SYuri Pankov 			break;
489ed5fe2f8SYuri Pankov 		case 'H':
490ed5fe2f8SYuri Pankov 			opts.di_scripted = B_TRUE;
491ed5fe2f8SYuri Pankov 			break;
492ed5fe2f8SYuri Pankov 		case 'P':
493ed5fe2f8SYuri Pankov 			if (opts.di_condensed) {
494ed5fe2f8SYuri Pankov 				usage(argv[0]);
495e98897e3SJoshua M. Clulow 				errx(1, "-c and -P are mutually exclusive");
496ed5fe2f8SYuri Pankov 			}
497ed5fe2f8SYuri Pankov 			opts.di_physical = B_TRUE;
498ed5fe2f8SYuri Pankov 			break;
499ed5fe2f8SYuri Pankov 		case 'p':
500ed5fe2f8SYuri Pankov 			opts.di_parseable = B_TRUE;
501ed5fe2f8SYuri Pankov 			break;
502ed5fe2f8SYuri Pankov 		case '?':
503ed5fe2f8SYuri Pankov 			usage(argv[0]);
504e98897e3SJoshua M. Clulow 			errx(1, "unknown option -%c", optopt);
505ed5fe2f8SYuri Pankov 		default:
506e98897e3SJoshua M. Clulow 			errx(-1, "unexpected error on option -%c", optopt);
507ed5fe2f8SYuri Pankov 		}
508ed5fe2f8SYuri Pankov 	}
509ed5fe2f8SYuri Pankov 
510ed5fe2f8SYuri Pankov 	if (!opts.di_scripted) {
511ed5fe2f8SYuri Pankov 		if (opts.di_physical) {
512ed5fe2f8SYuri Pankov 			printf("DISK                    VID      PID"
513ed5fe2f8SYuri Pankov 			    "              SERIAL               FLT LOC"
514ed5fe2f8SYuri Pankov 			    " LOCATION\n");
515ed5fe2f8SYuri Pankov 		} else if (opts.di_condensed) {
516ed5fe2f8SYuri Pankov 			printf("TYPE    DISK                    VID      PID"
517ed5fe2f8SYuri Pankov 			    "              SERIAL\n");
518ed5fe2f8SYuri Pankov 			printf("\tSIZE          FLRS LOCATION\n");
519ed5fe2f8SYuri Pankov 		} else {
520ed5fe2f8SYuri Pankov 			printf("TYPE    DISK                    VID      PID"
521ed5fe2f8SYuri Pankov 			    "              SIZE          RMV SSD\n");
522ed5fe2f8SYuri Pankov 		}
523ed5fe2f8SYuri Pankov 	}
524ed5fe2f8SYuri Pankov 
525ed5fe2f8SYuri Pankov 	enumerate_disks(&opts);
526ed5fe2f8SYuri Pankov 
527ed5fe2f8SYuri Pankov 	return (0);
528ed5fe2f8SYuri Pankov }
529