1734Smw145384 /* 2734Smw145384 * CDDL HEADER START 3734Smw145384 * 4734Smw145384 * The contents of this file are subject to the terms of the 5*1623Stw21770 * Common Development and Distribution License (the "License"). 6*1623Stw21770 * You may not use this file except in compliance with the License. 7734Smw145384 * 8734Smw145384 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9734Smw145384 * or http://www.opensolaris.org/os/licensing. 10734Smw145384 * See the License for the specific language governing permissions 11734Smw145384 * and limitations under the License. 12734Smw145384 * 13734Smw145384 * When distributing Covered Code, include this CDDL HEADER in each 14734Smw145384 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15734Smw145384 * If applicable, add the following below this CDDL HEADER, with the 16734Smw145384 * fields enclosed by brackets "[]" replaced with your own identifying 17734Smw145384 * information: Portions Copyright [yyyy] [name of copyright owner] 18734Smw145384 * 19734Smw145384 * CDDL HEADER END 20734Smw145384 */ 21734Smw145384 /* 22*1623Stw21770 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23734Smw145384 * Use is subject to license terms. 24734Smw145384 */ 25734Smw145384 26734Smw145384 #pragma ident "%Z%%M% %I% %E% SMI" 27734Smw145384 28734Smw145384 #include <meta.h> 29734Smw145384 #include <assert.h> 30734Smw145384 #include <ctype.h> 31734Smw145384 #include <mdiox.h> 32734Smw145384 #include <meta.h> 33734Smw145384 #include <stdio.h> 34734Smw145384 #include <stdlib.h> 35734Smw145384 #include <strings.h> 36734Smw145384 #include <sys/lvm/md_mddb.h> 37734Smw145384 #include <sys/lvm/md_names.h> 38734Smw145384 #include <sys/lvm/md_crc.h> 39734Smw145384 #include <sys/lvm/md_convert.h> 40734Smw145384 41734Smw145384 42734Smw145384 /* 43734Smw145384 * Design Notes: 44734Smw145384 * 45734Smw145384 * All of the code in this file supports the addition of metastat -c output 46734Smw145384 * for the verbose option of metaimport. Some of this code is also used by 47734Smw145384 * the command metastat for concise output(cmd/lvm/util/metastat.c). 48734Smw145384 * The code is designed to produce the same output as metastat -c does for a 49734Smw145384 * given diskset--with a couple exceptions. 50734Smw145384 * The primary differences between the output for the metastat -c command and 51734Smw145384 * metastat output for metaimport -v are: 52734Smw145384 * - the set name is not printed next to each metadevice 53734Smw145384 * - top-level state information is not printed for some metadevices 54734Smw145384 * - the percent that a disk has completed resyncing is not listed 55734Smw145384 * in metaimport -v. 56734Smw145384 * 57734Smw145384 * 58734Smw145384 * The general layout of this file is as follows: 59734Smw145384 * 60734Smw145384 * - report_metastat_info() 61734Smw145384 * This is the primary entry point for the functions in this file, with 62734Smw145384 * the exception of several functions that are also called from 63734Smw145384 * cmd/io/lvm/util/metastat.c 64734Smw145384 * report_metastat_info() calls functions to read in all the the 65734Smw145384 * Directory blocks and Record blocks and then process the information 66734Smw145384 * needed to print out the metadevice records in the same format as 67734Smw145384 * metastat -c. 68734Smw145384 * 69734Smw145384 * - read_all_mdrecords() 70734Smw145384 * Reads in all the Directory blocks in the diskset and verifies their 71734Smw145384 * validity. For each Directly block, it loops through all Directory 72734Smw145384 * Entries and for each one that contains a metadevice record calls 73734Smw145384 * read_md_record(). Because the output is designed to imitate the 74734Smw145384 * output of metastat -c, we ignore metadevice records for 75734Smw145384 * optimized resync, changelog, and translog. 76734Smw145384 * 77734Smw145384 * - read_md_record() 78734Smw145384 * Reads in a Directory Entry and its associated Record block. The 79734Smw145384 * revision information for the Record block is checked and it is 80734Smw145384 * determined whether or not it is a 64bit Record block or a 32bit record 81734Smw145384 * block. For each valid Record block, it allocates an md_im_rec_t 82734Smw145384 * structure and calls extract_mduser_data(). 83734Smw145384 * 84734Smw145384 * - extract_mduser_data() 85734Smw145384 * Populates the md_im_rec_t data structure with information about the 86734Smw145384 * record's associated metadevice. Also, the name of the metadevice is 87734Smw145384 * either copied from the NM namespace(if it exists there) or is generated 88734Smw145384 * from the record's un_self_id. 89734Smw145384 * 90734Smw145384 * - process_toplevel_devices() 91734Smw145384 * For a given metadevice type, searchs through the md_im_rec_t **mdimpp, 92734Smw145384 * list of all metadevices in the set, to find all records of the 93734Smw145384 * specified type that do not have a parent and puts them on a temp list. 94734Smw145384 * The temp list is then iterated through and the associated processing 95734Smw145384 * function is called. 96734Smw145384 * 97734Smw145384 * - process_(trans, hotspare, hotspare_pool, soft_part, mirror, stripe, raid) 98734Smw145384 * These functions are called by using the dfunc field in the mdimpp list. 99734Smw145384 * Each process function only understands its own type of metadevice. Once 100734Smw145384 * it processes the metadevice it was called for, it then loops through 101734Smw145384 * all of the underlying metadevices. After printing the name of the 102734Smw145384 * underlying metadevice, it puts in on a list to be processed. If the 103734Smw145384 * underlying device is a physical device, then print_physical_device is 104734Smw145384 * called. 105734Smw145384 * Once all information about the original metadevice is processed, it 106734Smw145384 * loops through the list of underlying metadevices and calls the 107734Smw145384 * appropriate function to process them. 108734Smw145384 * 109734Smw145384 * - process_toplevel_softparts() 110734Smw145384 * To match the output for metastat -c, all top-level softpartions 111734Smw145384 * are printed out in groups based on their underlying metadevice--so that 112734Smw145384 * the underlying metadevice only needs to be processed once. 113734Smw145384 * 114734Smw145384 * - meta_get_(sm_state, raid_col_state, stripe_state, hs_state) 115734Smw145384 * These functions are used to retrieve the metadevice state information. 116734Smw145384 * They are also used by the metastat concise routines in 117734Smw145384 * cmd/lvm/util/metastat.c. 118734Smw145384 * 119734Smw145384 */ 120734Smw145384 121734Smw145384 122734Smw145384 /* 123734Smw145384 * md_im_rec is a doubly linked list used to store the rb_data for each 124734Smw145384 * directory entry that corresponds to a metadevice. 125734Smw145384 * n_key: is set, if there is an associated entry in the NM namespace. 126734Smw145384 * dfunc: is set to point to the function that processes the particular 127734Smw145384 * metadevice associated with the record. 128734Smw145384 * hs_record_id: is only set, if the metadevice is a hotspare. 129734Smw145384 * un_self_id: is set for all other records. This is also used to generate 130734Smw145384 * the name of the metadevice if there is no entry for the metadevice in 131734Smw145384 * the NM namespace--n_key is not set. 132734Smw145384 */ 133734Smw145384 typedef struct md_im_rec { 134734Smw145384 mdkey_t n_key; /* NM namespace key */ 135734Smw145384 struct md_im_rec *next; 136734Smw145384 struct md_im_rec *prev; 137734Smw145384 uint_t md_type; 138734Smw145384 uint_t has_parent; /* either 0(no parent) or 1 */ 139734Smw145384 minor_t un_self_id; 140734Smw145384 mddb_recid_t hs_record_id; /* hotspare recid */ 141734Smw145384 char *n_name; /* name of metadevice */ 142734Smw145384 void (*dfunc) (); 143734Smw145384 ushort_t record_len; 144734Smw145384 /* pointer to the unit structure for the metadevice, e.g. rb_data[0] */ 145734Smw145384 void *record; 146734Smw145384 } md_im_rec_t; 147734Smw145384 148734Smw145384 /* 149734Smw145384 * md_im_list is used to group toplevel metadevices by type and to group 150734Smw145384 * the underlying devices for a particular metadevice. 151734Smw145384 */ 152734Smw145384 typedef struct md_im_list { 153734Smw145384 struct md_im_list *next; 154734Smw145384 struct md_im_rec *mdrec; 155734Smw145384 } md_im_list_t; 156734Smw145384 157734Smw145384 158734Smw145384 /* 159734Smw145384 * MAXSIZEMDRECNAME is the value that has historically been used to allocate 160734Smw145384 * space for the metadevice name 161734Smw145384 */ 162734Smw145384 #define MAXSIZEMDRECNAME 20 163734Smw145384 #define NAMEWIDTH 16 164734Smw145384 #define offsetof(s, m) ((size_t)(&(((s *)0)->m))) 165734Smw145384 #define NOT_PHYSICAL_DEV 0 166734Smw145384 #define PHYSICAL_DEV 1 167734Smw145384 168734Smw145384 169734Smw145384 /* 170734Smw145384 * strip_blacks() 171734Smw145384 * 172734Smw145384 * Strip blanks from string. Used for size field in concise output. 173734Smw145384 */ 174734Smw145384 static char * 175734Smw145384 strip_blanks(char *s) 176734Smw145384 { 177734Smw145384 char *p; 178734Smw145384 179734Smw145384 for (p = s; *p; ) { 180734Smw145384 if (*p == ' ') { 181734Smw145384 char *t; 182734Smw145384 for (t = p; *t; t++) { 183734Smw145384 *t = *(t + 1); 184734Smw145384 } 185734Smw145384 } else { 186734Smw145384 p++; 187734Smw145384 } 188734Smw145384 } 189734Smw145384 190734Smw145384 return (s); 191734Smw145384 } 192734Smw145384 193734Smw145384 194734Smw145384 /* 195734Smw145384 * print_concise_entry() 196734Smw145384 * 197734Smw145384 * Print properly indented metadevice name, type and size for concise output. 198734Smw145384 * This function is also called from: cmd/lvm/util/metastat.c. 199734Smw145384 */ 200734Smw145384 void 201734Smw145384 print_concise_entry(int indent, char *name, diskaddr_t size, char mtype) 202734Smw145384 { 203734Smw145384 int i; 204734Smw145384 int width = NAMEWIDTH; /* minumum field width for name */ 205734Smw145384 char in[MAXPATHLEN]; 206734Smw145384 char *sz; 207734Smw145384 208734Smw145384 in[0] = 0; 209734Smw145384 for (i = 0; i < indent; i++) 210734Smw145384 (void) strlcat(in, " ", sizeof (in)); 211734Smw145384 212734Smw145384 /* set up minimum field width. negative for left justified */ 213734Smw145384 width -= indent; 214734Smw145384 if (width < 0) 215734Smw145384 width = 0; /* overflowed; no minimum field needed */ 216734Smw145384 else 217734Smw145384 width = 0 - width; /* negative for left justification */ 218734Smw145384 219734Smw145384 if (size == 0) { 220734Smw145384 sz = "-"; 221734Smw145384 } else { 222734Smw145384 sz = strip_blanks(meta_number_to_string(size, DEV_BSIZE)); 223734Smw145384 } 224734Smw145384 225734Smw145384 (void) printf("%s%*s %c %6s", in, width, name, mtype, sz); 226734Smw145384 } 227734Smw145384 228734Smw145384 229734Smw145384 /* 230734Smw145384 * free_mdrec_list_entry() 231734Smw145384 * 232734Smw145384 * Removing entry from the list of metadevices in the diskset(mdimpp). 233734Smw145384 * This function will not remove the dummy entry at the head of the 234734Smw145384 * list, so we don't have to set mdrec equal to NULL. 235734Smw145384 */ 236734Smw145384 static void 237734Smw145384 free_mdrec_list_entry(md_im_rec_t **mdrec) 238734Smw145384 { 239734Smw145384 (*mdrec)->prev->next = (*mdrec)->next; 240734Smw145384 if ((*mdrec)->next != NULL) { 241734Smw145384 (*mdrec)->next->prev = (*mdrec)->prev; 242734Smw145384 } 243734Smw145384 Free((*mdrec)->record); 244734Smw145384 Free((*mdrec)->n_name); 245734Smw145384 Free(*mdrec); 246734Smw145384 } 247734Smw145384 248734Smw145384 249734Smw145384 /* 250734Smw145384 * ucomponent_append() 251734Smw145384 * 252734Smw145384 * Appending entry to the underlying component list. The list 253734Smw145384 * is used to group all of the underlying devices before 254734Smw145384 * processing them. 255734Smw145384 */ 256734Smw145384 static void 257734Smw145384 ucomponent_append( 258734Smw145384 md_im_list_t **ucomp_head, 259734Smw145384 md_im_list_t **ucomp_tail, 260734Smw145384 md_im_list_t *ucomp 261734Smw145384 ) 262734Smw145384 { 263734Smw145384 ucomp->next = NULL; 264734Smw145384 if (*ucomp_head == NULL) { 265734Smw145384 *ucomp_head = ucomp; 266734Smw145384 *ucomp_tail = ucomp; 267734Smw145384 } else { 268734Smw145384 (*ucomp_tail)->next = ucomp; 269734Smw145384 *ucomp_tail = (*ucomp_tail)->next; 270734Smw145384 } 271734Smw145384 } 272734Smw145384 273734Smw145384 274734Smw145384 /* 275734Smw145384 * free_md_im_list_entries() 276734Smw145384 * 277734Smw145384 * Freeing entries on an md_im_list_t. This list is used to group 278734Smw145384 * underlying components for processing and to group top-level metadevices 279734Smw145384 * by type. 280734Smw145384 */ 281734Smw145384 static void 282734Smw145384 free_md_im_list_entries(md_im_list_t **list_head) 283734Smw145384 { 284734Smw145384 md_im_list_t *tmp_list_entry = *list_head; 285734Smw145384 md_im_list_t *rm_list_entry; 286734Smw145384 287734Smw145384 while (tmp_list_entry != NULL) { 288734Smw145384 rm_list_entry = tmp_list_entry; 289734Smw145384 tmp_list_entry = tmp_list_entry->next; 290734Smw145384 Free(rm_list_entry); 291734Smw145384 } 292734Smw145384 } 293734Smw145384 294734Smw145384 295734Smw145384 /* 296734Smw145384 * print_physical_device() 297734Smw145384 * 298734Smw145384 * If a metadevice has an underlying component that is a physical 299734Smw145384 * device, then this searches the pnm_rec_t list to match an entry's 300734Smw145384 * n_key to the key for the underlying component. The ctd name of the 301734Smw145384 * physical device is printed on the same line as the metadevice. 302734Smw145384 */ 303734Smw145384 static void 304734Smw145384 print_physical_device( 305734Smw145384 pnm_rec_t *phys_nm, 306734Smw145384 mdkey_t key 307734Smw145384 ) 308734Smw145384 { 309734Smw145384 pnm_rec_t *tmpphys_nm; 310734Smw145384 311734Smw145384 for (tmpphys_nm = phys_nm; tmpphys_nm != NULL; 312734Smw145384 tmpphys_nm = tmpphys_nm->next) { 313734Smw145384 if (tmpphys_nm->n_key == key) { 314734Smw145384 (void) printf(" %s", tmpphys_nm->n_name); 315734Smw145384 break; 316734Smw145384 } 317734Smw145384 } 318734Smw145384 } 319734Smw145384 320734Smw145384 321734Smw145384 /* 322734Smw145384 * get_stripe_req_size() 323734Smw145384 * 324734Smw145384 * Given a 64bit stripe unit, compute the size of the stripe unit. 325734Smw145384 * This function is a derivation of: 326734Smw145384 * common/lvm/md_convert.c:get_big_stripe_req_size() 327734Smw145384 * and any changes made to either this function or get_big_stripe_req_size() 328734Smw145384 * should be reviewed to make sure the functionality in both places is correct. 329734Smw145384 * 330734Smw145384 * Returns: 331734Smw145384 * total size of the 64bit stripe 332734Smw145384 */ 333734Smw145384 size_t 334734Smw145384 get_stripe_req_size(ms_unit_t *un) 335734Smw145384 { 336734Smw145384 struct ms_row *mdr; 337734Smw145384 uint_t row; 338734Smw145384 uint_t ncomps = 0; 339734Smw145384 size_t mdsize = 0; 340734Smw145384 size_t first_comp = 0; 341734Smw145384 342734Smw145384 343734Smw145384 /* Compute the offset of the first component */ 344734Smw145384 first_comp = sizeof (ms_unit_t) + 345734Smw145384 sizeof (struct ms_row) * (un->un_nrows - 1); 346734Smw145384 first_comp = roundup(first_comp, sizeof (long long)); 347734Smw145384 348734Smw145384 /* 349734Smw145384 * Requestor wants to have the total size, add the sizes of 350734Smw145384 * all components 351734Smw145384 */ 352734Smw145384 mdr = &un->un_row[0]; 353734Smw145384 for (row = 0; (row < un->un_nrows); row++) 354734Smw145384 ncomps += mdr[row].un_ncomp; 355734Smw145384 mdsize = first_comp + sizeof (ms_comp_t) * ncomps; 356734Smw145384 return (mdsize); 357734Smw145384 } 358734Smw145384 359734Smw145384 360734Smw145384 /* 361734Smw145384 * meta_get_sm_state() 362734Smw145384 * 363734Smw145384 * Gets the state for the underlying components(submirrors) of a mirror. 364734Smw145384 * This function is also called from: cmd/lvm/util/metastat.c. 365734Smw145384 * 366734Smw145384 * Returns: 367734Smw145384 * string for state of the sub-mirror 368734Smw145384 */ 369734Smw145384 static char * 370734Smw145384 meta_get_sm_state( 371734Smw145384 sm_state_t state 372734Smw145384 ) 373734Smw145384 { 374734Smw145384 /* all is well */ 375734Smw145384 if (state & SMS_RUNNING) { 376734Smw145384 return (NULL); 377734Smw145384 } 378734Smw145384 379734Smw145384 /* resyncing, needs repair */ 380734Smw145384 if ((state & (SMS_COMP_RESYNC | SMS_ATTACHED_RESYNC | 381734Smw145384 SMS_OFFLINE_RESYNC))) { 382734Smw145384 return (gettext("resyncing")); 383734Smw145384 } 384734Smw145384 385734Smw145384 /* needs repair */ 386734Smw145384 if (state & (SMS_COMP_ERRED | SMS_ATTACHED | SMS_OFFLINE)) 387734Smw145384 return (gettext("maint")); 388734Smw145384 389734Smw145384 /* unknown */ 390734Smw145384 return (gettext("unknown")); 391734Smw145384 } 392734Smw145384 393734Smw145384 394734Smw145384 /* 395734Smw145384 * meta_get_raid_col_state() 396734Smw145384 * 397734Smw145384 * Gets the state for the underlying components(columns) of a raid. 398734Smw145384 * This function is also called from: cmd/lvm/util/metastat.c. 399734Smw145384 * 400734Smw145384 * Returns: 401734Smw145384 * string for state of the raid column 402734Smw145384 * 403734Smw145384 */ 404734Smw145384 char * 405734Smw145384 meta_get_raid_col_state( 406734Smw145384 rcs_state_t state 407734Smw145384 ) 408734Smw145384 { 409734Smw145384 switch (state) { 410734Smw145384 case RCS_INIT: 411734Smw145384 return (gettext("initializing")); 412734Smw145384 case RCS_OKAY: 413734Smw145384 return (NULL); 414734Smw145384 case RCS_INIT_ERRED: 415734Smw145384 /*FALLTHROUGH*/ 416734Smw145384 case RCS_ERRED: 417734Smw145384 return (gettext("maint")); 418734Smw145384 case RCS_LAST_ERRED: 419734Smw145384 return (gettext("last-erred")); 420734Smw145384 case RCS_RESYNC: 421734Smw145384 return (gettext("resyncing")); 422734Smw145384 default: 423734Smw145384 return (gettext("unknown")); 424734Smw145384 } 425734Smw145384 } 426734Smw145384 427734Smw145384 428734Smw145384 /* 429734Smw145384 * meta_get_stripe_state() 430734Smw145384 * 431734Smw145384 * Gets the state for the underlying components of a stripe. 432734Smw145384 * This function is also called from: cmd/lvm/util/metastat.c. 433734Smw145384 * 434734Smw145384 * Returns: 435734Smw145384 * string for state of the stripe 436734Smw145384 * 437734Smw145384 */ 438734Smw145384 char * 439734Smw145384 meta_get_stripe_state( 440734Smw145384 comp_state_t state 441734Smw145384 ) 442734Smw145384 { 443734Smw145384 switch (state) { 444734Smw145384 case CS_OKAY: 445734Smw145384 return (NULL); 446734Smw145384 case CS_ERRED: 447734Smw145384 return (gettext("maint")); 448734Smw145384 case CS_LAST_ERRED: 449734Smw145384 return (gettext("last-erred")); 450734Smw145384 case CS_RESYNC: 451734Smw145384 return (gettext("resyncing")); 452734Smw145384 default: 453734Smw145384 return (gettext("invalid")); 454734Smw145384 } 455734Smw145384 } 456734Smw145384 457734Smw145384 458734Smw145384 /* 459734Smw145384 * meta_get_hs_state() 460734Smw145384 * 461734Smw145384 * Gets the state for the underlying components(hotspares) of a hotspare pool. 462734Smw145384 * This function is also called from: cmd/lvm/util/metastat.c. 463734Smw145384 * 464734Smw145384 * Returns: 465734Smw145384 * string for state of the hotspare 466734Smw145384 * 467734Smw145384 */ 468734Smw145384 char * 469734Smw145384 meta_get_hs_state( 470734Smw145384 hotspare_states_t state 471734Smw145384 ) 472734Smw145384 { 473734Smw145384 switch (state) { 474734Smw145384 case HSS_AVAILABLE: 475734Smw145384 return (NULL); 476734Smw145384 case HSS_RESERVED: 477734Smw145384 return (gettext("in-use")); 478734Smw145384 case HSS_BROKEN: 479734Smw145384 return (gettext("broken")); 480734Smw145384 case HSS_UNUSED: 481734Smw145384 /* FALLTHROUGH */ 482734Smw145384 default: 483734Smw145384 return (gettext("invalid")); 484734Smw145384 } 485734Smw145384 } 486734Smw145384 487734Smw145384 488734Smw145384 /* 489734Smw145384 * process_trans() 490734Smw145384 * 491734Smw145384 * Prints unit information for a trans metadevice and calls the respective 492734Smw145384 * functions to process the underlying metadevices. 493734Smw145384 * 494734Smw145384 */ 495734Smw145384 static void 496734Smw145384 process_trans( 497734Smw145384 md_im_rec_t **mdimpp, 498734Smw145384 int indent, 499734Smw145384 pnm_rec_t *phys_nm, 500734Smw145384 md_im_rec_t *mdrec 501734Smw145384 ) 502734Smw145384 { 503734Smw145384 mt_unit_t *mt; 504734Smw145384 mdc_unit_t uc; 505734Smw145384 md_im_rec_t *tmpmdrec; 506734Smw145384 int underlying_device = PHYSICAL_DEV; 507734Smw145384 508734Smw145384 mt = (mt_unit_t *)mdrec->record; 509734Smw145384 uc = mt->c; 510734Smw145384 511734Smw145384 /* Printing name, size, and type of metadevice */ 512734Smw145384 print_concise_entry(indent, mdrec->n_name, 513734Smw145384 uc.un_total_blocks, 't'); 514734Smw145384 515734Smw145384 /* 516734Smw145384 * Loops through md_im_rec_t **mdimpp list of all metadevices to find 517734Smw145384 * record that matches the underlying device. 518734Smw145384 * Trans devices can only have one underlying device, so once a 519734Smw145384 * match is found, we are done. 520734Smw145384 */ 521734Smw145384 for (tmpmdrec = *mdimpp; tmpmdrec != NULL; 522734Smw145384 tmpmdrec = tmpmdrec->next) { 523734Smw145384 if (tmpmdrec->n_key == mt->un_m_key) { 524734Smw145384 /* Printing name of the underlying metadevice */ 525734Smw145384 (void) printf(" %s", tmpmdrec->n_name); 526734Smw145384 underlying_device = NOT_PHYSICAL_DEV; 527734Smw145384 break; 528734Smw145384 } 529734Smw145384 } 530734Smw145384 531734Smw145384 /* 532734Smw145384 * If a metadevice was not found, then the underlying device must be a 533734Smw145384 * physical device. Otherwise, call the functions to process the 534734Smw145384 * underlying devices. 535734Smw145384 */ 536734Smw145384 if (underlying_device == PHYSICAL_DEV) { 537734Smw145384 print_physical_device(phys_nm, mt->un_m_key); 538734Smw145384 (void) printf("\n"); 539734Smw145384 } else { 540734Smw145384 /* process underlying component */ 541734Smw145384 (void) printf("\n"); 542734Smw145384 indent += META_INDENT; 543734Smw145384 tmpmdrec->dfunc(mdimpp, indent, phys_nm, tmpmdrec); 544734Smw145384 } 545734Smw145384 546734Smw145384 /* 547734Smw145384 * Removing the md_entry from the list 548734Smw145384 * of all metadevices 549734Smw145384 */ 550734Smw145384 free_mdrec_list_entry(&mdrec); 551734Smw145384 } 552734Smw145384 553734Smw145384 554734Smw145384 /* 555734Smw145384 * process_hotspare() 556734Smw145384 * 557734Smw145384 * Searches though list of physical devices to match hotspare record. 558734Smw145384 * Prints physical device name and state of a hotspare unit. 559734Smw145384 * 560734Smw145384 */ 561734Smw145384 /*ARGSUSED*/ 562734Smw145384 static void 563734Smw145384 process_hotspare( 564734Smw145384 md_im_rec_t **mdimpp, 565734Smw145384 int indent, 566734Smw145384 pnm_rec_t *phys_nm, 567734Smw145384 md_im_rec_t *mdrec 568734Smw145384 ) 569734Smw145384 { 570734Smw145384 hot_spare_t *hs; 571734Smw145384 pnm_rec_t *tmpphys_nm; 572734Smw145384 char *state = NULL; 573734Smw145384 574734Smw145384 hs = (hot_spare_t *)mdrec->record; 575734Smw145384 576734Smw145384 /* 577734Smw145384 * Loops through physical namespace to find the device that matches 578734Smw145384 * the hotspare entry. 579734Smw145384 */ 580734Smw145384 for (tmpphys_nm = phys_nm; tmpphys_nm != NULL; 581734Smw145384 tmpphys_nm = tmpphys_nm->next) { 582734Smw145384 if (tmpphys_nm->n_key == 583734Smw145384 ((hot_spare_t *)hs)->hs_key) { 584734Smw145384 /* Printing name of hotspare device */ 585734Smw145384 (void) printf(" %s", tmpphys_nm->n_name); 586734Smw145384 break; 587734Smw145384 } 588734Smw145384 } 589734Smw145384 590734Smw145384 state = meta_get_hs_state(hs->hs_state); 591734Smw145384 if (state != NULL) 592734Smw145384 (void) printf(" (%s)", state); 593734Smw145384 594734Smw145384 /* Not removing entry, because it can be processed more than once. */ 595734Smw145384 } 596734Smw145384 597734Smw145384 598734Smw145384 /* 599734Smw145384 * process_hotspare_pool() 600734Smw145384 * 601734Smw145384 * Prints concise unit information for a hotspare pool metadevice and calls a 602734Smw145384 * function to process each attached hotspare device. 603734Smw145384 * 604734Smw145384 */ 605734Smw145384 static void 606734Smw145384 process_hotspare_pool( 607734Smw145384 md_im_rec_t **mdimpp, 608734Smw145384 int indent, 609734Smw145384 pnm_rec_t *phys_nm, 610734Smw145384 md_im_rec_t *mdrec 611734Smw145384 ) 612734Smw145384 { 613734Smw145384 hot_spare_pool_ond_t *hsp; 614734Smw145384 int i; 615734Smw145384 md_im_rec_t *tmpmdrec; 616734Smw145384 617734Smw145384 hsp = (hot_spare_pool_ond_t *)mdrec->record; 618734Smw145384 619734Smw145384 /* 620734Smw145384 * Printing name, size, and type of metadevice. Setting size field to 621734Smw145384 * 0, so that output is the as metastat -c. 622734Smw145384 */ 623734Smw145384 print_concise_entry(indent, mdrec->n_name, 624734Smw145384 0, 'h'); 625734Smw145384 626734Smw145384 /* Looping through list of attached hotspare devices. */ 627734Smw145384 for (i = 0; i < hsp->hsp_nhotspares; i++) { 628734Smw145384 /* Looking for the matching record for the hotspare device. */ 629734Smw145384 for (tmpmdrec = *mdimpp; tmpmdrec != NULL; 630734Smw145384 tmpmdrec = tmpmdrec->next) { 631734Smw145384 if (tmpmdrec->hs_record_id == hsp->hsp_hotspares[i]) { 632734Smw145384 /* Calling function to print name of hotspare */ 633734Smw145384 tmpmdrec->dfunc(mdimpp, indent, phys_nm, 634734Smw145384 tmpmdrec); 635734Smw145384 } 636734Smw145384 } 637734Smw145384 } 638734Smw145384 (void) printf("\n"); 639734Smw145384 640734Smw145384 /* 641734Smw145384 * Removing the md_entry from the list 642734Smw145384 * of all metadevices 643734Smw145384 */ 644734Smw145384 free_mdrec_list_entry(&mdrec); 645734Smw145384 } 646734Smw145384 647734Smw145384 648734Smw145384 /* 649734Smw145384 * process_raid() 650734Smw145384 * 651734Smw145384 * Prints concise unit information for a raid metadevice and calls the 652734Smw145384 * respective functions to process the underlying metadevices. 653734Smw145384 * 654734Smw145384 */ 655734Smw145384 static void 656734Smw145384 process_raid( 657734Smw145384 md_im_rec_t **mdimpp, 658734Smw145384 int indent, 659734Smw145384 pnm_rec_t *phys_nm, 660734Smw145384 md_im_rec_t *mdrec 661734Smw145384 ) 662734Smw145384 { 663734Smw145384 mr_unit_t *mr; 664734Smw145384 mr_column_t *mc; 665734Smw145384 mdc_unit_t uc; 666734Smw145384 int i; 667734Smw145384 md_im_rec_t *tmpmdrec; 668734Smw145384 md_im_rec_t *hstmpmdrec; 669734Smw145384 md_im_list_t *ucomp_head = NULL; 670734Smw145384 md_im_list_t *ucomp_tail = NULL; 671734Smw145384 md_im_list_t *ucomp = NULL; 672734Smw145384 pnm_rec_t *tmpphys_nm; 673734Smw145384 int underlying_device; 674734Smw145384 675734Smw145384 mr = (mr_unit_t *)mdrec->record; 676734Smw145384 uc = mr->c; 677734Smw145384 678734Smw145384 /* Printing name, size, and type of metadevice */ 679734Smw145384 print_concise_entry(indent, mdrec->n_name, 680734Smw145384 uc.un_total_blocks, 'r'); 681734Smw145384 682734Smw145384 /* Loops through raid columns to find underlying metadevices */ 683734Smw145384 for (i = 0, mc = &mr->un_column[0]; i < mr->un_totalcolumncnt; 684734Smw145384 i++, mc++) { 685734Smw145384 char *state = NULL; 686734Smw145384 char *hsname = NULL; 687734Smw145384 688734Smw145384 /* 689734Smw145384 * Need to assume that underlying device is a physical device, 690734Smw145384 * unless we find a matching metadevice record. 691734Smw145384 */ 692734Smw145384 underlying_device = PHYSICAL_DEV; 693734Smw145384 694734Smw145384 /* 695734Smw145384 * Loops through list of metadevices to find record that matches 696734Smw145384 * the underlying device. 697734Smw145384 */ 698734Smw145384 for (tmpmdrec = *mdimpp; tmpmdrec != NULL; 699734Smw145384 tmpmdrec = tmpmdrec->next) { 700734Smw145384 if (tmpmdrec->n_key == mc->un_orig_key) { 701734Smw145384 /* check if hotspare device enabled */ 702734Smw145384 if (mc->un_hs_id != NULL) { 703734Smw145384 /* 704734Smw145384 * Find matching metadevice record 705734Smw145384 * for the hotspare device. 706734Smw145384 */ 707734Smw145384 for (hstmpmdrec = *mdimpp; 708734Smw145384 hstmpmdrec != NULL; 709734Smw145384 hstmpmdrec = hstmpmdrec->next) { 710734Smw145384 if (hstmpmdrec->hs_record_id == 711734Smw145384 mc->un_hs_id) { 712734Smw145384 /* print name of hs */ 713734Smw145384 hstmpmdrec->dfunc( 714734Smw145384 mdimpp, indent, 715734Smw145384 phys_nm, 716734Smw145384 hstmpmdrec); 717734Smw145384 break; 718734Smw145384 } 719734Smw145384 } 720734Smw145384 } 721734Smw145384 /* print name of underlying metadevice */ 722734Smw145384 (void) printf(" %s", tmpmdrec->n_name); 723734Smw145384 underlying_device = NOT_PHYSICAL_DEV; 724734Smw145384 ucomp = Zalloc(sizeof (md_im_list_t)); 725734Smw145384 ucomp->mdrec = tmpmdrec; 726734Smw145384 ucomponent_append(&ucomp_head, &ucomp_tail, 727734Smw145384 ucomp); 728734Smw145384 } 729734Smw145384 } 730734Smw145384 731734Smw145384 if (underlying_device == PHYSICAL_DEV) { 732734Smw145384 print_physical_device(phys_nm, mc->un_orig_key); 733734Smw145384 } 734734Smw145384 state = meta_get_raid_col_state(mc->un_devstate); 735734Smw145384 736734Smw145384 /* 737734Smw145384 * An underlying hotspare must be a physical device. 738734Smw145384 * If support is ever added for soft-partitions under 739734Smw145384 * hotspare pools, then this code should be updated to 740734Smw145384 * include a search for underlying metadevices. 741734Smw145384 */ 742734Smw145384 if (mc->un_hs_id != 0) { 743734Smw145384 for (tmpphys_nm = phys_nm; tmpphys_nm != NULL; 744734Smw145384 tmpphys_nm = tmpphys_nm->next) { 745734Smw145384 if (tmpphys_nm->n_key == mc->un_hs_key) { 746734Smw145384 hsname = tmpphys_nm->n_name; 747734Smw145384 break; 748734Smw145384 } 749734Smw145384 } 750734Smw145384 } 751734Smw145384 752734Smw145384 if (state != NULL) { 753734Smw145384 if (hsname != NULL) 754734Smw145384 (void) printf(" (%s-%s)", state, 755734Smw145384 hsname); 756734Smw145384 else 757734Smw145384 (void) printf(" (%s)", state); 758734Smw145384 } else if (hsname != NULL) { 759734Smw145384 (void) printf(gettext(" (spared-%s)"), hsname); 760734Smw145384 } 761734Smw145384 } 762734Smw145384 (void) printf("\n"); 763734Smw145384 764734Smw145384 /* process underlying components */ 765734Smw145384 indent += META_INDENT; 766734Smw145384 for (ucomp = ucomp_head; ucomp != NULL; 767734Smw145384 ucomp = ucomp->next) { 768734Smw145384 ucomp->mdrec->dfunc(mdimpp, indent, phys_nm, 769734Smw145384 ucomp->mdrec); 770734Smw145384 } 771734Smw145384 free_md_im_list_entries(&ucomp_head); 772734Smw145384 773734Smw145384 /* 774734Smw145384 * Removing the md_entry from the list 775734Smw145384 * of all metadevices 776734Smw145384 */ 777734Smw145384 free_mdrec_list_entry(&mdrec); 778734Smw145384 } 779734Smw145384 780734Smw145384 781734Smw145384 /* 782734Smw145384 * process_mirror() 783734Smw145384 * 784734Smw145384 * Prints concise unit information for a mirror metadevice and calls the 785734Smw145384 * respective functions to process the underlying metadevices. 786734Smw145384 * 787734Smw145384 */ 788734Smw145384 static void 789734Smw145384 process_mirror( 790734Smw145384 md_im_rec_t **mdimpp, 791734Smw145384 int indent, 792734Smw145384 pnm_rec_t *phys_nm, 793734Smw145384 md_im_rec_t *mdrec 794734Smw145384 ) 795734Smw145384 { 796734Smw145384 mm_unit_t *mm; 797734Smw145384 mm_submirror_t *sm; 798734Smw145384 mdc_unit_t uc; 799734Smw145384 int i; 800734Smw145384 md_im_rec_t *tmpmdrec; 801734Smw145384 md_im_list_t *ucomp_head = NULL; 802734Smw145384 md_im_list_t *ucomp_tail = NULL; 803734Smw145384 md_im_list_t *ucomp = NULL; 804734Smw145384 805734Smw145384 mm = (mm_unit_t *)mdrec->record; 806734Smw145384 uc = mm->c; 807734Smw145384 808734Smw145384 /* Printing name, size, and type of metadevice */ 809734Smw145384 print_concise_entry(indent, mdrec->n_name, 810734Smw145384 uc.un_total_blocks, 'm'); 811734Smw145384 812734Smw145384 /* Looping through sub-mirrors to find underlying devices */ 813734Smw145384 for (i = 0, sm = &mm->un_sm[0]; i < mm->un_nsm; i++, sm++) { 814734Smw145384 char *state = NULL; 815734Smw145384 816734Smw145384 for (tmpmdrec = *mdimpp; tmpmdrec != NULL; 817734Smw145384 tmpmdrec = tmpmdrec->next) { 818734Smw145384 if (tmpmdrec->n_key == sm->sm_key) { 819734Smw145384 (void) printf(" %s", tmpmdrec->n_name); 820734Smw145384 ucomp = Zalloc(sizeof (md_im_list_t)); 821734Smw145384 ucomp->mdrec = tmpmdrec; 822734Smw145384 ucomponent_append(&ucomp_head, &ucomp_tail, 823734Smw145384 ucomp); 824734Smw145384 } 825734Smw145384 } 826734Smw145384 827734Smw145384 /* 828734Smw145384 * It is not possible to have an underlying physical device 829734Smw145384 * for a submirror, so there is no need to search the phys_nm 830734Smw145384 * list. 831734Smw145384 */ 832734Smw145384 833734Smw145384 /* Printing the state for the submirror */ 834734Smw145384 state = meta_get_sm_state(sm->sm_state); 835734Smw145384 if (state != NULL) { 836734Smw145384 (void) printf(" (%s)", state); 837734Smw145384 } 838734Smw145384 } 839734Smw145384 (void) printf("\n"); 840734Smw145384 841734Smw145384 /* process underlying components */ 842734Smw145384 indent += META_INDENT; 843734Smw145384 for (ucomp = ucomp_head; ucomp != NULL; 844734Smw145384 ucomp = ucomp->next) { 845734Smw145384 ucomp->mdrec->dfunc(mdimpp, indent, phys_nm, 846734Smw145384 ucomp->mdrec); 847734Smw145384 } 848734Smw145384 free_md_im_list_entries(&ucomp_head); 849734Smw145384 850734Smw145384 /* 851734Smw145384 * Removing the md_entry from the list 852734Smw145384 * of all metadevices 853734Smw145384 */ 854734Smw145384 free_mdrec_list_entry(&mdrec); 855734Smw145384 } 856734Smw145384 857734Smw145384 858734Smw145384 /* 859734Smw145384 * process_stripe() 860734Smw145384 * 861734Smw145384 * Prints concise unit information for a stripe metadevice and calls the 862734Smw145384 * respective functions to process the underlying metadevices. 863734Smw145384 * 864734Smw145384 */ 865734Smw145384 static void 866734Smw145384 process_stripe( 867734Smw145384 md_im_rec_t **mdimpp, 868734Smw145384 int indent, 869734Smw145384 pnm_rec_t *phys_nm, 870734Smw145384 md_im_rec_t *mdrec 871734Smw145384 ) 872734Smw145384 { 873734Smw145384 ms_unit_t *ms; 874734Smw145384 mdc_unit_t uc; 875734Smw145384 md_im_rec_t *tmpmdrec; 876734Smw145384 md_im_list_t *ucomp_head = NULL; 877734Smw145384 md_im_list_t *ucomp_tail = NULL; 878734Smw145384 md_im_list_t *ucomp = NULL; 879734Smw145384 pnm_rec_t *tmpphys_nm; 880734Smw145384 int underlying_device; 881734Smw145384 uint_t row; 882734Smw145384 883734Smw145384 ms = (ms_unit_t *)mdrec->record; 884734Smw145384 uc = ms->c; 885734Smw145384 886734Smw145384 /* Printing name, size, and type of metadevice */ 887734Smw145384 print_concise_entry(indent, mdrec->n_name, 888734Smw145384 uc.un_total_blocks, 's'); 889734Smw145384 890734Smw145384 /* Looping through stripe rows */ 891734Smw145384 for (row = 0; (row < ms->un_nrows); ++row) { 892734Smw145384 struct ms_row *mdr = &ms->un_row[row]; 893734Smw145384 ms_comp_t *mdcomp = (void *)&((char *)ms) 894734Smw145384 [ms->un_ocomp]; 895734Smw145384 uint_t comp, c; 896734Smw145384 897734Smw145384 /* 898734Smw145384 * Looping through the components in each row to find the 899734Smw145384 * underlying devices. 900734Smw145384 */ 901734Smw145384 for (comp = 0, c = mdr->un_icomp; (comp < mdr->un_ncomp); 902734Smw145384 ++comp, ++c) { 903734Smw145384 char *state = NULL; 904734Smw145384 char *hsname = NULL; 905734Smw145384 ms_comp_t *mdc = &mdcomp[c]; 906734Smw145384 md_m_shared_t *mdm = &mdc->un_mirror; 907734Smw145384 908734Smw145384 /* 909734Smw145384 * Need to assume that underlying device is a 910734Smw145384 * physical device, unless we find a matching 911734Smw145384 * metadevice record. 912734Smw145384 */ 913734Smw145384 underlying_device = PHYSICAL_DEV; 914734Smw145384 915734Smw145384 for (tmpmdrec = *mdimpp; tmpmdrec != NULL; 916734Smw145384 tmpmdrec = tmpmdrec->next) { 917734Smw145384 if (tmpmdrec->n_key == mdc->un_key) { 918734Smw145384 (void) printf(" %s", tmpmdrec->n_name); 919734Smw145384 underlying_device = NOT_PHYSICAL_DEV; 920734Smw145384 ucomp = Zalloc(sizeof (md_im_list_t)); 921734Smw145384 ucomp->mdrec = tmpmdrec; 922734Smw145384 ucomponent_append(&ucomp_head, 923734Smw145384 &ucomp_tail, ucomp); 924734Smw145384 } 925734Smw145384 } 926734Smw145384 /* if an underlying metadevice was not found */ 927734Smw145384 if (underlying_device == PHYSICAL_DEV) { 928734Smw145384 print_physical_device(phys_nm, mdc->un_key); 929734Smw145384 } 930734Smw145384 state = meta_get_stripe_state(mdm->ms_state); 931734Smw145384 932734Smw145384 /* 933734Smw145384 * An underlying hotspare must be a physical device. 934734Smw145384 * If support is ever added for soft-partitions under 935734Smw145384 * hotspare pools, then this code should be updated to 936734Smw145384 * include a search for underlying metadevices. 937734Smw145384 */ 938734Smw145384 if (mdm->ms_hs_key != 0) { 939734Smw145384 for (tmpphys_nm = phys_nm; tmpphys_nm != NULL; 940734Smw145384 tmpphys_nm = tmpphys_nm->next) { 941734Smw145384 if (tmpphys_nm->n_key == 942734Smw145384 mdm->ms_hs_key) { 943734Smw145384 hsname = tmpphys_nm->n_name; 944734Smw145384 break; 945734Smw145384 } 946734Smw145384 } 947734Smw145384 } 948734Smw145384 if (state != NULL) { 949734Smw145384 if (hsname != NULL) { 950734Smw145384 (void) printf(" (%s-%s)", state, 951734Smw145384 hsname); 952734Smw145384 } else { 953734Smw145384 (void) printf(" (%s)", state); 954734Smw145384 } 955734Smw145384 } else if (hsname != NULL) { 956734Smw145384 (void) printf(gettext(" (spared-%s)"), hsname); 957734Smw145384 } 958734Smw145384 } 959734Smw145384 } 960734Smw145384 (void) printf("\n"); 961734Smw145384 962734Smw145384 /* Process underlying metadevices */ 963734Smw145384 indent += META_INDENT; 964734Smw145384 for (ucomp = ucomp_head; ucomp != NULL; 965734Smw145384 ucomp = ucomp->next) { 966734Smw145384 ucomp->mdrec->dfunc(mdimpp, indent, phys_nm, 967734Smw145384 ucomp->mdrec); 968734Smw145384 } 969734Smw145384 free_md_im_list_entries(&ucomp_head); 970734Smw145384 971734Smw145384 /* 972734Smw145384 * Removing the md_entry from the list 973734Smw145384 * of all metadevices 974734Smw145384 */ 975734Smw145384 free_mdrec_list_entry(&mdrec); 976734Smw145384 } 977734Smw145384 978734Smw145384 979734Smw145384 /* 980734Smw145384 * process_softpart() 981734Smw145384 * 982734Smw145384 * Prints concise unit information for a softpart metadevice and calls the 983734Smw145384 * respective functions to process the underlying metadevices. 984734Smw145384 * 985734Smw145384 */ 986734Smw145384 static void 987734Smw145384 process_softpart( 988734Smw145384 md_im_rec_t **mdimpp, 989734Smw145384 int indent, 990734Smw145384 pnm_rec_t *phys_nm, 991734Smw145384 md_im_rec_t *mdrec 992734Smw145384 ) 993734Smw145384 { 994734Smw145384 mp_unit_t *mp; 995734Smw145384 mdc_unit_t uc; 996734Smw145384 md_im_rec_t *tmpmdrec; 997734Smw145384 int underlying_device = PHYSICAL_DEV; 998734Smw145384 999734Smw145384 mp = (mp_unit_t *)mdrec->record; 1000734Smw145384 uc = mp->c; 1001734Smw145384 1002734Smw145384 /* Printing name, size, and type of metadevice */ 1003734Smw145384 print_concise_entry(indent, mdrec->n_name, 1004734Smw145384 uc.un_total_blocks, 'p'); 1005734Smw145384 1006734Smw145384 /* 1007734Smw145384 * Loops through md_im_rec_t **mdimpp list of all metadevices to find 1008734Smw145384 * record that matches the underlying device. 1009734Smw145384 * Softpartitions can only have one underlying device, so once a 1010734Smw145384 * match is found, we are done. 1011734Smw145384 */ 1012734Smw145384 for (tmpmdrec = *mdimpp; tmpmdrec != NULL; 1013734Smw145384 tmpmdrec = tmpmdrec->next) { 1014734Smw145384 if (tmpmdrec->n_key == mp->un_key) { 1015734Smw145384 /* Printing name of the underlying metadevice */ 1016734Smw145384 (void) printf(" %s", tmpmdrec->n_name); 1017734Smw145384 underlying_device = NOT_PHYSICAL_DEV; 1018734Smw145384 break; 1019734Smw145384 } 1020734Smw145384 } 1021734Smw145384 1022734Smw145384 /* This is only executed if an underlying metadevice was not found */ 1023734Smw145384 if (underlying_device == PHYSICAL_DEV) { 1024734Smw145384 print_physical_device(phys_nm, mp->un_key); 1025734Smw145384 (void) printf("\n"); 1026734Smw145384 } else { 1027734Smw145384 /* Process underlying metadevice */ 1028734Smw145384 (void) printf("\n"); 1029734Smw145384 indent += META_INDENT; 1030734Smw145384 tmpmdrec->dfunc(mdimpp, indent, phys_nm, 1031734Smw145384 tmpmdrec); 1032734Smw145384 } 1033734Smw145384 1034734Smw145384 /* 1035734Smw145384 * Removing the md_entry from the list 1036734Smw145384 * of all metadevices 1037734Smw145384 */ 1038734Smw145384 free_mdrec_list_entry(&mdrec); 1039734Smw145384 } 1040734Smw145384 1041734Smw145384 1042734Smw145384 /* 1043734Smw145384 * process_toplevel_softparts() 1044734Smw145384 * 1045734Smw145384 * Toplevel softpartions need to be grouped so that their underlying devices 1046734Smw145384 * can be printed just once. 1047734Smw145384 */ 1048734Smw145384 static void 1049734Smw145384 process_toplevel_softparts( 1050734Smw145384 md_im_rec_t **mdimpp, 1051734Smw145384 int indent, 1052734Smw145384 pnm_rec_t *phys_nm 1053734Smw145384 ) 1054734Smw145384 { 1055734Smw145384 mp_unit_t *mp; 1056734Smw145384 mdc_unit_t uc; 1057734Smw145384 md_im_rec_t *mdrec; 1058734Smw145384 md_im_rec_t *comp_mdrec; /* pntr to underlying component's record */ 1059734Smw145384 md_im_rec_t *tmp_mdrec, *rm_mdrec; 1060734Smw145384 mp_unit_t *tmp_mp; 1061734Smw145384 int underlying_device; 1062734Smw145384 1063734Smw145384 /* 1064734Smw145384 * Loops through md_im_rec_t **mdimpp list of all metadevices to find 1065734Smw145384 * all softpartions that are toplevel softpartitions(softparts w/out 1066734Smw145384 * a parent). Groups output for these entries so that the function to 1067734Smw145384 * process the underlying metadevice is only called once. 1068734Smw145384 */ 1069734Smw145384 for (mdrec = *mdimpp; mdrec != NULL; mdrec = mdrec->next) { 1070734Smw145384 1071734Smw145384 underlying_device = PHYSICAL_DEV; 1072734Smw145384 if ((mdrec->md_type == MDDB_F_SOFTPART) && 1073734Smw145384 (mdrec->has_parent == 0)) { 1074734Smw145384 mp = (mp_unit_t *)mdrec->record; 1075734Smw145384 uc = mp->c; 1076734Smw145384 /* Printing name, size, and type of metadevice */ 1077734Smw145384 print_concise_entry(indent, mdrec->n_name, 1078734Smw145384 uc.un_total_blocks, 'p'); 1079734Smw145384 /* 1080734Smw145384 * Looking for record that matches underlying 1081734Smw145384 * component. 1082734Smw145384 */ 1083734Smw145384 for (comp_mdrec = *mdimpp; comp_mdrec != NULL; 1084734Smw145384 comp_mdrec = comp_mdrec->next) { 1085734Smw145384 if (comp_mdrec->n_key == mp->un_key) { 1086734Smw145384 /* Print name of underlying device */ 1087734Smw145384 (void) printf(" %s", 1088734Smw145384 comp_mdrec->n_name); 1089734Smw145384 underlying_device = NOT_PHYSICAL_DEV; 1090734Smw145384 break; 1091734Smw145384 } 1092734Smw145384 } 1093734Smw145384 if (underlying_device == PHYSICAL_DEV) { 1094734Smw145384 print_physical_device(phys_nm, mp->un_key); 1095734Smw145384 } 1096734Smw145384 (void) printf("\n"); 1097734Smw145384 1098734Smw145384 /* 1099734Smw145384 * Looking for any other toplevel softpartitions with 1100734Smw145384 * same underlying device. We know that all other 1101734Smw145384 * matching metadevices, that share the same underlying 1102734Smw145384 * metadevice, are also soft-partitions. 1103734Smw145384 */ 1104734Smw145384 for (tmp_mdrec = mdrec->next; tmp_mdrec != NULL; ) { 1105734Smw145384 tmp_mp = (mp_unit_t *)tmp_mdrec->record; 1106734Smw145384 if ((tmp_mdrec->has_parent == 0) && 1107734Smw145384 (tmp_mp->un_key == mp->un_key)) { 1108734Smw145384 uc = tmp_mp->c; 1109734Smw145384 print_concise_entry(indent, 1110734Smw145384 tmp_mdrec->n_name, 1111734Smw145384 uc.un_total_blocks, 'p'); 1112734Smw145384 if (underlying_device == 1113734Smw145384 NOT_PHYSICAL_DEV) { 1114734Smw145384 (void) printf(" %s", 1115734Smw145384 comp_mdrec->n_name); 1116734Smw145384 } else { 1117734Smw145384 print_physical_device( 1118734Smw145384 phys_nm, tmp_mp->un_key); 1119734Smw145384 } 1120734Smw145384 (void) printf("\n"); 1121734Smw145384 /* 1122734Smw145384 * Need to advance so that will not lose 1123734Smw145384 * position after removing processed 1124734Smw145384 * record. 1125734Smw145384 */ 1126734Smw145384 rm_mdrec = tmp_mdrec; 1127734Smw145384 tmp_mdrec = tmp_mdrec->next; 1128734Smw145384 /* 1129734Smw145384 * Removing the md_entry from the list 1130734Smw145384 * of all metadevices. 1131734Smw145384 */ 1132734Smw145384 free_mdrec_list_entry(&rm_mdrec); 1133734Smw145384 } else { 1134734Smw145384 tmp_mdrec = tmp_mdrec->next; 1135734Smw145384 } 1136734Smw145384 } 1137734Smw145384 /* Process the underlying device */ 1138734Smw145384 if (underlying_device == NOT_PHYSICAL_DEV) { 1139734Smw145384 indent += META_INDENT; 1140734Smw145384 comp_mdrec->dfunc(mdimpp, indent, phys_nm, 1141734Smw145384 comp_mdrec); 1142734Smw145384 } 1143734Smw145384 } 1144734Smw145384 } 1145734Smw145384 } 1146734Smw145384 1147734Smw145384 1148734Smw145384 /* 1149734Smw145384 * process_toplevel_devices() 1150734Smw145384 * 1151734Smw145384 * Search through list of metadevices for metadevices of md_type that do not 1152734Smw145384 * have a parent. 1153734Smw145384 * 1154734Smw145384 */ 1155734Smw145384 static void 1156734Smw145384 process_toplevel_devices( 1157734Smw145384 md_im_rec_t **mdimpp, 1158734Smw145384 pnm_rec_t *pnm, 1159734Smw145384 uint_t md_type 1160734Smw145384 ) 1161734Smw145384 { 1162734Smw145384 md_im_rec_t *mdrec; 1163734Smw145384 md_im_list_t *mdrec_tl_tail = NULL; 1164734Smw145384 md_im_list_t *mdrec_tl_head = NULL; 1165734Smw145384 md_im_list_t *tmp_tl_list = NULL; 1166734Smw145384 int indent = 0; 1167734Smw145384 1168734Smw145384 indent += META_INDENT; 1169734Smw145384 1170734Smw145384 /* 1171734Smw145384 * Need to group soft partitions so that common underlying device 1172734Smw145384 * are only processed once. 1173734Smw145384 */ 1174734Smw145384 if (md_type == MDDB_F_SOFTPART) { 1175734Smw145384 process_toplevel_softparts(mdimpp, indent, pnm); 1176734Smw145384 return; 1177734Smw145384 } 1178734Smw145384 1179734Smw145384 /* 1180734Smw145384 * Search the list of metadevices to find all metadevices that match 1181734Smw145384 * the type and don't have a parent. Put them on a separate list 1182734Smw145384 * that will be processed. 1183734Smw145384 */ 1184734Smw145384 for (mdrec = *mdimpp; mdrec != NULL; mdrec = mdrec->next) { 1185734Smw145384 if ((mdrec->md_type == md_type)&&(mdrec->has_parent == 0)) { 1186734Smw145384 tmp_tl_list = Zalloc(sizeof (md_im_list_t)); 1187734Smw145384 tmp_tl_list->mdrec = mdrec; 1188734Smw145384 tmp_tl_list->next = NULL; 1189734Smw145384 if (mdrec_tl_tail == NULL) { 1190734Smw145384 mdrec_tl_tail = tmp_tl_list; 1191734Smw145384 mdrec_tl_head = mdrec_tl_tail; 1192734Smw145384 } else { 1193734Smw145384 mdrec_tl_tail->next = tmp_tl_list; 1194734Smw145384 mdrec_tl_tail = mdrec_tl_tail->next; 1195734Smw145384 } 1196734Smw145384 } 1197734Smw145384 1198734Smw145384 } 1199734Smw145384 1200734Smw145384 /* 1201734Smw145384 * Loop through list and process all top-level metadevices of a 1202734Smw145384 * given type. 1203734Smw145384 */ 1204734Smw145384 for (tmp_tl_list = mdrec_tl_head; tmp_tl_list != NULL; 1205734Smw145384 tmp_tl_list = tmp_tl_list->next) { 1206734Smw145384 tmp_tl_list->mdrec->dfunc(mdimpp, indent, pnm, 1207734Smw145384 tmp_tl_list->mdrec); 1208734Smw145384 } 1209734Smw145384 1210734Smw145384 free_md_im_list_entries(&mdrec_tl_head); 1211734Smw145384 } 1212734Smw145384 1213734Smw145384 1214734Smw145384 /* 1215734Smw145384 * extract_mduser_data() 1216734Smw145384 * 1217734Smw145384 * Converts or copies the (mddb_rb_t->rb_data) metadevice record to a 64bit 1218734Smw145384 * record. 1219734Smw145384 * Sets the dfunc field to point to the appropriate function to process the 1220734Smw145384 * metadevice. 1221734Smw145384 * Sets the parent field for the metadevice. 1222734Smw145384 * Extracts the name from the NM namespace if it is available, otherwise 1223734Smw145384 * generates it from the metadevice's minor number. 1224734Smw145384 * 1225734Smw145384 * Returns: 1226734Smw145384 * < 0 for failure 1227734Smw145384 * 0 for success 1228734Smw145384 * 1229734Smw145384 */ 1230734Smw145384 static int 1231734Smw145384 extract_mduser_data( 1232734Smw145384 mddb_rb_t *nm, 1233734Smw145384 md_im_rec_t *mdrec, 1234734Smw145384 void *rbp, 1235734Smw145384 int is_32bit_record, 1236734Smw145384 md_error_t *ep 1237734Smw145384 ) 1238734Smw145384 { 1239734Smw145384 mdc_unit_t uc; 1240734Smw145384 hot_spare_t *hs; 1241734Smw145384 hot_spare_pool_ond_t *hsp; 1242734Smw145384 size_t newreqsize; 1243734Smw145384 mddb_rb_t *rbp_nm = nm; 1244734Smw145384 struct nm_rec *nm_record; 1245734Smw145384 struct nm_name *nmname; 1246734Smw145384 char *uname = NULL; 1247734Smw145384 1248734Smw145384 1249734Smw145384 /*LINTED*/ 1250734Smw145384 nm_record = (struct nm_rec *)((caddr_t)(&rbp_nm->rb_data)); 1251734Smw145384 1252734Smw145384 /* 1253734Smw145384 * Setting the un_self_id or the hs_self_id, in the case of hotspare 1254734Smw145384 * records, for each metadevice entry. Also setting has_parent and 1255734Smw145384 * setting dfunc so that it points to the correct function to process 1256734Smw145384 * the record type. 1257734Smw145384 * If the record was stored ondisk in 32bit format, then it is 1258734Smw145384 * converted to the 64bits equivalent 64bit format and the memory 1259734Smw145384 * for the 32bit pointer is freed. 1260734Smw145384 */ 1261734Smw145384 switch (mdrec->md_type) { 1262734Smw145384 case MDDB_F_SOFTPART: 1263734Smw145384 if (is_32bit_record) { 1264734Smw145384 mp_unit32_od_t *small_un; 1265734Smw145384 mp_unit_t *big_un; 1266734Smw145384 1267734Smw145384 small_un = (mp_unit32_od_t *)((uintptr_t)rbp + 1268734Smw145384 (sizeof (mddb_rb_t) - sizeof (int))); 1269734Smw145384 newreqsize = sizeof (mp_unit_t) + 1270734Smw145384 ((small_un->un_numexts - 1) * 1271734Smw145384 sizeof (struct mp_ext)); 1272734Smw145384 big_un = (void *)Zalloc(newreqsize); 1273734Smw145384 softpart_convert((caddr_t)small_un, 1274734Smw145384 (caddr_t)big_un, SMALL_2_BIG); 1275734Smw145384 mdrec->record = (void *)big_un; 1276734Smw145384 } else { 1277734Smw145384 mp_unit_t *big_un; 1278734Smw145384 1279734Smw145384 big_un = (mp_unit_t *)((uintptr_t)rbp + 1280734Smw145384 (sizeof (mddb_rb_t) - sizeof (int))); 1281734Smw145384 newreqsize = sizeof (mp_unit_t) + 1282734Smw145384 ((big_un->un_numexts - 1) * 1283734Smw145384 sizeof (struct mp_ext)); 1284734Smw145384 mdrec->record = (void *)Zalloc(newreqsize); 1285734Smw145384 bcopy(big_un, mdrec->record, newreqsize); 1286734Smw145384 } 1287734Smw145384 uc = ((mp_unit_t *)mdrec->record)->c; 1288734Smw145384 mdrec->dfunc = &process_softpart; 1289734Smw145384 mdrec->un_self_id = uc.un_self_id; 1290734Smw145384 mdrec->has_parent = MD_HAS_PARENT( 1291734Smw145384 uc.un_parent); 1292734Smw145384 break; 1293734Smw145384 case MDDB_F_STRIPE: 1294734Smw145384 if (is_32bit_record) { 1295734Smw145384 ms_unit32_od_t *small_un; 1296734Smw145384 ms_unit_t *big_un; 1297734Smw145384 1298734Smw145384 small_un = (ms_unit32_od_t *)((uintptr_t)rbp + 1299734Smw145384 (sizeof (mddb_rb_t) - sizeof (int))); 1300734Smw145384 newreqsize = get_big_stripe_req_size( 1301734Smw145384 small_un, COMPLETE_STRUCTURE); 1302734Smw145384 big_un = (void *)Zalloc(newreqsize); 1303734Smw145384 stripe_convert((caddr_t)small_un, 1304734Smw145384 (caddr_t)big_un, SMALL_2_BIG); 1305734Smw145384 mdrec->record = (void *)big_un; 1306734Smw145384 } else { 1307734Smw145384 ms_unit_t *big_un; 1308734Smw145384 1309734Smw145384 big_un = (ms_unit_t *)((uintptr_t)rbp + 1310734Smw145384 (sizeof (mddb_rb_t) - sizeof (int))); 1311734Smw145384 newreqsize = get_stripe_req_size(big_un); 1312734Smw145384 mdrec->record = (void *)Zalloc(newreqsize); 1313734Smw145384 bcopy(big_un, mdrec->record, newreqsize); 1314734Smw145384 } 1315734Smw145384 uc = ((ms_unit_t *)mdrec->record)->c; 1316734Smw145384 mdrec->dfunc = &process_stripe; 1317734Smw145384 mdrec->un_self_id = uc.un_self_id; 1318734Smw145384 mdrec->has_parent = MD_HAS_PARENT( 1319734Smw145384 uc.un_parent); 1320734Smw145384 break; 1321734Smw145384 case MDDB_F_MIRROR: 1322734Smw145384 if (is_32bit_record) { 1323734Smw145384 mm_unit32_od_t *small_un; 1324734Smw145384 mm_unit_t *big_un; 1325734Smw145384 1326734Smw145384 small_un = (mm_unit32_od_t *)((uintptr_t)rbp + 1327734Smw145384 (sizeof (mddb_rb_t) - sizeof (int))); 1328734Smw145384 newreqsize = sizeof (mm_unit_t); 1329734Smw145384 big_un = (void *)Zalloc(newreqsize); 1330734Smw145384 mirror_convert((caddr_t)small_un, 1331734Smw145384 (caddr_t)big_un, SMALL_2_BIG); 1332734Smw145384 mdrec->record = (void *)big_un; 1333734Smw145384 } else { 1334734Smw145384 mm_unit_t *big_un; 1335734Smw145384 1336734Smw145384 big_un = (mm_unit_t *)((uintptr_t)rbp + 1337734Smw145384 (sizeof (mddb_rb_t) - sizeof (int))); 1338734Smw145384 newreqsize = sizeof (mm_unit_t); 1339734Smw145384 mdrec->record = (void *)Zalloc(newreqsize); 1340734Smw145384 bcopy(big_un, mdrec->record, newreqsize); 1341734Smw145384 } 1342734Smw145384 uc = ((mm_unit_t *)mdrec->record)->c; 1343734Smw145384 mdrec->dfunc = &process_mirror; 1344734Smw145384 mdrec->un_self_id = uc.un_self_id; 1345734Smw145384 mdrec->has_parent = MD_HAS_PARENT( 1346734Smw145384 uc.un_parent); 1347734Smw145384 break; 1348734Smw145384 case MDDB_F_RAID: 1349734Smw145384 if (is_32bit_record) { 1350734Smw145384 mr_unit32_od_t *small_un; 1351734Smw145384 mr_unit_t *big_un; 1352734Smw145384 uint_t ncol; 1353734Smw145384 1354734Smw145384 small_un = (mr_unit32_od_t *)((uintptr_t)rbp + 1355734Smw145384 (sizeof (mddb_rb_t) - sizeof (int))); 1356734Smw145384 ncol = small_un->un_totalcolumncnt; 1357734Smw145384 newreqsize = sizeof (mr_unit_t) + 1358734Smw145384 ((ncol - 1) * sizeof (mr_column_t)); 1359734Smw145384 big_un = (void *)Zalloc(newreqsize); 1360734Smw145384 raid_convert((caddr_t)small_un, 1361734Smw145384 (caddr_t)big_un, SMALL_2_BIG); 1362734Smw145384 mdrec->record = (void *)big_un; 1363734Smw145384 } else { 1364734Smw145384 mr_unit_t *big_un; 1365734Smw145384 uint_t ncol; 1366734Smw145384 1367734Smw145384 big_un = (mr_unit_t *)((uintptr_t)rbp + 1368734Smw145384 (sizeof (mddb_rb_t) - sizeof (int))); 1369734Smw145384 ncol = big_un->un_totalcolumncnt; 1370734Smw145384 newreqsize = sizeof (mr_unit_t) + 1371734Smw145384 ((ncol - 1) * sizeof (mr_column_t)); 1372734Smw145384 mdrec->record = (void *)Zalloc(newreqsize); 1373734Smw145384 bcopy(big_un, mdrec->record, newreqsize); 1374734Smw145384 } 1375734Smw145384 uc = ((mr_unit_t *)mdrec->record)->c; 1376734Smw145384 mdrec->dfunc = &process_raid; 1377734Smw145384 mdrec->un_self_id = uc.un_self_id; 1378734Smw145384 mdrec->has_parent = MD_HAS_PARENT( 1379734Smw145384 uc.un_parent); 1380734Smw145384 break; 1381734Smw145384 case MDDB_F_TRANS_MASTER: 1382734Smw145384 if (is_32bit_record) { 1383734Smw145384 mt_unit32_od_t *small_un; 1384734Smw145384 mt_unit_t *big_un; 1385734Smw145384 1386734Smw145384 small_un = (mt_unit32_od_t *)((uintptr_t)rbp + 1387734Smw145384 (sizeof (mddb_rb_t) - sizeof (int))); 1388734Smw145384 newreqsize = sizeof (mt_unit_t); 1389734Smw145384 big_un = (void *)Zalloc(newreqsize); 1390734Smw145384 trans_master_convert((caddr_t)small_un, 1391734Smw145384 (caddr_t)big_un, SMALL_2_BIG); 1392734Smw145384 mdrec->record = (void *)big_un; 1393734Smw145384 } else { 1394734Smw145384 mt_unit_t *big_un; 1395734Smw145384 1396734Smw145384 big_un = (mt_unit_t *)((uintptr_t)rbp + 1397734Smw145384 (sizeof (mddb_rb_t) - sizeof (int))); 1398734Smw145384 newreqsize = sizeof (mt_unit_t); 1399734Smw145384 mdrec->record = (void *)Zalloc(newreqsize); 1400734Smw145384 bcopy(big_un, mdrec->record, newreqsize); 1401734Smw145384 } 1402734Smw145384 uc = ((mt_unit_t *)mdrec->record)->c; 1403734Smw145384 mdrec->dfunc = &process_trans; 1404734Smw145384 mdrec->un_self_id = uc.un_self_id; 1405734Smw145384 mdrec->has_parent = MD_HAS_PARENT( 1406734Smw145384 uc.un_parent); 1407734Smw145384 break; 1408734Smw145384 case MDDB_F_HOTSPARE: 1409734Smw145384 if (is_32bit_record) { 1410734Smw145384 hot_spare32_od_t *small_un; 1411734Smw145384 hot_spare_t *big_un; 1412734Smw145384 1413734Smw145384 small_un = (hot_spare32_od_t *)((uintptr_t)rbp + 1414734Smw145384 (sizeof (mddb_rb_t) - sizeof (int))); 1415734Smw145384 newreqsize = sizeof (hot_spare_t); 1416734Smw145384 big_un = (void *)Zalloc(newreqsize); 1417734Smw145384 hs_convert((caddr_t)small_un, 1418734Smw145384 (caddr_t)big_un, SMALL_2_BIG); 1419734Smw145384 mdrec->record = (void *)big_un; 1420734Smw145384 } else { 1421734Smw145384 hot_spare_t *big_un; 1422734Smw145384 1423734Smw145384 big_un = (hot_spare_t *)((uintptr_t)rbp + 1424734Smw145384 (sizeof (mddb_rb_t) - sizeof (int))); 1425734Smw145384 newreqsize = sizeof (hot_spare_t); 1426734Smw145384 mdrec->record = (void *)Zalloc(newreqsize); 1427734Smw145384 bcopy(big_un, mdrec->record, newreqsize); 1428734Smw145384 } 1429734Smw145384 hs = (hot_spare_t *)mdrec->record; 1430734Smw145384 mdrec->dfunc = &process_hotspare; 1431734Smw145384 mdrec->un_self_id = NULL; 1432734Smw145384 mdrec->hs_record_id = hs->hs_record_id; 1433734Smw145384 mdrec->has_parent = 1; 1434734Smw145384 break; 1435734Smw145384 case MDDB_F_HOTSPARE_POOL: 1436734Smw145384 /* 1437734Smw145384 * Ondisk and incore records are always same size. 1438734Smw145384 */ 1439734Smw145384 hsp = (hot_spare_pool_ond_t *)((uintptr_t)rbp + 1440734Smw145384 (sizeof (mddb_rb_t) - sizeof (int))); 1441734Smw145384 newreqsize = sizeof (hot_spare_pool_ond_t) + 1442734Smw145384 (sizeof (mddb_recid_t) * hsp->hsp_nhotspares); 1443734Smw145384 mdrec->record = (void *)Zalloc(newreqsize); 1444734Smw145384 bcopy(hsp, mdrec->record, newreqsize); 1445734Smw145384 hsp = (hot_spare_pool_ond_t *)mdrec->record; 1446734Smw145384 mdrec->dfunc = &process_hotspare_pool; 1447*1623Stw21770 /* 1448*1623Stw21770 * If the hsp has descriptive name we'll get 1449*1623Stw21770 * the un_self_id 1450*1623Stw21770 */ 1451*1623Stw21770 if (HSP_ID_IS_FN(hsp->hsp_self_id)) 1452*1623Stw21770 mdrec->un_self_id = hsp->hsp_self_id; 1453*1623Stw21770 else 1454*1623Stw21770 mdrec->un_self_id = NULL; 1455734Smw145384 mdrec->has_parent = 0; 1456734Smw145384 break; 1457734Smw145384 /* All valid cases have been dealt with */ 1458734Smw145384 default: 1459734Smw145384 (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL); 1460734Smw145384 return (-1); 1461734Smw145384 } 1462734Smw145384 1463734Smw145384 /* 1464734Smw145384 * If metadevice record has an entry in the NM namespace 1465734Smw145384 * then it is copied into the mdrec->n_name field. 1466734Smw145384 */ 1467734Smw145384 if (mdrec->un_self_id != NULL) { 1468734Smw145384 for (nmname = &nm_record->r_name[0]; nmname->n_key != 0; 1469734Smw145384 /*LINTED*/ 1470734Smw145384 nmname = (struct nm_name *)((char *)nmname + 1471734Smw145384 NAMSIZ(nmname))) { 1472734Smw145384 /* 1473*1623Stw21770 * Extract the metadevice/hsp name if it is 1474*1623Stw21770 * in the namespace. 1475*1623Stw21770 * 1476*1623Stw21770 * If it is a hot spare pool we will find our 1477*1623Stw21770 * match by comparing the NM record's n_key 1478*1623Stw21770 * with the extracted key from the hsp_self_id 1479*1623Stw21770 * Else, match the un_self_id for the record 1480*1623Stw21770 * to the n_minor name in the NM record. 1481734Smw145384 */ 1482*1623Stw21770 if (mdrec->md_type == MDDB_F_HOTSPARE_POOL) { 1483*1623Stw21770 if (nmname->n_key == 1484*1623Stw21770 HSP_ID_TO_KEY(hsp->hsp_self_id)) { 1485*1623Stw21770 mdrec->n_key = nmname->n_key; 1486*1623Stw21770 uname = Strdup(nmname->n_name); 1487*1623Stw21770 mdrec->n_name = uname; 1488*1623Stw21770 break; 1489*1623Stw21770 } 1490*1623Stw21770 } else { 1491*1623Stw21770 if ((nmname->n_minor) == (uc.un_self_id)) { 1492*1623Stw21770 (*mdrec).n_key = nmname->n_key; 1493*1623Stw21770 uname = Strdup(nmname->n_name); 1494*1623Stw21770 mdrec->n_name = uname; 1495*1623Stw21770 break; 1496*1623Stw21770 } 1497*1623Stw21770 } 1498734Smw145384 } 1499734Smw145384 } 1500734Smw145384 1501734Smw145384 /* 1502734Smw145384 * If the metadevice name is not in the namespace, then 1503734Smw145384 * then we will generate the name from the minor number 1504734Smw145384 * for the metadevice. In the case of records for a hotspare 1505734Smw145384 * pool we use hsp_self_id, otherwise we use un_self_id. 1506734Smw145384 */ 1507734Smw145384 if (uname == NULL) { 1508734Smw145384 if (mdrec->md_type == MDDB_F_HOTSPARE_POOL) { 1509734Smw145384 uname = Malloc(MAXSIZEMDRECNAME); 1510734Smw145384 (void) sprintf(uname, "hsp%03u", 1511734Smw145384 HSP_ID(hsp->hsp_self_id)); 1512734Smw145384 mdrec->n_name = uname; 1513734Smw145384 } else if (mdrec->md_type != MDDB_F_HOTSPARE) { 1514734Smw145384 /* 1515734Smw145384 * Generate the metadevice name for all other records 1516734Smw145384 * (except for hotspares, because hotspares can only 1517734Smw145384 * be physical devices.) 1518734Smw145384 */ 1519734Smw145384 uname = Malloc(MAXSIZEMDRECNAME); 1520734Smw145384 (void) sprintf(uname, "d%lu", 1521734Smw145384 MD_MIN2UNIT(mdrec->un_self_id)); 1522734Smw145384 mdrec->n_name = uname; 1523734Smw145384 } 1524734Smw145384 } 1525734Smw145384 1526734Smw145384 return (0); 1527734Smw145384 } 1528734Smw145384 1529734Smw145384 1530734Smw145384 /* 1531734Smw145384 * read_mdrecord() 1532734Smw145384 * 1533734Smw145384 * Reads the mddb_rb32_od_t or mddb_rb_t and the associated metadevice record 1534734Smw145384 * from the disk. Runs magic, checksum, and revision checks on the record 1535734Smw145384 * block. 1536734Smw145384 * 1537734Smw145384 * Returns: 1538734Smw145384 * < 0 for failure 1539734Smw145384 * 0 for success 1540734Smw145384 * 1541734Smw145384 */ 1542734Smw145384 static int 1543734Smw145384 read_mdrecord( 1544734Smw145384 md_im_rec_t **mdimpp, 1545734Smw145384 mddb_mb_t *mbp, 1546734Smw145384 mddb_rb_t *nm, 1547734Smw145384 mddb_de_t *dep, 1548734Smw145384 char *diskname, 1549734Smw145384 int fd, 1550734Smw145384 md_timeval32_t *lastaccess, 1551734Smw145384 md_error_t *ep 1552734Smw145384 ) 1553734Smw145384 { 1554734Smw145384 int cnt, rval = 0; 1555734Smw145384 daddr_t pblk; 1556734Smw145384 md_im_rec_t *tmp_mdrec; 1557734Smw145384 void *rbp = NULL; 1558734Smw145384 char *rbp_tmp = NULL; 1559734Smw145384 mddb_rb32_t *rbp_32; 1560734Smw145384 mddb_rb_t *rbp_64; 1561734Smw145384 crc_skip_t *skip = NULL; 1562*1623Stw21770 int is_32bit_record; 1563734Smw145384 1564734Smw145384 tmp_mdrec = Zalloc(sizeof (md_im_rec_t)); 1565734Smw145384 rbp = (void *)Zalloc(dbtob(dep->de_blkcount)); 1566734Smw145384 rbp_tmp = (char *)rbp; 1567734Smw145384 1568734Smw145384 /* Read in the appropriate record and return configurations */ 1569734Smw145384 for (cnt = 0; cnt < dep->de_blkcount; cnt++) { 1570734Smw145384 if ((pblk = getphysblk(dep->de_blks[cnt], mbp)) < 0) { 1571734Smw145384 rval = mdmddberror(ep, MDE_DB_BLKRANGE, 1572734Smw145384 NODEV32, MD_LOCAL_SET, 1573734Smw145384 dep->de_blks[cnt], diskname); 1574734Smw145384 return (rval); 1575734Smw145384 } 1576734Smw145384 1577734Smw145384 if (lseek(fd, (off_t)dbtob(pblk), SEEK_SET) < 0) { 1578734Smw145384 rval = mdsyserror(ep, errno, diskname); 1579734Smw145384 return (rval); 1580734Smw145384 } 1581734Smw145384 1582734Smw145384 if (read(fd, rbp_tmp, DEV_BSIZE) != DEV_BSIZE) { 1583734Smw145384 rval = mdsyserror(ep, errno, diskname); 1584734Smw145384 return (rval); 1585734Smw145384 } 1586734Smw145384 1587734Smw145384 rbp_tmp += DEV_BSIZE; 1588734Smw145384 } 1589734Smw145384 tmp_mdrec->md_type = dep->de_flags; 1590734Smw145384 1591734Smw145384 /* 1592734Smw145384 * The only place to discover whether or not the record is a 1593734Smw145384 * 32bit or 64bit record is from the record's rb_revision field. 1594734Smw145384 * The mddb_rb_t and mddb_rb32_t structures are identical for the 1595734Smw145384 * following fields: 1596734Smw145384 * rb_magic, rb_revision, rb_checksum, and rb_checksum_fiddle. 1597734Smw145384 * So we can assume that the record is a 32bit structure when we 1598734Smw145384 * check the record's magic number and revision and when we calculate 1599734Smw145384 * the records checksum. 1600734Smw145384 */ 1601734Smw145384 rbp_32 = (mddb_rb32_t *)rbp; 1602734Smw145384 1603734Smw145384 /* 1604734Smw145384 * Checking the magic number for the record block. 1605734Smw145384 */ 1606734Smw145384 if (rbp_32->rb_magic != MDDB_MAGIC_RB) { 1607734Smw145384 rval = -1; 1608734Smw145384 (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL); 1609734Smw145384 goto out; 1610734Smw145384 } 1611734Smw145384 1612734Smw145384 /* 1613734Smw145384 * Checking the revision for the record block. Must match either 1614734Smw145384 * revision for the current 64bit or 32bit record block. Also, 1615734Smw145384 * setting the flag for whether or not it is a 32bit record. 1616734Smw145384 */ 1617*1623Stw21770 is_32bit_record = 0; 1618*1623Stw21770 switch (rbp_32->rb_revision) { 1619*1623Stw21770 case MDDB_REV_RB: 1620*1623Stw21770 case MDDB_REV_RBFN: 1621734Smw145384 is_32bit_record = 1; 1622*1623Stw21770 break; 1623*1623Stw21770 case MDDB_REV_RB64: 1624*1623Stw21770 case MDDB_REV_RB64FN: 1625*1623Stw21770 break; 1626*1623Stw21770 default: 1627734Smw145384 rval = -1; 1628734Smw145384 (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL); 1629734Smw145384 goto out; 1630734Smw145384 } 1631734Smw145384 1632734Smw145384 /* 1633734Smw145384 * Calculating the checksum for this record block. Need 1634734Smw145384 * to skip the rb's checksum fiddle. 1635734Smw145384 */ 1636734Smw145384 skip = (crc_skip_t *)Malloc(sizeof (crc_skip_t)); 1637734Smw145384 skip->skip_next = NULL; 1638734Smw145384 skip->skip_offset = offsetof(mddb_rb_t, rb_checksum_fiddle); 1639734Smw145384 skip->skip_size = 3 * sizeof (uint_t); 1640734Smw145384 if (crcchk(rbp_32, &rbp_32->rb_checksum, dep->de_recsize, skip)) { 1641734Smw145384 rval = -1; 1642734Smw145384 (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL); 1643734Smw145384 goto out; 1644734Smw145384 } 1645734Smw145384 1646734Smw145384 /* mddb_rb_t and mddb_rb32_t differ before the rb_timestamp field */ 1647734Smw145384 if (!is_32bit_record) { 1648734Smw145384 if ((*lastaccess).tv_sec < rbp_32->rb_timestamp.tv_sec) { 1649734Smw145384 *lastaccess = rbp_32->rb_timestamp; 1650734Smw145384 } else if ((*lastaccess).tv_sec == 1651734Smw145384 rbp_32->rb_timestamp.tv_sec) { 1652734Smw145384 if ((*lastaccess).tv_usec < 1653734Smw145384 rbp_32->rb_timestamp.tv_usec) 1654734Smw145384 *lastaccess = rbp_32->rb_timestamp; 1655734Smw145384 } 1656734Smw145384 } else { 1657734Smw145384 rbp_64 = (mddb_rb_t *)rbp; 1658734Smw145384 if ((*lastaccess).tv_sec < rbp_64->rb_timestamp.tv_sec) { 1659734Smw145384 *lastaccess = rbp_64->rb_timestamp; 1660734Smw145384 } else if ((*lastaccess).tv_sec == 1661734Smw145384 rbp_64->rb_timestamp.tv_sec) { 1662734Smw145384 if ((*lastaccess).tv_usec < 1663734Smw145384 rbp_64->rb_timestamp.tv_usec) 1664734Smw145384 *lastaccess = rbp_64->rb_timestamp; 1665734Smw145384 } 1666734Smw145384 } 1667734Smw145384 1668734Smw145384 /* Populates the fields in md_im_rec_t *tmp_mdrec. */ 1669734Smw145384 rval = extract_mduser_data(nm, tmp_mdrec, rbp, is_32bit_record, ep); 1670734Smw145384 if (rval < 0) 1671734Smw145384 goto out; 1672734Smw145384 1673734Smw145384 /* Adding record to the head of the list of all metadevices. */ 1674734Smw145384 tmp_mdrec->prev = NULL; 1675734Smw145384 if (*mdimpp == NULL) { 1676734Smw145384 tmp_mdrec->next = NULL; 1677734Smw145384 *mdimpp = tmp_mdrec; 1678734Smw145384 } else { 1679734Smw145384 (*mdimpp)->prev = tmp_mdrec; 1680734Smw145384 tmp_mdrec->next = *mdimpp; 1681734Smw145384 *mdimpp = tmp_mdrec; 1682734Smw145384 } 1683734Smw145384 1684734Smw145384 out: 1685734Smw145384 /* Free the skip list */ 1686734Smw145384 while (skip) { 1687734Smw145384 crc_skip_t *skip_rm = skip; 1688734Smw145384 1689734Smw145384 skip = skip->skip_next; 1690734Smw145384 Free(skip_rm); 1691734Smw145384 } 1692734Smw145384 1693734Smw145384 if (rbp) 1694734Smw145384 Free(rbp); 1695734Smw145384 1696734Smw145384 return (rval); 1697734Smw145384 } 1698734Smw145384 1699734Smw145384 1700734Smw145384 /* 1701734Smw145384 * read_all_mdrecords() 1702734Smw145384 * 1703734Smw145384 * Reads the directory block and directory entries. 1704734Smw145384 * Runs magic, checksum, and revision checks on the directory block. 1705734Smw145384 * 1706734Smw145384 * Returns: 1707734Smw145384 * < 0 for failure 1708734Smw145384 * 0 for success 1709734Smw145384 */ 1710734Smw145384 static int 1711734Smw145384 read_all_mdrecords( 1712734Smw145384 md_im_rec_t **mdimpp, 1713734Smw145384 mddb_mb_t *mbp, 1714734Smw145384 mddb_lb_t *lbp, 1715734Smw145384 mddb_rb_t *nm, 1716734Smw145384 mdname_t *rsp, 1717734Smw145384 int fd, 1718734Smw145384 md_timeval32_t *lastaccess, 1719734Smw145384 md_error_t *ep 1720734Smw145384 ) 1721734Smw145384 { 1722734Smw145384 int dbblk, rval = 0; 1723734Smw145384 char db[DEV_BSIZE]; 1724734Smw145384 mddb_de_t *dep; 1725734Smw145384 int desize; 1726734Smw145384 /*LINTED*/ 1727734Smw145384 mddb_db_t *dbp = (mddb_db_t *)&db; 1728734Smw145384 1729734Smw145384 /* Read in all directory blocks */ 1730734Smw145384 for (dbblk = lbp->lb_dbfirstblk; 1731734Smw145384 dbblk != 0; 1732734Smw145384 dbblk = dbp->db_nextblk) { 1733734Smw145384 1734734Smw145384 if ((rval = read_database_block(ep, fd, mbp, dbblk, 1735734Smw145384 dbp, sizeof (db))) <= 0) 1736734Smw145384 goto out; 1737734Smw145384 1738734Smw145384 /* 1739734Smw145384 * Set ep with error code for MDE_DB_NODB. This is the 1740734Smw145384 * error code used in the kernel when there is a problem 1741734Smw145384 * with reading records in. Checks the magic number, the 1742734Smw145384 * revision, and the checksum for each directory block. 1743734Smw145384 */ 1744734Smw145384 if (dbp->db_magic != MDDB_MAGIC_DB) { 1745734Smw145384 rval = -1; 1746734Smw145384 (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL); 1747734Smw145384 goto out; 1748734Smw145384 } 1749734Smw145384 1750734Smw145384 if (revchk(MDDB_REV_DB, dbp->db_revision)) { 1751734Smw145384 rval = -1; 1752734Smw145384 (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL); 1753734Smw145384 goto out; 1754734Smw145384 } 1755734Smw145384 1756734Smw145384 if (crcchk(dbp, &dbp->db_checksum, MDDB_BSIZE, NULL)) { 1757734Smw145384 rval = -1; 1758734Smw145384 (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL); 1759734Smw145384 goto out; 1760734Smw145384 } 1761734Smw145384 1762734Smw145384 /* 1763734Smw145384 * If db timestamp is more recent than the previously recorded 1764734Smw145384 * last modified timestamp, then update last modified. 1765734Smw145384 */ 1766734Smw145384 if ((*lastaccess).tv_sec < dbp->db_timestamp.tv_sec) { 1767734Smw145384 *lastaccess = dbp->db_timestamp; 1768734Smw145384 } else if ((*lastaccess).tv_sec == dbp->db_timestamp.tv_sec) { 1769734Smw145384 if ((*lastaccess).tv_usec < dbp->db_timestamp.tv_usec) 1770734Smw145384 *lastaccess = dbp->db_timestamp; 1771734Smw145384 } 1772734Smw145384 1773734Smw145384 /* Creates dep list of all directory entries in the db */ 1774734Smw145384 if (dbp->db_firstentry != NULL) { 1775734Smw145384 /* LINTED */ 1776734Smw145384 dep = (mddb_de_t *)((caddr_t)(&dbp->db_firstentry) 1777734Smw145384 + sizeof (dbp->db_firstentry)); 1778734Smw145384 dbp->db_firstentry = dep; 1779734Smw145384 while (dep && dep->de_next) { 1780734Smw145384 desize = sizeof (*dep) - 1781734Smw145384 sizeof (dep->de_blks) + 1782734Smw145384 sizeof (daddr_t) * dep->de_blkcount; 1783734Smw145384 /* LINTED */ 1784734Smw145384 dep->de_next = (mddb_de_t *) 1785734Smw145384 ((caddr_t)dep + desize); 1786734Smw145384 dep = dep->de_next; 1787734Smw145384 } 1788734Smw145384 } 1789734Smw145384 1790734Smw145384 /* 1791734Smw145384 * Process all directory entries in the directory block. 1792734Smw145384 * For each directory entry, read_mdrec is called to read 1793734Smw145384 * in the record data. 1794734Smw145384 */ 1795734Smw145384 for (dep = dbp->db_firstentry; dep != NULL; 1796734Smw145384 dep = dep->de_next) { 1797734Smw145384 1798734Smw145384 /* 1799734Smw145384 * de_flags is set to the type of metadevice. 1800734Smw145384 * If directory entry does not correspond to a 1801734Smw145384 * specific metadevice then it is set to zero. 1802734Smw145384 * All namespace records(NM, SHR_NM, DID_SHR_NM) have a 1803734Smw145384 * value of zero in their de_flags field. 1804734Smw145384 */ 1805734Smw145384 if ((dep->de_flags != 0)&& 1806734Smw145384 (dep->de_flags != MDDB_F_OPT) && 1807734Smw145384 (dep->de_flags != MDDB_F_TRANS_LOG) && 1808734Smw145384 (dep->de_flags != MDDB_F_CHANGELOG)) { 1809734Smw145384 rval = read_mdrecord(mdimpp, mbp, nm, dep, 1810734Smw145384 rsp->cname, fd, lastaccess, ep); 1811734Smw145384 if (rval < 0) 1812734Smw145384 goto out; 1813734Smw145384 } 1814734Smw145384 } 1815734Smw145384 } 1816734Smw145384 1817734Smw145384 out: 1818734Smw145384 return (rval); 1819734Smw145384 } 1820734Smw145384 1821734Smw145384 1822734Smw145384 /* 1823734Smw145384 * report_metastat_info() 1824734Smw145384 * 1825734Smw145384 * Generates the metastat -c output. Also, updates the global variable 1826734Smw145384 * for a last accessed timestamp. 1827734Smw145384 * 1828734Smw145384 * Returns: 1829734Smw145384 * < 0 for failure 1830734Smw145384 * 0 for success 1831734Smw145384 * 1832734Smw145384 */ 1833734Smw145384 int 1834734Smw145384 report_metastat_info( 1835734Smw145384 mddb_mb_t *mb, 1836734Smw145384 mddb_lb_t *lbp, 1837734Smw145384 mddb_rb_t *nm, 1838734Smw145384 pnm_rec_t **pnm, 1839734Smw145384 mdname_t *rsp, 1840734Smw145384 int fd, 1841734Smw145384 md_timeval32_t *lastaccess, 1842734Smw145384 md_error_t *ep 1843734Smw145384 ) 1844734Smw145384 { 1845734Smw145384 int rval = 0; 1846734Smw145384 /* list of all metadevices in diskset */ 1847734Smw145384 md_im_rec_t *mdimp = NULL; 1848734Smw145384 md_im_rec_t *tmp_mdrec, *rm_mdrec; 1849734Smw145384 1850734Smw145384 /* Read in metadevice records and add entries to mdimp list. */ 1851734Smw145384 rval = read_all_mdrecords(&mdimp, mb, lbp, nm, rsp, fd, lastaccess, 1852734Smw145384 ep); 1853734Smw145384 if (rval < 0) 1854734Smw145384 goto out; 1855734Smw145384 1856734Smw145384 /* Adding a fake record to the head of the list of all metadevices. */ 1857734Smw145384 if (mdimp != NULL) { 1858734Smw145384 tmp_mdrec = Zalloc(sizeof (md_im_rec_t)); 1859734Smw145384 tmp_mdrec->prev = NULL; 1860734Smw145384 mdimp->prev = tmp_mdrec; 1861734Smw145384 tmp_mdrec->next = mdimp; 1862734Smw145384 mdimp = tmp_mdrec; 1863734Smw145384 } 1864734Smw145384 1865734Smw145384 /* Calling functions to process all metadevices on mdimp list */ 1866734Smw145384 process_toplevel_devices(&mdimp, *pnm, MDDB_F_SOFTPART); 1867734Smw145384 process_toplevel_devices(&mdimp, *pnm, MDDB_F_TRANS_MASTER); 1868734Smw145384 process_toplevel_devices(&mdimp, *pnm, MDDB_F_MIRROR); 1869734Smw145384 process_toplevel_devices(&mdimp, *pnm, MDDB_F_RAID); 1870734Smw145384 process_toplevel_devices(&mdimp, *pnm, MDDB_F_STRIPE); 1871734Smw145384 process_toplevel_devices(&mdimp, *pnm, MDDB_F_HOTSPARE_POOL); 1872734Smw145384 (void) printf("\n"); 1873734Smw145384 1874734Smw145384 out: 1875734Smw145384 /* 1876734Smw145384 * If mdreclist is not null, then this will walk through all 1877734Smw145384 * elements and free them. 1878734Smw145384 */ 1879734Smw145384 tmp_mdrec = mdimp; 1880734Smw145384 while (tmp_mdrec != NULL) { 1881734Smw145384 rm_mdrec = tmp_mdrec; 1882734Smw145384 tmp_mdrec = tmp_mdrec->next; 1883734Smw145384 if (rm_mdrec->record != NULL) 1884734Smw145384 Free(rm_mdrec->record); 1885734Smw145384 if (rm_mdrec->n_name != NULL) 1886734Smw145384 Free(rm_mdrec->n_name); 1887734Smw145384 Free(rm_mdrec); 1888734Smw145384 } 1889734Smw145384 1890734Smw145384 free_pnm_rec_list(pnm); 1891734Smw145384 return (rval); 1892734Smw145384 } 1893