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