1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <meta.h>
  27 #include <assert.h>
  28 #include <ctype.h>
  29 #include <mdiox.h>
  30 #include <meta.h>
  31 #include <stdio.h>
  32 #include <stdlib.h>
  33 #include <stddef.h>
  34 #include <strings.h>
  35 #include <sys/lvm/md_mddb.h>
  36 #include <sys/lvm/md_names.h>
  37 #include <sys/lvm/md_crc.h>
  38 #include <sys/lvm/md_convert.h>
  39 
  40 
  41 /*
  42  * Design Notes:
  43  *
  44  * All of the code in this file supports the addition of metastat -c output
  45  * for the verbose option of metaimport.  Some of this code is also used by
  46  * the command metastat for concise output(cmd/lvm/util/metastat.c).
  47  * The code is designed to produce the same output as metastat -c does for a
  48  * given diskset--with a couple exceptions.
  49  * The primary differences between the output for the metastat -c command and
  50  * metastat output for metaimport -v are:
  51  *  - the set name is not printed next to each metadevice
  52  *  - top-level state information is not printed for some metadevices
  53  *  - the percent that a disk has completed resyncing is not listed
  54  * in metaimport -v.
  55  *
  56  *
  57  * The general layout of this file is as follows:
  58  *
  59  *  - report_metastat_info()
  60  *      This is the primary entry point for the functions in this file, with
  61  *      the exception of several functions that are also called from
  62  *      cmd/io/lvm/util/metastat.c
  63  *      report_metastat_info() calls functions to read in all the the
  64  *      Directory blocks and Record blocks and then process the information
  65  *      needed to print out the metadevice records in the same format as
  66  *      metastat -c.
  67  *
  68  *  - read_all_mdrecords()
  69  *      Reads in all the Directory blocks in the diskset and verifies their
  70  *      validity.  For each Directly block, it loops through all Directory
  71  *      Entries and for each one that contains a metadevice record calls
  72  *      read_md_record().  Because the output is designed to imitate the
  73  *      output of metastat -c, we ignore metadevice records for
  74  *      optimized resync, changelog, and translog.
  75  *
  76  *  - read_md_record()
  77  *      Reads in a Directory Entry and its associated Record block.  The
  78  *      revision information for the Record block is checked and it is
  79  *      determined whether or not it is a 64bit Record block or a 32bit record
  80  *      block.  For each valid Record block, it allocates an md_im_rec_t
  81  *      structure and calls extract_mduser_data().
  82  *
  83  *  - extract_mduser_data()
  84  *      Populates the md_im_rec_t data structure with information about the
  85  *      record's associated metadevice.  Also, the name of the metadevice is
  86  *      either copied from the NM namespace(if it exists there) or is generated
  87  *      from the record's un_self_id.
  88  *
  89  *  - process_toplevel_devices()
  90  *      For a given metadevice type, searchs through the md_im_rec_t **mdimpp,
  91  *      list of all metadevices in the set, to find all records of the
  92  *      specified type that do not have a parent and puts them on a temp list.
  93  *      The temp list is then iterated through and the associated processing
  94  *      function is called.
  95  *
  96  *  - process_(trans, hotspare, hotspare_pool, soft_part, mirror, stripe, raid)
  97  *      These functions are called by using the dfunc field in the mdimpp list.
  98  *      Each process function only understands its own type of metadevice. Once
  99  *      it processes the metadevice it was called for, it then loops through
 100  *      all of the underlying metadevices.  After printing the name of the
 101  *      underlying metadevice, it puts in on a list to be processed.  If the
 102  *      underlying device is a physical device, then print_physical_device is
 103  *      called.
 104  *      Once all information about the original metadevice is processed, it
 105  *      loops through the list of underlying metadevices and calls the
 106  *      appropriate function to process them.
 107  *
 108  *  - process_toplevel_softparts()
 109  *      To match the output for metastat -c, all top-level softpartions
 110  *      are printed out in groups based on their underlying metadevice--so that
 111  *      the underlying metadevice only needs to be processed once.
 112  *
 113  *  - meta_get_(sm_state, raid_col_state, stripe_state, hs_state)
 114  *      These functions are used to retrieve the metadevice state information.
 115  *      They are also used by the metastat concise routines in
 116  *      cmd/lvm/util/metastat.c.
 117  *
 118  */
 119 
 120 
 121 /*
 122  * md_im_rec is a doubly linked list used to store the rb_data for each
 123  * directory entry that corresponds to a metadevice.
 124  * n_key: is set, if there is an associated entry in the NM namespace.
 125  * dfunc: is set to point to the function that processes the particular
 126  * metadevice associated with the record.
 127  * hs_record_id: is only set, if the metadevice is a hotspare.
 128  * un_self_id: is set for all other records. This is also used to generate
 129  * the name of the metadevice if there is no entry for the metadevice in
 130  * the NM namespace--n_key is not set.
 131  */
 132 typedef struct md_im_rec {
 133         mdkey_t                 n_key; /* NM namespace key */
 134         struct md_im_rec        *next;
 135         struct md_im_rec        *prev;
 136         uint_t                  md_type;
 137         uint_t                  has_parent; /* either 0(no parent) or 1 */
 138         minor_t                 un_self_id;
 139         mddb_recid_t            hs_record_id; /* hotspare recid */
 140         char                    *n_name;  /* name of metadevice */
 141         void                    (*dfunc) ();
 142         ushort_t                record_len;
 143         /* pointer to the unit structure for the metadevice, e.g. rb_data[0] */
 144         void                    *record;
 145 } md_im_rec_t;
 146 
 147 /*
 148  * md_im_list is used to group toplevel metadevices by type and to group
 149  * the underlying devices for a particular metadevice.
 150  */
 151 typedef struct md_im_list {
 152         struct md_im_list       *next;
 153         struct md_im_rec        *mdrec;
 154 } md_im_list_t;
 155 
 156 
 157 /*
 158  * MAXSIZEMDRECNAME is the value that has historically been used to allocate
 159  * space for the metadevice name
 160  */
 161 #define MAXSIZEMDRECNAME        20
 162 #define NAMEWIDTH               16
 163 #define NOT_PHYSICAL_DEV        0
 164 #define PHYSICAL_DEV            1
 165 
 166 
 167 /*
 168  * strip_blacks()
 169  *
 170  * Strip blanks from string.  Used for size field in concise output.
 171  */
 172 static char *
 173 strip_blanks(char *s)
 174 {
 175         char *p;
 176 
 177         for (p = s; *p; ) {
 178                 if (*p == ' ') {
 179                         char *t;
 180                         for (t = p; *t; t++) {
 181                                 *t = *(t + 1);
 182                         }
 183                 } else {
 184                         p++;
 185                 }
 186         }
 187 
 188         return (s);
 189 }
 190 
 191 
 192 /*
 193  * print_concise_entry()
 194  *
 195  * Print properly indented metadevice name, type and size for concise output.
 196  * This function is also called from: cmd/lvm/util/metastat.c.
 197  */
 198 void
 199 print_concise_entry(int indent, char *name, diskaddr_t size, char mtype)
 200 {
 201         int     i;
 202         int     width = NAMEWIDTH;      /* minumum field width for name */
 203         char    in[MAXPATHLEN];
 204         char    *sz;
 205 
 206         in[0] = 0;
 207         for (i = 0; i < indent; i++)
 208                 (void) strlcat(in, " ", sizeof (in));
 209 
 210         /* set up minimum field width. negative for left justified */
 211         width -= indent;
 212         if (width < 0)
 213                 width = 0;      /* overflowed; no minimum field needed */
 214         else
 215                 width = 0 - width; /* negative for left justification */
 216 
 217         if (size == 0) {
 218                 sz = "-";
 219         } else {
 220                 sz = strip_blanks(meta_number_to_string(size, DEV_BSIZE));
 221         }
 222 
 223         (void) printf("%s%*s %c %6s", in, width, name, mtype, sz);
 224 }
 225 
 226 
 227 /*
 228  * free_mdrec_list_entry()
 229  *
 230  * Removing entry from the list of metadevices in the diskset(mdimpp).
 231  * This function will not remove the dummy entry at the head of the
 232  * list, so we don't have to set mdrec equal to NULL.
 233  */
 234 static void
 235 free_mdrec_list_entry(md_im_rec_t  **mdrec)
 236 {
 237         (*mdrec)->prev->next = (*mdrec)->next;
 238         if ((*mdrec)->next != NULL) {
 239                 (*mdrec)->next->prev = (*mdrec)->prev;
 240         }
 241         Free((*mdrec)->record);
 242         Free((*mdrec)->n_name);
 243         Free(*mdrec);
 244 }
 245 
 246 
 247 /*
 248  * ucomponent_append()
 249  *
 250  * Appending entry to the underlying component list.  The list
 251  * is used to group all of the underlying devices before
 252  * processing them.
 253  */
 254 static void
 255 ucomponent_append(
 256         md_im_list_t    **ucomp_head,
 257         md_im_list_t    **ucomp_tail,
 258         md_im_list_t    *ucomp
 259 )
 260 {
 261         ucomp->next = NULL;
 262         if (*ucomp_head == NULL) {
 263                 *ucomp_head = ucomp;
 264                 *ucomp_tail = ucomp;
 265         } else {
 266                 (*ucomp_tail)->next = ucomp;
 267                 *ucomp_tail = (*ucomp_tail)->next;
 268         }
 269 }
 270 
 271 
 272 /*
 273  * free_md_im_list_entries()
 274  *
 275  * Freeing entries on an md_im_list_t.  This list is used to group
 276  * underlying components for processing and to group top-level metadevices
 277  * by type.
 278  */
 279 static void
 280 free_md_im_list_entries(md_im_list_t **list_head)
 281 {
 282         md_im_list_t    *tmp_list_entry = *list_head;
 283         md_im_list_t    *rm_list_entry;
 284 
 285         while (tmp_list_entry != NULL) {
 286                 rm_list_entry = tmp_list_entry;
 287                 tmp_list_entry = tmp_list_entry->next;
 288                 Free(rm_list_entry);
 289         }
 290 }
 291 
 292 
 293 /*
 294  * print_physical_device()
 295  *
 296  * If a metadevice has an underlying component that is a physical
 297  * device, then this searches the pnm_rec_t list to match an entry's
 298  * n_key to the key for the underlying component.  The ctd name of the
 299  * physical device is printed on the same line as the metadevice.
 300  */
 301 static void
 302 print_physical_device(
 303         pnm_rec_t       *phys_nm,
 304         mdkey_t         key
 305 )
 306 {
 307         pnm_rec_t       *tmpphys_nm;
 308 
 309         for (tmpphys_nm = phys_nm; tmpphys_nm != NULL;
 310             tmpphys_nm = tmpphys_nm->next) {
 311                 if (tmpphys_nm->n_key == key) {
 312                         (void) printf(" %s", tmpphys_nm->n_name);
 313                         break;
 314                 }
 315         }
 316 }
 317 
 318 
 319 /*
 320  * get_stripe_req_size()
 321  *
 322  * Given a 64bit stripe unit, compute the size of the stripe unit.
 323  * This function is a derivation of:
 324  *      common/lvm/md_convert.c:get_big_stripe_req_size()
 325  * and any changes made to either this function or get_big_stripe_req_size()
 326  * should be reviewed to make sure the functionality in both places is correct.
 327  *
 328  * Returns:
 329  *      total size of the 64bit stripe
 330  */
 331 size_t
 332 get_stripe_req_size(ms_unit_t *un)
 333 {
 334         struct ms_row *mdr;
 335         uint_t row;
 336         uint_t ncomps = 0;
 337         size_t mdsize = 0;
 338         size_t first_comp = 0;
 339 
 340 
 341         /* Compute the offset of the first component */
 342         first_comp = sizeof (ms_unit_t) +
 343             sizeof (struct ms_row) * (un->un_nrows - 1);
 344         first_comp = roundup(first_comp, sizeof (long long));
 345 
 346         /*
 347          * Requestor wants to have the total size, add the sizes of
 348          * all components
 349          */
 350         mdr = &un->un_row[0];
 351         for (row = 0; (row < un->un_nrows); row++)
 352             ncomps += mdr[row].un_ncomp;
 353         mdsize = first_comp + sizeof (ms_comp_t) * ncomps;
 354         return (mdsize);
 355 }
 356 
 357 
 358 /*
 359  * meta_get_sm_state()
 360  *
 361  * Gets the state for the underlying components(submirrors) of a mirror.
 362  * This function is also called from: cmd/lvm/util/metastat.c.
 363  *
 364  * Returns:
 365  *      string for state of the sub-mirror
 366  */
 367 static char *
 368 meta_get_sm_state(
 369         sm_state_t      state
 370 )
 371 {
 372         /* all is well */
 373         if (state & SMS_RUNNING) {
 374                 return (NULL);
 375         }
 376 
 377         /* resyncing, needs repair */
 378         if ((state & (SMS_COMP_RESYNC | SMS_ATTACHED_RESYNC |
 379             SMS_OFFLINE_RESYNC))) {
 380                 return (gettext("resyncing"));
 381         }
 382 
 383         /* needs repair */
 384         if (state & (SMS_COMP_ERRED | SMS_ATTACHED | SMS_OFFLINE))
 385                 return (gettext("maint"));
 386 
 387         /* unknown */
 388         return (gettext("unknown"));
 389 }
 390 
 391 
 392 /*
 393  * meta_get_raid_col_state()
 394  *
 395  * Gets the state for the underlying components(columns) of a raid.
 396  * This function is also called from: cmd/lvm/util/metastat.c.
 397  *
 398  * Returns:
 399  *      string for state of the raid column
 400  *
 401  */
 402 char *
 403 meta_get_raid_col_state(
 404         rcs_state_t     state
 405 )
 406 {
 407         switch (state) {
 408                 case RCS_INIT:
 409                         return (gettext("initializing"));
 410                 case RCS_OKAY:
 411                         return (NULL);
 412                 case RCS_INIT_ERRED:
 413                         /*FALLTHROUGH*/
 414                 case RCS_ERRED:
 415                         return (gettext("maint"));
 416                 case RCS_LAST_ERRED:
 417                         return (gettext("last-erred"));
 418                 case RCS_RESYNC:
 419                         return (gettext("resyncing"));
 420                 default:
 421                         return (gettext("unknown"));
 422         }
 423 }
 424 
 425 
 426 /*
 427  * meta_get_stripe_state()
 428  *
 429  * Gets the state for the underlying components of a stripe.
 430  * This function is also called from: cmd/lvm/util/metastat.c.
 431  *
 432  * Returns:
 433  *      string for state of the stripe
 434  *
 435  */
 436 char *
 437 meta_get_stripe_state(
 438         comp_state_t    state
 439 )
 440 {
 441         switch (state) {
 442                 case CS_OKAY:
 443                         return (NULL);
 444                 case CS_ERRED:
 445                         return (gettext("maint"));
 446                 case CS_LAST_ERRED:
 447                         return (gettext("last-erred"));
 448                 case CS_RESYNC:
 449                         return (gettext("resyncing"));
 450                 default:
 451                         return (gettext("invalid"));
 452         }
 453 }
 454 
 455 
 456 /*
 457  * meta_get_hs_state()
 458  *
 459  * Gets the state for the underlying components(hotspares) of a hotspare pool.
 460  * This function is also called from: cmd/lvm/util/metastat.c.
 461  *
 462  * Returns:
 463  *      string for state of the hotspare
 464  *
 465  */
 466 char *
 467 meta_get_hs_state(
 468         hotspare_states_t       state
 469 )
 470 {
 471         switch (state) {
 472                 case HSS_AVAILABLE:
 473                         return (NULL);
 474                 case HSS_RESERVED:
 475                         return (gettext("in-use"));
 476                 case HSS_BROKEN:
 477                         return (gettext("broken"));
 478                 case HSS_UNUSED:
 479                         /* FALLTHROUGH */
 480                 default:
 481                         return (gettext("invalid"));
 482         }
 483 }
 484 
 485 
 486 /*
 487  * process_trans()
 488  *
 489  * Prints unit information for a trans metadevice and calls the respective
 490  * functions to process the underlying metadevices.
 491  *
 492  */
 493 static void
 494 process_trans(
 495         md_im_rec_t     **mdimpp,
 496         int             indent,
 497         pnm_rec_t       *phys_nm,
 498         md_im_rec_t     *mdrec
 499 )
 500 {
 501         mt_unit_t       *mt;
 502         mdc_unit_t      uc;
 503         md_im_rec_t     *tmpmdrec;
 504         int             underlying_device = PHYSICAL_DEV;
 505 
 506         mt = (mt_unit_t *)mdrec->record;
 507         uc = mt->c;
 508 
 509         /* Printing name, size, and type of metadevice */
 510         print_concise_entry(indent, mdrec->n_name,
 511             uc.un_total_blocks, 't');
 512 
 513         /*
 514          * Loops through md_im_rec_t **mdimpp list of all metadevices to find
 515          * record that matches the underlying device.
 516          * Trans devices can only have one underlying device, so once a
 517          * match is found, we are done.
 518          */
 519         for (tmpmdrec = *mdimpp; tmpmdrec != NULL;
 520             tmpmdrec = tmpmdrec->next) {
 521                 if (tmpmdrec->n_key == mt->un_m_key) {
 522                         /* Printing name of the underlying metadevice */
 523                         (void) printf(" %s", tmpmdrec->n_name);
 524                         underlying_device = NOT_PHYSICAL_DEV;
 525                         break;
 526                 }
 527         }
 528 
 529         /*
 530          * If a metadevice was not found, then the underlying device must be a
 531          * physical device.  Otherwise, call the functions to process the
 532          * underlying devices.
 533          */
 534         if (underlying_device == PHYSICAL_DEV) {
 535                 print_physical_device(phys_nm, mt->un_m_key);
 536                 (void) printf("\n");
 537         } else {
 538                 /* process underlying component */
 539                 (void) printf("\n");
 540                 indent += META_INDENT;
 541                 tmpmdrec->dfunc(mdimpp, indent, phys_nm, tmpmdrec);
 542         }
 543 
 544         /*
 545          * Removing the md_entry from the list
 546          * of all metadevices
 547          */
 548         free_mdrec_list_entry(&mdrec);
 549 }
 550 
 551 
 552 /*
 553  * process_hotspare()
 554  *
 555  * Searches though list of physical devices to match hotspare record.
 556  * Prints physical device name and state of a hotspare unit.
 557  *
 558  */
 559 /*ARGSUSED*/
 560 static void
 561 process_hotspare(
 562         md_im_rec_t     **mdimpp,
 563         int             indent,
 564         pnm_rec_t       *phys_nm,
 565         md_im_rec_t     *mdrec
 566 )
 567 {
 568         hot_spare_t     *hs;
 569         pnm_rec_t       *tmpphys_nm;
 570         char            *state = NULL;
 571 
 572         hs =  (hot_spare_t *)mdrec->record;
 573 
 574         /*
 575          * Loops through physical namespace to find the device that matches
 576          * the hotspare entry.
 577          */
 578         for (tmpphys_nm = phys_nm; tmpphys_nm != NULL;
 579             tmpphys_nm = tmpphys_nm->next) {
 580                 if (tmpphys_nm->n_key ==
 581                     ((hot_spare_t *)hs)->hs_key) {
 582                         /* Printing name of hotspare device */
 583                         (void) printf(" %s", tmpphys_nm->n_name);
 584                         break;
 585                 }
 586         }
 587 
 588         state = meta_get_hs_state(hs->hs_state);
 589         if (state != NULL)
 590                 (void) printf(" (%s)", state);
 591 
 592         /* Not removing entry, because it can be processed more than once. */
 593 }
 594 
 595 
 596 /*
 597  * process_hotspare_pool()
 598  *
 599  * Prints concise unit information for a hotspare pool metadevice and calls a
 600  * function to process each attached hotspare device.
 601  *
 602  */
 603 static void
 604 process_hotspare_pool(
 605         md_im_rec_t     **mdimpp,
 606         int             indent,
 607         pnm_rec_t       *phys_nm,
 608         md_im_rec_t     *mdrec
 609 )
 610 {
 611         hot_spare_pool_ond_t    *hsp;
 612         int                     i;
 613         md_im_rec_t             *tmpmdrec;
 614 
 615         hsp =  (hot_spare_pool_ond_t *)mdrec->record;
 616 
 617         /*
 618          * Printing name, size, and type of metadevice. Setting size field to
 619          * 0, so that output is the as metastat -c.
 620          */
 621         print_concise_entry(indent, mdrec->n_name,
 622             0, 'h');
 623 
 624         /* Looping through list of attached hotspare devices. */
 625         for (i = 0; i < hsp->hsp_nhotspares; i++) {
 626                 /* Looking for the matching record for the hotspare device. */
 627                 for (tmpmdrec = *mdimpp; tmpmdrec != NULL;
 628                     tmpmdrec = tmpmdrec->next) {
 629                         if (tmpmdrec->hs_record_id == hsp->hsp_hotspares[i]) {
 630                                 /* Calling function to print name of hotspare */
 631                                 tmpmdrec->dfunc(mdimpp, indent, phys_nm,
 632                                     tmpmdrec);
 633                         }
 634                 }
 635         }
 636         (void) printf("\n");
 637 
 638         /*
 639          * Removing the md_entry from the list
 640          * of all metadevices
 641          */
 642         free_mdrec_list_entry(&mdrec);
 643 }
 644 
 645 
 646 /*
 647  * process_raid()
 648  *
 649  * Prints concise unit information for a raid metadevice and calls the
 650  * respective functions to process the underlying metadevices.
 651  *
 652  */
 653 static void
 654 process_raid(
 655         md_im_rec_t     **mdimpp,
 656         int             indent,
 657         pnm_rec_t       *phys_nm,
 658         md_im_rec_t     *mdrec
 659 )
 660 {
 661         mr_unit_t       *mr;
 662         mr_column_t     *mc;
 663         mdc_unit_t      uc;
 664         int             i;
 665         md_im_rec_t     *tmpmdrec;
 666         md_im_rec_t     *hstmpmdrec;
 667         md_im_list_t    *ucomp_head = NULL;
 668         md_im_list_t    *ucomp_tail = NULL;
 669         md_im_list_t    *ucomp = NULL;
 670         pnm_rec_t       *tmpphys_nm;
 671         int             underlying_device;
 672 
 673         mr =  (mr_unit_t *)mdrec->record;
 674         uc = mr->c;
 675 
 676         /* Printing name, size, and type of metadevice */
 677         print_concise_entry(indent, mdrec->n_name,
 678             uc.un_total_blocks, 'r');
 679 
 680         /* Loops through raid columns to find underlying metadevices */
 681         for (i = 0, mc = &mr->un_column[0];  i < mr->un_totalcolumncnt;
 682             i++, mc++) {
 683                 char    *state = NULL;
 684                 char    *hsname = NULL;
 685 
 686                 /*
 687                  * Need to assume that underlying device is a physical device,
 688                  * unless we find a matching metadevice record.
 689                  */
 690                 underlying_device = PHYSICAL_DEV;
 691 
 692                 /*
 693                  * Loops through list of metadevices to find record that matches
 694                  * the underlying device.
 695                  */
 696                 for (tmpmdrec = *mdimpp; tmpmdrec != NULL;
 697                     tmpmdrec = tmpmdrec->next) {
 698                         if (tmpmdrec->n_key == mc->un_orig_key) {
 699                                 /* check if hotspare device enabled */
 700                                 if (mc->un_hs_id !=  NULL) {
 701                                         /*
 702                                          * Find matching metadevice record
 703                                          * for the hotspare device.
 704                                          */
 705                                         for (hstmpmdrec = *mdimpp;
 706                                             hstmpmdrec != NULL;
 707                                             hstmpmdrec = hstmpmdrec->next) {
 708                                                 if (hstmpmdrec->hs_record_id ==
 709                                                     mc->un_hs_id) {
 710                                                         /* print name of hs */
 711                                                         hstmpmdrec->dfunc(
 712                                                             mdimpp, indent,
 713                                                             phys_nm,
 714                                                             hstmpmdrec);
 715                                                         break;
 716                                                 }
 717                                         }
 718                                 }
 719                                 /* print name of underlying metadevice */
 720                                 (void) printf(" %s", tmpmdrec->n_name);
 721                                 underlying_device = NOT_PHYSICAL_DEV;
 722                                 ucomp = Zalloc(sizeof (md_im_list_t));
 723                                 ucomp->mdrec = tmpmdrec;
 724                                 ucomponent_append(&ucomp_head, &ucomp_tail,
 725                                     ucomp);
 726                         }
 727                 }
 728 
 729                 if (underlying_device == PHYSICAL_DEV) {
 730                         print_physical_device(phys_nm, mc->un_orig_key);
 731                 }
 732                 state = meta_get_raid_col_state(mc->un_devstate);
 733 
 734                 /*
 735                  * An underlying hotspare must be a physical device.
 736                  * If support is ever added for soft-partitions under
 737                  * hotspare pools, then this code should be updated to
 738                  * include a search for underlying metadevices.
 739                  */
 740                 if (mc->un_hs_id != 0) {
 741                         for (tmpphys_nm = phys_nm; tmpphys_nm != NULL;
 742                             tmpphys_nm = tmpphys_nm->next) {
 743                                 if (tmpphys_nm->n_key == mc->un_hs_key) {
 744                                         hsname = tmpphys_nm->n_name;
 745                                         break;
 746                                 }
 747                         }
 748                 }
 749 
 750                 if (state != NULL) {
 751                         if (hsname != NULL)
 752                                 (void) printf(" (%s-%s)", state,
 753                                     hsname);
 754                         else
 755                                 (void) printf(" (%s)", state);
 756                 } else if (hsname != NULL) {
 757                         (void) printf(gettext(" (spared-%s)"), hsname);
 758                 }
 759         }
 760         (void) printf("\n");
 761 
 762         /* process underlying components */
 763         indent += META_INDENT;
 764         for (ucomp = ucomp_head; ucomp != NULL;
 765             ucomp = ucomp->next) {
 766                 ucomp->mdrec->dfunc(mdimpp, indent, phys_nm,
 767                     ucomp->mdrec);
 768         }
 769         free_md_im_list_entries(&ucomp_head);
 770 
 771         /*
 772          * Removing the md_entry from the list
 773          * of all metadevices
 774          */
 775         free_mdrec_list_entry(&mdrec);
 776 }
 777 
 778 
 779 /*
 780  * process_mirror()
 781  *
 782  * Prints concise unit information for a mirror metadevice and calls the
 783  * respective functions to process the underlying metadevices.
 784  *
 785  */
 786 static void
 787 process_mirror(
 788         md_im_rec_t     **mdimpp,
 789         int             indent,
 790         pnm_rec_t       *phys_nm,
 791         md_im_rec_t     *mdrec
 792 )
 793 {
 794         mm_unit_t       *mm;
 795         mm_submirror_t  *sm;
 796         mdc_unit_t      uc;
 797         int             i;
 798         md_im_rec_t     *tmpmdrec;
 799         md_im_list_t    *ucomp_head = NULL;
 800         md_im_list_t    *ucomp_tail = NULL;
 801         md_im_list_t    *ucomp = NULL;
 802 
 803         mm =  (mm_unit_t *)mdrec->record;
 804         uc = mm->c;
 805 
 806         /* Printing name, size, and type of metadevice */
 807         print_concise_entry(indent, mdrec->n_name,
 808             uc.un_total_blocks, 'm');
 809 
 810         /* Looping through sub-mirrors to find underlying devices */
 811         for (i = 0, sm = &mm->un_sm[0]; i < mm->un_nsm; i++, sm++) {
 812                 char    *state = NULL;
 813 
 814                 for (tmpmdrec = *mdimpp; tmpmdrec != NULL;
 815                     tmpmdrec = tmpmdrec->next) {
 816                         if (tmpmdrec->n_key == sm->sm_key) {
 817                                 (void) printf(" %s", tmpmdrec->n_name);
 818                                 ucomp = Zalloc(sizeof (md_im_list_t));
 819                                 ucomp->mdrec = tmpmdrec;
 820                                 ucomponent_append(&ucomp_head, &ucomp_tail,
 821                                     ucomp);
 822                         }
 823                 }
 824 
 825                 /*
 826                  * It is not possible to have an underlying physical device
 827                  * for a submirror, so there is no need to search the phys_nm
 828                  * list.
 829                  */
 830 
 831                 /* Printing the state for the submirror */
 832                 state = meta_get_sm_state(sm->sm_state);
 833                 if (state != NULL) {
 834                         (void) printf(" (%s)", state);
 835                 }
 836         }
 837         (void) printf("\n");
 838 
 839         /* process underlying components */
 840         indent += META_INDENT;
 841         for (ucomp = ucomp_head; ucomp != NULL;
 842             ucomp = ucomp->next) {
 843                 ucomp->mdrec->dfunc(mdimpp, indent, phys_nm,
 844                     ucomp->mdrec);
 845         }
 846         free_md_im_list_entries(&ucomp_head);
 847 
 848         /*
 849          * Removing the md_entry from the list
 850          * of all metadevices
 851          */
 852         free_mdrec_list_entry(&mdrec);
 853 }
 854 
 855 
 856 /*
 857  * process_stripe()
 858  *
 859  * Prints concise unit information for a stripe metadevice and calls the
 860  * respective functions to process the underlying metadevices.
 861  *
 862  */
 863 static void
 864 process_stripe(
 865         md_im_rec_t     **mdimpp,
 866         int             indent,
 867         pnm_rec_t       *phys_nm,
 868         md_im_rec_t     *mdrec
 869 )
 870 {
 871         ms_unit_t       *ms;
 872         mdc_unit_t      uc;
 873         md_im_rec_t     *tmpmdrec;
 874         md_im_list_t    *ucomp_head = NULL;
 875         md_im_list_t    *ucomp_tail = NULL;
 876         md_im_list_t    *ucomp = NULL;
 877         pnm_rec_t       *tmpphys_nm;
 878         int             underlying_device;
 879         uint_t          row;
 880 
 881         ms =  (ms_unit_t *)mdrec->record;
 882         uc = ms->c;
 883 
 884         /* Printing name, size, and type of metadevice */
 885         print_concise_entry(indent, mdrec->n_name,
 886             uc.un_total_blocks, 's');
 887 
 888         /* Looping through stripe rows */
 889         for (row = 0; (row < ms->un_nrows); ++row) {
 890                 struct ms_row   *mdr = &ms->un_row[row];
 891                 ms_comp_t       *mdcomp = (void *)&((char *)ms)
 892                     [ms->un_ocomp];
 893                 uint_t          comp, c;
 894 
 895                 /*
 896                  * Looping through the components in each row to find the
 897                  * underlying devices.
 898                  */
 899                 for (comp = 0, c = mdr->un_icomp; (comp < mdr->un_ncomp);
 900                     ++comp, ++c) {
 901                         char            *state = NULL;
 902                         char            *hsname = NULL;
 903                         ms_comp_t       *mdc = &mdcomp[c];
 904                         md_m_shared_t   *mdm = &mdc->un_mirror;
 905 
 906                         /*
 907                          * Need to assume that underlying device is a
 908                          * physical device, unless we find a matching
 909                          * metadevice record.
 910                          */
 911                         underlying_device = PHYSICAL_DEV;
 912 
 913                         for (tmpmdrec = *mdimpp; tmpmdrec != NULL;
 914                             tmpmdrec = tmpmdrec->next) {
 915                                 if (tmpmdrec->n_key == mdc->un_key) {
 916                                         (void) printf(" %s", tmpmdrec->n_name);
 917                                         underlying_device = NOT_PHYSICAL_DEV;
 918                                         ucomp = Zalloc(sizeof (md_im_list_t));
 919                                         ucomp->mdrec = tmpmdrec;
 920                                         ucomponent_append(&ucomp_head,
 921                                             &ucomp_tail, ucomp);
 922                                 }
 923                         }
 924                         /* if an underlying metadevice was not found */
 925                         if (underlying_device == PHYSICAL_DEV) {
 926                                 print_physical_device(phys_nm, mdc->un_key);
 927                         }
 928                         state = meta_get_stripe_state(mdm->ms_state);
 929 
 930                         /*
 931                          * An underlying hotspare must be a physical device.
 932                          * If support is ever added for soft-partitions under
 933                          * hotspare pools, then this code should be updated to
 934                          * include a search for underlying metadevices.
 935                          */
 936                         if (mdm->ms_hs_key != 0) {
 937                                 for (tmpphys_nm = phys_nm; tmpphys_nm != NULL;
 938                                     tmpphys_nm = tmpphys_nm->next) {
 939                                         if (tmpphys_nm->n_key ==
 940                                             mdm->ms_hs_key) {
 941                                                 hsname = tmpphys_nm->n_name;
 942                                                 break;
 943                                         }
 944                                 }
 945                         }
 946                         if (state != NULL) {
 947                                 if (hsname != NULL) {
 948                                         (void) printf(" (%s-%s)", state,
 949                                             hsname);
 950                                 } else {
 951                                         (void) printf(" (%s)", state);
 952                                 }
 953                         } else if (hsname != NULL) {
 954                                 (void) printf(gettext(" (spared-%s)"), hsname);
 955                         }
 956                 }
 957         }
 958         (void) printf("\n");
 959 
 960         /* Process underlying metadevices */
 961         indent += META_INDENT;
 962         for (ucomp = ucomp_head; ucomp != NULL;
 963             ucomp = ucomp->next) {
 964                 ucomp->mdrec->dfunc(mdimpp, indent, phys_nm,
 965                     ucomp->mdrec);
 966         }
 967         free_md_im_list_entries(&ucomp_head);
 968 
 969         /*
 970          * Removing the md_entry from the list
 971          * of all metadevices
 972          */
 973         free_mdrec_list_entry(&mdrec);
 974 }
 975 
 976 
 977 /*
 978  * process_softpart()
 979  *
 980  * Prints concise unit information for a softpart metadevice and calls the
 981  * respective functions to process the underlying metadevices.
 982  *
 983  */
 984 static void
 985 process_softpart(
 986         md_im_rec_t     **mdimpp,
 987         int             indent,
 988         pnm_rec_t       *phys_nm,
 989         md_im_rec_t     *mdrec
 990 )
 991 {
 992         mp_unit_t       *mp;
 993         mdc_unit_t      uc;
 994         md_im_rec_t     *tmpmdrec;
 995         int             underlying_device = PHYSICAL_DEV;
 996 
 997         mp =  (mp_unit_t *)mdrec->record;
 998         uc = mp->c;
 999 
1000         /* Printing name, size, and type of metadevice */
1001         print_concise_entry(indent, mdrec->n_name,
1002             uc.un_total_blocks, 'p');
1003 
1004         /*
1005          * Loops through md_im_rec_t **mdimpp list of all metadevices to find
1006          * record that matches the underlying device.
1007          * Softpartitions can only have one underlying device, so once a
1008          * match is found, we are done.
1009          */
1010         for (tmpmdrec = *mdimpp; tmpmdrec != NULL;
1011             tmpmdrec = tmpmdrec->next) {
1012                 if (tmpmdrec->n_key == mp->un_key) {
1013                         /* Printing name of the underlying metadevice */
1014                         (void) printf(" %s", tmpmdrec->n_name);
1015                         underlying_device = NOT_PHYSICAL_DEV;
1016                         break;
1017                 }
1018         }
1019 
1020         /* This is only executed if an underlying metadevice was not found */
1021         if (underlying_device == PHYSICAL_DEV) {
1022                 print_physical_device(phys_nm, mp->un_key);
1023                 (void) printf("\n");
1024         } else {
1025                 /* Process underlying metadevice */
1026                 (void) printf("\n");
1027                 indent += META_INDENT;
1028                 tmpmdrec->dfunc(mdimpp, indent, phys_nm,
1029                     tmpmdrec);
1030         }
1031 
1032         /*
1033          * Removing the md_entry from the list
1034          * of all metadevices
1035          */
1036         free_mdrec_list_entry(&mdrec);
1037 }
1038 
1039 
1040 /*
1041  * process_toplevel_softparts()
1042  *
1043  * Toplevel softpartions need to be grouped so that their underlying devices
1044  * can be printed just once.
1045  */
1046 static void
1047 process_toplevel_softparts(
1048         md_im_rec_t     **mdimpp,
1049         int             indent,
1050         pnm_rec_t       *phys_nm
1051 )
1052 {
1053         mp_unit_t       *mp;
1054         mdc_unit_t      uc;
1055         md_im_rec_t     *mdrec;
1056         md_im_rec_t     *comp_mdrec; /* pntr to underlying component's record */
1057         md_im_rec_t     *tmp_mdrec, *rm_mdrec;
1058         mp_unit_t       *tmp_mp;
1059         int             underlying_device;
1060 
1061         /*
1062          * Loops through md_im_rec_t **mdimpp list of all metadevices to find
1063          * all softpartions that are toplevel softpartitions(softparts w/out
1064          * a parent). Groups output for these entries so that the function to
1065          * process the underlying metadevice is only called once.
1066          */
1067         for (mdrec = *mdimpp; mdrec != NULL; mdrec = mdrec->next) {
1068 
1069                 underlying_device = PHYSICAL_DEV;
1070                 if ((mdrec->md_type == MDDB_F_SOFTPART) &&
1071                     (mdrec->has_parent == 0)) {
1072                         mp =  (mp_unit_t *)mdrec->record;
1073                         uc = mp->c;
1074                         /* Printing name, size, and type of metadevice */
1075                         print_concise_entry(indent, mdrec->n_name,
1076                             uc.un_total_blocks, 'p');
1077                         /*
1078                          * Looking for record that matches underlying
1079                          * component.
1080                          */
1081                         for (comp_mdrec = *mdimpp; comp_mdrec != NULL;
1082                             comp_mdrec = comp_mdrec->next) {
1083                                 if (comp_mdrec->n_key == mp->un_key) {
1084                                         /* Print name of underlying device */
1085                                         (void) printf(" %s",
1086                                             comp_mdrec->n_name);
1087                                         underlying_device = NOT_PHYSICAL_DEV;
1088                                         break;
1089                                 }
1090                         }
1091                         if (underlying_device == PHYSICAL_DEV) {
1092                                 print_physical_device(phys_nm, mp->un_key);
1093                         }
1094                         (void) printf("\n");
1095 
1096                         /*
1097                          * Looking for any other toplevel softpartitions with
1098                          * same underlying device. We know that all other
1099                          * matching metadevices, that share the same underlying
1100                          * metadevice, are also soft-partitions.
1101                          */
1102                         for (tmp_mdrec = mdrec->next; tmp_mdrec != NULL; ) {
1103                                 tmp_mp = (mp_unit_t *)tmp_mdrec->record;
1104                                 if ((tmp_mdrec->has_parent == 0) &&
1105                                     (tmp_mp->un_key == mp->un_key)) {
1106                                         uc = tmp_mp->c;
1107                                         print_concise_entry(indent,
1108                                             tmp_mdrec->n_name,
1109                                             uc.un_total_blocks, 'p');
1110                                         if (underlying_device ==
1111                                             NOT_PHYSICAL_DEV) {
1112                                                 (void) printf(" %s",
1113                                                     comp_mdrec->n_name);
1114                                         } else {
1115                                                 print_physical_device(
1116                                                     phys_nm, tmp_mp->un_key);
1117                                         }
1118                                         (void) printf("\n");
1119                                         /*
1120                                          * Need to advance so that will not lose
1121                                          * position after removing processed
1122                                          * record.
1123                                          */
1124                                         rm_mdrec = tmp_mdrec;
1125                                         tmp_mdrec = tmp_mdrec->next;
1126                                         /*
1127                                          * Removing the md_entry from the list
1128                                          * of all metadevices.
1129                                          */
1130                                         free_mdrec_list_entry(&rm_mdrec);
1131                                 } else {
1132                                         tmp_mdrec = tmp_mdrec->next;
1133                                 }
1134                         }
1135                         /* Process the underlying device */
1136                         if (underlying_device == NOT_PHYSICAL_DEV) {
1137                                 indent += META_INDENT;
1138                                 comp_mdrec->dfunc(mdimpp, indent, phys_nm,
1139                                     comp_mdrec);
1140                         }
1141                 }
1142         }
1143 }
1144 
1145 
1146 /*
1147  * process_toplevel_devices()
1148  *
1149  * Search through list of metadevices for metadevices of md_type that do not
1150  * have a parent.
1151  *
1152  */
1153 static void
1154 process_toplevel_devices(
1155         md_im_rec_t     **mdimpp,
1156         pnm_rec_t       *pnm,
1157         uint_t          md_type
1158 )
1159 {
1160         md_im_rec_t     *mdrec;
1161         md_im_list_t    *mdrec_tl_tail = NULL;
1162         md_im_list_t    *mdrec_tl_head = NULL;
1163         md_im_list_t    *tmp_tl_list = NULL;
1164         int             indent = 0;
1165 
1166         indent += META_INDENT;
1167 
1168         /*
1169          * Need to group soft partitions so that common underlying device
1170          * are only processed once.
1171          */
1172         if (md_type == MDDB_F_SOFTPART) {
1173                 process_toplevel_softparts(mdimpp, indent, pnm);
1174                 return;
1175         }
1176 
1177         /*
1178          * Search the list of metadevices to find all metadevices that match
1179          * the type and don't have a parent.  Put them on a separate list
1180          * that will be processed.
1181          */
1182         for (mdrec = *mdimpp; mdrec != NULL; mdrec = mdrec->next) {
1183                 if ((mdrec->md_type == md_type)&&(mdrec->has_parent == 0)) {
1184                         tmp_tl_list = Zalloc(sizeof (md_im_list_t));
1185                         tmp_tl_list->mdrec = mdrec;
1186                         tmp_tl_list->next = NULL;
1187                         if (mdrec_tl_tail == NULL) {
1188                                 mdrec_tl_tail = tmp_tl_list;
1189                                 mdrec_tl_head = mdrec_tl_tail;
1190                         } else {
1191                                 mdrec_tl_tail->next = tmp_tl_list;
1192                                 mdrec_tl_tail = mdrec_tl_tail->next;
1193                         }
1194                 }
1195 
1196         }
1197 
1198         /*
1199          * Loop through list and process all top-level metadevices of a
1200          * given type.
1201          */
1202         for (tmp_tl_list = mdrec_tl_head; tmp_tl_list != NULL;
1203             tmp_tl_list = tmp_tl_list->next) {
1204                 tmp_tl_list->mdrec->dfunc(mdimpp, indent, pnm,
1205                     tmp_tl_list->mdrec);
1206         }
1207 
1208         free_md_im_list_entries(&mdrec_tl_head);
1209 }
1210 
1211 
1212 /*
1213  * extract_mduser_data()
1214  *
1215  * Converts or copies the (mddb_rb_t->rb_data) metadevice record to a 64bit
1216  * record.
1217  * Sets the dfunc field to point to the appropriate function to process the
1218  * metadevice.
1219  * Sets the parent field for the metadevice.
1220  * Extracts the name from the NM namespace if it is available, otherwise
1221  * generates it from the metadevice's minor number.
1222  *
1223  * Returns:
1224  *      < 0 for failure
1225  *        0 for success
1226  *
1227  */
1228 static int
1229 extract_mduser_data(
1230         mddb_rb_t               *nm,
1231         md_im_rec_t             *mdrec,
1232         void                    *rbp,
1233         int                     is_32bit_record,
1234         md_error_t              *ep
1235 )
1236 {
1237         mdc_unit_t              uc;
1238         hot_spare_t             *hs;
1239         hot_spare_pool_ond_t    *hsp;
1240         size_t                  newreqsize;
1241         mddb_rb_t               *rbp_nm = nm;
1242         struct nm_rec           *nm_record;
1243         struct nm_name          *nmname;
1244         char                    *uname = NULL;
1245 
1246 
1247         /*LINTED*/
1248         nm_record = (struct nm_rec *)((caddr_t)(&rbp_nm->rb_data));
1249 
1250         /*
1251          * Setting the un_self_id or the hs_self_id, in the case of hotspare
1252          * records, for each metadevice entry. Also setting has_parent and
1253          * setting dfunc so that it points to the correct function to process
1254          * the record type.
1255          * If the record was stored ondisk in 32bit format, then it is
1256          * converted to the 64bits equivalent 64bit format and the memory
1257          * for the 32bit pointer is freed.
1258          */
1259         switch (mdrec->md_type) {
1260                 case MDDB_F_SOFTPART:
1261                         if (is_32bit_record) {
1262                                 mp_unit32_od_t  *small_un;
1263                                 mp_unit_t       *big_un;
1264 
1265                                 small_un = (mp_unit32_od_t *)((uintptr_t)rbp +
1266                                     (sizeof (mddb_rb_t) - sizeof (int)));
1267                                 newreqsize = sizeof (mp_unit_t) +
1268                                     ((small_un->un_numexts - 1) *
1269                                     sizeof (struct mp_ext));
1270                                 big_un = (void *)Zalloc(newreqsize);
1271                                 softpart_convert((caddr_t)small_un,
1272                                     (caddr_t)big_un, SMALL_2_BIG);
1273                                 mdrec->record = (void *)big_un;
1274                         } else {
1275                                 mp_unit_t       *big_un;
1276 
1277                                 big_un = (mp_unit_t *)((uintptr_t)rbp +
1278                                     (sizeof (mddb_rb_t) - sizeof (int)));
1279                                 newreqsize = sizeof (mp_unit_t) +
1280                                     ((big_un->un_numexts - 1) *
1281                                     sizeof (struct mp_ext));
1282                                 mdrec->record = (void *)Zalloc(newreqsize);
1283                                 bcopy(big_un, mdrec->record, newreqsize);
1284                         }
1285                         uc = ((mp_unit_t *)mdrec->record)->c;
1286                         mdrec->dfunc = &process_softpart;
1287                         mdrec->un_self_id = uc.un_self_id;
1288                         mdrec->has_parent = MD_HAS_PARENT(
1289                             uc.un_parent);
1290                         break;
1291                 case MDDB_F_STRIPE:
1292                         if (is_32bit_record) {
1293                                 ms_unit32_od_t  *small_un;
1294                                 ms_unit_t       *big_un;
1295 
1296                                 small_un = (ms_unit32_od_t *)((uintptr_t)rbp +
1297                                     (sizeof (mddb_rb_t) - sizeof (int)));
1298                                 newreqsize = get_big_stripe_req_size(
1299                                     small_un, COMPLETE_STRUCTURE);
1300                                     big_un = (void *)Zalloc(newreqsize);
1301                                 stripe_convert((caddr_t)small_un,
1302                                     (caddr_t)big_un, SMALL_2_BIG);
1303                                 mdrec->record = (void *)big_un;
1304                         } else {
1305                                 ms_unit_t       *big_un;
1306 
1307                                 big_un = (ms_unit_t *)((uintptr_t)rbp +
1308                                     (sizeof (mddb_rb_t) - sizeof (int)));
1309                                 newreqsize = get_stripe_req_size(big_un);
1310                                 mdrec->record = (void *)Zalloc(newreqsize);
1311                                 bcopy(big_un, mdrec->record, newreqsize);
1312                         }
1313                         uc = ((ms_unit_t *)mdrec->record)->c;
1314                         mdrec->dfunc = &process_stripe;
1315                         mdrec->un_self_id = uc.un_self_id;
1316                         mdrec->has_parent = MD_HAS_PARENT(
1317                             uc.un_parent);
1318                         break;
1319                 case MDDB_F_MIRROR:
1320                         if (is_32bit_record) {
1321                                 mm_unit32_od_t  *small_un;
1322                                 mm_unit_t       *big_un;
1323 
1324                                 small_un = (mm_unit32_od_t *)((uintptr_t)rbp +
1325                                     (sizeof (mddb_rb_t) - sizeof (int)));
1326                                 newreqsize = sizeof (mm_unit_t);
1327                                 big_un = (void *)Zalloc(newreqsize);
1328                                 mirror_convert((caddr_t)small_un,
1329                                     (caddr_t)big_un, SMALL_2_BIG);
1330                                 mdrec->record = (void *)big_un;
1331                         } else {
1332                                 mm_unit_t       *big_un;
1333 
1334                                 big_un = (mm_unit_t *)((uintptr_t)rbp +
1335                                     (sizeof (mddb_rb_t) - sizeof (int)));
1336                                 newreqsize = sizeof (mm_unit_t);
1337                                 mdrec->record = (void *)Zalloc(newreqsize);
1338                                 bcopy(big_un, mdrec->record, newreqsize);
1339                         }
1340                         uc = ((mm_unit_t *)mdrec->record)->c;
1341                         mdrec->dfunc = &process_mirror;
1342                         mdrec->un_self_id = uc.un_self_id;
1343                         mdrec->has_parent = MD_HAS_PARENT(
1344                             uc.un_parent);
1345                         break;
1346                 case MDDB_F_RAID:
1347                         if (is_32bit_record) {
1348                                 mr_unit32_od_t  *small_un;
1349                                 mr_unit_t       *big_un;
1350                                 uint_t          ncol;
1351 
1352                                 small_un = (mr_unit32_od_t *)((uintptr_t)rbp +
1353                                     (sizeof (mddb_rb_t) - sizeof (int)));
1354                                 ncol = small_un->un_totalcolumncnt;
1355                                 newreqsize = sizeof (mr_unit_t) +
1356                                     ((ncol - 1) * sizeof (mr_column_t));
1357                                 big_un = (void *)Zalloc(newreqsize);
1358                                 raid_convert((caddr_t)small_un,
1359                                     (caddr_t)big_un, SMALL_2_BIG);
1360                                 mdrec->record = (void *)big_un;
1361                         } else {
1362                                 mr_unit_t       *big_un;
1363                                 uint_t          ncol;
1364 
1365                                 big_un = (mr_unit_t *)((uintptr_t)rbp +
1366                                     (sizeof (mddb_rb_t) - sizeof (int)));
1367                                 ncol = big_un->un_totalcolumncnt;
1368                                 newreqsize = sizeof (mr_unit_t) +
1369                                     ((ncol - 1) * sizeof (mr_column_t));
1370                                 mdrec->record = (void *)Zalloc(newreqsize);
1371                                 bcopy(big_un, mdrec->record, newreqsize);
1372                         }
1373                         uc = ((mr_unit_t *)mdrec->record)->c;
1374                         mdrec->dfunc = &process_raid;
1375                         mdrec->un_self_id = uc.un_self_id;
1376                         mdrec->has_parent = MD_HAS_PARENT(
1377                             uc.un_parent);
1378                         break;
1379                 case MDDB_F_TRANS_MASTER:
1380                         if (is_32bit_record) {
1381                                 mt_unit32_od_t  *small_un;
1382                                 mt_unit_t       *big_un;
1383 
1384                                 small_un = (mt_unit32_od_t *)((uintptr_t)rbp +
1385                                     (sizeof (mddb_rb_t) - sizeof (int)));
1386                                 newreqsize = sizeof (mt_unit_t);
1387                                 big_un = (void *)Zalloc(newreqsize);
1388                                 trans_master_convert((caddr_t)small_un,
1389                                     (caddr_t)big_un, SMALL_2_BIG);
1390                                 mdrec->record = (void *)big_un;
1391                         } else {
1392                                 mt_unit_t       *big_un;
1393 
1394                                 big_un = (mt_unit_t *)((uintptr_t)rbp +
1395                                     (sizeof (mddb_rb_t) - sizeof (int)));
1396                                 newreqsize = sizeof (mt_unit_t);
1397                                 mdrec->record = (void *)Zalloc(newreqsize);
1398                                 bcopy(big_un, mdrec->record, newreqsize);
1399                         }
1400                         uc = ((mt_unit_t *)mdrec->record)->c;
1401                         mdrec->dfunc = &process_trans;
1402                         mdrec->un_self_id = uc.un_self_id;
1403                         mdrec->has_parent = MD_HAS_PARENT(
1404                             uc.un_parent);
1405                         break;
1406                 case MDDB_F_HOTSPARE:
1407                         if (is_32bit_record) {
1408                                 hot_spare32_od_t        *small_un;
1409                                 hot_spare_t             *big_un;
1410 
1411                                 small_un = (hot_spare32_od_t *)((uintptr_t)rbp +
1412                                     (sizeof (mddb_rb_t) - sizeof (int)));
1413                                 newreqsize = sizeof (hot_spare_t);
1414                                 big_un = (void *)Zalloc(newreqsize);
1415                                 hs_convert((caddr_t)small_un,
1416                                     (caddr_t)big_un, SMALL_2_BIG);
1417                                 mdrec->record = (void *)big_un;
1418                         } else {
1419                                 hot_spare_t             *big_un;
1420 
1421                                 big_un = (hot_spare_t *)((uintptr_t)rbp +
1422                                     (sizeof (mddb_rb_t) - sizeof (int)));
1423                                 newreqsize = sizeof (hot_spare_t);
1424                                 mdrec->record = (void *)Zalloc(newreqsize);
1425                                 bcopy(big_un, mdrec->record, newreqsize);
1426                         }
1427                         hs = (hot_spare_t *)mdrec->record;
1428                         mdrec->dfunc = &process_hotspare;
1429                         mdrec->un_self_id = NULL;
1430                         mdrec->hs_record_id = hs->hs_record_id;
1431                         mdrec->has_parent = 1;
1432                         break;
1433                 case MDDB_F_HOTSPARE_POOL:
1434                         /*
1435                          * Ondisk and incore records are always same size.
1436                          */
1437                         hsp = (hot_spare_pool_ond_t *)((uintptr_t)rbp +
1438                             (sizeof (mddb_rb_t) - sizeof (int)));
1439                         newreqsize = sizeof (hot_spare_pool_ond_t) +
1440                             (sizeof (mddb_recid_t) * hsp->hsp_nhotspares);
1441                         mdrec->record = (void *)Zalloc(newreqsize);
1442                         bcopy(hsp, mdrec->record, newreqsize);
1443                         hsp = (hot_spare_pool_ond_t *)mdrec->record;
1444                         mdrec->dfunc = &process_hotspare_pool;
1445                         /*
1446                          * If the hsp has descriptive name we'll get
1447                          * the un_self_id
1448                          */
1449                         if (HSP_ID_IS_FN(hsp->hsp_self_id))
1450                                 mdrec->un_self_id = hsp->hsp_self_id;
1451                         else
1452                                 mdrec->un_self_id = NULL;
1453                         mdrec->has_parent = 0;
1454                         break;
1455                 /* All valid cases have been dealt with */
1456                 default:
1457                         (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL);
1458                         return (-1);
1459         }
1460 
1461         /*
1462          * If metadevice record has an entry in the NM namespace
1463          * then it is copied into the mdrec->n_name field.
1464          */
1465         if (mdrec->un_self_id != NULL) {
1466                 for (nmname = &nm_record->r_name[0]; nmname->n_key != 0;
1467                 /*LINTED*/
1468                     nmname = (struct nm_name *)((char *)nmname +
1469                     NAMSIZ(nmname))) {
1470                         /*
1471                          * Extract the metadevice/hsp name if it is
1472                          * in the namespace.
1473                          *
1474                          * If it is a hot spare pool we will find our
1475                          * match by comparing the NM record's n_key
1476                          * with the extracted key from the hsp_self_id
1477                          * Else, match the un_self_id for the record
1478                          * to the n_minor name in the NM record.
1479                          */
1480                             if (mdrec->md_type == MDDB_F_HOTSPARE_POOL) {
1481                                 if (nmname->n_key ==
1482                                     HSP_ID_TO_KEY(hsp->hsp_self_id)) {
1483                                         mdrec->n_key = nmname->n_key;
1484                                         uname = Strdup(nmname->n_name);
1485                                         mdrec->n_name = uname;
1486                                         break;
1487                                 }
1488                             } else {
1489                                 if ((nmname->n_minor) == (uc.un_self_id)) {
1490                                         (*mdrec).n_key = nmname->n_key;
1491                                         uname = Strdup(nmname->n_name);
1492                                         mdrec->n_name = uname;
1493                                         break;
1494                                 }
1495                             }
1496                 }
1497         }
1498 
1499         /*
1500          * If the metadevice name is not in the namespace, then
1501          * then we will generate the name from the minor number
1502          * for the metadevice.  In the case of records for a hotspare
1503          * pool we use hsp_self_id, otherwise we use un_self_id.
1504          */
1505         if (uname == NULL) {
1506                 if (mdrec->md_type == MDDB_F_HOTSPARE_POOL) {
1507                         uname = Malloc(MAXSIZEMDRECNAME);
1508                         (void) sprintf(uname, "hsp%03u",
1509                             HSP_ID(hsp->hsp_self_id));
1510                         mdrec->n_name = uname;
1511                 } else if (mdrec->md_type != MDDB_F_HOTSPARE) {
1512                         /*
1513                          * Generate the metadevice name for all other records
1514                          * (except for hotspares, because hotspares can only
1515                          * be physical devices.)
1516                          */
1517                         uname = Malloc(MAXSIZEMDRECNAME);
1518                         (void) sprintf(uname, "d%lu",
1519                             MD_MIN2UNIT(mdrec->un_self_id));
1520                         mdrec->n_name = uname;
1521                 }
1522         }
1523 
1524         return (0);
1525 }
1526 
1527 
1528 /*
1529  * read_mdrecord()
1530  *
1531  * Reads the mddb_rb32_od_t or mddb_rb_t and the associated metadevice record
1532  * from the disk.  Runs magic, checksum, and revision checks on the record
1533  * block.
1534  *
1535  * Returns:
1536  *      < 0 for failure
1537  *        0 for success
1538  *
1539  */
1540 static int
1541 read_mdrecord(
1542         md_im_rec_t     **mdimpp,
1543         mddb_mb_t       *mbp,
1544         mddb_rb_t       *nm,
1545         mddb_de_t       *dep,
1546         char            *diskname,
1547         int             fd,
1548         md_timeval32_t  *lastaccess,
1549         md_error_t      *ep
1550 )
1551 {
1552         int             cnt, rval = 0;
1553         daddr_t         pblk;
1554         md_im_rec_t     *tmp_mdrec;
1555         void            *rbp = NULL;
1556         char            *rbp_tmp = NULL;
1557         mddb_rb32_t     *rbp_32;
1558         mddb_rb_t       *rbp_64;
1559         crc_skip_t      *skip = NULL;
1560         int             is_32bit_record;
1561 
1562         tmp_mdrec = Zalloc(sizeof (md_im_rec_t));
1563         rbp = (void *)Zalloc(dbtob(dep->de_blkcount));
1564         rbp_tmp = (char *)rbp;
1565 
1566         /* Read in the appropriate record and return configurations */
1567         for (cnt = 0; cnt < dep->de_blkcount; cnt++) {
1568                 if ((pblk = getphysblk(dep->de_blks[cnt], mbp)) < 0) {
1569                         rval = mdmddberror(ep, MDE_DB_BLKRANGE,
1570                             NODEV32, MD_LOCAL_SET,
1571                             dep->de_blks[cnt], diskname);
1572                         return (rval);
1573                 }
1574 
1575                 if (lseek(fd, (off_t)dbtob(pblk), SEEK_SET) < 0) {
1576                         rval = mdsyserror(ep, errno, diskname);
1577                         return (rval);
1578                 }
1579 
1580                 if (read(fd, rbp_tmp, DEV_BSIZE) != DEV_BSIZE) {
1581                         rval = mdsyserror(ep, errno, diskname);
1582                         return (rval);
1583                 }
1584 
1585                 rbp_tmp += DEV_BSIZE;
1586         }
1587         tmp_mdrec->md_type = dep->de_flags;
1588 
1589         /*
1590          * The only place to discover whether or not the record is a
1591          * 32bit or 64bit record is from the record's rb_revision field.
1592          * The mddb_rb_t and mddb_rb32_t structures are identical for the
1593          * following fields:
1594          *      rb_magic, rb_revision, rb_checksum, and rb_checksum_fiddle.
1595          * So we can assume that the record is a 32bit structure when we
1596          * check the record's magic number and revision and when we calculate
1597          * the records checksum.
1598          */
1599         rbp_32 = (mddb_rb32_t *)rbp;
1600 
1601         /*
1602          * Checking the magic number for the record block.
1603          */
1604         if (rbp_32->rb_magic != MDDB_MAGIC_RB) {
1605                 rval = -1;
1606                 (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL);
1607                 goto out;
1608         }
1609 
1610         /*
1611          * Checking the revision for the record block. Must match either
1612          * revision for the current 64bit or 32bit record block.  Also,
1613          * setting the flag for whether or not it is a 32bit record.
1614          */
1615         is_32bit_record = 0;
1616         switch (rbp_32->rb_revision) {
1617         case MDDB_REV_RB:
1618         case MDDB_REV_RBFN:
1619                 is_32bit_record = 1;
1620                 break;
1621         case MDDB_REV_RB64:
1622         case MDDB_REV_RB64FN:
1623                 break;
1624         default:
1625                 rval = -1;
1626                 (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL);
1627                 goto out;
1628         }
1629 
1630         /*
1631          * Calculating the checksum for this record block. Need
1632          * to skip the rb's checksum fiddle.
1633          */
1634         skip = (crc_skip_t *)Malloc(sizeof (crc_skip_t));
1635         skip->skip_next = NULL;
1636         skip->skip_offset = offsetof(mddb_rb_t, rb_checksum_fiddle);
1637         skip->skip_size = 3 * sizeof (uint_t);
1638         if (crcchk(rbp_32, &rbp_32->rb_checksum, dep->de_recsize, skip)) {
1639                 rval = -1;
1640                 (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL);
1641                 goto out;
1642         }
1643 
1644         /* mddb_rb_t and mddb_rb32_t differ before the rb_timestamp field */
1645         if (!is_32bit_record) {
1646                 if ((*lastaccess).tv_sec < rbp_32->rb_timestamp.tv_sec) {
1647                     *lastaccess = rbp_32->rb_timestamp;
1648                 } else if ((*lastaccess).tv_sec ==
1649                     rbp_32->rb_timestamp.tv_sec) {
1650                         if ((*lastaccess).tv_usec <
1651                             rbp_32->rb_timestamp.tv_usec)
1652                                 *lastaccess = rbp_32->rb_timestamp;
1653                 }
1654         } else {
1655                 rbp_64 = (mddb_rb_t *)rbp;
1656                 if ((*lastaccess).tv_sec < rbp_64->rb_timestamp.tv_sec) {
1657                     *lastaccess = rbp_64->rb_timestamp;
1658                 } else if ((*lastaccess).tv_sec ==
1659                     rbp_64->rb_timestamp.tv_sec) {
1660                         if ((*lastaccess).tv_usec <
1661                             rbp_64->rb_timestamp.tv_usec)
1662                                 *lastaccess = rbp_64->rb_timestamp;
1663                 }
1664         }
1665 
1666         /* Populates the fields in md_im_rec_t *tmp_mdrec. */
1667         rval = extract_mduser_data(nm, tmp_mdrec, rbp, is_32bit_record, ep);
1668         if (rval < 0)
1669                 goto out;
1670 
1671         /* Adding record to the head of the list of all metadevices. */
1672         tmp_mdrec->prev = NULL;
1673         if (*mdimpp == NULL) {
1674                 tmp_mdrec->next = NULL;
1675                 *mdimpp = tmp_mdrec;
1676         } else {
1677                 (*mdimpp)->prev = tmp_mdrec;
1678                 tmp_mdrec->next = *mdimpp;
1679                 *mdimpp = tmp_mdrec;
1680         }
1681 
1682 out:
1683         /* Free the skip list */
1684         while (skip) {
1685                 crc_skip_t      *skip_rm = skip;
1686 
1687                 skip = skip->skip_next;
1688                 Free(skip_rm);
1689         }
1690 
1691         if (rbp)
1692                 Free(rbp);
1693 
1694         return (rval);
1695 }
1696 
1697 
1698 /*
1699  * read_all_mdrecords()
1700  *
1701  * Reads the directory block and directory entries.
1702  * Runs magic, checksum, and revision checks on the directory block.
1703  *
1704  * Returns:
1705  *      < 0 for failure
1706  *        0 for success
1707  */
1708 static int
1709 read_all_mdrecords(
1710         md_im_rec_t     **mdimpp,
1711         mddb_mb_t       *mbp,
1712         mddb_lb_t       *lbp,
1713         mddb_rb_t       *nm,
1714         mdname_t        *rsp,
1715         int             fd,
1716         md_timeval32_t  *lastaccess,
1717         md_error_t      *ep
1718 )
1719 {
1720         int             dbblk, rval = 0;
1721         char            db[DEV_BSIZE];
1722         mddb_de_t       *dep;
1723         int             desize;
1724         /*LINTED*/
1725         mddb_db_t       *dbp = (mddb_db_t *)&db;
1726 
1727         /* Read in all directory blocks */
1728         for (dbblk = lbp->lb_dbfirstblk;
1729             dbblk != 0;
1730             dbblk = dbp->db_nextblk) {
1731 
1732                 if ((rval = read_database_block(ep, fd, mbp, dbblk,
1733                     dbp, sizeof (db))) <= 0)
1734                         goto out;
1735 
1736                 /*
1737                  * Set ep with error code for MDE_DB_NODB.  This is the
1738                  * error code used in the kernel when there is a problem
1739                  * with reading records in.  Checks the magic number, the
1740                  * revision, and the checksum for each directory block.
1741                  */
1742                 if (dbp->db_magic != MDDB_MAGIC_DB) {
1743                         rval = -1;
1744                         (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL);
1745                         goto out;
1746                 }
1747 
1748                 if (revchk(MDDB_REV_DB, dbp->db_revision)) {
1749                         rval = -1;
1750                         (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL);
1751                         goto out;
1752                 }
1753 
1754                 if (crcchk(dbp, &dbp->db_checksum, MDDB_BSIZE, NULL)) {
1755                         rval = -1;
1756                         (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL);
1757                         goto out;
1758                 }
1759 
1760                 /*
1761                  * If db timestamp is more recent than the previously recorded
1762                  * last modified timestamp, then update last modified.
1763                  */
1764                 if ((*lastaccess).tv_sec < dbp->db_timestamp.tv_sec) {
1765                         *lastaccess = dbp->db_timestamp;
1766                 } else if ((*lastaccess).tv_sec == dbp->db_timestamp.tv_sec) {
1767                         if ((*lastaccess).tv_usec < dbp->db_timestamp.tv_usec)
1768                                 *lastaccess = dbp->db_timestamp;
1769                 }
1770 
1771                 /* Creates dep list of all directory entries in the db */
1772                 if (dbp->db_firstentry != NULL) {
1773                         /* LINTED */
1774                         dep = (mddb_de_t *)((caddr_t)(&dbp->db_firstentry)
1775                             + sizeof (dbp->db_firstentry));
1776                         dbp->db_firstentry = dep;
1777                         while (dep && dep->de_next) {
1778                                 desize = sizeof (*dep) -
1779                                     sizeof (dep->de_blks) +
1780                                     sizeof (daddr_t) * dep->de_blkcount;
1781                                 /* LINTED */
1782                                 dep->de_next = (mddb_de_t *)
1783                                     ((caddr_t)dep + desize);
1784                                 dep = dep->de_next;
1785                         }
1786                 }
1787 
1788                 /*
1789                  * Process all directory entries in the directory block.
1790                  * For each directory entry, read_mdrec is called to read
1791                  * in the record data.
1792                  */
1793                 for (dep = dbp->db_firstentry; dep != NULL;
1794                     dep = dep->de_next) {
1795 
1796                         /*
1797                          * de_flags is set to the type of metadevice.
1798                          * If directory entry does not correspond to a
1799                          * specific metadevice then it is set to zero.
1800                          * All namespace records(NM, SHR_NM, DID_SHR_NM) have a
1801                          * value of zero in their de_flags field.
1802                          */
1803                         if ((dep->de_flags != 0)&&
1804                             (dep->de_flags != MDDB_F_OPT) &&
1805                             (dep->de_flags != MDDB_F_TRANS_LOG) &&
1806                             (dep->de_flags != MDDB_F_CHANGELOG)) {
1807                                 rval = read_mdrecord(mdimpp, mbp, nm, dep,
1808                                     rsp->cname, fd, lastaccess, ep);
1809                                 if (rval < 0)
1810                                         goto out;
1811                         }
1812                 }
1813         }
1814 
1815 out:
1816         return (rval);
1817 }
1818 
1819 
1820 /*
1821  * report_metastat_info()
1822  *
1823  * Generates the metastat -c output.  Also, updates the global variable
1824  * for a last accessed timestamp.
1825  *
1826  * Returns:
1827  *      < 0 for failure
1828  *        0 for success
1829  *
1830  */
1831 int
1832 report_metastat_info(
1833         mddb_mb_t               *mb,
1834         mddb_lb_t               *lbp,
1835         mddb_rb_t               *nm,
1836         pnm_rec_t               **pnm,
1837         mdname_t                *rsp,
1838         int                     fd,
1839         md_timeval32_t          *lastaccess,
1840         md_error_t              *ep
1841 )
1842 {
1843         int rval = 0;
1844         /* list of all metadevices in diskset */
1845         md_im_rec_t     *mdimp = NULL;
1846         md_im_rec_t     *tmp_mdrec, *rm_mdrec;
1847 
1848         /* Read in metadevice records and add entries to mdimp list. */
1849         rval = read_all_mdrecords(&mdimp, mb, lbp, nm, rsp, fd, lastaccess,
1850             ep);
1851         if (rval < 0)
1852                 goto out;
1853 
1854         /* Adding a fake record to the head of the list of all metadevices. */
1855         if (mdimp != NULL) {
1856                 tmp_mdrec = Zalloc(sizeof (md_im_rec_t));
1857                 tmp_mdrec->prev = NULL;
1858                 mdimp->prev = tmp_mdrec;
1859                 tmp_mdrec->next = mdimp;
1860                 mdimp = tmp_mdrec;
1861         }
1862 
1863         /* Calling functions to process all metadevices on mdimp list */
1864         process_toplevel_devices(&mdimp, *pnm, MDDB_F_SOFTPART);
1865         process_toplevel_devices(&mdimp, *pnm, MDDB_F_TRANS_MASTER);
1866         process_toplevel_devices(&mdimp, *pnm, MDDB_F_MIRROR);
1867         process_toplevel_devices(&mdimp, *pnm, MDDB_F_RAID);
1868         process_toplevel_devices(&mdimp, *pnm, MDDB_F_STRIPE);
1869         process_toplevel_devices(&mdimp, *pnm, MDDB_F_HOTSPARE_POOL);
1870         (void) printf("\n");
1871 
1872 out:
1873         /*
1874          * If mdreclist is not null, then this will walk through all
1875          * elements and free them.
1876          */
1877         tmp_mdrec = mdimp;
1878         while (tmp_mdrec != NULL) {
1879                 rm_mdrec = tmp_mdrec;
1880                 tmp_mdrec = tmp_mdrec->next;
1881                 if (rm_mdrec->record != NULL)
1882                         Free(rm_mdrec->record);
1883                 if (rm_mdrec->n_name != NULL)
1884                         Free(rm_mdrec->n_name);
1885                 Free(rm_mdrec);
1886         }
1887 
1888         free_pnm_rec_list(pnm);
1889         return (rval);
1890 }