2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
13 * Copyright (c) 2013 Joyent Inc., All rights reserved.
16 #include <sys/types.h>
29 #include <libdiskmgt.h>
30 #include <sys/nvpair.h>
31 #include <sys/param.h>
32 #include <sys/ccompile.h>
34 #include <fm/libtopo.h>
35 #include <fm/topo_hc.h>
36 #include <fm/topo_list.h>
37 #include <sys/fm/protocol.h>
38 #include <modules/common/disk/disk.h>
40 typedef struct di_opts
{
41 boolean_t di_scripted
;
42 boolean_t di_parseable
;
43 boolean_t di_physical
;
44 boolean_t di_condensed
;
47 typedef struct di_phys
{
49 const char *dp_serial
;
50 const char *dp_slotname
;
57 static void __NORETURN
58 fatal(int rv
, const char *fmt
, ...)
63 (void) vfprintf(stderr
, fmt
, ap
);
70 usage(const char *execname
)
72 (void) fprintf(stderr
, "Usage: %s [-Hp] [{-c|-P}]\n", execname
);
76 nvlist_query_string(nvlist_t
*nvl
, const char *label
, char **val
)
78 if (nvlist_lookup_string(nvl
, label
, val
) != 0)
83 display_string(const char *label
)
85 return ((label
) ? label
: "-");
89 display_tristate(int val
)
100 condensed_tristate(int val
, char c
)
110 disk_walker(topo_hdl_t
*hp
, tnode_t
*np
, void *arg
)
118 topo_led_state_t mode
;
119 topo_led_type_t type
;
120 char *name
, *slotname
, *serial
;
122 if (strcmp(topo_node_name(np
), DISK
) != 0)
123 return (TOPO_WALK_NEXT
);
125 if (topo_prop_get_string(np
, TOPO_PGROUP_STORAGE
,
126 TOPO_STORAGE_LOGICAL_DISK_NAME
, &name
, &err
) != 0) {
127 return (TOPO_WALK_NEXT
);
130 if (strcmp(name
, pp
->dp_dev
) != 0)
131 return (TOPO_WALK_NEXT
);
133 if (topo_prop_get_string(np
, TOPO_PGROUP_STORAGE
,
134 TOPO_STORAGE_SERIAL_NUM
, &serial
, &err
) == 0) {
135 pp
->dp_serial
= serial
;
138 pnp
= topo_node_parent(np
);
139 ppnp
= topo_node_parent(pnp
);
140 if (strcmp(topo_node_name(pnp
), BAY
) == 0) {
141 if (topo_node_facility(hp
, pnp
, TOPO_FAC_TYPE_INDICATOR
,
142 TOPO_FAC_TYPE_ANY
, &fl
, &err
) == 0) {
143 for (lp
= topo_list_next(&fl
.tf_list
); lp
!= NULL
;
144 lp
= topo_list_next(lp
)) {
147 if (topo_prop_get_uint32(lp
->tf_node
,
148 TOPO_PGROUP_FACILITY
, TOPO_FACILITY_TYPE
,
152 type
= (topo_led_type_t
)prop
;
154 if (topo_prop_get_uint32(lp
->tf_node
,
155 TOPO_PGROUP_FACILITY
, TOPO_LED_MODE
,
159 mode
= (topo_led_state_t
)prop
;
162 case TOPO_LED_TYPE_SERVICE
:
163 pp
->dp_faulty
= mode
? 1 : 0;
165 case TOPO_LED_TYPE_LOCATE
:
166 pp
->dp_locate
= mode
? 1 : 0;
174 if (topo_prop_get_string(pnp
, TOPO_PGROUP_PROTOCOL
,
175 TOPO_PROP_LABEL
, &slotname
, &err
) == 0) {
176 pp
->dp_slotname
= slotname
;
179 pp
->dp_slot
= topo_node_instance(pnp
);
182 pp
->dp_chassis
= topo_node_instance(ppnp
);
184 return (TOPO_WALK_TERMINATE
);
188 populate_physical(topo_hdl_t
*hp
, di_phys_t
*pp
)
193 pp
->dp_faulty
= pp
->dp_locate
= -1;
194 pp
->dp_chassis
= pp
->dp_slot
= -1;
197 wp
= topo_walk_init(hp
, FM_FMRI_SCHEME_HC
, disk_walker
, pp
, &err
);
199 fatal(-1, "unable to initialise topo walker: %s",
203 while ((err
= topo_walk_step(wp
, TOPO_WALK_CHILD
)) == TOPO_WALK_NEXT
)
206 if (err
== TOPO_WALK_ERR
)
207 fatal(-1, "topo walk failed");
213 enumerate_disks(di_opts_t
*opts
)
216 dm_descriptor_t
*media
;
218 int filter
[] = { DM_DT_FIXED
, -1 };
219 dm_descriptor_t
*disk
, *controller
;
220 nvlist_t
*mattrs
, *dattrs
, *cattrs
= NULL
;
222 uint64_t size
, total
;
229 char *vid
, *pid
, *opath
, *c
, *ctype
= NULL
;
232 char device
[MAXPATHLEN
];
237 if ((media
= dm_get_descriptors(DM_MEDIA
, filter
, &err
)) == NULL
) {
238 fatal(-1, "failed to obtain media descriptors: %s\n",
243 hp
= topo_open(TOPO_VERSION
, NULL
, &err
);
245 fatal(-1, "unable to obtain topo handle: %s",
250 (void) topo_snap_hold(hp
, NULL
, &err
);
252 fatal(-1, "unable to hold topo snapshot: %s",
256 for (i
= 0; media
!= NULL
&& media
[i
] != NULL
; i
++) {
257 if ((disk
= dm_get_associated_descriptors(media
[i
],
258 DM_DRIVE
, &err
)) == NULL
) {
262 mattrs
= dm_get_attributes(media
[i
], &err
);
263 err
= nvlist_lookup_uint64(mattrs
, DM_SIZE
, &size
);
265 err
= nvlist_lookup_uint32(mattrs
, DM_BLOCKSIZE
, &blocksize
);
269 dattrs
= dm_get_attributes(disk
[0], &err
);
271 nvlist_query_string(dattrs
, DM_VENDOR_ID
, &vid
);
272 nvlist_query_string(dattrs
, DM_PRODUCT_ID
, &pid
);
273 nvlist_query_string(dattrs
, DM_OPATH
, &opath
);
276 if (nvlist_lookup_boolean(dattrs
, DM_REMOVABLE
) == 0)
280 if (nvlist_lookup_boolean(dattrs
, DM_SOLIDSTATE
) == 0)
283 if ((controller
= dm_get_associated_descriptors(disk
[0],
284 DM_CONTROLLER
, &err
)) != NULL
) {
285 cattrs
= dm_get_attributes(controller
[0], &err
);
286 nvlist_query_string(cattrs
, DM_CTYPE
, &ctype
);
287 ctype
= strdup(ctype
);
288 for (c
= ctype
; *c
!= '\0'; c
++)
293 * Parse full device path to only show the device name,
294 * i.e. c0t1d0. Many paths will reference a particular
295 * slice (c0t1d0s0), so remove the slice if present.
297 if ((c
= strrchr(opath
, '/')) != NULL
)
298 (void) strlcpy(device
, c
+ 1, sizeof (device
));
300 (void) strlcpy(device
, opath
, sizeof (device
));
301 len
= strlen(device
);
302 if (device
[len
- 2] == 's' &&
303 (device
[len
- 1] >= '0' && device
[len
- 1] <= '9'))
304 device
[len
- 2] = '\0';
306 bzero(&phys
, sizeof (phys
));
307 phys
.dp_dev
= device
;
308 populate_physical(hp
, &phys
);
311 * The size is given in blocks, so multiply the number
312 * of blocks by the block size to get the total size,
313 * then convert to GiB.
315 total
= size
* blocksize
;
317 if (opts
->di_parseable
) {
318 (void) snprintf(sizestr
, sizeof (sizestr
),
321 total_in_GiB
= (double)total
/
322 1024.0 / 1024.0 / 1024.0;
323 (void) snprintf(sizestr
, sizeof (sizestr
),
324 "%7.2f GiB", total_in_GiB
);
327 if (opts
->di_parseable
) {
328 (void) snprintf(slotname
, sizeof (slotname
), "%d,%d",
329 phys
.dp_chassis
, phys
.dp_slot
);
330 } else if (phys
.dp_slotname
!= NULL
) {
331 (void) snprintf(slotname
, sizeof (slotname
),
332 "[%d] %s", phys
.dp_chassis
, phys
.dp_slotname
);
338 if (opts
->di_condensed
) {
339 (void) snprintf(statestr
, sizeof (statestr
), "%c%c%c%c",
340 condensed_tristate(phys
.dp_faulty
, 'F'),
341 condensed_tristate(phys
.dp_locate
, 'L'),
342 condensed_tristate(removable
, 'R'),
343 condensed_tristate(ssd
, 'S'));
346 if (opts
->di_physical
) {
347 if (opts
->di_scripted
) {
348 printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
350 display_string(phys
.dp_serial
),
351 display_tristate(phys
.dp_faulty
),
352 display_tristate(phys
.dp_locate
), slotname
);
354 printf("%-22s %-8s %-16s "
355 "%-20s %-3s %-3s %s\n",
357 display_string(phys
.dp_serial
),
358 display_tristate(phys
.dp_faulty
),
359 display_tristate(phys
.dp_locate
), slotname
);
361 } else if (opts
->di_condensed
) {
362 if (opts
->di_scripted
) {
363 printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
364 ctype
, device
, vid
, pid
,
365 display_string(phys
.dp_serial
),
366 sizestr
, statestr
, slotname
);
368 printf("%-7s %-22s %-8s %-16s "
369 "%-20s\n\t%-13s %-4s %s\n",
370 ctype
, device
, vid
, pid
,
371 display_string(phys
.dp_serial
),
372 sizestr
, statestr
, slotname
);
375 if (opts
->di_scripted
) {
376 printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
377 ctype
, device
, vid
, pid
, sizestr
,
378 display_tristate(removable
),
379 display_tristate(ssd
));
381 printf("%-7s %-22s %-8s %-16s "
382 "%-13s %-3s %-3s\n", ctype
, device
,
384 display_tristate(removable
),
385 display_tristate(ssd
));
392 dm_free_descriptors(controller
);
393 dm_free_descriptors(disk
);
396 dm_free_descriptors(media
);
397 topo_snap_release(hp
);
402 main(int argc
, char *argv
[])
407 .di_condensed
= B_FALSE
,
408 .di_scripted
= B_FALSE
,
409 .di_physical
= B_FALSE
,
410 .di_parseable
= B_FALSE
413 while ((c
= getopt(argc
, argv
, ":cHPp")) != EOF
) {
416 if (opts
.di_physical
) {
418 fatal(1, "-c and -P are mutually exclusive\n");
420 opts
.di_condensed
= B_TRUE
;
423 opts
.di_scripted
= B_TRUE
;
426 if (opts
.di_condensed
) {
428 fatal(1, "-c and -P are mutually exclusive\n");
430 opts
.di_physical
= B_TRUE
;
433 opts
.di_parseable
= B_TRUE
;
437 fatal(1, "unknown option -%c\n", optopt
);
439 fatal(-1, "unexpected error on option -%c\n", optopt
);
443 if (!opts
.di_scripted
) {
444 if (opts
.di_physical
) {
445 printf("DISK VID PID"
448 } else if (opts
.di_condensed
) {
449 printf("TYPE DISK VID PID"
451 printf("\tSIZE FLRS LOCATION\n");
453 printf("TYPE DISK VID PID"
458 enumerate_disks(&opts
);