Print this page
8708 Want diskinfo(1m) to list all disk bays, including those don't have disk installed


  13  * Copyright (c) 2013 Joyent Inc., All rights reserved.
  14  */
  15 
  16 #include <sys/types.h>
  17 #include <sys/stat.h>
  18 #include <fcntl.h>
  19 #include <errno.h>
  20 #include <string.h>
  21 #include <stdio.h>
  22 #include <unistd.h>
  23 #include <limits.h>
  24 #include <assert.h>
  25 #include <ctype.h>
  26 #include <stdarg.h>
  27 #include <strings.h>
  28 
  29 #include <libdiskmgt.h>
  30 #include <sys/nvpair.h>
  31 #include <sys/param.h>
  32 #include <sys/ccompile.h>

  33 
  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>
  39 
  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;
  45 } di_opts_t;
  46 



  47 typedef struct di_phys {
  48         const char *dp_dev;
  49         const char *dp_serial;
  50         const char *dp_slotname;







  51         int dp_chassis;
  52         int dp_slot;
  53         int dp_faulty;
  54         int dp_locate;

  55 } di_phys_t;
  56 
  57 static void __NORETURN
  58 fatal(int rv, const char *fmt, ...)
  59 {
  60         va_list ap;
  61 
  62         va_start(ap, fmt);
  63         (void) vfprintf(stderr, fmt, ap);
  64         va_end(ap);
  65 
  66         exit(rv);
  67 }
  68 

































  69 static void
  70 usage(const char *execname)
  71 {
  72         (void) fprintf(stderr, "Usage: %s [-Hp] [{-c|-P}]\n", execname);
  73 }
  74 
  75 static void
  76 nvlist_query_string(nvlist_t *nvl, const char *label, char **val)
  77 {
  78         if (nvlist_lookup_string(nvl, label, val) != 0)
  79                 *val = "-";
  80 }
  81 
  82 static const char *
  83 display_string(const char *label)
  84 {
  85         return ((label) ? label : "-");
  86 }
  87 
  88 static const char *
  89 display_tristate(int val)
  90 {
  91         if (val == 0)
  92                 return ("no");
  93         if (val == 1)
  94                 return ("yes");
  95 
  96         return ("-");
  97 }
  98 
  99 static char
 100 condensed_tristate(int val, char c)
 101 {
 102         if (val == 0)
 103                 return ('-');
 104         if (val == 1)
 105                 return (c);
 106 
 107         return ('?');
 108 }
 109 static int
 110 disk_walker(topo_hdl_t *hp, tnode_t *np, void *arg)

 111 {
 112         di_phys_t *pp = arg;
 113         tnode_t *pnp;
 114         tnode_t *ppnp;
 115         topo_faclist_t fl;
 116         topo_faclist_t *lp;
 117         int err;
 118         topo_led_state_t mode;
 119         topo_led_type_t type;
 120         char *name, *slotname, *serial;
 121 
 122         if (strcmp(topo_node_name(np), DISK) != 0)
 123                 return (TOPO_WALK_NEXT);
 124 
 125         if (topo_prop_get_string(np, TOPO_PGROUP_STORAGE,
 126             TOPO_STORAGE_LOGICAL_DISK_NAME, &name, &err) != 0) {
 127                 return (TOPO_WALK_NEXT);
 128         }
 129 
 130         if (strcmp(name, pp->dp_dev) != 0)
 131                 return (TOPO_WALK_NEXT);
 132 
 133         if (topo_prop_get_string(np, TOPO_PGROUP_STORAGE,
 134             TOPO_STORAGE_SERIAL_NUM, &serial, &err) == 0) {
 135                 pp->dp_serial = serial;
 136         }
 137 
 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)) {
 145                                 uint32_t prop;
 146 
 147                                 if (topo_prop_get_uint32(lp->tf_node,
 148                                     TOPO_PGROUP_FACILITY, TOPO_FACILITY_TYPE,
 149                                     &prop, &err) != 0) {
 150                                         continue;
 151                                 }
 152                                 type = (topo_led_type_t)prop;
 153 
 154                                 if (topo_prop_get_uint32(lp->tf_node,
 155                                     TOPO_PGROUP_FACILITY, TOPO_LED_MODE,
 156                                     &prop, &err) != 0) {
 157                                         continue;
 158                                 }
 159                                 mode = (topo_led_state_t)prop;
 160 
 161                                 switch (type) {
 162                                 case TOPO_LED_TYPE_SERVICE:
 163                                         pp->dp_faulty = mode ? 1 : 0;
 164                                         break;
 165                                 case TOPO_LED_TYPE_LOCATE:
 166                                         pp->dp_locate = mode ? 1 : 0;
 167                                         break;
 168                                 default:
 169                                         break;
 170                                 }
 171                         }
 172                 }
 173 
 174                 if (topo_prop_get_string(pnp, TOPO_PGROUP_PROTOCOL,
 175                     TOPO_PROP_LABEL, &slotname, &err) == 0) {
 176                         pp->dp_slotname = slotname;
 177                 }
 178 
 179                 pp->dp_slot = topo_node_instance(pnp);



















 180         }
 181 
 182         pp->dp_chassis = topo_node_instance(ppnp);




 183 
 184         return (TOPO_WALK_TERMINATE);


























 185 }
 186 
 187 static void
 188 populate_physical(topo_hdl_t *hp, di_phys_t *pp)
 189 {
 190         int err;
 191         topo_walk_t *wp;
 192 
 193         pp->dp_faulty = pp->dp_locate = -1;
 194         pp->dp_chassis = pp->dp_slot = -1;
 195 
 196         err = 0;
 197         wp = topo_walk_init(hp, FM_FMRI_SCHEME_HC, disk_walker, pp, &err);
 198         if (wp == NULL) {
 199                 fatal(-1, "unable to initialise topo walker: %s",
 200                     topo_strerror(err));
 201         }
 202 
 203         while ((err = topo_walk_step(wp, TOPO_WALK_CHILD)) == TOPO_WALK_NEXT)
 204                 ;
 205 
 206         if (err == TOPO_WALK_ERR)
 207                 fatal(-1, "topo walk failed");
 208 
 209         topo_walk_fini(wp);
 210 }
 211 
 212 static void
 213 enumerate_disks(di_opts_t *opts)
 214 {
 215         topo_hdl_t *hp;
 216         dm_descriptor_t *media;
 217         int err, i;
 218         int filter[] = { DM_DT_FIXED, -1 };
 219         dm_descriptor_t *disk, *controller;
 220         nvlist_t *mattrs, *dattrs, *cattrs = NULL;
 221 
 222         uint64_t size, total;
 223         uint32_t blocksize;
 224         double total_in_GiB;
 225         char sizestr[32];
 226         char slotname[32];
 227         char statestr[8];
 228 
 229         char *vid, *pid, *opath, *c, *ctype = NULL;
 230         boolean_t removable;
 231         boolean_t ssd;
 232         char device[MAXPATHLEN];
 233         di_phys_t phys;
 234         size_t len;

 235 


 236         err = 0;
 237         if ((media = dm_get_descriptors(DM_MEDIA, filter, &err)) == NULL) {
 238                 fatal(-1, "failed to obtain media descriptors: %s\n",
 239                     strerror(err));
 240         }
 241 
 242         err = 0;
 243         hp = topo_open(TOPO_VERSION, NULL, &err);
 244         if (hp == NULL) {
 245                 fatal(-1, "unable to obtain topo handle: %s",
 246                     topo_strerror(err));
 247         }
 248 
 249         err = 0;
 250         (void) topo_snap_hold(hp, NULL, &err);
 251         if (err != 0) {
 252                 fatal(-1, "unable to hold topo snapshot: %s",
 253                     topo_strerror(err));
 254         }
 255 
 256         for (i = 0; media != NULL && media[i] != NULL; i++) {
 257                 if ((disk = dm_get_associated_descriptors(media[i],
 258                     DM_DRIVE, &err)) == NULL) {
 259                         continue;
 260                 }
 261 


 262                 mattrs = dm_get_attributes(media[i], &err);
 263                 err = nvlist_lookup_uint64(mattrs, DM_SIZE, &size);
 264                 assert(err == 0);
 265                 err = nvlist_lookup_uint32(mattrs, DM_BLOCKSIZE, &blocksize);

 266                 assert(err == 0);
 267                 nvlist_free(mattrs);
 268 
 269                 dattrs = dm_get_attributes(disk[0], &err);
 270 
 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);
 274 
 275                 removable = B_FALSE;




 276                 if (nvlist_lookup_boolean(dattrs, DM_REMOVABLE) == 0)
 277                         removable = B_TRUE;
 278 
 279                 ssd = B_FALSE;
 280                 if (nvlist_lookup_boolean(dattrs, DM_SOLIDSTATE) == 0)
 281                         ssd = B_TRUE;
 282 


 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++)
 289                                 *c = toupper(*c);

 290                 }
 291 



 292                 /*
 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.
 296                  */
 297                 if ((c = strrchr(opath, '/')) != NULL)
 298                         (void) strlcpy(device, c + 1, sizeof (device));
 299                 else
 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';


 305 
 306                 bzero(&phys, sizeof (phys));
 307                 phys.dp_dev = device;
 308                 populate_physical(hp, &phys);

 309 


 310                 /*






































 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.
 314                  */
 315                 total = size * blocksize;
 316 
 317                 if (opts->di_parseable) {
 318                         (void) snprintf(sizestr, sizeof (sizestr),
 319                             "%llu", total);
 320                 } else {
 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);
 325                 }
 326 
 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);
 333                 } else {
 334                         slotname[0] = '-';
 335                         slotname[1] = '\0';
 336                 }
 337 
 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'));
 344                 }
 345 
 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",
 349                                     device, vid, pid,
 350                                     display_string(phys.dp_serial),
 351                                     display_tristate(phys.dp_faulty),
 352                                     display_tristate(phys.dp_locate), slotname);


 353                         } else {
 354                                 printf("%-22s  %-8s %-16s "
 355                                     "%-20s %-3s %-3s %s\n",
 356                                     device, vid, pid,
 357                                     display_string(phys.dp_serial),
 358                                     display_tristate(phys.dp_faulty),
 359                                     display_tristate(phys.dp_locate), slotname);


 360                         }
 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);
 367                         } else {
 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);
 373                         }
 374                 } else {
 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));



 380                         } else {
 381                                 printf("%-7s %-22s  %-8s %-16s "
 382                                     "%-13s %-3s %-3s\n", ctype, device,
 383                                     vid, pid, sizestr,
 384                                     display_tristate(removable),
 385                                     display_tristate(ssd));



 386                         }
 387                 }
 388 
 389                 free(ctype);
 390                 nvlist_free(cattrs);
 391                 nvlist_free(dattrs);
 392                 dm_free_descriptors(controller);
 393                 dm_free_descriptors(disk);
 394         }

 395 
 396         dm_free_descriptors(media);
 397         topo_snap_release(hp);
 398         topo_close(hp);












 399 }
 400 
 401 int
 402 main(int argc, char *argv[])
 403 {
 404         char c;
 405 
 406         di_opts_t opts = {
 407                 .di_condensed = B_FALSE,
 408                 .di_scripted = B_FALSE,
 409                 .di_physical = B_FALSE,
 410                 .di_parseable = B_FALSE
 411         };
 412 
 413         while ((c = getopt(argc, argv, ":cHPp")) != EOF) {
 414                 switch (c) {



 415                 case 'c':
 416                         if (opts.di_physical) {
 417                                 usage(argv[0]);
 418                                 fatal(1, "-c and -P are mutually exclusive\n");
 419                         }
 420                         opts.di_condensed = B_TRUE;
 421                         break;
 422                 case 'H':
 423                         opts.di_scripted = B_TRUE;
 424                         break;
 425                 case 'P':
 426                         if (opts.di_condensed) {
 427                                 usage(argv[0]);
 428                                 fatal(1, "-c and -P are mutually exclusive\n");
 429                         }
 430                         opts.di_physical = B_TRUE;
 431                         break;
 432                 case 'p':
 433                         opts.di_parseable = B_TRUE;
 434                         break;
 435                 case '?':
 436                         usage(argv[0]);
 437                         fatal(1, "unknown option -%c\n", optopt);
 438                 default:
 439                         fatal(-1, "unexpected error on option -%c\n", optopt);
 440                 }
 441         }
 442 
 443         if (!opts.di_scripted) {
 444                 if (opts.di_physical) {





 445                         printf("DISK                    VID      PID"
 446                             "              SERIAL               FLT LOC"
 447                             " LOCATION\n");
 448                 } else if (opts.di_condensed) {
 449                         printf("TYPE    DISK                    VID      PID"
 450                             "              SERIAL\n");
 451                         printf("\tSIZE          FLRS LOCATION\n");
 452                 } else {
 453                         printf("TYPE    DISK                    VID      PID"
 454                             "              SIZE          RMV SSD\n");
 455                 }
 456         }
 457 
 458         enumerate_disks(&opts);


 459 
 460         return (0);
 461 }


  13  * Copyright (c) 2013 Joyent Inc., All rights reserved.
  14  */
  15 
  16 #include <sys/types.h>
  17 #include <sys/stat.h>
  18 #include <fcntl.h>
  19 #include <errno.h>
  20 #include <string.h>
  21 #include <stdio.h>
  22 #include <unistd.h>
  23 #include <limits.h>
  24 #include <assert.h>
  25 #include <ctype.h>
  26 #include <stdarg.h>
  27 #include <strings.h>
  28 
  29 #include <libdiskmgt.h>
  30 #include <sys/nvpair.h>
  31 #include <sys/param.h>
  32 #include <sys/ccompile.h>
  33 #include <sys/list.h>
  34 
  35 #include <fm/libtopo.h>
  36 #include <fm/topo_hc.h>
  37 #include <fm/topo_list.h>
  38 #include <sys/fm/protocol.h>
  39 #include <modules/common/disk/disk.h>
  40 
  41 typedef struct di_opts {
  42         boolean_t di_allslots;
  43         boolean_t di_scripted;
  44         boolean_t di_parseable;
  45         boolean_t di_physical;
  46         boolean_t di_condensed;
  47 } di_opts_t;
  48 
  49 static list_t g_disks;
  50 static di_opts_t g_opts = { B_FALSE, B_FALSE, B_FALSE, B_FALSE, B_FALSE };
  51 
  52 typedef struct di_phys {
  53         uint64_t dp_size;
  54         uint32_t dp_blksize;
  55         char *dp_vid;
  56         char *dp_pid;
  57         boolean_t dp_removable;
  58         boolean_t dp_ssd;
  59         char *dp_dev;
  60         char *dp_ctype;
  61         char *dp_serial;
  62         char *dp_slotname;
  63         int dp_chassis;
  64         int dp_slot;
  65         int dp_faulty;
  66         int dp_locate;
  67         list_node_t dp_next;
  68 } di_phys_t;
  69 
  70 static void __NORETURN
  71 fatal(int rv, const char *fmt, ...)
  72 {
  73         va_list ap;
  74 
  75         va_start(ap, fmt);
  76         (void) vfprintf(stderr, fmt, ap);
  77         va_end(ap);
  78 
  79         exit(rv);
  80 }
  81 
  82 static void *
  83 safe_zmalloc(size_t size)
  84 {
  85         void *ptr = malloc(size);
  86         if (ptr == NULL)
  87                 fatal(-1, "failed to allocate memeory");
  88         memset(ptr, 0, size);
  89         return (ptr);
  90 }
  91 
  92 static char *
  93 safe_strdup(const char *s1)
  94 {
  95         char *s2 = strdup(s1);
  96         if (s2 == NULL)
  97                 fatal(-1, "failed to allocate memeory");
  98         return (s2);
  99 }
 100 
 101 static int
 102 safe_asprintf(char **ret, const char *fmt, ...)
 103 {
 104         va_list ap;
 105         int v;
 106 
 107         va_start(ap, fmt);
 108         v = vasprintf(ret, fmt, ap);
 109         va_end(ap);
 110         if (v == -1)
 111                 fatal(-1, "failed to allocate memeory");
 112         return (v);
 113 }
 114 
 115 static void
 116 usage(const char *execname)
 117 {
 118         (void) fprintf(stderr, "Usage: %s [-aHp] [{-c|-P}]\n", execname);
 119 }
 120 
 121 static void
 122 nvlist_query_string(nvlist_t *nvl, const char *label, char **val)
 123 {
 124         if (nvlist_lookup_string(nvl, label, val) != 0)
 125                 *val = "-";
 126 }
 127 
 128 static const char *
 129 display_string(const char *label)
 130 {
 131         return ((label) ? label : "-");
 132 }
 133 
 134 static const char *
 135 display_tristate(int val)
 136 {
 137         if (val == 0)
 138                 return ("no");
 139         if (val == 1)
 140                 return ("yes");
 141 
 142         return ("-");
 143 }
 144 
 145 static char
 146 condensed_tristate(int val, char c)
 147 {
 148         if (val == 0)
 149                 return ('-');
 150         if (val == 1)
 151                 return (c);
 152 
 153         return ('?');
 154 }
 155 
 156 static void
 157 set_disk_bay_info(topo_hdl_t *hp, tnode_t *np, di_phys_t *dip)
 158 {



 159         topo_faclist_t fl;
 160         topo_faclist_t *lp;

 161         topo_led_state_t mode;
 162         topo_led_type_t type;
 163         int err;
 164 
 165         if (strcmp(topo_node_name(np), BAY) != 0)
 166                 return;
 167 
 168         if (topo_node_facility(hp, np, TOPO_FAC_TYPE_INDICATOR,
















 169             TOPO_FAC_TYPE_ANY, &fl, &err) == 0) {
 170                 for (lp = topo_list_next(&fl.tf_list); lp != NULL;
 171                     lp = topo_list_next(lp)) {
 172                         uint32_t prop;
 173 
 174                         if (topo_prop_get_uint32(lp->tf_node,
 175                             TOPO_PGROUP_FACILITY, TOPO_FACILITY_TYPE,
 176                             &prop, &err) != 0) {
 177                                 continue;
 178                         }
 179                         type = (topo_led_type_t)prop;
 180 
 181                         if (topo_prop_get_uint32(lp->tf_node,
 182                             TOPO_PGROUP_FACILITY, TOPO_LED_MODE,
 183                             &prop, &err) != 0) {
 184                                 continue;
 185                         }
 186                         mode = (topo_led_state_t)prop;
 187 
 188                         switch (type) {
 189                         case TOPO_LED_TYPE_SERVICE:
 190                                 dip->dp_faulty = mode ? 1 : 0;
 191                                 break;
 192                         case TOPO_LED_TYPE_LOCATE:
 193                                 dip->dp_locate = mode ? 1 : 0;
 194                                 break;
 195                         default:
 196                                 break;
 197                         }
 198                 }
 199         }
 200 
 201         if (topo_prop_get_string(np, TOPO_PGROUP_PROTOCOL,
 202             TOPO_PROP_LABEL, &dip->dp_slotname, &err) == 0) {
 203                 dip->dp_slotname = safe_strdup(dip->dp_slotname);
 204         }
 205 
 206         dip->dp_slot = topo_node_instance(np);
 207         dip->dp_chassis = topo_node_instance(topo_node_parent(np));
 208 }
 209 
 210 static int
 211 bay_walker(topo_hdl_t *hp, tnode_t *np, void *arg)
 212 {
 213         di_phys_t *dip;
 214         int slot, chassis;
 215 
 216         if (strcmp(topo_node_name(np), BAY) != 0)
 217                 return (TOPO_WALK_NEXT);
 218 
 219         slot = topo_node_instance(np);
 220         chassis = topo_node_instance(topo_node_parent(np));
 221 
 222         for (dip = list_head(&g_disks); dip != NULL;
 223             dip = list_next(&g_disks, dip)) {
 224                 if (dip->dp_slot == slot && dip->dp_chassis == chassis)
 225                         return (TOPO_WALK_NEXT);
 226         }
 227 
 228         dip = safe_zmalloc(sizeof (di_phys_t));
 229         set_disk_bay_info(hp, np, dip);
 230         list_insert_tail(&g_disks, dip);
 231         return (TOPO_WALK_NEXT);
 232 }
 233 
 234 static int
 235 disk_walker(topo_hdl_t *hp, tnode_t *np, void *arg)
 236 {
 237         char *dev;
 238         di_phys_t *dip;
 239         int err;
 240 
 241         if (strcmp(topo_node_name(np), DISK) != 0)
 242                 return (TOPO_WALK_NEXT);
 243 
 244         if (topo_prop_get_string(np, TOPO_PGROUP_STORAGE,
 245             TOPO_STORAGE_LOGICAL_DISK_NAME, &dev, &err) != 0) {
 246                 return (TOPO_WALK_NEXT);
 247         }
 248 
 249         for (dip = list_head(&g_disks); dip != NULL;
 250             dip = list_next(&g_disks, dip)) {
 251                 if (strcmp(dip->dp_dev, dev) == 0) {
 252                         if (topo_prop_get_string(np, TOPO_PGROUP_STORAGE,
 253                             TOPO_STORAGE_SERIAL_NUM,
 254                             &dip->dp_serial, &err) == 0) {
 255                                 dip->dp_serial = safe_strdup(dip->dp_serial);
 256                         }
 257                         set_disk_bay_info(hp, topo_node_parent(np), dip);
 258                 }
 259         }
 260         return (TOPO_WALK_NEXT);
 261 }
 262 
 263 static void
 264 walk_topo_snapshot(topo_hdl_t *hp, topo_walk_cb_t cb)
 265 {
 266         int err = 0;
 267         topo_walk_t *wp;
 268 
 269         if ((wp = topo_walk_init(hp, FM_FMRI_SCHEME_HC, cb, NULL,
 270             &err)) == NULL) {




 271                 fatal(-1, "unable to initialise topo walker: %s",
 272                     topo_strerror(err));
 273         }
 274 
 275         while ((err = topo_walk_step(wp, TOPO_WALK_CHILD)) == TOPO_WALK_NEXT)
 276                 ;
 277 
 278         if (err == TOPO_WALK_ERR)
 279                 fatal(-1, "topo walk failed");

 280         topo_walk_fini(wp);
 281 }
 282 
 283 static void
 284 enumerate_disks()
 285 {
 286         topo_hdl_t *hp;
 287         dm_descriptor_t *media;

 288         int filter[] = { DM_DT_FIXED, -1 };
 289         dm_descriptor_t *disk, *controller;
 290         nvlist_t *mattrs, *dattrs, *cattrs;
 291 
 292         char *s, *c;
 293         di_phys_t *dip;










 294         size_t len;
 295         int err, i;
 296 
 297         list_create(&g_disks, sizeof (di_phys_t), offsetof(di_phys_t, dp_next));
 298 
 299         err = 0;
 300         if ((media = dm_get_descriptors(DM_MEDIA, filter, &err)) == NULL) {
 301                 fatal(-1, "failed to obtain media descriptors: %s\n",
 302                     strerror(err));
 303         }
 304 














 305         for (i = 0; media != NULL && media[i] != NULL; i++) {
 306                 if ((disk = dm_get_associated_descriptors(media[i],
 307                     DM_DRIVE, &err)) == NULL) {
 308                         continue;
 309                 }
 310 
 311                 dip = safe_zmalloc(sizeof (di_phys_t));
 312 
 313                 mattrs = dm_get_attributes(media[i], &err);
 314                 err = nvlist_lookup_uint64(mattrs, DM_SIZE, &dip->dp_size);
 315                 assert(err == 0);
 316                 err = nvlist_lookup_uint32(mattrs, DM_BLOCKSIZE,
 317                     &dip->dp_blksize);
 318                 assert(err == 0);
 319                 nvlist_free(mattrs);
 320 
 321                 dattrs = dm_get_attributes(disk[0], &err);
 322 
 323                 nvlist_query_string(dattrs, DM_VENDOR_ID, &dip->dp_vid);
 324                 nvlist_query_string(dattrs, DM_PRODUCT_ID, &dip->dp_pid);
 325                 nvlist_query_string(dattrs, DM_OPATH, &dip->dp_dev);
 326 
 327                 dip->dp_vid = safe_strdup(dip->dp_vid);
 328                 dip->dp_pid = safe_strdup(dip->dp_pid);
 329                 dip->dp_dev = safe_strdup(dip->dp_dev);
 330 
 331                 dip->dp_removable = B_FALSE;
 332                 if (nvlist_lookup_boolean(dattrs, DM_REMOVABLE) == 0)
 333                         dip->dp_removable = B_TRUE;
 334 
 335                 dip->dp_ssd = B_FALSE;
 336                 if (nvlist_lookup_boolean(dattrs, DM_SOLIDSTATE) == 0)
 337                         dip->dp_ssd = B_TRUE;
 338 
 339                 nvlist_free(dattrs);
 340 
 341                 if ((controller = dm_get_associated_descriptors(disk[0],
 342                     DM_CONTROLLER, &err)) != NULL) {
 343                         cattrs = dm_get_attributes(controller[0], &err);
 344                         nvlist_query_string(cattrs, DM_CTYPE, &dip->dp_ctype);
 345                         dip->dp_ctype = safe_strdup(dip->dp_ctype);
 346                         for (c = dip->dp_ctype; *c != '\0'; c++)
 347                                 *c = toupper(*c);
 348                         nvlist_free(cattrs);
 349                 }
 350 
 351                 dm_free_descriptors(controller);
 352                 dm_free_descriptors(disk);
 353 
 354                 /*
 355                  * Parse full device path to only show the device name,
 356                  * i.e. c0t1d0.  Many paths will reference a particular
 357                  * slice (c0t1d0s0), so remove the slice if present.
 358                  */
 359                 if ((c = strrchr(dip->dp_dev, '/')) != NULL) {
 360                         s = dip->dp_dev;
 361                         while ((*s++ = *++c))
 362                                 ;
 363                 }
 364                 len = strlen(dip->dp_dev);
 365                 if (dip->dp_dev[len - 2] == 's' &&
 366                     dip->dp_dev[len - 1] >= '0' &&
 367                     dip->dp_dev[len - 1] <= '9')
 368                         dip->dp_dev[len - 2] = '\0';
 369 
 370                 dip->dp_faulty = dip->dp_locate = -1;
 371                 dip->dp_chassis = dip->dp_slot = -1;
 372                 list_insert_tail(&g_disks, dip);
 373         }
 374 
 375         dm_free_descriptors(media);
 376 
 377         /*
 378          * Walk toplogy information to populate serial, chassis,
 379          * slot, faulty and locator information.
 380          */
 381 
 382         err = 0;
 383         hp = topo_open(TOPO_VERSION, NULL, &err);
 384         if (hp == NULL) {
 385                 fatal(-1, "unable to obtain topo handle: %s",
 386                     topo_strerror(err));
 387         }
 388 
 389         err = 0;
 390         (void) topo_snap_hold(hp, NULL, &err);
 391         if (err != 0) {
 392                 fatal(-1, "unable to hold topo snapshot: %s",
 393                     topo_strerror(err));
 394         }
 395 
 396         walk_topo_snapshot(hp, disk_walker);
 397 
 398         if (g_opts.di_allslots)
 399                 walk_topo_snapshot(hp, bay_walker);
 400 
 401         topo_snap_release(hp);
 402         topo_close(hp);
 403 }
 404 
 405 static void
 406 show_disks()
 407 {
 408         uint64_t total;
 409         double total_in_GiB;
 410         char *sizestr = NULL, *slotname = NULL, *statestr = NULL;
 411         di_phys_t *dip;
 412 
 413         for (dip = list_head(&g_disks); dip != NULL;
 414             dip = list_next(&g_disks, dip)) {
 415                 /*
 416                  * The size is given in blocks, so multiply the number
 417                  * of blocks by the block size to get the total size,
 418                  * then convert to GiB.
 419                  */
 420                 total = dip->dp_size * dip->dp_blksize;
 421 
 422                 if (g_opts.di_parseable) {
 423                         (void) safe_asprintf(&sizestr, "%llu", total);

 424                 } else {
 425                         total_in_GiB = (double)total /
 426                             1024.0 / 1024.0 / 1024.0;
 427                         (void) safe_asprintf(&sizestr,
 428                             "%7.2f GiB", (total_in_GiB));
 429                 }
 430 
 431                 if (g_opts.di_parseable) {
 432                         (void) safe_asprintf(&slotname, "%d,%d",
 433                             dip->dp_chassis, dip->dp_slot);
 434                 } else if (dip->dp_slotname != NULL) {
 435                         (void) safe_asprintf(&slotname, "[%d] %s",
 436                             dip->dp_chassis, dip->dp_slotname);
 437                 } else {
 438                         slotname = safe_strdup("-");

 439                 }
 440 
 441                 if (g_opts.di_condensed) {
 442                         (void) safe_asprintf(&statestr, "%c%c%c%c",
 443                             condensed_tristate(dip->dp_faulty, 'F'),
 444                             condensed_tristate(dip->dp_locate, 'L'),
 445                             condensed_tristate(dip->dp_removable, 'R'),
 446                             condensed_tristate(dip->dp_ssd, 'S'));
 447                 }
 448 
 449                 if (g_opts.di_physical) {
 450                         if (g_opts.di_scripted) {
 451                                 printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
 452                                     display_string(dip->dp_dev),
 453                                     display_string(dip->dp_vid),
 454                                     display_string(dip->dp_pid),
 455                                     display_string(dip->dp_serial),
 456                                     display_tristate(dip->dp_faulty),
 457                                     display_tristate(dip->dp_locate), slotname);
 458                         } else {
 459                                 printf("%-22s  %-8s %-16s "
 460                                     "%-20s %-3s %-3s %s\n",
 461                                     display_string(dip->dp_dev),
 462                                     display_string(dip->dp_vid),
 463                                     display_string(dip->dp_pid),
 464                                     display_string(dip->dp_serial),
 465                                     display_tristate(dip->dp_faulty),
 466                                     display_tristate(dip->dp_locate), slotname);
 467                         }
 468                 } else if (g_opts.di_condensed) {
 469                         if (g_opts.di_scripted) {
 470                                 printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
 471                                     display_string(dip->dp_ctype),
 472                                     display_string(dip->dp_dev),
 473                                     display_string(dip->dp_vid),
 474                                     display_string(dip->dp_pid),
 475                                     display_string(dip->dp_serial),
 476                                     sizestr, statestr, slotname);
 477                         } else {
 478                                 printf("%-7s %-22s  %-8s %-16s "
 479                                     "%-20s\n\t%-13s %-4s %s\n",
 480                                     display_string(dip->dp_ctype),
 481                                     display_string(dip->dp_dev),
 482                                     display_string(dip->dp_vid),
 483                                     display_string(dip->dp_pid),
 484                                     display_string(dip->dp_serial),
 485                                     sizestr, statestr, slotname);
 486                         }
 487                 } else {
 488                         if (g_opts.di_scripted) {
 489                                 printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
 490                                     display_string(dip->dp_ctype),
 491                                     display_string(dip->dp_dev),
 492                                     display_string(dip->dp_vid),
 493                                     display_string(dip->dp_pid), sizestr,
 494                                     display_tristate(dip->dp_removable),
 495                                     display_tristate(dip->dp_ssd));
 496                         } else {
 497                                 printf("%-7s %-22s  %-8s %-16s "
 498                                     "%-13s %-3s %-3s\n",
 499                                     display_string(dip->dp_ctype),
 500                                     display_string(dip->dp_dev),
 501                                     display_string(dip->dp_vid),
 502                                     display_string(dip->dp_pid), sizestr,
 503                                     display_tristate(dip->dp_removable),
 504                                     display_tristate(dip->dp_ssd));
 505                         }
 506                 }
 507         free(sizestr); free(slotname); free(statestr);
 508         sizestr = slotname = statestr = NULL;




 509         }
 510 }
 511 
 512 static void
 513 cleanup()
 514 {
 515         di_phys_t *dip;
 516         while ((dip = list_head(&g_disks)) != NULL) {
 517                 list_remove(&g_disks, dip);
 518                 free(dip->dp_vid);
 519                 free(dip->dp_pid);
 520                 free(dip->dp_dev);
 521                 free(dip->dp_ctype);
 522                 free(dip->dp_serial);
 523                 free(dip->dp_slotname);
 524                 free(dip);
 525         }
 526         list_destroy(&g_disks);
 527 }
 528 
 529 int
 530 main(int argc, char *argv[])
 531 {
 532         char c;
 533 
 534         while ((c = getopt(argc, argv, ":acHPp")) != EOF) {







 535                 switch (c) {
 536                 case 'a':
 537                         g_opts.di_allslots = B_TRUE;
 538                         break;
 539                 case 'c':
 540                         g_opts.di_condensed = B_TRUE;




 541                         break;
 542                 case 'H':
 543                         g_opts.di_scripted = B_TRUE;
 544                         break;
 545                 case 'P':
 546                         g_opts.di_physical = B_TRUE;




 547                         break;
 548                 case 'p':
 549                         g_opts.di_parseable = B_TRUE;
 550                         break;
 551                 case '?':
 552                         usage(argv[0]);
 553                         fatal(1, "unknown option -%c\n", optopt);
 554                 default:
 555                         fatal(-1, "unexpected error on option -%c\n", optopt);
 556                 }
 557         }
 558 
 559         if (g_opts.di_condensed && g_opts.di_physical) {
 560                 usage(argv[0]);
 561                 fatal(1, "-c and -P are mutually exclusive\n");
 562         }
 563 
 564         if (!g_opts.di_scripted) {
 565                 if (g_opts.di_physical) {
 566                         printf("DISK                    VID      PID"
 567                             "              SERIAL               FLT LOC"
 568                             " LOCATION\n");
 569                 } else if (g_opts.di_condensed) {
 570                         printf("TYPE    DISK                    VID      PID"
 571                             "              SERIAL\n");
 572                         printf("\tSIZE          FLRS LOCATION\n");
 573                 } else {
 574                         printf("TYPE    DISK                    VID      PID"
 575                             "              SIZE          RMV SSD\n");
 576                 }
 577         }
 578 
 579         enumerate_disks();
 580         show_disks();
 581         cleanup();
 582 
 583         return (0);
 584 }