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