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