xref: /onnv-gate/usr/src/lib/lvm/libmeta/common/meta_import.c (revision 4901:e5be9002831f)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51945Sjeanm  * Common Development and Distribution License (the "License").
61945Sjeanm  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*4901Sjr26306  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <assert.h>
290Sstevel@tonic-gate #include <ctype.h>
300Sstevel@tonic-gate #include <libdevinfo.h>
310Sstevel@tonic-gate #include <mdiox.h>
320Sstevel@tonic-gate #include <meta.h>
330Sstevel@tonic-gate #include "meta_repartition.h"
340Sstevel@tonic-gate #include "meta_set_prv.h"
350Sstevel@tonic-gate #include <stdio.h>
360Sstevel@tonic-gate #include <stdlib.h>
37734Smw145384 #include <strings.h>
380Sstevel@tonic-gate #include <sys/lvm/md_mddb.h>
390Sstevel@tonic-gate #include <sys/lvm/md_names.h>
400Sstevel@tonic-gate #include <sys/lvm/md_crc.h>
41734Smw145384 #include <sys/lvm/md_convert.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate typedef struct did_list {
440Sstevel@tonic-gate 	void		*rdid;	/* real did if replicated set */
450Sstevel@tonic-gate 	void		*did;	/* did stored in lb */
460Sstevel@tonic-gate 	char		*devname;
470Sstevel@tonic-gate 	dev_t		dev;
480Sstevel@tonic-gate 	uint_t		did_index;
490Sstevel@tonic-gate 	char		*minor_name;
501945Sjeanm 	char		*driver_name;
511945Sjeanm 	int		available;
520Sstevel@tonic-gate 	struct did_list	*next;
530Sstevel@tonic-gate } did_list_t;
540Sstevel@tonic-gate 
550Sstevel@tonic-gate typedef struct replicated_disk {
560Sstevel@tonic-gate 	void			*old_devid;
570Sstevel@tonic-gate 	void 			*new_devid;
580Sstevel@tonic-gate 	struct replicated_disk	*next;
590Sstevel@tonic-gate } replicated_disk_t;
600Sstevel@tonic-gate 
610Sstevel@tonic-gate /*
620Sstevel@tonic-gate  * The current implementation limits the max device id length to 256 bytes.
63734Smw145384  * Should the max device id length be increased, this definition would have to
640Sstevel@tonic-gate  * be bumped up accordingly
650Sstevel@tonic-gate  */
660Sstevel@tonic-gate #define	MAX_DEVID_LEN		256
670Sstevel@tonic-gate 
680Sstevel@tonic-gate /*
690Sstevel@tonic-gate  * We store a global list of all the replicated disks in the system. In
700Sstevel@tonic-gate  * order to prevent us from performing a linear search on this list, we
710Sstevel@tonic-gate  * store the disks in a two dimensional sparse array. The disks are bucketed
720Sstevel@tonic-gate  * based on the length of their device ids.
730Sstevel@tonic-gate  */
740Sstevel@tonic-gate static replicated_disk_t *replicated_disk_list[MAX_DEVID_LEN + 1] = {NULL};
750Sstevel@tonic-gate 
760Sstevel@tonic-gate /*
770Sstevel@tonic-gate  * The list of replicated disks is built just once and this flag is set
780Sstevel@tonic-gate  * once it's done
790Sstevel@tonic-gate  */
801945Sjeanm int replicated_disk_list_built_pass1 = 0;
811945Sjeanm int replicated_disk_list_built_pass2 = 0;
821945Sjeanm int *replicated_disk_list_built;
831945Sjeanm 
841945Sjeanm static void free_did_list(did_list_t *did_listp);
850Sstevel@tonic-gate 
860Sstevel@tonic-gate /*
870Sstevel@tonic-gate  * Map logical blk to physical
880Sstevel@tonic-gate  *
890Sstevel@tonic-gate  * This is based on the routine of the same name in the md kernel module (see
900Sstevel@tonic-gate  * file md_mddb.c), with the following caveats:
910Sstevel@tonic-gate  *
920Sstevel@tonic-gate  * - The kernel routine works on in core master blocks, or mddb_mb_ic_t; this
930Sstevel@tonic-gate  * routine works instead on the mddb_mb_t read directly from the disk
940Sstevel@tonic-gate  */
95734Smw145384 daddr_t
getphysblk(mddb_block_t blk,mddb_mb_t * mbp)960Sstevel@tonic-gate getphysblk(
970Sstevel@tonic-gate 	mddb_block_t	blk,
980Sstevel@tonic-gate 	mddb_mb_t	*mbp
990Sstevel@tonic-gate )
1000Sstevel@tonic-gate {
1010Sstevel@tonic-gate 	/*
1020Sstevel@tonic-gate 	 * Sanity check: is the block within range?  If so, we then assume
1030Sstevel@tonic-gate 	 * that the block range map in the master block is valid and
1040Sstevel@tonic-gate 	 * consistent with the block count.  Unfortunately, there is no
1050Sstevel@tonic-gate 	 * reliable way to validate this assumption.
1060Sstevel@tonic-gate 	 */
1070Sstevel@tonic-gate 	if (blk >= mbp->mb_blkcnt || blk >= mbp->mb_blkmap.m_consecutive)
1080Sstevel@tonic-gate 		return ((daddr_t)-1);
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 	return (mbp->mb_blkmap.m_firstblk + blk);
1110Sstevel@tonic-gate }
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate /*
1160Sstevel@tonic-gate  * drive_append()
1170Sstevel@tonic-gate  *
1180Sstevel@tonic-gate  * Append to tail of linked list of md_im_drive_info_t.
1190Sstevel@tonic-gate  *
1200Sstevel@tonic-gate  * Will allocate space for new node and copy args into new space.
1210Sstevel@tonic-gate  *
1220Sstevel@tonic-gate  * Returns pointer to new node.
1230Sstevel@tonic-gate  */
1240Sstevel@tonic-gate static md_im_drive_info_t *
drive_append(md_im_drive_info_t ** midpp,mddrivename_t * dnp,did_list_t * nonrep_did_listp,minor_t mnum,md_timeval32_t timestamp,md_im_replica_info_t * mirp)1250Sstevel@tonic-gate drive_append(
1260Sstevel@tonic-gate 	md_im_drive_info_t	**midpp,
1270Sstevel@tonic-gate 	mddrivename_t		*dnp,
1281945Sjeanm 	did_list_t		*nonrep_did_listp,
1291945Sjeanm 	minor_t			mnum,
1300Sstevel@tonic-gate 	md_timeval32_t		timestamp,
1310Sstevel@tonic-gate 	md_im_replica_info_t	*mirp
1320Sstevel@tonic-gate )
1330Sstevel@tonic-gate {
1340Sstevel@tonic-gate 	md_im_drive_info_t	*midp;
1350Sstevel@tonic-gate 	int			o_devid_sz;
1361945Sjeanm 	int			devid_sz;
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	for (; (*midpp != NULL); midpp = &((*midpp)->mid_next))
1390Sstevel@tonic-gate 		;
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	midp = *midpp = Zalloc(sizeof (md_im_drive_info_t));
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	midp->mid_dnp = dnp;
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	/*
1461945Sjeanm 	 * If rdid is not NULL then we know we are dealing with
1470Sstevel@tonic-gate 	 * replicated diskset case. 'devid_sz' will always be the
1481945Sjeanm 	 * size of a valid devid which can be 'did' or 'rdid'
1490Sstevel@tonic-gate 	 */
1501945Sjeanm 
1511945Sjeanm 	if (nonrep_did_listp->rdid) {
1521945Sjeanm 		devid_sz = devid_sizeof(nonrep_did_listp->rdid);
1531945Sjeanm 		midp->mid_devid = (void *)Malloc(devid_sz);
1541945Sjeanm 		(void) memcpy(midp->mid_devid, nonrep_did_listp->rdid,
1551945Sjeanm 		    devid_sz);
1560Sstevel@tonic-gate 		/*
1570Sstevel@tonic-gate 		 * Also need to store the 'other' devid
1580Sstevel@tonic-gate 		 */
1591945Sjeanm 		o_devid_sz = devid_sizeof((ddi_devid_t)(nonrep_did_listp->did));
1600Sstevel@tonic-gate 		midp->mid_o_devid = (void *)Malloc(o_devid_sz);
1611945Sjeanm 		(void) memcpy(midp->mid_o_devid, nonrep_did_listp->did,
1621945Sjeanm 		    o_devid_sz);
1630Sstevel@tonic-gate 		midp->mid_o_devid_sz = o_devid_sz;
1640Sstevel@tonic-gate 	} else {
1651945Sjeanm 		devid_sz = devid_sizeof(nonrep_did_listp->did);
1661945Sjeanm 		midp->mid_devid = (void *)Malloc(devid_sz);
1670Sstevel@tonic-gate 		/*
1680Sstevel@tonic-gate 		 * In the case of regular diskset, midp->mid_o_devid
1690Sstevel@tonic-gate 		 * will be a NULL pointer
1700Sstevel@tonic-gate 		 */
1711945Sjeanm 		(void) memcpy(midp->mid_devid, nonrep_did_listp->did, devid_sz);
1720Sstevel@tonic-gate 	}
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	midp->mid_devid_sz = devid_sz;
1750Sstevel@tonic-gate 	midp->mid_setcreatetimestamp = timestamp;
1761945Sjeanm 	midp->mid_available = nonrep_did_listp->available;
1771945Sjeanm 	if (nonrep_did_listp->minor_name) {
1781945Sjeanm 		(void) strlcpy(midp->mid_minor_name,
1791945Sjeanm 		    nonrep_did_listp->minor_name, MDDB_MINOR_NAME_MAX);
1801945Sjeanm 	}
1811945Sjeanm 	midp->mid_mnum = mnum;
1821945Sjeanm 	if (nonrep_did_listp->driver_name)
1831945Sjeanm 		midp->mid_driver_name = Strdup(nonrep_did_listp->driver_name);
1840Sstevel@tonic-gate 	midp->mid_replicas = mirp;
1851945Sjeanm 	if (nonrep_did_listp->devname)
1861945Sjeanm 		midp->mid_devname = Strdup(nonrep_did_listp->devname);
1870Sstevel@tonic-gate 	return (midp);
1880Sstevel@tonic-gate }
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate /*
1930Sstevel@tonic-gate  * drive_append_wrapper()
1940Sstevel@tonic-gate  *
1950Sstevel@tonic-gate  * Constant time append wrapper; the append function will always walk the list,
1960Sstevel@tonic-gate  * this will take a tail argument and use the append function on just the tail
1970Sstevel@tonic-gate  * node, doing the appropriate old-tail-next-pointer bookkeeping.
1980Sstevel@tonic-gate  */
1990Sstevel@tonic-gate static md_im_drive_info_t **
drive_append_wrapper(md_im_drive_info_t ** tailpp,mddrivename_t * dnp,did_list_t * nonrep_did_listp,minor_t mnum,md_timeval32_t timestamp,md_im_replica_info_t * mirp)2000Sstevel@tonic-gate drive_append_wrapper(
2010Sstevel@tonic-gate 	md_im_drive_info_t	**tailpp,
2020Sstevel@tonic-gate 	mddrivename_t		*dnp,
2031945Sjeanm 	did_list_t		*nonrep_did_listp,
2041945Sjeanm 	minor_t			mnum,
2050Sstevel@tonic-gate 	md_timeval32_t		timestamp,
2060Sstevel@tonic-gate 	md_im_replica_info_t	*mirp
2070Sstevel@tonic-gate )
2080Sstevel@tonic-gate {
2091945Sjeanm 	(void) drive_append(tailpp, dnp, nonrep_did_listp, mnum, timestamp,
2101945Sjeanm 	    mirp);
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	if ((*tailpp)->mid_next == NULL)
2130Sstevel@tonic-gate 		return (tailpp);
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	return (&((*tailpp)->mid_next));
2160Sstevel@tonic-gate }
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate /*
2210Sstevel@tonic-gate  * replica_append()
2220Sstevel@tonic-gate  *
2230Sstevel@tonic-gate  * Append to tail of linked list of md_im_replica_info_t.
2240Sstevel@tonic-gate  *
2250Sstevel@tonic-gate  * Will allocate space for new node and copy args into new space.
2260Sstevel@tonic-gate  *
2270Sstevel@tonic-gate  * Returns pointer to new node.
2280Sstevel@tonic-gate  */
2290Sstevel@tonic-gate static md_im_replica_info_t *
replica_append(md_im_replica_info_t ** mirpp,int flags,daddr32_t offset,daddr32_t length,md_timeval32_t timestamp)2300Sstevel@tonic-gate replica_append(
2310Sstevel@tonic-gate 	md_im_replica_info_t	**mirpp,
2320Sstevel@tonic-gate 	int			flags,
2330Sstevel@tonic-gate 	daddr32_t		offset,
2340Sstevel@tonic-gate 	daddr32_t		length,
2350Sstevel@tonic-gate 	md_timeval32_t		timestamp
2360Sstevel@tonic-gate )
2370Sstevel@tonic-gate {
2380Sstevel@tonic-gate 	md_im_replica_info_t	*mirp;
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	for (; (*mirpp != NULL); mirpp = &((*mirpp)->mir_next))
2410Sstevel@tonic-gate 		;
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	mirp = *mirpp = Zalloc(sizeof (md_im_replica_info_t));
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	mirp->mir_flags = flags;
2460Sstevel@tonic-gate 	mirp->mir_offset = offset;
2470Sstevel@tonic-gate 	mirp->mir_length = length;
2480Sstevel@tonic-gate 	mirp->mir_timestamp = timestamp;
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	return (mirp);
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate /*
2570Sstevel@tonic-gate  * replica_append_wrapper()
2580Sstevel@tonic-gate  *
2590Sstevel@tonic-gate  * Constant time append wrapper; the append function will always walk the list,
2600Sstevel@tonic-gate  * this will take a tail argument and use the append function on just the tail
2610Sstevel@tonic-gate  * node, doing the appropriate old-tail-next-pointer bookkeeping.
2620Sstevel@tonic-gate  */
2630Sstevel@tonic-gate static md_im_replica_info_t **
replica_append_wrapper(md_im_replica_info_t ** tailpp,int flags,daddr32_t offset,daddr32_t length,md_timeval32_t timestamp)2640Sstevel@tonic-gate replica_append_wrapper(
2650Sstevel@tonic-gate 	md_im_replica_info_t	**tailpp,
2660Sstevel@tonic-gate 	int			flags,
2670Sstevel@tonic-gate 	daddr32_t		offset,
2680Sstevel@tonic-gate 	daddr32_t		length,
2690Sstevel@tonic-gate 	md_timeval32_t		timestamp
2700Sstevel@tonic-gate )
2710Sstevel@tonic-gate {
2720Sstevel@tonic-gate 	(void) replica_append(tailpp, flags, offset, length, timestamp);
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	if ((*tailpp)->mir_next == NULL)
2750Sstevel@tonic-gate 		return (tailpp);
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	return (&(*tailpp)->mir_next);
2780Sstevel@tonic-gate }
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate /*
2810Sstevel@tonic-gate  * map_replica_disk()
2820Sstevel@tonic-gate  *
2830Sstevel@tonic-gate  * Searches the device id list for a specific
2840Sstevel@tonic-gate  * disk based on the locator block device id array index.
2850Sstevel@tonic-gate  *
2860Sstevel@tonic-gate  * Returns a pointer to the did_list node if a match was
2870Sstevel@tonic-gate  * found or NULL otherwise.
2880Sstevel@tonic-gate  */
2890Sstevel@tonic-gate static did_list_t *
map_replica_disk(did_list_t * did_listp,int did_index)2900Sstevel@tonic-gate map_replica_disk(
2910Sstevel@tonic-gate 	did_list_t	*did_listp,
2920Sstevel@tonic-gate 	int		did_index
2930Sstevel@tonic-gate )
2940Sstevel@tonic-gate {
2950Sstevel@tonic-gate 	did_list_t	*tailp = did_listp;
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	while (tailp != NULL) {
2980Sstevel@tonic-gate 		if (tailp->did_index == did_index)
2990Sstevel@tonic-gate 			return (tailp);
3000Sstevel@tonic-gate 		tailp = tailp->next;
3010Sstevel@tonic-gate 	}
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	/* not found, return failure */
3040Sstevel@tonic-gate 	return (NULL);
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate /*
3080Sstevel@tonic-gate  * replicated_list_lookup()
3090Sstevel@tonic-gate  *
3100Sstevel@tonic-gate  * looks up a replicated disk entry in the global replicated disk list
3110Sstevel@tonic-gate  * based upon the length of that disk's device id. returns the new device id
3120Sstevel@tonic-gate  * for the disk.
3130Sstevel@tonic-gate  * If you store the returned devid you must create a local copy.
3140Sstevel@tonic-gate  */
3151945Sjeanm void *
replicated_list_lookup(uint_t devid_len,void * old_devid)3160Sstevel@tonic-gate replicated_list_lookup(
3170Sstevel@tonic-gate 	uint_t	devid_len,
3180Sstevel@tonic-gate 	void	*old_devid
3190Sstevel@tonic-gate )
3200Sstevel@tonic-gate {
3210Sstevel@tonic-gate 	replicated_disk_t *head = NULL;
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	assert(devid_len <= MAX_DEVID_LEN);
3240Sstevel@tonic-gate 	head = replicated_disk_list[devid_len];
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	if (head == NULL)
3270Sstevel@tonic-gate 		return (NULL);
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 	do {
3300Sstevel@tonic-gate 		if (devid_compare((ddi_devid_t)old_devid,
3310Sstevel@tonic-gate 			(ddi_devid_t)head->old_devid) == 0)
3320Sstevel@tonic-gate 			return (head->new_devid);
3330Sstevel@tonic-gate 		head = head->next;
3340Sstevel@tonic-gate 	} while (head != NULL);
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	return (NULL);
3370Sstevel@tonic-gate }
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate /*
3400Sstevel@tonic-gate  * replicated_list_insert()
3410Sstevel@tonic-gate  *
3420Sstevel@tonic-gate  * inserts a replicated disk entry into the global replicated disk list
3430Sstevel@tonic-gate  */
3440Sstevel@tonic-gate static void
replicated_list_insert(size_t old_devid_len,void * old_devid,void * new_devid)3450Sstevel@tonic-gate replicated_list_insert(
3460Sstevel@tonic-gate 	size_t	old_devid_len,
3470Sstevel@tonic-gate 	void	*old_devid,
3480Sstevel@tonic-gate 	void	*new_devid
3490Sstevel@tonic-gate )
3500Sstevel@tonic-gate {
3510Sstevel@tonic-gate 	replicated_disk_t	*repl_disk, **first_entry;
3520Sstevel@tonic-gate 	void			*repl_old_devid = NULL;
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 	assert(old_devid_len <= MAX_DEVID_LEN);
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 	repl_disk = Zalloc(sizeof (replicated_disk_t));
3570Sstevel@tonic-gate 	repl_old_devid = Zalloc(old_devid_len);
3580Sstevel@tonic-gate 	(void) memcpy(repl_old_devid, (void *)old_devid, old_devid_len);
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	repl_disk->old_devid = repl_old_devid;
3610Sstevel@tonic-gate 	repl_disk->new_devid = new_devid;
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 	first_entry = &replicated_disk_list[old_devid_len];
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	if (*first_entry == NULL) {
3660Sstevel@tonic-gate 		*first_entry = repl_disk;
3670Sstevel@tonic-gate 		return;
3680Sstevel@tonic-gate 	}
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	repl_disk->next = *first_entry;
3710Sstevel@tonic-gate 	replicated_disk_list[old_devid_len] = repl_disk;
3720Sstevel@tonic-gate }
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate /*
3750Sstevel@tonic-gate  * get_replica_disks()
3760Sstevel@tonic-gate  *
3770Sstevel@tonic-gate  * Will step through the locator records in the supplied locator block, and add
3780Sstevel@tonic-gate  * each one with an active replica to a supplied list of md_im_drive_info_t, and
3790Sstevel@tonic-gate  * add the appropriate replicas to the md_im_replica_info_t contained therein.
3800Sstevel@tonic-gate  */
3810Sstevel@tonic-gate static void
get_replica_disks(md_im_set_desc_t * misp,did_list_t * did_listp,mddb_mb_t * mb,mddb_lb_t * lbp,md_error_t * ep)3820Sstevel@tonic-gate get_replica_disks(
3830Sstevel@tonic-gate 	md_im_set_desc_t	*misp,
3840Sstevel@tonic-gate 	did_list_t		*did_listp,
3850Sstevel@tonic-gate 	mddb_mb_t		*mb,
3860Sstevel@tonic-gate 	mddb_lb_t		*lbp,
3871945Sjeanm 	md_error_t		*ep
3880Sstevel@tonic-gate )
3890Sstevel@tonic-gate {
3900Sstevel@tonic-gate 	mddrivename_t		*dnp;
3910Sstevel@tonic-gate 	int			indx, on_list;
3920Sstevel@tonic-gate 	mdsetname_t		*sp = metasetname(MD_LOCAL_NAME, ep);
3930Sstevel@tonic-gate 	int			flags;
3940Sstevel@tonic-gate 	did_list_t		*replica_disk;
3950Sstevel@tonic-gate 	daddr32_t		offset;
3960Sstevel@tonic-gate 	daddr32_t		length;
3970Sstevel@tonic-gate 	md_timeval32_t		timestamp;
3980Sstevel@tonic-gate 	md_im_replica_info_t	**mirpp = NULL;
3990Sstevel@tonic-gate 	md_im_drive_info_t	**midpp = &misp->mis_drives;
4000Sstevel@tonic-gate 	md_im_drive_info_t	*midp;
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	for (indx = 0; indx < lbp->lb_loccnt; indx++) {
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 		on_list = 0;
4051945Sjeanm 		if ((lbp->lb_locators[indx].l_flags == 0) ||
4061945Sjeanm 		    (lbp->lb_locators[indx].l_flags & MDDB_F_DELETED))
4071945Sjeanm 			continue;
4081945Sjeanm 
4091945Sjeanm 		/*
4101945Sjeanm 		 * search the device id list for a
4111945Sjeanm 		 * specific ctds based on the locator
4121945Sjeanm 		 * block device id array index.
4131945Sjeanm 		 */
4141945Sjeanm 		replica_disk = map_replica_disk(did_listp, indx);
4151945Sjeanm 
4161945Sjeanm 		assert(replica_disk != NULL);
4171945Sjeanm 
4181945Sjeanm 
4191945Sjeanm 		/*
4201945Sjeanm 		 * metadrivename() can fail for a slice name
4211945Sjeanm 		 * if there is not an existing mddrivename_t.
4221945Sjeanm 		 * So we use metadiskname() to strip the slice
4231945Sjeanm 		 * number.
4241945Sjeanm 		 */
4251945Sjeanm 		dnp = metadrivename(&sp, metadiskname(replica_disk->devname),
4261945Sjeanm 		    ep);
4271945Sjeanm 
4281945Sjeanm 		for (midp = misp->mis_drives; midp != NULL;
4291945Sjeanm 			midp = midp->mid_next) {
4301945Sjeanm 			if (dnp == midp->mid_dnp) {
4311945Sjeanm 				/*
4321945Sjeanm 				 * You could get a dnp match, but if 1 disk
4331945Sjeanm 				 * is unavailable and the other isn't, they
4341945Sjeanm 				 * will have the same dnp due
4351945Sjeanm 				 * to the name being the same, but in fact
4361945Sjeanm 				 * are different disks.
4371945Sjeanm 				 */
4381945Sjeanm 				if (midp->mid_available ==
4391945Sjeanm 				    replica_disk->available) {
4400Sstevel@tonic-gate 					on_list = 1;
4410Sstevel@tonic-gate 					mirpp = &midp->mid_replicas;
4420Sstevel@tonic-gate 					break;
4430Sstevel@tonic-gate 				}
4440Sstevel@tonic-gate 			}
4451945Sjeanm 		}
4461945Sjeanm 
4471945Sjeanm 		/*
4481945Sjeanm 		 * New on the list so add it
4491945Sjeanm 		 */
4501945Sjeanm 		if (!on_list) {
4511945Sjeanm 			mddb_mb_t	*mbp;
4521945Sjeanm 			uint_t		sliceno;
4531945Sjeanm 			mdname_t	*rsp;
4541945Sjeanm 			int		fd = -1;
4551945Sjeanm 
4561945Sjeanm 			mbp = Malloc(DEV_BSIZE);
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 			/*
4591945Sjeanm 			 * If the disk isn't available, we don't
4601945Sjeanm 			 * want to try to read from it.
4610Sstevel@tonic-gate 			 */
4621945Sjeanm 			if (replica_disk->available == MD_IM_DISK_AVAILABLE) {
4630Sstevel@tonic-gate 				/* determine the replica slice */
4640Sstevel@tonic-gate 				if (meta_replicaslice(dnp, &sliceno,
4650Sstevel@tonic-gate 				    ep) != 0) {
4660Sstevel@tonic-gate 					Free(mbp);
4670Sstevel@tonic-gate 					continue;
4680Sstevel@tonic-gate 				}
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 				/*
4710Sstevel@tonic-gate 				 * if the replica slice size is zero,
4720Sstevel@tonic-gate 				 * don't bother opening
4730Sstevel@tonic-gate 				 */
4740Sstevel@tonic-gate 				if (dnp->vtoc.parts[sliceno].size == 0) {
4750Sstevel@tonic-gate 					Free(mbp);
4760Sstevel@tonic-gate 					continue;
4770Sstevel@tonic-gate 				}
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 				if ((rsp = metaslicename(dnp, sliceno,
4800Sstevel@tonic-gate 				    ep)) == NULL) {
4810Sstevel@tonic-gate 					Free(mbp);
4820Sstevel@tonic-gate 					continue;
4830Sstevel@tonic-gate 				}
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 				if ((fd = open(rsp->rname,
4860Sstevel@tonic-gate 				    O_RDONLY| O_NDELAY)) < 0) {
4870Sstevel@tonic-gate 					Free(mbp);
4880Sstevel@tonic-gate 					continue;
4890Sstevel@tonic-gate 				}
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 				/*
4920Sstevel@tonic-gate 				 * a drive may not have a master block
4930Sstevel@tonic-gate 				 */
4940Sstevel@tonic-gate 				if (read_master_block(ep, fd, mbp,
4950Sstevel@tonic-gate 				    DEV_BSIZE) <= 0) {
4960Sstevel@tonic-gate 					mdclrerror(ep);
4970Sstevel@tonic-gate 					Free(mbp);
4980Sstevel@tonic-gate 					(void) close(fd);
4990Sstevel@tonic-gate 					continue;
5000Sstevel@tonic-gate 				}
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 				(void) close(fd);
5030Sstevel@tonic-gate 			}
5041945Sjeanm 			midpp = drive_append_wrapper(midpp, dnp,
5051945Sjeanm 			    replica_disk,
5061945Sjeanm 			    meta_getminor(replica_disk->dev),
5071945Sjeanm 			    mbp->mb_setcreatetime, NULL);
5081945Sjeanm 			mirpp = &((*midpp)->mid_replicas);
5091945Sjeanm 			Free(mbp);
5101945Sjeanm 		}
5111945Sjeanm 
5121945Sjeanm 		/*
5131945Sjeanm 		 * For either of these assertions to fail, it implies
5141945Sjeanm 		 * a NULL return from metadrivename() above.  Since
5151945Sjeanm 		 * the args came from a presumed valid locator block,
5161945Sjeanm 		 * that's Bad.
5171945Sjeanm 		 */
5181945Sjeanm 		assert(midpp != NULL);
5191945Sjeanm 		assert(mirpp != NULL);
5201945Sjeanm 
5211945Sjeanm 		/*
5221945Sjeanm 		 * Extract the parameters describing this replica.
5231945Sjeanm 		 *
5241945Sjeanm 		 * The magic "1" in the length calculation accounts
5251945Sjeanm 		 * for the length of the master block, in addition to
5261945Sjeanm 		 * the block count it describes.  (The master block
5271945Sjeanm 		 * will always take up one block on the disk, and
5281945Sjeanm 		 * there will always only be one master block per
5291945Sjeanm 		 * replica, even though much of the code is structured
5301945Sjeanm 		 * to handle noncontiguous replicas.)
5311945Sjeanm 		 */
5321945Sjeanm 		flags = lbp->lb_locators[indx].l_flags;
5331945Sjeanm 		offset = lbp->lb_locators[indx].l_blkno;
5341945Sjeanm 		length = mb->mb_blkcnt + 1;
5351945Sjeanm 		timestamp = mb->mb_setcreatetime;
5361945Sjeanm 
5371945Sjeanm 		mirpp = replica_append_wrapper(mirpp, flags,
5381945Sjeanm 			offset, length, timestamp);
5391945Sjeanm 
5401945Sjeanm 		/*
5411945Sjeanm 		 * If we're here it means -
5421945Sjeanm 		 *
5431945Sjeanm 		 * we've added the disk to the list of
5441945Sjeanm 		 *    disks.
5451945Sjeanm 		 */
5461945Sjeanm 
5471945Sjeanm 		/*
5481945Sjeanm 		 * We need to bump up the number of active
5491945Sjeanm 		 * replica count for each such replica that is
5501945Sjeanm 		 * active so that it can be used later for replica
5511945Sjeanm 		 * quorum check.
5521945Sjeanm 		 */
5531945Sjeanm 		if (flags & MDDB_F_ACTIVE) {
5540Sstevel@tonic-gate 			misp->mis_active_replicas++;
5550Sstevel@tonic-gate 		}
5560Sstevel@tonic-gate 	}
5570Sstevel@tonic-gate }
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 
560734Smw145384 /*
561734Smw145384  * append_pnm_rec()
562734Smw145384  *
563734Smw145384  * Append pnm_rec_t entry to list of physical devices in the diskset.  Entry
564734Smw145384  * contains a mapping of n_key in NM namespace(or min_key in DID_NM namespace)
565734Smw145384  * to name of the physical device.  This list will be used to ensure that the
566734Smw145384  * correct names of the physical devices are printed in the metastat output--the
567734Smw145384  * NM namespace might have stale information about where the physical devices
568734Smw145384  * were previously located when the diskset was last active.
569734Smw145384  */
570734Smw145384 static void
append_pnm_rec(pnm_rec_t ** pnm,mdkey_t min_key,char * n_name)571734Smw145384 append_pnm_rec(
572734Smw145384 	pnm_rec_t	**pnm,
573734Smw145384 	mdkey_t		min_key,
574734Smw145384 	char		*n_name
575734Smw145384 )
576734Smw145384 {
577734Smw145384 	pnm_rec_t 	*tmp_pnm;
578734Smw145384 	char 		*p;
579734Smw145384 	int 		len;
580734Smw145384 
581734Smw145384 	if ((p = strrchr(n_name, '/')) != NULL)
582734Smw145384 		p++;
583734Smw145384 
584734Smw145384 	/*
585734Smw145384 	 * Allocates pnm_rec_t record for the physical
586734Smw145384 	 * device.
587734Smw145384 	 */
588734Smw145384 	len = strlen(p) + 1; /* Length of name plus Null term */
589734Smw145384 	tmp_pnm  = Malloc(sizeof (pnm_rec_t) + len);
590734Smw145384 	(void) strncpy(tmp_pnm->n_name, p, len);
591734Smw145384 	tmp_pnm->n_key = min_key;
592734Smw145384 
593734Smw145384 	/*
594734Smw145384 	 * Adds new element to head of pnm_rec_t list.
595734Smw145384 	 */
596734Smw145384 	if (*pnm == NULL) {
597734Smw145384 		tmp_pnm->next = NULL;
598734Smw145384 		*pnm = tmp_pnm;
599734Smw145384 	} else {
600734Smw145384 		tmp_pnm->next = *pnm;
601734Smw145384 		*pnm = tmp_pnm;
602734Smw145384 	}
603734Smw145384 }
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate /*
606734Smw145384  * free_pnm_rec_list()
607734Smw145384  *
608734Smw145384  * Freeing all pnm_rec_t entries on the list of physical devices in the
609734Smw145384  * diskset.
610734Smw145384  */
611734Smw145384 void
free_pnm_rec_list(pnm_rec_t ** pnm)612734Smw145384 free_pnm_rec_list(pnm_rec_t **pnm)
613734Smw145384 {
614734Smw145384 	pnm_rec_t	*tmp_pnm, *rm_pnm;
615734Smw145384 
616734Smw145384 	for (tmp_pnm = *pnm; tmp_pnm != NULL; ) {
617734Smw145384 		rm_pnm = tmp_pnm;
618734Smw145384 		tmp_pnm = tmp_pnm->next;
619734Smw145384 		Free(rm_pnm);
620734Smw145384 	}
621734Smw145384 
622734Smw145384 	*pnm = NULL;
623734Smw145384 }
624734Smw145384 
625734Smw145384 
626734Smw145384 /*
627734Smw145384  * get_disks_from_didnamespace()
628734Smw145384  * This function was origionally called: get_nonreplica_disks()
6290Sstevel@tonic-gate  *
6300Sstevel@tonic-gate  * Extracts the disks without replicas from the locator name space and adds them
6310Sstevel@tonic-gate  * to the supplied list of md_im_drive_info_t.
632734Smw145384  * If the print verbose option was given then this function will also
633734Smw145384  * correct the nm namespace so that the n_name is the right ctd name
6340Sstevel@tonic-gate  */
6350Sstevel@tonic-gate static void
get_disks_from_didnamespace(md_im_set_desc_t * misp,pnm_rec_t ** pnm,mddb_rb_t * nm,mddb_rb_t * shrnm,mddb_rb_t * did_nm,mddb_rb_t * did_shrnm,uint_t imp_flags,int replicated,md_error_t * ep)636734Smw145384 get_disks_from_didnamespace(
6370Sstevel@tonic-gate 	md_im_set_desc_t	*misp,
638734Smw145384 	pnm_rec_t		**pnm,
6391945Sjeanm 	mddb_rb_t		*nm,
6401945Sjeanm 	mddb_rb_t		*shrnm,
6410Sstevel@tonic-gate 	mddb_rb_t		*did_nm,
6420Sstevel@tonic-gate 	mddb_rb_t		*did_shrnm,
643734Smw145384 	uint_t 			imp_flags,
644734Smw145384 	int			replicated,
645734Smw145384 	md_error_t		*ep
6460Sstevel@tonic-gate )
6470Sstevel@tonic-gate {
6480Sstevel@tonic-gate 	char			*search_path = "/dev";
6490Sstevel@tonic-gate 	devid_nmlist_t		*nmlist;
6500Sstevel@tonic-gate 	md_im_drive_info_t	*midp, **midpp = &misp->mis_drives;
6510Sstevel@tonic-gate 	mddrivename_t		*dnp;
6520Sstevel@tonic-gate 	mdsetname_t		*sp = metasetname(MD_LOCAL_NAME, ep);
6530Sstevel@tonic-gate 	mddb_rb_t		*rbp_did = did_nm;
6540Sstevel@tonic-gate 	mddb_rb_t		*rbp_did_shr = did_shrnm;
6551945Sjeanm 	mddb_rb_t		*rbp_nm = nm;
6561945Sjeanm 	mddb_rb_t		*rbp_shr_nm = shrnm;
6570Sstevel@tonic-gate 	int			on_list = 0;
6580Sstevel@tonic-gate 	struct devid_min_rec	*did_rec;
6590Sstevel@tonic-gate 	struct devid_shr_rec	*did_shr_rec;
6601945Sjeanm 	struct nm_rec		*namesp_rec;
6611945Sjeanm 	struct nm_shr_rec	*namesp_shr_rec;
6620Sstevel@tonic-gate 	struct did_shr_name	*did;
6630Sstevel@tonic-gate 	struct did_min_name	*min;
6640Sstevel@tonic-gate 	void			*r_did;	/* NULL if not a replicated diskset */
6650Sstevel@tonic-gate 	void			*valid_did;
6661945Sjeanm 	int			avail = 0;
6671945Sjeanm 	struct nm_name		*nmp;
6681945Sjeanm 	struct nm_shared_name	*snmp;
6691945Sjeanm 	mdkey_t			drv_key, key, dev_key;
6701945Sjeanm 	minor_t			mnum = 0;
6711945Sjeanm 	did_list_t		*nonrep_did_listp;
6721945Sjeanm 	size_t			used_size, offset;
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 	/*
6750Sstevel@tonic-gate 	 * We got a pointer to an mddb record, which we expect to contain a
6760Sstevel@tonic-gate 	 * name record; extract the pointer thereto.
6770Sstevel@tonic-gate 	 */
6780Sstevel@tonic-gate 	/* LINTED */
6790Sstevel@tonic-gate 	did_rec = (struct devid_min_rec *)((caddr_t)(&rbp_did->rb_data));
6800Sstevel@tonic-gate 	/* LINTED */
6810Sstevel@tonic-gate 	did_shr_rec = (struct devid_shr_rec *)
6820Sstevel@tonic-gate 	    ((caddr_t)(&rbp_did_shr->rb_data));
6831945Sjeanm 	/* LINTED */
6841945Sjeanm 	namesp_rec = (struct nm_rec *)((caddr_t)(&rbp_nm->rb_data));
6851945Sjeanm 	/* LINTED */
6861945Sjeanm 	namesp_shr_rec = (struct nm_shr_rec *)((caddr_t)(&rbp_shr_nm->rb_data));
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	/*
6890Sstevel@tonic-gate 	 * Skip the nm_rec_hdr and iterate on the array of struct minor_name
6900Sstevel@tonic-gate 	 * at the end of the devid_min_rec
6910Sstevel@tonic-gate 	 */
6920Sstevel@tonic-gate 	for (min = &did_rec->minor_name[0]; min->min_devid_key != 0;
6930Sstevel@tonic-gate 	    /* LINTED */
6940Sstevel@tonic-gate 	    min = (struct did_min_name *)((char *)min + DID_NAMSIZ(min))) {
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 		on_list = 0;
6970Sstevel@tonic-gate 		r_did = NULL;
6981945Sjeanm 		nonrep_did_listp = Zalloc(sizeof (struct did_list));
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate 		/*
7011945Sjeanm 		 * For a given DID_NM key, locate the corresponding device
7020Sstevel@tonic-gate 		 * id from DID_NM_SHR
7030Sstevel@tonic-gate 		 */
7040Sstevel@tonic-gate 		for (did = &did_shr_rec->device_id[0]; did->did_key != 0;
7050Sstevel@tonic-gate 		    /* LINTED */
7060Sstevel@tonic-gate 		    did = (struct did_shr_name *)
7070Sstevel@tonic-gate 		    ((char *)did + DID_SHR_NAMSIZ(did))) {
7080Sstevel@tonic-gate 			/*
7090Sstevel@tonic-gate 			 * We got a match, this is the device id we're
7100Sstevel@tonic-gate 			 * looking for
7110Sstevel@tonic-gate 			 */
7120Sstevel@tonic-gate 			if (min->min_devid_key == did->did_key)
7130Sstevel@tonic-gate 				break;
7140Sstevel@tonic-gate 		}
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 		if (did->did_key == 0) {
7170Sstevel@tonic-gate 			/* we didn't find a match */
7180Sstevel@tonic-gate 			assert(did->did_key != 0);
7190Sstevel@tonic-gate 			md_exit(NULL, 1);
7200Sstevel@tonic-gate 		}
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 		/*
7230Sstevel@tonic-gate 		 * If replicated diskset
7240Sstevel@tonic-gate 		 */
7250Sstevel@tonic-gate 		if (replicated) {
7261945Sjeanm 			size_t		new_devid_len, old_devid_len;
7270Sstevel@tonic-gate 			char		*temp;
7280Sstevel@tonic-gate 			/*
7290Sstevel@tonic-gate 			 * In this case, did->did_devid will
7300Sstevel@tonic-gate 			 * be invalid so lookup the real one
7310Sstevel@tonic-gate 			 */
7320Sstevel@tonic-gate 			temp = replicated_list_lookup(did->did_size,
7330Sstevel@tonic-gate 			    did->did_devid);
7341945Sjeanm 			if (temp == NULL) {
7351945Sjeanm 				/* we have a partial replicated set, fake it */
7361945Sjeanm 				new_devid_len = did->did_size;
7371945Sjeanm 				r_did = Zalloc(new_devid_len);
7381945Sjeanm 				(void) memcpy(r_did, did->did_devid,
7391945Sjeanm 				    new_devid_len);
7401945Sjeanm 			} else {
7411945Sjeanm 				new_devid_len = devid_sizeof((ddi_devid_t)temp);
7421945Sjeanm 				r_did = Zalloc(new_devid_len);
7431945Sjeanm 				(void) memcpy(r_did, temp, new_devid_len);
7441945Sjeanm 			}
7450Sstevel@tonic-gate 			valid_did = r_did;
7461945Sjeanm 			nonrep_did_listp->rdid = Zalloc(new_devid_len);
7471945Sjeanm 			(void) memcpy(nonrep_did_listp->rdid, r_did,
7481945Sjeanm 			    new_devid_len);
7491945Sjeanm 			old_devid_len =
7501945Sjeanm 			    devid_sizeof((ddi_devid_t)did->did_devid);
7511945Sjeanm 			nonrep_did_listp->did = Zalloc(old_devid_len);
7521945Sjeanm 			(void) memcpy((void *)nonrep_did_listp->did,
7531945Sjeanm 			    (void *)did->did_devid, old_devid_len);
7540Sstevel@tonic-gate 		} else {
7551945Sjeanm 			size_t		new_devid_len;
7561945Sjeanm 
7570Sstevel@tonic-gate 			valid_did = did->did_devid;
7581945Sjeanm 			new_devid_len =
7591945Sjeanm 			    devid_sizeof((ddi_devid_t)did->did_devid);
7601945Sjeanm 			nonrep_did_listp->did = Zalloc(new_devid_len);
7611945Sjeanm 			(void) memcpy((void *)nonrep_did_listp->did,
7621945Sjeanm 			    (void *)did->did_devid, new_devid_len);
7630Sstevel@tonic-gate 		}
7640Sstevel@tonic-gate 
7651945Sjeanm 		/*
7661945Sjeanm 		 * Get a ctds mapping for that device id.
7671945Sjeanm 		 * Since disk is being imported into this system,
7681945Sjeanm 		 * just use the first ctds in list.
7691945Sjeanm 		 */
7700Sstevel@tonic-gate 		if (meta_deviceid_to_nmlist(search_path,
7710Sstevel@tonic-gate 		    (ddi_devid_t)valid_did,
7720Sstevel@tonic-gate 		    &min->min_name[0], &nmlist) == 0) {
7731945Sjeanm 			/*
7741945Sjeanm 			 * We know the disk is available. Use the
7751945Sjeanm 			 * device information in nmlist.
7761945Sjeanm 			 */
7771945Sjeanm 			assert(nmlist[0].devname != NULL);
7781945Sjeanm 			nonrep_did_listp->devname = Strdup(nmlist[0].devname);
7791945Sjeanm 			nonrep_did_listp->available = MD_IM_DISK_AVAILABLE;
7801945Sjeanm 			avail = 0;
7811945Sjeanm 			mnum = meta_getminor(nmlist[0].dev);
7821945Sjeanm 			devid_free_nmlist(nmlist);
7831945Sjeanm 		} else {
784734Smw145384 			/*
7851945Sjeanm 			 * The disk is not available. That means we need to
7861945Sjeanm 			 * use the (old) device information stored in the
7871945Sjeanm 			 * namespace.
7881945Sjeanm 			 */
7891945Sjeanm 			/* search in nm space for a match */
7901945Sjeanm 			offset = sizeof (struct nm_rec) -
7911945Sjeanm 			    sizeof (struct nm_name);
7921945Sjeanm 			used_size =  namesp_rec->r_rec_hdr.r_used_size - offset;
7931945Sjeanm 			for (nmp = &namesp_rec->r_name[0]; nmp->n_key != 0;
7941945Sjeanm 			    /* LINTED */
7951945Sjeanm 			    nmp = (struct nm_name *)((char *)nmp +
7961945Sjeanm 			    NAMSIZ(nmp))) {
7971945Sjeanm 				if (nmp->n_key == min->min_key)
7981945Sjeanm 					break;
7991945Sjeanm 			    used_size -=  NAMSIZ(nmp);
8001945Sjeanm 			    if ((int)used_size <= 0) {
8011945Sjeanm 				md_exit(NULL, 1);
8021945Sjeanm 			    }
8031945Sjeanm 			}
8041945Sjeanm 
8051945Sjeanm 			if (nmp->n_key == 0) {
8061945Sjeanm 				assert(nmp->n_key != 0);
8071945Sjeanm 				md_exit(NULL, 1);
8081945Sjeanm 			}
8091945Sjeanm 			dev_key = nmp->n_dir_key;
8101945Sjeanm 			snmp = &namesp_shr_rec->sr_name[0];
8111945Sjeanm 			key = snmp->sn_key;
8121945Sjeanm 			/*
8131945Sjeanm 			 * Use the namespace n_dir_key to look in the
8141945Sjeanm 			 * shared namespace. When we find the matching
8151945Sjeanm 			 * key, that is the devname and minor number we
8161945Sjeanm 			 * want.
817734Smw145384 			 */
8181945Sjeanm 			offset = sizeof (struct nm_shr_rec) -
8191945Sjeanm 			    sizeof (struct nm_shared_name);
8201945Sjeanm 			used_size = namesp_shr_rec->sr_rec_hdr.r_used_size -
8211945Sjeanm 			    offset;
8221945Sjeanm 			while (key != 0) {
8231945Sjeanm 				if (dev_key == key) {
8241945Sjeanm 					/*
8251945Sjeanm 					 * This complicated looking series
8261945Sjeanm 					 * of code creates a devname of the
8271945Sjeanm 					 * form  <sn_name>/<n_name> which
8281945Sjeanm 					 * will look like /dev/dsk/c1t4d0s0.
8291945Sjeanm 					 */
8301945Sjeanm 					nonrep_did_listp->devname =
8311945Sjeanm 					    Zalloc(strlen(nmp->n_name) +
8321945Sjeanm 					    strlen(snmp->sn_name) + 2);
8331945Sjeanm 					(void) strlcpy(
8341945Sjeanm 					    nonrep_did_listp->devname,
8351945Sjeanm 					    snmp->sn_name,
8361945Sjeanm 					    strlen(snmp->sn_name));
8371945Sjeanm 					(void) strlcat(
8381945Sjeanm 					    nonrep_did_listp->devname, "/",
8391945Sjeanm 					    strlen(nmp->n_name) +
8401945Sjeanm 					    strlen(snmp->sn_name) + 2);
8411945Sjeanm 					(void) strlcat(
8421945Sjeanm 					    nonrep_did_listp->devname,
8431945Sjeanm 					    nmp->n_name,
8441945Sjeanm 					    strlen(nmp->n_name) +
8451945Sjeanm 					    strlen(snmp->sn_name) + 2);
8461945Sjeanm 					mnum = nmp->n_minor;
8471945Sjeanm 					break;
8481945Sjeanm 				}
8491945Sjeanm 				/* LINTED */
8501945Sjeanm 				snmp = (struct nm_shared_name *)((char *)snmp +
8511945Sjeanm 				    SHR_NAMSIZ(snmp));
8521945Sjeanm 				key = snmp->sn_key;
8531945Sjeanm 				used_size -= SHR_NAMSIZ(snmp);
8541945Sjeanm 				if ((int)used_size <= 0) {
8551945Sjeanm 					md_exit(NULL, 1);
8561945Sjeanm 				}
8571945Sjeanm 			}
8581945Sjeanm 			if (key == 0) {
8591945Sjeanm 				nonrep_did_listp->devname = NULL;
8601945Sjeanm 				mnum = 0;
861734Smw145384 			}
862127Shshaw 
8631945Sjeanm 			nonrep_did_listp->available = MD_IM_DISK_NOT_AVAILABLE;
8641945Sjeanm 			nonrep_did_listp->minor_name = Strdup(min->min_name);
8651945Sjeanm 			avail = 1;
8661945Sjeanm 			drv_key = nmp->n_drv_key;
8671945Sjeanm 			snmp = &namesp_shr_rec->sr_name[0];
8681945Sjeanm 			key = snmp->sn_key;
8691945Sjeanm 			/*
8701945Sjeanm 			 * Use the namespace n_drv_key to look in the
8711945Sjeanm 			 * shared namespace. When we find the matching
8721945Sjeanm 			 * key, that is the driver name for the disk.
8731945Sjeanm 			 */
8741945Sjeanm 			offset = sizeof (struct nm_shr_rec) -
8751945Sjeanm 			    sizeof (struct nm_shared_name);
8761945Sjeanm 			used_size = namesp_shr_rec->sr_rec_hdr.r_used_size -
8771945Sjeanm 			    offset;
8781945Sjeanm 			while (key != 0) {
8791945Sjeanm 				if (drv_key == key) {
8801945Sjeanm 					nonrep_did_listp->driver_name =
8811945Sjeanm 					    Strdup(snmp->sn_name);
8821945Sjeanm 					break;
8831945Sjeanm 				}
8841945Sjeanm 				/* LINTED */
8851945Sjeanm 				snmp = (struct nm_shared_name *)((char *)snmp +
8861945Sjeanm 				    SHR_NAMSIZ(snmp));
8871945Sjeanm 				key = snmp->sn_key;
8881945Sjeanm 				used_size -= SHR_NAMSIZ(snmp);
8891945Sjeanm 				if ((int)used_size <= 0) {
8901945Sjeanm 					md_exit(NULL, 1);
8911945Sjeanm 				}
8921945Sjeanm 			}
8931945Sjeanm 			if (key == 0)
8941945Sjeanm 				nonrep_did_listp->driver_name = NULL;
8951945Sjeanm 		}
8961945Sjeanm 		dnp = metadrivename(&sp,
8971945Sjeanm 		    metadiskname(nonrep_did_listp->devname), ep);
8981945Sjeanm 		/*
8991945Sjeanm 		 * Add drive to pnm_rec_t list of physical devices for
9001945Sjeanm 		 * metastat output.
9011945Sjeanm 		 */
9021945Sjeanm 		if (imp_flags & META_IMP_VERBOSE) {
9031945Sjeanm 			append_pnm_rec(pnm, min->min_key,
9041945Sjeanm 			    nonrep_did_listp->devname);
9051945Sjeanm 		}
9061945Sjeanm 
9071945Sjeanm 		assert(dnp != NULL);
9081945Sjeanm 		/* Is it already on the list? */
9091945Sjeanm 		for (midp = misp->mis_drives; midp != NULL;
9101945Sjeanm 		    midp = midp->mid_next) {
9111945Sjeanm 			if (midp->mid_dnp == dnp) {
9121945Sjeanm 				if (midp->mid_available ==
9131945Sjeanm 				    nonrep_did_listp->available) {
914127Shshaw 					on_list = 1;
915127Shshaw 					break;
916127Shshaw 				}
917127Shshaw 			}
9181945Sjeanm 		}
9191945Sjeanm 
9201945Sjeanm 		if (!on_list) {
9211945Sjeanm 			mddb_mb_t	*mbp;
9221945Sjeanm 			uint_t		sliceno;
9231945Sjeanm 			mdname_t	*rsp;
9241945Sjeanm 			int		fd = -1;
9251945Sjeanm 
9261945Sjeanm 			mbp = Malloc(DEV_BSIZE);
9271945Sjeanm 
9281945Sjeanm 			if (!avail) {
929127Shshaw 				/* determine the replica slice */
930127Shshaw 				if (meta_replicaslice(dnp, &sliceno,
931127Shshaw 				    ep) != 0) {
932127Shshaw 					Free(mbp);
9331945Sjeanm 					free_did_list(nonrep_did_listp);
934127Shshaw 					continue;
9350Sstevel@tonic-gate 				}
9360Sstevel@tonic-gate 
937127Shshaw 				/*
938127Shshaw 				 * if the replica slice size is zero,
939127Shshaw 				 * don't bother opening
940127Shshaw 				 */
941127Shshaw 				if (dnp->vtoc.parts[sliceno].size
942127Shshaw 				    == 0) {
943127Shshaw 					Free(mbp);
9441945Sjeanm 					free_did_list(nonrep_did_listp);
945127Shshaw 					continue;
946127Shshaw 				}
9470Sstevel@tonic-gate 
948127Shshaw 				if ((rsp = metaslicename(dnp, sliceno,
949127Shshaw 				    ep)) == NULL) {
950127Shshaw 					Free(mbp);
9511945Sjeanm 					free_did_list(nonrep_did_listp);
952127Shshaw 					continue;
953127Shshaw 				}
9540Sstevel@tonic-gate 
955127Shshaw 				if ((fd = open(rsp->rname,
956127Shshaw 				    O_RDONLY| O_NDELAY)) < 0) {
957127Shshaw 					Free(mbp);
9581945Sjeanm 					free_did_list(nonrep_did_listp);
959127Shshaw 					continue;
960127Shshaw 				}
9610Sstevel@tonic-gate 
962127Shshaw 				/*
963127Shshaw 				 * a drive may not have a master block
964127Shshaw 				 */
965127Shshaw 				if (read_master_block(ep, fd, mbp,
966127Shshaw 				    DEV_BSIZE) <= 0) {
967127Shshaw 					mdclrerror(ep);
968127Shshaw 					Free(mbp);
9691945Sjeanm 					free_did_list(nonrep_did_listp);
9701945Sjeanm 					(void) close(fd);
9711945Sjeanm 					continue;
972127Shshaw 				}
9730Sstevel@tonic-gate 
974127Shshaw 				(void) close(fd);
9750Sstevel@tonic-gate 			}
9761945Sjeanm 			/*
9771945Sjeanm 			 * If it is replicated diskset,
9781945Sjeanm 			 * r_did will be non-NULL.
9791945Sjeanm 			 * Passing the devname as NULL because field
9801945Sjeanm 			 * is not currently used for a non-replica disk.
9811945Sjeanm 			 */
9821945Sjeanm 			midpp = drive_append_wrapper(midpp,
9831945Sjeanm 			    dnp, nonrep_did_listp,
9841945Sjeanm 			    mnum, mbp->mb_setcreatetime, NULL);
9851945Sjeanm 			Free(mbp);
9861945Sjeanm 			free_did_list(nonrep_did_listp);
9870Sstevel@tonic-gate 		}
9881945Sjeanm 	free_did_list(nonrep_did_listp);
9890Sstevel@tonic-gate 	}
9900Sstevel@tonic-gate }
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate /*
9930Sstevel@tonic-gate  * set_append()
9940Sstevel@tonic-gate  *
9950Sstevel@tonic-gate  * Append to tail of linked list of md_im_set_desc_t.
9960Sstevel@tonic-gate  *
9970Sstevel@tonic-gate  * Will allocate space for new node AND populate it by extracting disks with
9980Sstevel@tonic-gate  * and without replicas from the locator blocks and locator namespace.
9990Sstevel@tonic-gate  *
10000Sstevel@tonic-gate  * Returns pointer to new node.
10010Sstevel@tonic-gate  */
10020Sstevel@tonic-gate static md_im_set_desc_t *
set_append(md_im_set_desc_t ** mispp,did_list_t * did_listp,mddb_mb_t * mb,mddb_lb_t * lbp,mddb_rb_t * nm,mddb_rb_t * shrnm,pnm_rec_t ** pnm,mddb_rb_t * did_nm,mddb_rb_t * did_shrnm,uint_t imp_flags,md_error_t * ep)10030Sstevel@tonic-gate set_append(
10040Sstevel@tonic-gate 	md_im_set_desc_t	**mispp,
10050Sstevel@tonic-gate 	did_list_t		*did_listp,
10060Sstevel@tonic-gate 	mddb_mb_t		*mb,
10070Sstevel@tonic-gate 	mddb_lb_t		*lbp,
10080Sstevel@tonic-gate 	mddb_rb_t		*nm,
10091945Sjeanm 	mddb_rb_t		*shrnm,
1010734Smw145384 	pnm_rec_t		**pnm,
10110Sstevel@tonic-gate 	mddb_rb_t		*did_nm,
10120Sstevel@tonic-gate 	mddb_rb_t		*did_shrnm,
1013734Smw145384 	uint_t 			imp_flags,
1014734Smw145384 	md_error_t		*ep
10150Sstevel@tonic-gate )
10160Sstevel@tonic-gate {
1017734Smw145384 
10180Sstevel@tonic-gate 	md_im_set_desc_t	*misp;
10190Sstevel@tonic-gate 	set_t			setno = mb->mb_setno;
10201945Sjeanm 	int			partial = imp_flags & MD_IM_PARTIAL_DISKSET;
10211945Sjeanm 	int			replicated = imp_flags & MD_IM_SET_REPLICATED;
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	/* run to end of list */
10240Sstevel@tonic-gate 	for (; (*mispp != NULL); mispp = &((*mispp)->mis_next))
10250Sstevel@tonic-gate 		;
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 	/* allocate new list element */
10280Sstevel@tonic-gate 	misp = *mispp = Zalloc(sizeof (md_im_set_desc_t));
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate 	if (replicated)
10310Sstevel@tonic-gate 		misp->mis_flags = MD_IM_SET_REPLICATED;
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate 	misp->mis_oldsetno = setno;
10341945Sjeanm 	misp->mis_partial = partial;
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate 	/* Get the disks with and without replicas */
10371945Sjeanm 	get_replica_disks(misp, did_listp, mb, lbp, ep);
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate 	if (nm != NULL && did_nm != NULL && did_shrnm != NULL) {
10401945Sjeanm 		get_disks_from_didnamespace(misp, pnm, nm, shrnm, did_nm,
1041734Smw145384 		    did_shrnm, imp_flags, replicated, ep);
10420Sstevel@tonic-gate 	}
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 	/*
1045734Smw145384 	 * An error in this struct could come from either of
1046734Smw145384 	 * the above routines;
10470Sstevel@tonic-gate 	 * in both cases, we want to pass it back on up.
10480Sstevel@tonic-gate 	 */
1049734Smw145384 
10500Sstevel@tonic-gate 	return (misp);
10510Sstevel@tonic-gate }
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate /*
10550Sstevel@tonic-gate  * add_disk_names()
10560Sstevel@tonic-gate  *
10570Sstevel@tonic-gate  * Iterator to walk the minor node tree of the device snapshot, adding only the
10580Sstevel@tonic-gate  * first non-block instance of each non-cdrom minor node to a list of disks.
10590Sstevel@tonic-gate  */
10600Sstevel@tonic-gate static int
add_disk_names(di_node_t node,di_minor_t minor,void * args)10610Sstevel@tonic-gate add_disk_names(di_node_t node, di_minor_t minor, void *args)
10620Sstevel@tonic-gate {
10630Sstevel@tonic-gate 	char			*search_path = "/dev";
10640Sstevel@tonic-gate 	ddi_devid_t		devid = di_devid(node);
10650Sstevel@tonic-gate 	devid_nmlist_t		*nm;
10660Sstevel@tonic-gate 	char			*min = di_minor_name(minor);
10670Sstevel@tonic-gate 	md_im_names_t		*cnames = (md_im_names_t *)args;
10680Sstevel@tonic-gate 	static di_node_t	save_node = NULL;
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate 	/*
10710Sstevel@tonic-gate 	 * skip CD devices
10720Sstevel@tonic-gate 	 * If a device does not have a device id, we can't
10730Sstevel@tonic-gate 	 * do anything with it so just exclude it from our
10740Sstevel@tonic-gate 	 * list.
10750Sstevel@tonic-gate 	 *
10760Sstevel@tonic-gate 	 * This would also encompass CD devices and floppy
10770Sstevel@tonic-gate 	 * devices that don't have a device id.
10780Sstevel@tonic-gate 	 */
10790Sstevel@tonic-gate 	if (devid == NULL) {
10800Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
10810Sstevel@tonic-gate 	}
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate 	/* char disk devices (as opposed to block) */
10840Sstevel@tonic-gate 	if (di_minor_spectype(minor) == S_IFCHR) {
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate 		/* only first occurrence (slice 0) of each instance */
10870Sstevel@tonic-gate 		if (save_node == NULL || node != save_node) {
10880Sstevel@tonic-gate 			save_node = node;
10890Sstevel@tonic-gate 			if (meta_deviceid_to_nmlist(search_path, devid,
10900Sstevel@tonic-gate 			    min, &nm) == 0) {
10910Sstevel@tonic-gate 				int	index = cnames->min_count++;
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate 				assert(nm->devname != NULL);
10940Sstevel@tonic-gate 				cnames->min_names =
10950Sstevel@tonic-gate 					Realloc(cnames->min_names,
10960Sstevel@tonic-gate 						cnames->min_count *
10970Sstevel@tonic-gate 						sizeof (char *));
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate 				assert(cnames->min_names != NULL);
11000Sstevel@tonic-gate 				cnames->min_names[index] =
11010Sstevel@tonic-gate 					metadiskname(nm->devname);
11020Sstevel@tonic-gate 				devid_free_nmlist(nm);
11030Sstevel@tonic-gate 			}
11040Sstevel@tonic-gate 		}
11050Sstevel@tonic-gate 	}
11060Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
11070Sstevel@tonic-gate }
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate /*
11120Sstevel@tonic-gate  * meta_list_disks()
11130Sstevel@tonic-gate  *
11140Sstevel@tonic-gate  * Snapshots the device tree and extracts disk devices from the snapshot.
11150Sstevel@tonic-gate  */
11160Sstevel@tonic-gate int
meta_list_disks(md_error_t * ep,md_im_names_t * cnames)11170Sstevel@tonic-gate meta_list_disks(md_error_t *ep, md_im_names_t *cnames)
11180Sstevel@tonic-gate {
11190Sstevel@tonic-gate 	di_node_t root_node;
11200Sstevel@tonic-gate 
11210Sstevel@tonic-gate 	assert(cnames != NULL);
11220Sstevel@tonic-gate 	cnames->min_count = 0;
11230Sstevel@tonic-gate 	cnames->min_names = NULL;
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 	if ((root_node = di_init("/", DINFOCPYALL|DINFOFORCE))
11260Sstevel@tonic-gate 	    == DI_NODE_NIL) {
11270Sstevel@tonic-gate 		return (mdsyserror(ep, errno, NULL));
11280Sstevel@tonic-gate 	}
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate 	(void) di_walk_minor(root_node, DDI_NT_BLOCK, 0, cnames,
11310Sstevel@tonic-gate 	    add_disk_names);
11320Sstevel@tonic-gate 
11330Sstevel@tonic-gate 	di_fini(root_node);
11340Sstevel@tonic-gate 	return (0);
11350Sstevel@tonic-gate }
11360Sstevel@tonic-gate 
11370Sstevel@tonic-gate /*
11380Sstevel@tonic-gate  * meta_imp_drvused
11390Sstevel@tonic-gate  *
11400Sstevel@tonic-gate  * Checks if given drive is mounted, swapped, part of disk configuration
11410Sstevel@tonic-gate  * or in use by SVM.  ep also has error code set up if drive is in use.
11420Sstevel@tonic-gate  *
11430Sstevel@tonic-gate  * Returns 1 if drive is in use.
11440Sstevel@tonic-gate  * Returns 0 if drive is not in use.
11450Sstevel@tonic-gate  */
11460Sstevel@tonic-gate int
meta_imp_drvused(mdsetname_t * sp,mddrivename_t * dnp,md_error_t * ep)11470Sstevel@tonic-gate meta_imp_drvused(
11480Sstevel@tonic-gate 	mdsetname_t		*sp,
11490Sstevel@tonic-gate 	mddrivename_t		*dnp,
11500Sstevel@tonic-gate 	md_error_t		*ep
11510Sstevel@tonic-gate )
11520Sstevel@tonic-gate {
11530Sstevel@tonic-gate 	md_error_t		status = mdnullerror;
11540Sstevel@tonic-gate 	md_error_t		*db_ep = &status;
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate 	/*
11570Sstevel@tonic-gate 	 * We pass in db_ep to meta_setup_db_locations
11580Sstevel@tonic-gate 	 * and never ever use the error contained therein
11590Sstevel@tonic-gate 	 * because all we're interested in is a check to
11600Sstevel@tonic-gate 	 * see whether any local metadbs are present.
11610Sstevel@tonic-gate 	 */
11620Sstevel@tonic-gate 	if ((meta_check_drivemounted(sp, dnp, ep) != 0) ||
11630Sstevel@tonic-gate 	    (meta_check_driveswapped(sp, dnp, ep) != 0) ||
11640Sstevel@tonic-gate 	    (((meta_setup_db_locations(db_ep) == 0) &&
11650Sstevel@tonic-gate 	    ((meta_check_drive_inuse(sp, dnp, 1, ep) != 0) ||
11660Sstevel@tonic-gate 	    (meta_check_driveinset(sp, dnp, ep) != 0))))) {
11670Sstevel@tonic-gate 		return (1);
11680Sstevel@tonic-gate 	} else {
11690Sstevel@tonic-gate 		return (0);
11700Sstevel@tonic-gate 	}
11710Sstevel@tonic-gate }
11720Sstevel@tonic-gate 
11730Sstevel@tonic-gate /*
11740Sstevel@tonic-gate  * meta_prune_cnames()
11750Sstevel@tonic-gate  *
11760Sstevel@tonic-gate  * Removes in-use disks from the list prior to further processing.
11770Sstevel@tonic-gate  *
11780Sstevel@tonic-gate  * Return value depends on err_on_prune flag: if set, and one or more disks
11790Sstevel@tonic-gate  * are pruned, the return list will be the pruned disks.  If not set, or if no
11800Sstevel@tonic-gate  * disks are pruned, the return list will be the unpruned disks.
11810Sstevel@tonic-gate  */
11820Sstevel@tonic-gate mddrivenamelist_t *
meta_prune_cnames(md_error_t * ep,md_im_names_t * cnames,int err_on_prune)11830Sstevel@tonic-gate meta_prune_cnames(
11840Sstevel@tonic-gate 	md_error_t *ep,
11850Sstevel@tonic-gate 	md_im_names_t *cnames,
11860Sstevel@tonic-gate 	int err_on_prune
11870Sstevel@tonic-gate )
11880Sstevel@tonic-gate {
11890Sstevel@tonic-gate 	int			d;
11900Sstevel@tonic-gate 	int			fcount = 0;
11910Sstevel@tonic-gate 	mddrivenamelist_t	*dnlp = NULL;
11920Sstevel@tonic-gate 	mddrivenamelist_t	**dnlpp = &dnlp;
11930Sstevel@tonic-gate 	mddrivenamelist_t	*fdnlp = NULL;
11940Sstevel@tonic-gate 	mddrivenamelist_t	**fdnlpp = &fdnlp;
11950Sstevel@tonic-gate 	mdsetname_t		*sp = metasetname(MD_LOCAL_NAME, ep);
11960Sstevel@tonic-gate 
11970Sstevel@tonic-gate 	for (d = 0; d < cnames->min_count; ++d) {
11980Sstevel@tonic-gate 		mddrivename_t	*dnp;
11990Sstevel@tonic-gate 
12000Sstevel@tonic-gate 		dnp = metadrivename(&sp, cnames->min_names[d], ep);
12010Sstevel@tonic-gate 		if (dnp == NULL) {
12020Sstevel@tonic-gate 			/*
12030Sstevel@tonic-gate 			 * Assuming we're interested in knowing about
12040Sstevel@tonic-gate 			 * whatever error occurred, but not in stopping.
12050Sstevel@tonic-gate 			 */
12060Sstevel@tonic-gate 			mde_perror(ep, cnames->min_names[d]);
12070Sstevel@tonic-gate 			mdclrerror(ep);
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate 			continue;
12100Sstevel@tonic-gate 		}
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate 		/*
12130Sstevel@tonic-gate 		 * Check if the drive is inuse.
12140Sstevel@tonic-gate 		 */
12150Sstevel@tonic-gate 		if (meta_imp_drvused(sp, dnp, ep)) {
12160Sstevel@tonic-gate 			fdnlpp = meta_drivenamelist_append_wrapper(fdnlpp, dnp);
12170Sstevel@tonic-gate 			fcount++;
12180Sstevel@tonic-gate 			mdclrerror(ep);
12190Sstevel@tonic-gate 		} else {
12200Sstevel@tonic-gate 			dnlpp = meta_drivenamelist_append_wrapper(dnlpp, dnp);
12210Sstevel@tonic-gate 		}
12220Sstevel@tonic-gate 	}
12230Sstevel@tonic-gate 
12240Sstevel@tonic-gate 	if (fcount) {
12250Sstevel@tonic-gate 		if (err_on_prune) {
12260Sstevel@tonic-gate 			(void) mddserror(ep, MDE_DS_DRIVEINUSE, 0,
12270Sstevel@tonic-gate 			    NULL, fdnlp->drivenamep->cname, NULL);
12280Sstevel@tonic-gate 			metafreedrivenamelist(dnlp);
12290Sstevel@tonic-gate 			return (fdnlp);
12300Sstevel@tonic-gate 		}
12310Sstevel@tonic-gate 		metafreedrivenamelist(fdnlp);
12320Sstevel@tonic-gate 	}
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate 	return (dnlp);
12350Sstevel@tonic-gate }
12360Sstevel@tonic-gate 
12370Sstevel@tonic-gate /*
12380Sstevel@tonic-gate  * read_master_block()
12390Sstevel@tonic-gate  *
12400Sstevel@tonic-gate  * Returns:
12410Sstevel@tonic-gate  *	< 0 for failure
12420Sstevel@tonic-gate  *	  0 for no valid master block
12430Sstevel@tonic-gate  *	  1 for valid master block
12440Sstevel@tonic-gate  *
12450Sstevel@tonic-gate  * The supplied buffer will be filled in for EITHER 0 or 1.
12460Sstevel@tonic-gate  */
12470Sstevel@tonic-gate int
read_master_block(md_error_t * ep,int fd,void * bp,int bsize)12480Sstevel@tonic-gate read_master_block(
12490Sstevel@tonic-gate 	md_error_t	*ep,
12500Sstevel@tonic-gate 	int		fd,
12510Sstevel@tonic-gate 	void		*bp,
12520Sstevel@tonic-gate 	int		bsize
12530Sstevel@tonic-gate )
12540Sstevel@tonic-gate {
12550Sstevel@tonic-gate 	mddb_mb_t	*mbp = bp;
12560Sstevel@tonic-gate 	int		rval = 1;
12570Sstevel@tonic-gate 
12580Sstevel@tonic-gate 	assert(bp != NULL);
12590Sstevel@tonic-gate 
12600Sstevel@tonic-gate 	if (lseek(fd, (off_t)dbtob(16), SEEK_SET) < 0)
12610Sstevel@tonic-gate 		return (mdsyserror(ep, errno, NULL));
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate 	if (read(fd, bp, bsize) != bsize)
12640Sstevel@tonic-gate 		return (mdsyserror(ep, errno, NULL));
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate 	/*
12670Sstevel@tonic-gate 	 * The master block magic number can either be MDDB_MAGIC_MB in
12680Sstevel@tonic-gate 	 * the case of a real master block, or, it can be MDDB_MAGIC_DU
12690Sstevel@tonic-gate 	 * in the case of a dummy master block
12700Sstevel@tonic-gate 	 */
12710Sstevel@tonic-gate 	if ((mbp->mb_magic != MDDB_MAGIC_MB) &&
12720Sstevel@tonic-gate 	    (mbp->mb_magic != MDDB_MAGIC_DU)) {
12730Sstevel@tonic-gate 		rval = 0;
12740Sstevel@tonic-gate 		(void) mdmddberror(ep, MDE_DB_MASTER, 0, 0, 0, NULL);
12750Sstevel@tonic-gate 	}
12760Sstevel@tonic-gate 
12770Sstevel@tonic-gate 	if (mbp->mb_revision != MDDB_REV_MB) {
12780Sstevel@tonic-gate 		rval = 0;
12790Sstevel@tonic-gate 	}
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate 	return (rval);
12820Sstevel@tonic-gate }
12830Sstevel@tonic-gate 
12840Sstevel@tonic-gate /*
12850Sstevel@tonic-gate  * read_locator_block()
12860Sstevel@tonic-gate  *
12870Sstevel@tonic-gate  * Returns:
12880Sstevel@tonic-gate  *	< 0 for failure
12890Sstevel@tonic-gate  *	  0 for no valid locator block
12900Sstevel@tonic-gate  *	  1 for valid locator block
12910Sstevel@tonic-gate  */
12920Sstevel@tonic-gate int
read_locator_block(md_error_t * ep,int fd,mddb_mb_t * mbp,void * bp,int bsize)12930Sstevel@tonic-gate read_locator_block(
12940Sstevel@tonic-gate 	md_error_t	*ep,
12950Sstevel@tonic-gate 	int		fd,
12960Sstevel@tonic-gate 	mddb_mb_t	*mbp,
12970Sstevel@tonic-gate 	void		*bp,
12980Sstevel@tonic-gate 	int		bsize
12990Sstevel@tonic-gate )
13000Sstevel@tonic-gate {
13010Sstevel@tonic-gate 	mddb_lb_t	*lbp = bp;
13020Sstevel@tonic-gate 
13030Sstevel@tonic-gate 	assert(bp != NULL);
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate 	if (lseek(fd, (off_t)dbtob(mbp->mb_blkmap.m_firstblk), SEEK_SET) < 0)
13060Sstevel@tonic-gate 		return (mdsyserror(ep, errno, NULL));
13070Sstevel@tonic-gate 
13080Sstevel@tonic-gate 	if (read(fd, bp, bsize) != bsize)
13090Sstevel@tonic-gate 		return (mdsyserror(ep, errno, NULL));
13100Sstevel@tonic-gate 
13110Sstevel@tonic-gate 	return ((lbp->lb_magic == MDDB_MAGIC_LB) ? 1 : 0);
13120Sstevel@tonic-gate }
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate int
phys_read(md_error_t * ep,int fd,mddb_mb_t * mbp,daddr_t blk,void * bp,int bcount)13150Sstevel@tonic-gate phys_read(
13160Sstevel@tonic-gate 	md_error_t	*ep,
13170Sstevel@tonic-gate 	int		fd,
13180Sstevel@tonic-gate 	mddb_mb_t	*mbp,
13190Sstevel@tonic-gate 	daddr_t		blk,
13200Sstevel@tonic-gate 	void		*bp,
13210Sstevel@tonic-gate 	int		bcount
13220Sstevel@tonic-gate )
13230Sstevel@tonic-gate {
13240Sstevel@tonic-gate 	daddr_t		pblk;
13250Sstevel@tonic-gate 
13260Sstevel@tonic-gate 	if ((pblk = getphysblk(blk, mbp)) < 0)
13270Sstevel@tonic-gate 		return (mdmddberror(ep, MDE_DB_BLKRANGE, NODEV32,
13280Sstevel@tonic-gate 			MD_LOCAL_SET, blk, NULL));
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 	if (lseek(fd, (off_t)dbtob(pblk), SEEK_SET) < 0)
13310Sstevel@tonic-gate 		return (mdsyserror(ep, errno, NULL));
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate 	if (read(fd, bp, bcount) != bcount)
13340Sstevel@tonic-gate 		return (mdsyserror(ep, errno, NULL));
13350Sstevel@tonic-gate 
13360Sstevel@tonic-gate 	return (bcount);
13370Sstevel@tonic-gate }
13380Sstevel@tonic-gate 
13390Sstevel@tonic-gate /*
13400Sstevel@tonic-gate  * read_locator_block_did()
13410Sstevel@tonic-gate  *
13420Sstevel@tonic-gate  * Returns:
13430Sstevel@tonic-gate  * 	< 0 for failure
13440Sstevel@tonic-gate  *	  0 for no valid locator name struct
13450Sstevel@tonic-gate  *	  1 for valid locator name struct
13460Sstevel@tonic-gate  */
13470Sstevel@tonic-gate int
read_locator_block_did(md_error_t * ep,int fd,mddb_mb_t * mbp,mddb_lb_t * lbp,void * bp,int bsize)13480Sstevel@tonic-gate read_locator_block_did(
13490Sstevel@tonic-gate 	md_error_t	*ep,
13500Sstevel@tonic-gate 	int		fd,
13510Sstevel@tonic-gate 	mddb_mb_t	*mbp,
13520Sstevel@tonic-gate 	mddb_lb_t	*lbp,
13530Sstevel@tonic-gate 	void		*bp,
13540Sstevel@tonic-gate 	int		bsize
13550Sstevel@tonic-gate )
13560Sstevel@tonic-gate {
13570Sstevel@tonic-gate 	int		lb_didfirstblk = lbp->lb_didfirstblk;
13580Sstevel@tonic-gate 	mddb_did_blk_t	*lbdidp = bp;
13590Sstevel@tonic-gate 	int		rval;
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate 	assert(bp != NULL);
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate 	if ((rval = phys_read(ep, fd, mbp, lb_didfirstblk, bp, bsize)) < 0)
13640Sstevel@tonic-gate 		return (rval);
13650Sstevel@tonic-gate 
13660Sstevel@tonic-gate 	return ((lbdidp->blk_magic == MDDB_MAGIC_DI) ? 1 : 0);
13670Sstevel@tonic-gate }
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate /*
13700Sstevel@tonic-gate  * read_locator_names()
13710Sstevel@tonic-gate  *
13720Sstevel@tonic-gate  * Returns:
13730Sstevel@tonic-gate  *	< 0 for failure
13740Sstevel@tonic-gate  *	  0 for no valid locator name struct
13750Sstevel@tonic-gate  *	  1 for valid locator name struct
13760Sstevel@tonic-gate  */
13770Sstevel@tonic-gate int
read_locator_names(md_error_t * ep,int fd,mddb_mb_t * mbp,mddb_lb_t * lbp,void * bp,int bsize)13780Sstevel@tonic-gate read_locator_names(
13790Sstevel@tonic-gate 	md_error_t	*ep,
13800Sstevel@tonic-gate 	int		fd,
13810Sstevel@tonic-gate 	mddb_mb_t	*mbp,
13820Sstevel@tonic-gate 	mddb_lb_t	*lbp,
13830Sstevel@tonic-gate 	void		*bp,
13840Sstevel@tonic-gate 	int		bsize
13850Sstevel@tonic-gate )
13860Sstevel@tonic-gate {
13870Sstevel@tonic-gate 	int		lnfirstblk = lbp->lb_lnfirstblk;
13880Sstevel@tonic-gate 	mddb_ln_t	*lnp = bp;
13890Sstevel@tonic-gate 	int		rval;
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate 	assert(bp != NULL);
13920Sstevel@tonic-gate 
13930Sstevel@tonic-gate 	if ((rval = phys_read(ep, fd, mbp, lnfirstblk, bp, bsize)) < 0)
13940Sstevel@tonic-gate 		return (rval);
13950Sstevel@tonic-gate 
13960Sstevel@tonic-gate 	return ((lnp->ln_magic == MDDB_MAGIC_LN) ? 1 : 0);
13970Sstevel@tonic-gate }
13980Sstevel@tonic-gate 
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate int
read_database_block(md_error_t * ep,int fd,mddb_mb_t * mbp,int dbblk,void * bp,int bsize)14010Sstevel@tonic-gate read_database_block(
14020Sstevel@tonic-gate 	md_error_t	*ep,
14030Sstevel@tonic-gate 	int		fd,
14040Sstevel@tonic-gate 	mddb_mb_t	*mbp,
14050Sstevel@tonic-gate 	int		dbblk,
14060Sstevel@tonic-gate 	void		*bp,
14070Sstevel@tonic-gate 	int		bsize
14080Sstevel@tonic-gate )
14090Sstevel@tonic-gate {
14100Sstevel@tonic-gate 	mddb_db_t	*dbp = bp;
14110Sstevel@tonic-gate 	int		rval;
14120Sstevel@tonic-gate 
14130Sstevel@tonic-gate 	assert(bp != NULL);
14140Sstevel@tonic-gate 
14150Sstevel@tonic-gate 	if ((rval = phys_read(ep, fd, mbp, dbblk, bp, bsize)) < 0)
14160Sstevel@tonic-gate 		return (rval);
14170Sstevel@tonic-gate 
14180Sstevel@tonic-gate 	return ((dbp->db_magic == MDDB_MAGIC_DB) ? 1 : 0);
14190Sstevel@tonic-gate }
14200Sstevel@tonic-gate 
14210Sstevel@tonic-gate int
read_loc_didblks(md_error_t * ep,int fd,mddb_mb_t * mbp,int didblk,void * bp,int bsize)14220Sstevel@tonic-gate read_loc_didblks(
14230Sstevel@tonic-gate 	md_error_t	*ep,
14240Sstevel@tonic-gate 	int		fd,
14250Sstevel@tonic-gate 	mddb_mb_t	*mbp,
14260Sstevel@tonic-gate 	int		didblk,
14270Sstevel@tonic-gate 	void		*bp,
14280Sstevel@tonic-gate 	int		bsize
14290Sstevel@tonic-gate )
14300Sstevel@tonic-gate {
14310Sstevel@tonic-gate 	mddb_did_blk_t	*didbp = bp;
14320Sstevel@tonic-gate 	int		rval;
14330Sstevel@tonic-gate 
14340Sstevel@tonic-gate 	assert(bp != NULL);
14350Sstevel@tonic-gate 
14360Sstevel@tonic-gate 	if ((rval = phys_read(ep, fd, mbp, didblk, bp, bsize)) < 0)
14370Sstevel@tonic-gate 		return (rval);
14380Sstevel@tonic-gate 
14390Sstevel@tonic-gate 	return ((didbp->blk_magic == MDDB_MAGIC_DI) ? 1 : 0);
14400Sstevel@tonic-gate }
14410Sstevel@tonic-gate 
14420Sstevel@tonic-gate 
14430Sstevel@tonic-gate int
read_loc_didinfo(md_error_t * ep,int fd,mddb_mb_t * mbp,int infoblk,void * bp,int bsize)14440Sstevel@tonic-gate read_loc_didinfo(
14450Sstevel@tonic-gate 	md_error_t	*ep,
14460Sstevel@tonic-gate 	int		fd,
14470Sstevel@tonic-gate 	mddb_mb_t	*mbp,
14480Sstevel@tonic-gate 	int		infoblk,
14490Sstevel@tonic-gate 	void		*bp,
14500Sstevel@tonic-gate 	int		bsize
14510Sstevel@tonic-gate )
14520Sstevel@tonic-gate {
14530Sstevel@tonic-gate 	int		rval = 1;
14540Sstevel@tonic-gate 	mddb_did_info_t	*infop = bp;
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate 	assert(bp != NULL);
14570Sstevel@tonic-gate 
14580Sstevel@tonic-gate 	if ((rval = phys_read(ep, fd, mbp, infoblk, bp, bsize)) < 0)
14590Sstevel@tonic-gate 		return (rval);
14600Sstevel@tonic-gate 
14610Sstevel@tonic-gate 	return ((infop->info_flags & MDDB_DID_EXISTS) ? 1 : 0);
14620Sstevel@tonic-gate }
14630Sstevel@tonic-gate 
14640Sstevel@tonic-gate /*
14650Sstevel@tonic-gate  * meta_nm_rec()
14660Sstevel@tonic-gate  *
14670Sstevel@tonic-gate  * Return the DE corresponding to the requested namespace record type.
14680Sstevel@tonic-gate  * Modifies dbp to have a firstentry if one isn't there.
14690Sstevel@tonic-gate  */
14700Sstevel@tonic-gate static mddb_de_t *
meta_nm_rec(mddb_db_t * dbp,mddb_type_t rectype)14710Sstevel@tonic-gate meta_nm_rec(mddb_db_t *dbp, mddb_type_t rectype)
14720Sstevel@tonic-gate {
14730Sstevel@tonic-gate 	mddb_de_t *dep;
14740Sstevel@tonic-gate 	int	desize;
14750Sstevel@tonic-gate 
14760Sstevel@tonic-gate 	if (dbp->db_firstentry != NULL) {
14770Sstevel@tonic-gate 		/* LINTED */
14780Sstevel@tonic-gate 		dep = (mddb_de_t *)((caddr_t)(&dbp->db_firstentry)
14790Sstevel@tonic-gate 				    + sizeof (dbp->db_firstentry));
14800Sstevel@tonic-gate 		dbp->db_firstentry = dep;
14810Sstevel@tonic-gate 		while (dep && dep->de_next) {
14820Sstevel@tonic-gate 			desize = sizeof (*dep) - sizeof (dep->de_blks) +
14830Sstevel@tonic-gate 				sizeof (daddr_t) * dep->de_blkcount;
14840Sstevel@tonic-gate 			/* LINTED */
14850Sstevel@tonic-gate 			dep->de_next = (mddb_de_t *)
14860Sstevel@tonic-gate 				((caddr_t)dep + desize);
14870Sstevel@tonic-gate 			dep = dep->de_next;
14880Sstevel@tonic-gate 		}
14890Sstevel@tonic-gate 	}
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 	for (dep = dbp->db_firstentry; dep != NULL; dep = dep->de_next) {
14920Sstevel@tonic-gate 		if (dep->de_type1 == rectype)
14930Sstevel@tonic-gate 			break;
14940Sstevel@tonic-gate 	}
14950Sstevel@tonic-gate 	return (dep);
14960Sstevel@tonic-gate }
14970Sstevel@tonic-gate 
14980Sstevel@tonic-gate /*
14990Sstevel@tonic-gate  * read_nm_rec()
15000Sstevel@tonic-gate  *
15010Sstevel@tonic-gate  * Reads the NM, NM_DID or NM_DID_SHR record in the mddb and stores the
15020Sstevel@tonic-gate  * configuration data in the buffer 'nm'
15030Sstevel@tonic-gate  *
15040Sstevel@tonic-gate  * Returns:
15050Sstevel@tonic-gate  *	< 0 for failure
15060Sstevel@tonic-gate  *	  0 for no valid NM/DID_NM/DID_NM_SHR record
15070Sstevel@tonic-gate  *	  1 for valid NM/DID_NM/DID_NM_SHR record
15080Sstevel@tonic-gate  *
15090Sstevel@tonic-gate  */
15100Sstevel@tonic-gate static int
read_nm_rec(md_error_t * ep,int fd,mddb_mb_t * mbp,mddb_lb_t * lbp,char ** nm,mddb_type_t rectype,char * diskname)15110Sstevel@tonic-gate read_nm_rec(
15120Sstevel@tonic-gate 	md_error_t 	*ep,
15130Sstevel@tonic-gate 	int 		fd,
15140Sstevel@tonic-gate 	mddb_mb_t	*mbp,
15150Sstevel@tonic-gate 	mddb_lb_t	*lbp,
15160Sstevel@tonic-gate 	char		**nm,
15170Sstevel@tonic-gate 	mddb_type_t	rectype,
15180Sstevel@tonic-gate 	char		*diskname
15190Sstevel@tonic-gate )
15200Sstevel@tonic-gate {
15210Sstevel@tonic-gate 	int		cnt, dbblk, rval = 0;
15220Sstevel@tonic-gate 	char		db[DEV_BSIZE];
15230Sstevel@tonic-gate 	mddb_de_t	*dep;
15240Sstevel@tonic-gate 	/*LINTED*/
15250Sstevel@tonic-gate 	mddb_db_t	*dbp = (mddb_db_t *)&db;
15260Sstevel@tonic-gate 	char 		*tmpnm = NULL;
15270Sstevel@tonic-gate 	daddr_t		pblk;
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate 	for (dbblk = lbp->lb_dbfirstblk;
15300Sstevel@tonic-gate 	    dbblk != 0;
15310Sstevel@tonic-gate 	    dbblk = dbp->db_nextblk) {
15320Sstevel@tonic-gate 
15330Sstevel@tonic-gate 		if ((rval = read_database_block(ep, fd, mbp, dbblk, dbp,
15340Sstevel@tonic-gate 		    sizeof (db))) <= 0)
15350Sstevel@tonic-gate 			return (rval);
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate 		/*
15380Sstevel@tonic-gate 		 * Locate NM/DID_NM/DID_NM_SHR record. Normally there is
15390Sstevel@tonic-gate 		 * only one record per mddb. There is a rare case when we
15400Sstevel@tonic-gate 		 * can't expand the record. If this is the case then we
15410Sstevel@tonic-gate 		 * will have multiple NM/DID_NM/DID_NM_SHR records linked
15420Sstevel@tonic-gate 		 * with r_next_recid.
15430Sstevel@tonic-gate 		 *
15440Sstevel@tonic-gate 		 * For now assume the normal case and handle the extended
15450Sstevel@tonic-gate 		 * namespace in Phase 2.
15460Sstevel@tonic-gate 		 */
15470Sstevel@tonic-gate 		if ((dep = meta_nm_rec(dbp, rectype)) != NULL)
15480Sstevel@tonic-gate 			break;
15490Sstevel@tonic-gate 	}
15500Sstevel@tonic-gate 
15510Sstevel@tonic-gate 	/* If meta_nm_rec() never succeeded, bail out */
15520Sstevel@tonic-gate 	if (dep == NULL)
15530Sstevel@tonic-gate 		return (0);
15540Sstevel@tonic-gate 
15550Sstevel@tonic-gate 	/* Read in the appropriate record and return configurations */
15560Sstevel@tonic-gate 	tmpnm = (char *)Zalloc(dbtob(dep->de_blkcount));
15570Sstevel@tonic-gate 	*nm = tmpnm;
15580Sstevel@tonic-gate 
15590Sstevel@tonic-gate 	for (cnt = 0; cnt < dep->de_blkcount; cnt++) {
15600Sstevel@tonic-gate 		if ((pblk = getphysblk(dep->de_blks[cnt], mbp)) < 0) {
15610Sstevel@tonic-gate 			rval = mdmddberror(ep, MDE_DB_BLKRANGE,
15620Sstevel@tonic-gate 			    NODEV32, MD_LOCAL_SET,
15630Sstevel@tonic-gate 			    dep->de_blks[cnt], diskname);
15640Sstevel@tonic-gate 			return (rval);
15650Sstevel@tonic-gate 		}
15660Sstevel@tonic-gate 
15670Sstevel@tonic-gate 		if (lseek(fd, (off_t)dbtob(pblk), SEEK_SET) < 0) {
15680Sstevel@tonic-gate 			rval = mdsyserror(ep, errno, diskname);
15690Sstevel@tonic-gate 			return (rval);
15700Sstevel@tonic-gate 		}
15710Sstevel@tonic-gate 
15720Sstevel@tonic-gate 		if (read(fd, tmpnm, DEV_BSIZE) != DEV_BSIZE) {
15730Sstevel@tonic-gate 			rval = mdsyserror(ep, errno, diskname);
15740Sstevel@tonic-gate 			return (rval);
15750Sstevel@tonic-gate 		}
15760Sstevel@tonic-gate 
15770Sstevel@tonic-gate 		tmpnm += DEV_BSIZE;
15780Sstevel@tonic-gate 	}
15790Sstevel@tonic-gate 	return (1);
15800Sstevel@tonic-gate }
15810Sstevel@tonic-gate 
15820Sstevel@tonic-gate /*
15830Sstevel@tonic-gate  * is_replicated
15840Sstevel@tonic-gate  *
15850Sstevel@tonic-gate  * Determines whether a disk has been replicated or not. It checks to see
15860Sstevel@tonic-gate  * if the device id stored in the master block is the same as the device id
15870Sstevel@tonic-gate  * registered for that disk on the current system. If the two device ids are
15880Sstevel@tonic-gate  * different, then we know that the disk has been replicated.
15890Sstevel@tonic-gate  *
15900Sstevel@tonic-gate  * If need_devid is set and the disk is replicated, fill in the new_devid.
15910Sstevel@tonic-gate  * Also, if need_devid is set, this routine allocates memory for the device
15920Sstevel@tonic-gate  * ids; the caller of this routine is responsible for free'ing up the memory.
15930Sstevel@tonic-gate  *
15940Sstevel@tonic-gate  * Returns:
15951945Sjeanm  * 	MD_IM_SET_REPLICATED	if it's a replicated disk
15961945Sjeanm  * 	0 			if it's not a replicated disk
15970Sstevel@tonic-gate  */
15980Sstevel@tonic-gate static int
is_replicated(int fd,mddb_mb_t * mbp,int need_devid,void ** new_devid)15990Sstevel@tonic-gate is_replicated(
16000Sstevel@tonic-gate 	int fd,
16010Sstevel@tonic-gate 	mddb_mb_t *mbp,
16020Sstevel@tonic-gate 	int need_devid,
16030Sstevel@tonic-gate 	void **new_devid
16040Sstevel@tonic-gate )
16050Sstevel@tonic-gate {
16060Sstevel@tonic-gate 	ddi_devid_t	current_devid;
16070Sstevel@tonic-gate 	int		retval = 0;
16080Sstevel@tonic-gate 	size_t		new_devid_len;
16090Sstevel@tonic-gate 
16100Sstevel@tonic-gate 	if (mbp->mb_devid_magic != MDDB_MAGIC_DE)
16110Sstevel@tonic-gate 		return (retval);
16120Sstevel@tonic-gate 
16130Sstevel@tonic-gate 	if (devid_get(fd, &current_devid) != 0)
16140Sstevel@tonic-gate 		return (retval);
16150Sstevel@tonic-gate 
16160Sstevel@tonic-gate 	if (devid_compare((ddi_devid_t)mbp->mb_devid, current_devid) != 0)
16171945Sjeanm 		retval = MD_IM_SET_REPLICATED;
16180Sstevel@tonic-gate 
16190Sstevel@tonic-gate 	if (retval && need_devid) {
16200Sstevel@tonic-gate 		new_devid_len = devid_sizeof(current_devid);
16210Sstevel@tonic-gate 		*new_devid = Zalloc(new_devid_len);
16220Sstevel@tonic-gate 		(void) memcpy(*new_devid, (void *)current_devid, new_devid_len);
16230Sstevel@tonic-gate 	}
16240Sstevel@tonic-gate 
16250Sstevel@tonic-gate 	devid_free(current_devid);
16260Sstevel@tonic-gate 	return (retval);
16270Sstevel@tonic-gate }
16280Sstevel@tonic-gate 
16290Sstevel@tonic-gate /*
16300Sstevel@tonic-gate  * free_replicated_disks_list()
16310Sstevel@tonic-gate  *
16320Sstevel@tonic-gate  * this frees up all the memory allocated by build_replicated_disks_list
16330Sstevel@tonic-gate  */
16340Sstevel@tonic-gate static void
free_replicated_disks_list()16350Sstevel@tonic-gate free_replicated_disks_list()
16360Sstevel@tonic-gate {
16370Sstevel@tonic-gate 	replicated_disk_t 	**repl_disk, *temp;
16380Sstevel@tonic-gate 	int 			index;
16390Sstevel@tonic-gate 
16400Sstevel@tonic-gate 	for (index = 0; index <= MAX_DEVID_LEN; index++) {
16410Sstevel@tonic-gate 		repl_disk = &replicated_disk_list[index];
16420Sstevel@tonic-gate 
16430Sstevel@tonic-gate 		while (*repl_disk != NULL) {
16440Sstevel@tonic-gate 			temp = *repl_disk;
16450Sstevel@tonic-gate 			*repl_disk = (*repl_disk)->next;
16460Sstevel@tonic-gate 
16470Sstevel@tonic-gate 			Free(temp->old_devid);
16480Sstevel@tonic-gate 			Free(temp->new_devid);
16490Sstevel@tonic-gate 			Free(temp);
16500Sstevel@tonic-gate 		}
16510Sstevel@tonic-gate 	}
16520Sstevel@tonic-gate }
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate /*
16550Sstevel@tonic-gate  * build_replicated_disks_list()
16560Sstevel@tonic-gate  *
16570Sstevel@tonic-gate  * Builds a list of disks that have been replicated using either a
16580Sstevel@tonic-gate  * remote replication or a point-in-time replication software. The
16590Sstevel@tonic-gate  * list is stored as a two dimensional sparse array.
16600Sstevel@tonic-gate  *
16610Sstevel@tonic-gate  * Returns
16620Sstevel@tonic-gate  * 	1	on success
16630Sstevel@tonic-gate  * 	0 	on failure
16640Sstevel@tonic-gate  */
16651945Sjeanm int
build_replicated_disks_list(md_error_t * ep,mddrivenamelist_t * dnlp)16660Sstevel@tonic-gate build_replicated_disks_list(
16670Sstevel@tonic-gate 	md_error_t *ep,
16680Sstevel@tonic-gate 	mddrivenamelist_t *dnlp
16690Sstevel@tonic-gate )
16700Sstevel@tonic-gate {
16710Sstevel@tonic-gate 	uint_t			sliceno;
16720Sstevel@tonic-gate 	int			fd = -1;
16730Sstevel@tonic-gate 	mddrivenamelist_t	*dp;
16740Sstevel@tonic-gate 	mdname_t		*rsp;
16750Sstevel@tonic-gate 	mddb_mb_t		*mbp;
16760Sstevel@tonic-gate 
16770Sstevel@tonic-gate 	mbp = Malloc(DEV_BSIZE);
16780Sstevel@tonic-gate 
16790Sstevel@tonic-gate 	for (dp = dnlp; dp != NULL; dp = dp->next) {
16800Sstevel@tonic-gate 		mddrivename_t *dnp;
16810Sstevel@tonic-gate 		void *new_devid;
16820Sstevel@tonic-gate 
16830Sstevel@tonic-gate 		dnp = dp->drivenamep;
16840Sstevel@tonic-gate 		/* determine the replica slice */
16850Sstevel@tonic-gate 		if (meta_replicaslice(dnp, &sliceno, ep) != 0)
16860Sstevel@tonic-gate 			continue;
16870Sstevel@tonic-gate 
16880Sstevel@tonic-gate 		/*
16890Sstevel@tonic-gate 		 * if the replica slice size is zero, don't bother opening
16900Sstevel@tonic-gate 		 */
16910Sstevel@tonic-gate 		if (dnp->vtoc.parts[sliceno].size == 0)
16920Sstevel@tonic-gate 			continue;
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate 		if ((rsp = metaslicename(dnp, sliceno, ep)) == NULL)
16950Sstevel@tonic-gate 			continue;
16960Sstevel@tonic-gate 
16970Sstevel@tonic-gate 		if ((fd = open(rsp->rname, O_RDONLY| O_NDELAY)) < 0)
16980Sstevel@tonic-gate 			return (mdsyserror(ep, errno, rsp->rname));
16990Sstevel@tonic-gate 
17000Sstevel@tonic-gate 		/* a drive may not have a master block so we just continue */
17010Sstevel@tonic-gate 		if (read_master_block(ep, fd, mbp, DEV_BSIZE) <= 0) {
17020Sstevel@tonic-gate 			(void) close(fd);
17030Sstevel@tonic-gate 			mdclrerror(ep);
17040Sstevel@tonic-gate 			continue;
17050Sstevel@tonic-gate 		}
17060Sstevel@tonic-gate 
17070Sstevel@tonic-gate 		if (is_replicated(fd, mbp, 1, &new_devid)) {
17080Sstevel@tonic-gate 			replicated_list_insert(mbp->mb_devid_len,
17090Sstevel@tonic-gate 			    mbp->mb_devid, new_devid);
17100Sstevel@tonic-gate 		}
17110Sstevel@tonic-gate 		(void) close(fd);
17120Sstevel@tonic-gate 	}
17131945Sjeanm 	*replicated_disk_list_built = 1;
17140Sstevel@tonic-gate 
17150Sstevel@tonic-gate 	Free(mbp);
17160Sstevel@tonic-gate 	return (1);
17170Sstevel@tonic-gate }
17180Sstevel@tonic-gate 
17190Sstevel@tonic-gate /*
17200Sstevel@tonic-gate  * free_did_list()
17210Sstevel@tonic-gate  *
17220Sstevel@tonic-gate  * Frees the did_list allocated as part of build_did_list
17230Sstevel@tonic-gate  */
17240Sstevel@tonic-gate static void
free_did_list(did_list_t * did_listp)17250Sstevel@tonic-gate free_did_list(
17260Sstevel@tonic-gate 	did_list_t	*did_listp
17270Sstevel@tonic-gate )
17280Sstevel@tonic-gate {
17290Sstevel@tonic-gate 	did_list_t	*temp, *head;
17300Sstevel@tonic-gate 
17310Sstevel@tonic-gate 	head = did_listp;
17320Sstevel@tonic-gate 
17330Sstevel@tonic-gate 	while (head != NULL) {
17340Sstevel@tonic-gate 		temp = head;
17350Sstevel@tonic-gate 		head = head->next;
17360Sstevel@tonic-gate 		if (temp->rdid)
17370Sstevel@tonic-gate 			Free(temp->rdid);
17380Sstevel@tonic-gate 		if (temp->did)
17390Sstevel@tonic-gate 			Free(temp->did);
17400Sstevel@tonic-gate 		if (temp->devname)
17410Sstevel@tonic-gate 			Free(temp->devname);
17420Sstevel@tonic-gate 		if (temp->minor_name)
17430Sstevel@tonic-gate 			Free(temp->minor_name);
17441945Sjeanm 		if (temp->driver_name)
17451945Sjeanm 			Free(temp->driver_name);
17461945Sjeanm 		Free(temp);
17471945Sjeanm 	}
17481945Sjeanm }
17491945Sjeanm 
17501945Sjeanm /*
17511945Sjeanm  * meta_free_im_replica_info
17521945Sjeanm  *
17531945Sjeanm  * Frees the md_im_replica_info list
17541945Sjeanm  */
17551945Sjeanm static void
meta_free_im_replica_info(md_im_replica_info_t * mirp)17561945Sjeanm meta_free_im_replica_info(
17571945Sjeanm 	md_im_replica_info_t	*mirp
17581945Sjeanm )
17591945Sjeanm {
17601945Sjeanm 	md_im_replica_info_t	*r, *temp;
17611945Sjeanm 
17621945Sjeanm 	r = mirp;
17631945Sjeanm 
17641945Sjeanm 	while (r != NULL) {
17651945Sjeanm 		temp = r;
17661945Sjeanm 		r = r->mir_next;
17671945Sjeanm 
17681945Sjeanm 		Free(temp);
17691945Sjeanm 	}
17701945Sjeanm }
17711945Sjeanm 
17721945Sjeanm /*
17731945Sjeanm  * meta_free_im_drive_info
17741945Sjeanm  *
17751945Sjeanm  * Frees the md_im_drive_info list
17761945Sjeanm  */
17771945Sjeanm static void
meta_free_im_drive_info(md_im_drive_info_t * midp)17781945Sjeanm meta_free_im_drive_info(
17791945Sjeanm 	md_im_drive_info_t	*midp
17801945Sjeanm )
17811945Sjeanm {
17821945Sjeanm 	md_im_drive_info_t	*d, *temp;
17831945Sjeanm 
17841945Sjeanm 	d = midp;
17851945Sjeanm 
17861945Sjeanm 	while (d != NULL) {
17871945Sjeanm 		temp = d;
17881945Sjeanm 		d = d->mid_next;
17891945Sjeanm 
17901945Sjeanm 		if (temp->mid_available & MD_IM_DISK_NOT_AVAILABLE)
17911945Sjeanm 			/*
17921945Sjeanm 			 * dnp is not on the drivenamelist and is a temp
17931945Sjeanm 			 * dnp for metaimport if the disk is unavailable.
17941945Sjeanm 			 * We need to specifically free it because of this.
17951945Sjeanm 			 * If the disk is available, standard drivelist freeing
17961945Sjeanm 			 * will kick in so we don't need to do it.
17971945Sjeanm 			 */
17981945Sjeanm 			metafreedrivename(temp->mid_dnp);
17991945Sjeanm 		if (temp->mid_devid)
18001945Sjeanm 			Free(temp->mid_devid);
18011945Sjeanm 		if (temp->mid_o_devid)
18021945Sjeanm 			Free(temp->mid_o_devid);
18031945Sjeanm 		if (temp->mid_driver_name)
18041945Sjeanm 			Free(temp->mid_driver_name);
18051945Sjeanm 		if (temp->mid_devname)
18061945Sjeanm 			Free(temp->mid_devname);
18071945Sjeanm 		if (temp->mid_replicas) {
18081945Sjeanm 			meta_free_im_replica_info(temp->mid_replicas);
18091945Sjeanm 			temp->mid_replicas = NULL;
18101945Sjeanm 		}
18111945Sjeanm 		if (temp->overlap) {
18121945Sjeanm 			meta_free_im_drive_info(temp->overlap);
18131945Sjeanm 			temp->overlap = NULL;
18141945Sjeanm 		}
18151945Sjeanm 		Free(temp);
18161945Sjeanm 	}
18171945Sjeanm }
18181945Sjeanm 
18191945Sjeanm /*
18201945Sjeanm  * meta_free_im_set_desc
18211945Sjeanm  *
18221945Sjeanm  * Frees the md_im_set_desc_t list
18231945Sjeanm  */
18241945Sjeanm void
meta_free_im_set_desc(md_im_set_desc_t * misp)18251945Sjeanm meta_free_im_set_desc(
18261945Sjeanm 	md_im_set_desc_t	*misp
18271945Sjeanm )
18281945Sjeanm {
18291945Sjeanm 	md_im_set_desc_t	*s, *temp;
18301945Sjeanm 
18311945Sjeanm 	s = misp;
18321945Sjeanm 
18331945Sjeanm 	while (s != NULL) {
18341945Sjeanm 		temp = s;
18351945Sjeanm 		s = s->mis_next;
18361945Sjeanm 		if (temp->mis_drives) {
18371945Sjeanm 			meta_free_im_drive_info(temp->mis_drives);
18381945Sjeanm 			temp->mis_drives = NULL;
18391945Sjeanm 		}
18400Sstevel@tonic-gate 		Free(temp);
18410Sstevel@tonic-gate 	}
18420Sstevel@tonic-gate }
18430Sstevel@tonic-gate 
18440Sstevel@tonic-gate /*
18450Sstevel@tonic-gate  * build_did_list()
18460Sstevel@tonic-gate  *
18470Sstevel@tonic-gate  * Build a list of device ids corresponding to disks in the locator block.
18480Sstevel@tonic-gate  * Memory is allocated here for the nodes in the did_list. The callers of
18490Sstevel@tonic-gate  * this routine must also call free_did_list to free up the memory after
18500Sstevel@tonic-gate  * they're done.
18510Sstevel@tonic-gate  *
18520Sstevel@tonic-gate  * Returns:
18530Sstevel@tonic-gate  *	< 0 		for failure
18540Sstevel@tonic-gate  *	  0 		for no valid locator block device id array
18550Sstevel@tonic-gate  *	  1 		for valid locator block device id array
18560Sstevel@tonic-gate  *	  ENOTSUP	partial diskset, not all disks in a diskset on the
18570Sstevel@tonic-gate  *			system where import is being executed
18580Sstevel@tonic-gate  */
18590Sstevel@tonic-gate static int
build_did_list(md_error_t * ep,int fd,mddb_mb_t * mb,mddb_lb_t * lbp,mddb_did_blk_t * lbdidp,mddb_ln_t * lnp,did_list_t ** did_listp,int replicated)18600Sstevel@tonic-gate build_did_list(
18610Sstevel@tonic-gate 	md_error_t	*ep,
18620Sstevel@tonic-gate 	int		fd,
18630Sstevel@tonic-gate 	mddb_mb_t	*mb,
18641945Sjeanm 	mddb_lb_t	*lbp,
18650Sstevel@tonic-gate 	mddb_did_blk_t	*lbdidp,
18661945Sjeanm 	mddb_ln_t	*lnp,
18670Sstevel@tonic-gate 	did_list_t	**did_listp,
18680Sstevel@tonic-gate 	int		replicated
18690Sstevel@tonic-gate )
18700Sstevel@tonic-gate {
18710Sstevel@tonic-gate 	char 		*search_path = "/dev";
18720Sstevel@tonic-gate 	char		*minor_name;
18730Sstevel@tonic-gate 	int		rval, cnt;
18740Sstevel@tonic-gate 	devid_nmlist_t	*nm;
18750Sstevel@tonic-gate 	uint_t		did_info_length = 0;
18760Sstevel@tonic-gate 	uint_t		did_info_firstblk = 0;
18770Sstevel@tonic-gate 	did_list_t	*new, *head = NULL;
18780Sstevel@tonic-gate 	char		*bp = NULL, *temp;
18790Sstevel@tonic-gate 	mddb_did_info_t	*did_info = NULL;
18800Sstevel@tonic-gate 	void		*did = NULL;
18810Sstevel@tonic-gate 	size_t		new_devid_len;
18821945Sjeanm 	int		partial = 0;
18831945Sjeanm 	int		partial_replicated = 0;
18840Sstevel@tonic-gate 
18850Sstevel@tonic-gate 	for (cnt = 0; cnt < MDDB_NLB; cnt++) {
18861945Sjeanm 		partial_replicated = 0;
18870Sstevel@tonic-gate 		did_info = &lbdidp->blk_info[cnt];
18880Sstevel@tonic-gate 
18890Sstevel@tonic-gate 		if (!(did_info->info_flags & MDDB_DID_EXISTS))
18900Sstevel@tonic-gate 			continue;
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate 		new = Zalloc(sizeof (did_list_t));
18930Sstevel@tonic-gate 		new->did = Zalloc(did_info->info_length);
18940Sstevel@tonic-gate 
18950Sstevel@tonic-gate 		/*
18961945Sjeanm 		 * If we can re-use the buffer that has already been
18970Sstevel@tonic-gate 		 * read in then just use it.  Otherwise free
18980Sstevel@tonic-gate 		 * the previous one and alloc a new one
18990Sstevel@tonic-gate 		 */
1900*4901Sjr26306 		if (did_info->info_firstblk != did_info_firstblk) {
19010Sstevel@tonic-gate 
19020Sstevel@tonic-gate 			did_info_length = dbtob(did_info->info_blkcnt);
19030Sstevel@tonic-gate 			did_info_firstblk = did_info->info_firstblk;
19040Sstevel@tonic-gate 
19050Sstevel@tonic-gate 			if (bp)
19060Sstevel@tonic-gate 				Free(bp);
19070Sstevel@tonic-gate 			bp = temp = Zalloc(did_info_length);
19080Sstevel@tonic-gate 
19090Sstevel@tonic-gate 			if ((rval = phys_read(ep, fd, mb, did_info_firstblk,
19100Sstevel@tonic-gate 			    (void *)bp, did_info_length)) < 0)
19110Sstevel@tonic-gate 				return (rval);
19120Sstevel@tonic-gate 		} else {
19130Sstevel@tonic-gate 			temp = bp;
19140Sstevel@tonic-gate 		}
19150Sstevel@tonic-gate 
19160Sstevel@tonic-gate 		temp += did_info->info_offset;
19170Sstevel@tonic-gate 		(void) memcpy(new->did, temp, did_info->info_length);
19180Sstevel@tonic-gate 		new->did_index = cnt;
19190Sstevel@tonic-gate 		minor_name = did_info->info_minor_name;
19200Sstevel@tonic-gate 
19210Sstevel@tonic-gate 		/*
19220Sstevel@tonic-gate 		 * If we are not able to find the ctd mapping corresponding
19230Sstevel@tonic-gate 		 * to a given device id, it probably means the device id in
19240Sstevel@tonic-gate 		 * question is not registered with the system.
19250Sstevel@tonic-gate 		 *
19260Sstevel@tonic-gate 		 * Highly likely that the only time this happens, we've hit
19270Sstevel@tonic-gate 		 * a case where not all the disks that are a part of the
19280Sstevel@tonic-gate 		 * diskset were moved before importing the diskset.
19290Sstevel@tonic-gate 		 *
19300Sstevel@tonic-gate 		 * If set is a replicated diskset, then the device id we get
19310Sstevel@tonic-gate 		 * from 'lb' will be the 'other' did and we need to lookup
19320Sstevel@tonic-gate 		 * the real one before we call this routine.
19330Sstevel@tonic-gate 		 */
19340Sstevel@tonic-gate 		if (replicated) {
19350Sstevel@tonic-gate 		    temp = replicated_list_lookup(did_info->info_length,
19360Sstevel@tonic-gate 			new->did);
19371945Sjeanm 		    if (temp == NULL) {
19381945Sjeanm 			/* we have a partial replicated set, fake it */
19391945Sjeanm 			new_devid_len = devid_sizeof((ddi_devid_t)new->did);
19401945Sjeanm 			new->rdid = Zalloc(new_devid_len);
19411945Sjeanm 			(void) memcpy(new->rdid, new->did, new_devid_len);
19421945Sjeanm 			did = new->rdid;
19431945Sjeanm 			partial_replicated = 1;
19441945Sjeanm 		    } else {
19451945Sjeanm 			new_devid_len = devid_sizeof((ddi_devid_t)temp);
19461945Sjeanm 			new->rdid = Zalloc(new_devid_len);
19471945Sjeanm 			(void) memcpy(new->rdid, temp, new_devid_len);
19481945Sjeanm 			did = new->rdid;
19491945Sjeanm 		    }
19500Sstevel@tonic-gate 		} else {
19510Sstevel@tonic-gate 		    did = new->did;
19520Sstevel@tonic-gate 		}
19530Sstevel@tonic-gate 
19540Sstevel@tonic-gate 		if (devid_valid((ddi_devid_t)(did)) == 0) {
19550Sstevel@tonic-gate 			return (-1);
19560Sstevel@tonic-gate 		}
19570Sstevel@tonic-gate 
19581945Sjeanm 		if (partial_replicated || meta_deviceid_to_nmlist(search_path,
19591945Sjeanm 		    (ddi_devid_t)did, minor_name, &nm) != 0) {
19601945Sjeanm 			int	len = 0;
19611945Sjeanm 
19621945Sjeanm 			/*
19631945Sjeanm 			 * Partial diskset case. We'll need to get the
19641945Sjeanm 			 * device information from the metadb instead
19651945Sjeanm 			 * of the output (nm) of meta_deviceid_to_nmlist.
19661945Sjeanm 			 */
19671945Sjeanm 			len = strlen(lnp->ln_prefixes[0].pre_data) +
19681945Sjeanm 			    strlen(lnp->ln_suffixes[0][cnt].suf_data) + 2;
19691945Sjeanm 			new->devname = Zalloc(len);
19701945Sjeanm 			(void) strlcpy(new->devname,
19711945Sjeanm 			    lnp->ln_prefixes[0].pre_data,
19721945Sjeanm 			    strlen(lnp->ln_prefixes[0].pre_data) + 1);
19731945Sjeanm 			(void) strlcat(new->devname, "/", len);
19741945Sjeanm 			(void) strlcat(new->devname,
19751945Sjeanm 			    lnp->ln_suffixes[0][cnt].suf_data, len);
19761945Sjeanm 			new->minor_name = Strdup(minor_name);
19771945Sjeanm 			new->next = head;
19781945Sjeanm 			new->available = MD_IM_DISK_NOT_AVAILABLE;
19791945Sjeanm 			new->driver_name = Strdup(lbp->lb_drvnm[0].dn_data);
19801945Sjeanm 			new->dev = lbp->lb_locators[cnt].l_dev;
19811945Sjeanm 			head = new;
19821945Sjeanm 			partial = ENOTSUP;
19831945Sjeanm 			continue;
19840Sstevel@tonic-gate 		}
19850Sstevel@tonic-gate 
19861945Sjeanm 		/*
19871945Sjeanm 		 * Disk is there. Grab device information from nm structure.
19881945Sjeanm 		 */
19890Sstevel@tonic-gate 		assert(nm->devname != NULL);
19900Sstevel@tonic-gate 		new->devname = Strdup(nm->devname);
19910Sstevel@tonic-gate 		new->dev = nm->dev;
19920Sstevel@tonic-gate 		new->minor_name = Strdup(minor_name);
19931945Sjeanm 		new->available = MD_IM_DISK_AVAILABLE;
19940Sstevel@tonic-gate 
19950Sstevel@tonic-gate 		devid_free_nmlist(nm);
19960Sstevel@tonic-gate 
19970Sstevel@tonic-gate 		new->next = head;
19980Sstevel@tonic-gate 		head = new;
19990Sstevel@tonic-gate 	}
20000Sstevel@tonic-gate 
20010Sstevel@tonic-gate 	/* Free the last bp */
20020Sstevel@tonic-gate 	if (bp)
20030Sstevel@tonic-gate 		Free(bp);
20040Sstevel@tonic-gate 	*did_listp = head;
20051945Sjeanm 	if (partial)
20061945Sjeanm 		return (partial);
20070Sstevel@tonic-gate 	return (1);
20080Sstevel@tonic-gate }
200957Sjeanm /*
201057Sjeanm  * check_nm_disks
201157Sjeanm  *	Checks the disks listed in the shared did namespace to see if they
201257Sjeanm  *	are accessable on the system. If not, return ENOTSUP error to
201357Sjeanm  *	indicate we have a partial diskset.
201457Sjeanm  * Returns:
201557Sjeanm  *	< 0 		for failure
201657Sjeanm  *	  0		success
201757Sjeanm  *	  ENOTSUP	partial diskset, not all disks in a diskset on the
201857Sjeanm  *			system where import is being executed
201957Sjeanm  */
202057Sjeanm static int
check_nm_disks(struct devid_min_rec * did_nmp,struct devid_shr_rec * did_shrnmp)202157Sjeanm check_nm_disks(
202257Sjeanm 	struct devid_min_rec	*did_nmp,
202357Sjeanm 	struct devid_shr_rec	*did_shrnmp
202457Sjeanm )
202557Sjeanm {
202657Sjeanm 	char 		*search_path = "/dev";
202757Sjeanm 	char		*minor_name = NULL;
202857Sjeanm 	uint_t		used_size, min_used_size;
202957Sjeanm 	ddi_devid_t	did;
203057Sjeanm 	devid_nmlist_t	*nm;
203157Sjeanm 	void		*did_min_namep;
203257Sjeanm 	void		*did_shr_namep;
203357Sjeanm 	size_t		did_nsize, did_shr_nsize;
203457Sjeanm 
203557Sjeanm 	used_size = did_shrnmp->did_rec_hdr.r_used_size -
203657Sjeanm 	    sizeof (struct nm_rec_hdr);
203757Sjeanm 	min_used_size = did_nmp->min_rec_hdr.r_used_size -
203857Sjeanm 	    sizeof (struct nm_rec_hdr);
203957Sjeanm 	did_shr_namep = (void *)(&did_shrnmp->device_id[0]);
204057Sjeanm 	while (used_size > (int)sizeof (struct did_shr_name)) {
204157Sjeanm 		did_min_namep = (void *)(&did_nmp->minor_name[0]);
204257Sjeanm 		/* grab device id and minor name from the shared spaces */
204357Sjeanm 		did = (ddi_devid_t)(((struct did_shr_name *)
204457Sjeanm 		    did_shr_namep)->did_devid);
204557Sjeanm 		if (devid_valid(did) == 0) {
204657Sjeanm 			return (-1);
204757Sjeanm 		}
204857Sjeanm 
204957Sjeanm 		/*
205057Sjeanm 		 * We need to check that the DID_NM and DID_SHR_NM are in
205157Sjeanm 		 * sync. It is possible that we took a panic between writing
205257Sjeanm 		 * the two areas to disk. This would be cleaned up on the
205357Sjeanm 		 * next snarf but we don't know for sure that snarf has even
205457Sjeanm 		 * happened since we're reading from disk.
205557Sjeanm 		 */
205657Sjeanm 		while (((struct did_shr_name *)did_shr_namep)->did_key !=
205757Sjeanm 		    ((struct did_min_name *)did_min_namep)->min_devid_key) {
205857Sjeanm 			did_nsize = DID_NAMSIZ((struct did_min_name *)
205957Sjeanm 			    did_min_namep);
206057Sjeanm 			did_min_namep = ((void *)((char *)did_min_namep +
206157Sjeanm 			    did_nsize));
206257Sjeanm 			min_used_size -= did_nsize;
206357Sjeanm 			if (min_used_size < (int)sizeof (struct did_min_name))
206457Sjeanm 				continue;
206557Sjeanm 		}
206657Sjeanm 		minor_name = ((struct did_min_name *)did_min_namep)->min_name;
206757Sjeanm 
206857Sjeanm 		/*
206957Sjeanm 		 * Try to find disk in the system. If we can't find the
207057Sjeanm 		 * disk, we have a partial diskset.
207157Sjeanm 		 */
207257Sjeanm 		if ((meta_deviceid_to_nmlist(search_path,
207357Sjeanm 		    did, minor_name, &nm)) != 0) {
20741945Sjeanm 			/* Partial diskset detected */
207557Sjeanm 			return (ENOTSUP);
207657Sjeanm 		}
207757Sjeanm 		devid_free_nmlist(nm);
207857Sjeanm 		used_size -= DID_SHR_NAMSIZ((struct did_shr_name *)
207957Sjeanm 		    did_shr_namep);
208057Sjeanm 		/* increment to next item in the shared spaces */
208157Sjeanm 		did_shr_nsize = DID_SHR_NAMSIZ((struct did_shr_name *)
208257Sjeanm 		    did_shr_namep);
208357Sjeanm 		did_shr_namep = ((void *)((char *)did_shr_namep +
208457Sjeanm 		    did_shr_nsize));
208557Sjeanm 	}
208657Sjeanm 	return (0);
208757Sjeanm }
20880Sstevel@tonic-gate 
2089734Smw145384 
20900Sstevel@tonic-gate /*
2091734Smw145384  * report_metadb_info()
2092734Smw145384  *
2093734Smw145384  * Generates metadb output for the diskset.
2094734Smw145384  *
2095734Smw145384  */
2096734Smw145384 static void
report_metadb_info(md_im_set_desc_t * misp,char * indent)2097734Smw145384 report_metadb_info(
2098734Smw145384 	md_im_set_desc_t	*misp,
2099734Smw145384 	char			*indent
2100734Smw145384 )
2101734Smw145384 {
2102734Smw145384 	md_im_drive_info_t	*d;
2103734Smw145384 	md_im_replica_info_t	*r;
2104734Smw145384 	char			*unk_str = "";
2105734Smw145384 	int			i;
2106734Smw145384 
2107734Smw145384 	(void) printf("%s\t%5.5s\t\t%9.9s\t%11.11s\n", indent, gettext("flags"),
2108734Smw145384 	    gettext("first blk"), gettext("block count"));
2109734Smw145384 
2110734Smw145384 	unk_str = gettext("unknown");
2111734Smw145384 
2112734Smw145384 	/*
2113734Smw145384 	 * Looping through all drives in the diskset to print
2114734Smw145384 	 * out information about the drive and if the verbose
2115734Smw145384 	 * option is set print out replica data.
2116734Smw145384 	 */
2117734Smw145384 	for (d = misp->mis_drives; d != NULL; d = d->mid_next) {
2118734Smw145384 
2119734Smw145384 		if (d->mid_replicas != NULL) {
2120734Smw145384 			for (r = d->mid_replicas; r != NULL;
2121734Smw145384 			    r = r->mir_next) {
2122734Smw145384 				(void) printf("%s", indent);
2123734Smw145384 				for (i = 0; i < MDDB_FLAGS_LEN; i++) {
2124734Smw145384 					if (r->mir_flags & (1 << i)) {
2125734Smw145384 						(void) putchar(
2126734Smw145384 						    MDDB_FLAGS_STRING[i]);
2127734Smw145384 					} else {
2128734Smw145384 						(void) putchar(' ');
2129734Smw145384 					}
2130734Smw145384 				}
2131734Smw145384 				if ((r->mir_offset == -1) && (r->mir_length
2132734Smw145384 				    == -1)) {
2133734Smw145384 					(void) printf("%7.7s\t\t%7.7s\t",
2134734Smw145384 					    unk_str, unk_str);
2135734Smw145384 				} else if (r->mir_length == -1) {
2136734Smw145384 					(void) printf("%i\t\t%7.7s\t",
2137734Smw145384 					    r->mir_offset, unk_str);
2138734Smw145384 				} else {
2139734Smw145384 					(void) printf("%i\t\t%i\t",
2140734Smw145384 					    r->mir_offset, r->mir_length);
2141734Smw145384 				}
2142734Smw145384 				(void) printf("\t%s\n",
2143734Smw145384 				    d->mid_devname);
2144734Smw145384 			}
2145734Smw145384 		}
2146734Smw145384 	}
2147734Smw145384 	(void) printf("\n");
2148734Smw145384 }
2149734Smw145384 
21501945Sjeanm /*
21511945Sjeanm  * meta_replica_quorum will determine if the disks in the set to be
21521945Sjeanm  * imported have enough valid replicas to have quorum.
21531945Sjeanm  *
21541945Sjeanm  * RETURN:
21551945Sjeanm  *	-1	Set doesn't have quorum
21561945Sjeanm  *	0	Set does have quorum
21571945Sjeanm  */
21581945Sjeanm int
meta_replica_quorum(md_im_set_desc_t * misp)21591945Sjeanm meta_replica_quorum(
21601945Sjeanm 	md_im_set_desc_t *misp
21611945Sjeanm )
21621945Sjeanm {
21631945Sjeanm 	md_im_drive_info_t	*midp;
21641945Sjeanm 	md_im_replica_info_t    *midr;
21651945Sjeanm 	int			replica_count = 0;
21661945Sjeanm 
21671945Sjeanm 	for (midp = misp->mis_drives; midp != NULL;
21681945Sjeanm 		midp = midp->mid_next) {
21691945Sjeanm 
21701945Sjeanm 		if (midp->mid_available == MD_IM_DISK_NOT_AVAILABLE)
21711945Sjeanm 			continue;
21721945Sjeanm 
21731945Sjeanm 		/*
21741945Sjeanm 		 * The drive is okay. Now count its replicas
21751945Sjeanm 		 */
21761945Sjeanm 		for (midr = midp->mid_replicas; midr != NULL;
21771945Sjeanm 			midr = midr->mir_next) {
21781945Sjeanm 			replica_count++;
21791945Sjeanm 		}
21801945Sjeanm 	}
21811945Sjeanm 
21821945Sjeanm 	if (misp->mis_active_replicas & 1) {
21831945Sjeanm 		/* odd number of replicas */
21841945Sjeanm 		if (replica_count < (misp->mis_active_replicas + 1)/2)
21851945Sjeanm 			return (-1);
21861945Sjeanm 	} else {
21871945Sjeanm 		/* even number of replicas */
21881945Sjeanm 		if (replica_count <= ((misp->mis_active_replicas + 1)/2))
21891945Sjeanm 			return (-1);
21901945Sjeanm 	}
21911945Sjeanm 
21921945Sjeanm 	return (0);
21931945Sjeanm }
21941945Sjeanm 
21951945Sjeanm 
21961945Sjeanm /*
21971945Sjeanm  * Choose the best drive to use for the metaimport command.
21981945Sjeanm  */
21991945Sjeanm md_im_drive_info_t *
pick_good_disk(md_im_set_desc_t * misp)22001945Sjeanm pick_good_disk(md_im_set_desc_t *misp)
22011945Sjeanm {
22021945Sjeanm 	md_timeval32_t		*setcrtime; /* set creation time */
22031945Sjeanm 	md_im_drive_info_t	*good_disk = NULL;
22041945Sjeanm 	md_im_drive_info_t	*midp = NULL;
22051945Sjeanm 	md_im_replica_info_t	*mirp;
22061945Sjeanm 
22071945Sjeanm 	setcrtime = &(misp->mis_drives->mid_replicas->mir_timestamp);
22081945Sjeanm 	for (midp = misp->mis_drives; (midp != NULL) && (good_disk == NULL);
22091945Sjeanm 	    midp = midp->mid_next) {
22101945Sjeanm 		/* drive must be available */
22111945Sjeanm 		if (midp->mid_available == MD_IM_DISK_NOT_AVAILABLE) {
22121945Sjeanm 			continue;
22131945Sjeanm 		}
22141945Sjeanm 		for (mirp = midp->mid_replicas; mirp != NULL;
22151945Sjeanm 		    mirp = mirp->mir_next) {
22161945Sjeanm 			/* replica must be active to be a good one */
22171945Sjeanm 			if (mirp->mir_flags & MDDB_F_ACTIVE) {
22181945Sjeanm 				if ((setcrtime->tv_sec ==
22191945Sjeanm 				    midp-> mid_setcreatetimestamp.tv_sec) &&
22201945Sjeanm 				    (setcrtime->tv_usec ==
22211945Sjeanm 				    midp->mid_setcreatetimestamp.tv_usec)) {
22221945Sjeanm 					good_disk = midp;
22231945Sjeanm 					break;
22241945Sjeanm 				}
22251945Sjeanm 			}
22261945Sjeanm 		}
22271945Sjeanm 	}
22281945Sjeanm 	return (good_disk);
22291945Sjeanm }
2230734Smw145384 
2231734Smw145384 /*
2232734Smw145384  * report_set_info()
2233734Smw145384  *
2234734Smw145384  * Returns:
2235734Smw145384  *	< 0 for failure
2236734Smw145384  *	  0 for success
2237734Smw145384  *
2238734Smw145384  */
2239734Smw145384 static int
report_set_info(md_im_set_desc_t * misp,mddb_mb_t * mb,mddb_lb_t * lbp,mddb_rb_t * nm,pnm_rec_t ** pnm,mdname_t * rsp,int fd,uint_t imp_flags,int set_count,int overlap,md_im_drive_info_t * overlap_disks,md_error_t * ep)2240734Smw145384 report_set_info(
2241734Smw145384 	md_im_set_desc_t	*misp,
2242734Smw145384 	mddb_mb_t		*mb,
2243734Smw145384 	mddb_lb_t		*lbp,
2244734Smw145384 	mddb_rb_t		*nm,
2245734Smw145384 	pnm_rec_t		**pnm,
2246734Smw145384 	mdname_t		*rsp,
2247734Smw145384 	int			fd,
2248734Smw145384 	uint_t			imp_flags,
2249734Smw145384 	int			set_count,
22501945Sjeanm 	int			overlap,
22511945Sjeanm 	md_im_drive_info_t	*overlap_disks,
2252734Smw145384 	md_error_t		*ep
2253734Smw145384 )
2254734Smw145384 {
2255734Smw145384 	int 			rval = 0;
2256734Smw145384 	md_im_drive_info_t	*d;
2257734Smw145384 	md_im_drive_info_t	*good_disk = NULL;
2258734Smw145384 	int			i;
2259734Smw145384 	int			in = META_INDENT;
2260734Smw145384 	char			indent[MAXPATHLEN];
2261734Smw145384 	md_timeval32_t		lastaccess; /* stores last modified timestamp */
22621945Sjeanm 	int			has_overlap = 0;
22631945Sjeanm 	int			no_quorum = 0;
22641945Sjeanm 	int			partial = 0;
2265734Smw145384 
2266734Smw145384 	/* Calculates the correct indentation. */
2267734Smw145384 	indent[0] = 0;
2268734Smw145384 	for (i = 0; i < in; i++)
2269734Smw145384 		(void) strlcat(indent, " ", sizeof (indent));
2270734Smw145384 
2271734Smw145384 	/*
2272734Smw145384 	 * This will print before the information for the first diskset
2273734Smw145384 	 * if the verbose option was set.
2274734Smw145384 	 */
2275734Smw145384 	if (set_count == 1) {
2276734Smw145384 		if (imp_flags & META_IMP_REPORT) {
2277734Smw145384 			(void) printf("\n%s:\n\n",
2278734Smw145384 			    gettext("Disksets eligible for import"));
2279734Smw145384 		}
2280734Smw145384 	}
2281734Smw145384 
22821945Sjeanm 	partial = misp->mis_partial;
22831945Sjeanm 	good_disk = pick_good_disk(misp);
22841945Sjeanm 	if (good_disk == NULL) {
22851945Sjeanm 		return (rval);
22861945Sjeanm 	}
22871945Sjeanm 
2288734Smw145384 	/*
2289734Smw145384 	 * Make the distinction between a regular diskset and
22901945Sjeanm 	 * a replicated diskset.  Also make the distinction
22911945Sjeanm 	 * between a partial vs. full diskset.
2292734Smw145384 	 */
22931945Sjeanm 	if (partial == MD_IM_PARTIAL_DISKSET) {
22941945Sjeanm 		if (misp->mis_flags & MD_IM_SET_REPLICATED) {
22951945Sjeanm 			if (imp_flags & META_IMP_REPORT) {
22961945Sjeanm 				(void) printf("%i)  %s:\n", set_count, gettext(
22971945Sjeanm 				    "Found partial replicated diskset "
22981945Sjeanm 				    "containing disks"));
22991945Sjeanm 			} else {
23001945Sjeanm 				(void) printf("\n%s:\n", gettext(
23011945Sjeanm 				    "Importing partial replicated diskset "
23021945Sjeanm 				    "containing disks"));
23031945Sjeanm 			}
2304734Smw145384 		} else {
23051945Sjeanm 			if (imp_flags & META_IMP_REPORT) {
23061945Sjeanm 				(void) printf("%i)  %s:\n", set_count, gettext(
23071945Sjeanm 				    "Found partial regular diskset containing "
23081945Sjeanm 				    "disks"));
23091945Sjeanm 			} else {
23101945Sjeanm 				(void) printf("\n%s:\n", gettext(
23111945Sjeanm 				    "Importing partial regular diskset "
23121945Sjeanm 				    "containing disks"));
23131945Sjeanm 			}
2314734Smw145384 		}
2315734Smw145384 	} else {
23161945Sjeanm 		if (misp->mis_flags & MD_IM_SET_REPLICATED) {
23171945Sjeanm 			if (imp_flags & META_IMP_REPORT) {
23181945Sjeanm 				(void) printf("%i)  %s:\n", set_count, gettext(
23191945Sjeanm 				    "Found replicated diskset containing "
23201945Sjeanm 				    "disks"));
23211945Sjeanm 			} else {
23221945Sjeanm 				(void) printf("\n%s:\n", gettext(
23231945Sjeanm 				    "Importing replicated diskset containing "
23241945Sjeanm 				    "disks"));
23251945Sjeanm 			}
2326734Smw145384 		} else {
23271945Sjeanm 			if (imp_flags & META_IMP_REPORT) {
23281945Sjeanm 				(void) printf("%i)  %s:\n", set_count, gettext(
23291945Sjeanm 				    "Found regular diskset containing disks"));
23301945Sjeanm 			} else {
23311945Sjeanm 				(void) printf("\n%s:\n", gettext(
23321945Sjeanm 				    "Importing regular diskset containing "
23331945Sjeanm 				    "disks"));
23341945Sjeanm 			}
2335734Smw145384 		}
2336734Smw145384 	}
2337734Smw145384 
2338734Smw145384 	/*
23391945Sjeanm 	 * Check each drive in the set. If it's unavailable or
23401945Sjeanm 	 * an overlap tell the user.
2341734Smw145384 	 */
2342734Smw145384 	for (d = misp->mis_drives; d != NULL; d = d->mid_next) {
23431945Sjeanm 		(void) fprintf(stdout, "  %s", d->mid_dnp->cname);
23441945Sjeanm 		if (d->mid_available == MD_IM_DISK_NOT_AVAILABLE) {
23451945Sjeanm 			(void) fprintf(stdout, " (UNAVAIL)");
23461945Sjeanm 		}
23471945Sjeanm 		if (overlap) {
23481945Sjeanm 			md_im_drive_info_t	**chain;
23491945Sjeanm 			/*
23501945Sjeanm 			 * There is the potential for an overlap, see if
23511945Sjeanm 			 * this disk is one of the overlapped disks.
23521945Sjeanm 			 */
23531945Sjeanm 			for (chain = &overlap_disks; *chain != NULL;
23541945Sjeanm 			    chain = &(*chain)->overlap) {
23551945Sjeanm 				if (strcmp(d->mid_dnp->cname,
23561945Sjeanm 				    (*chain)->mid_dnp->cname) == 0) {
23571945Sjeanm 					(void) fprintf(stdout, " (CONFLICT)");
23581945Sjeanm 					has_overlap = 1;
2359734Smw145384 					break;
2360734Smw145384 				}
2361734Smw145384 			}
2362734Smw145384 		}
23631945Sjeanm 		(void) fprintf(stdout, "\n");
2364734Smw145384 	}
2365734Smw145384 
2366734Smw145384 	/*
23671945Sjeanm 	 * This note explains the (UNAVAIL) that appears next to the
23681945Sjeanm 	 * disks in the diskset that are not available.
2369734Smw145384 	 */
23701945Sjeanm 	if (partial) {
23711945Sjeanm 		(void) printf("%s%s\n%s%s\n\n", indent,
23721945Sjeanm 		    gettext("(UNAVAIL) WARNING: This disk is unavailable on"
23731945Sjeanm 		    " this system."), indent, gettext("Import may corrupt "
23741945Sjeanm 		    "data in the diskset."));
2375734Smw145384 	}
2376734Smw145384 
2377734Smw145384 	/*
23781945Sjeanm 	 * This note explains the (CONFLICT) that appears next to the
23791945Sjeanm 	 * disks whose lb_inittime timestamp does not
2380734Smw145384 	 * match the rest of the diskset.
2381734Smw145384 	 */
23821945Sjeanm 	if (has_overlap) {
2383734Smw145384 		(void) printf("%s%s\n%s%s\n\n", indent,
23841945Sjeanm 		    gettext("(CONFLICT) WARNING: This disk has been reused in "
23851945Sjeanm 		    "another diskset or system configuration."), indent,
23861945Sjeanm 		    gettext("Import may corrupt data in the diskset."));
2387734Smw145384 	}
2388734Smw145384 
2389734Smw145384 	/*
2390734Smw145384 	 * If the verbose flag was given on the command line,
2391734Smw145384 	 * we will print out the metastat -c information , the
2392734Smw145384 	 * creation time, and last modified time for the diskset.
2393734Smw145384 	 */
2394734Smw145384 	if (imp_flags & META_IMP_VERBOSE) {
2395734Smw145384 		(void) printf("%s%s\n", indent,
2396734Smw145384 		    gettext("Metadatabase information:"));
2397734Smw145384 		report_metadb_info(misp, indent);
2398734Smw145384 
2399734Smw145384 		/*
2400734Smw145384 		 * Printing creation time and last modified time.
2401734Smw145384 		 * Last modified: uses the global variable "lastaccess",
2402734Smw145384 		 * which is set to the last updated timestamp from all of
2403734Smw145384 		 * the database blocks(db_timestamp) or record blocks
2404734Smw145384 		 * (rb_timestamp).
2405734Smw145384 		 * Creation time is the locator block init time
2406734Smw145384 		 * (lb_inittime).
2407734Smw145384 		 */
2408734Smw145384 		lastaccess = good_disk->mid_replicas->mir_timestamp;
2409734Smw145384 
2410734Smw145384 		(void) printf("%s%s\n", indent,
2411734Smw145384 		    gettext("Metadevice information:"));
2412734Smw145384 		rval = report_metastat_info(mb, lbp, nm, pnm, rsp, fd,
2413734Smw145384 		    &lastaccess, ep);
2414734Smw145384 		if (rval < 0) {
2415734Smw145384 			return (rval);
2416734Smw145384 		}
2417734Smw145384 
2418734Smw145384 		(void) printf("%s%s:\t%s\n", indent,
2419734Smw145384 		    gettext("Creation time"),
2420734Smw145384 		    meta_print_time(&good_disk->mid_replicas->mir_timestamp));
2421734Smw145384 		(void) printf("%s%s:\t%s\n", indent,
2422734Smw145384 		    gettext("Last modified time"),
2423734Smw145384 		    meta_print_time(&lastaccess));
2424734Smw145384 	} else {
2425734Smw145384 		/*
2426734Smw145384 		 * Even if the verbose option is not set, we will print the
2427734Smw145384 		 * creation time for the diskset.
2428734Smw145384 		 */
2429734Smw145384 		(void) printf("%s%s:\t%s\n", indent, gettext("Creation time"),
2430734Smw145384 		    meta_print_time(&good_disk->mid_replicas->mir_timestamp));
2431734Smw145384 	}
2432734Smw145384 
2433734Smw145384 
2434734Smw145384 	/*
2435734Smw145384 	 * If the diskset is not actually being imported, then we
2436734Smw145384 	 * print out extra information about how to import it.
2437734Smw145384 	 * If the verbose flag was not set, then we will also
2438734Smw145384 	 * print out information about how to obtain verbose output.
2439734Smw145384 	 */
2440734Smw145384 	if (imp_flags & META_IMP_REPORT) {
2441734Smw145384 		/*
2442734Smw145384 		 * TRANSLATION_NOTE
2443734Smw145384 		 *
2444734Smw145384 		 * The translation of the phrase "For more information
2445734Smw145384 		 * about this set" will be followed by a ":" and a
2446734Smw145384 		 * suggested command (untranslatable) that the user
2447734Smw145384 		 * may use to request additional information.
2448734Smw145384 		 */
2449734Smw145384 		if (!(imp_flags & META_IMP_VERBOSE)) {
2450734Smw145384 		(void) printf("%s%s:\n%s  %s -r -v %s\n", indent,
2451734Smw145384 		    gettext("For more information about this diskset"),
2452734Smw145384 		    indent, myname, good_disk->mid_dnp->cname);
2453734Smw145384 		}
24541945Sjeanm 
24551945Sjeanm 		if (meta_replica_quorum(misp) != 0)
24561945Sjeanm 			no_quorum = 1;
24571945Sjeanm 
2458734Smw145384 		/*
2459734Smw145384 		 * TRANSLATION_NOTE
2460734Smw145384 		 *
2461734Smw145384 		 * The translation of the phrase "To import this set"
2462734Smw145384 		 * will be followed by a ":" and a suggested command
2463734Smw145384 		 * (untranslatable) that the user may use to import
2464734Smw145384 		 * the specified diskset.
2465734Smw145384 		 */
24661945Sjeanm 		if (partial || has_overlap || no_quorum) {
24671945Sjeanm 			(void) printf("%s%s:\n%s  %s -f -s <newsetname> %s\n",
24681945Sjeanm 			    indent, gettext("To import this diskset"), indent,
24691945Sjeanm 			    myname, good_disk->mid_dnp->cname);
24701945Sjeanm 		} else {
24711945Sjeanm 			(void) printf("%s%s:\n%s  %s -s <newsetname> %s\n",
24721945Sjeanm 			    indent, gettext("To import this diskset"), indent,
24731945Sjeanm 			    myname, good_disk->mid_dnp->cname);
24741945Sjeanm 		}
2475734Smw145384 	}
2476734Smw145384 	(void) printf("\n\n");
2477734Smw145384 
2478734Smw145384 	return (rval);
2479734Smw145384 }
2480734Smw145384 
2481734Smw145384 
2482734Smw145384 /*
2483734Smw145384  * meta_get_and_report_set_info
24840Sstevel@tonic-gate  *
24850Sstevel@tonic-gate  * Scans a given drive for set specific information. If the given drive
24860Sstevel@tonic-gate  * has a shared metadb, scans the shared metadb for information pertaining
24870Sstevel@tonic-gate  * to the set.
24881945Sjeanm  * If imp_flags has META_IMP_PASS1 set don't report.
24890Sstevel@tonic-gate  *
24900Sstevel@tonic-gate  * Returns:
24910Sstevel@tonic-gate  * 	<0 	for failure
24920Sstevel@tonic-gate  *	0	success but no replicas were found
24930Sstevel@tonic-gate  *	1	success and a replica was found
24940Sstevel@tonic-gate  */
24950Sstevel@tonic-gate int
meta_get_and_report_set_info(mddrivenamelist_t * dp,md_im_set_desc_t ** mispp,int local_mb_ok,uint_t imp_flags,int * set_count,int overlap,md_im_drive_info_t * overlap_disks,md_error_t * ep)2496734Smw145384 meta_get_and_report_set_info(
2497734Smw145384 	mddrivenamelist_t	*dp,
2498734Smw145384 	md_im_set_desc_t	**mispp,
2499734Smw145384 	int			local_mb_ok,
2500734Smw145384 	uint_t			imp_flags,
2501734Smw145384 	int			*set_count,
25021945Sjeanm 	int			overlap,
25031945Sjeanm 	md_im_drive_info_t	*overlap_disks,
2504734Smw145384 	md_error_t 		*ep
25050Sstevel@tonic-gate )
25060Sstevel@tonic-gate {
25070Sstevel@tonic-gate 	uint_t			s;
25080Sstevel@tonic-gate 	mdname_t		*rsp;
25090Sstevel@tonic-gate 	int			fd;
25100Sstevel@tonic-gate 	char			mb[DEV_BSIZE];
25110Sstevel@tonic-gate 				/*LINTED*/
25120Sstevel@tonic-gate 	mddb_mb_t		*mbp = (mddb_mb_t *)mb;
25130Sstevel@tonic-gate 	char			lb[dbtob(MDDB_LBCNT)];
25140Sstevel@tonic-gate 				/*LINTED*/
25150Sstevel@tonic-gate 	mddb_lb_t		*lbp = (mddb_lb_t *)lb;
25160Sstevel@tonic-gate 	mddb_did_blk_t		*lbdidp = NULL;
25170Sstevel@tonic-gate 	mddb_ln_t		*lnp = NULL;
25180Sstevel@tonic-gate 	int			lnsize, lbdid_size;
25190Sstevel@tonic-gate 	int			rval = 0;
25200Sstevel@tonic-gate 	char			db[DEV_BSIZE];
25210Sstevel@tonic-gate 				/*LINTED*/
25220Sstevel@tonic-gate 	mddb_db_t		*dbp = (mddb_db_t *)db;
25230Sstevel@tonic-gate 	did_list_t		*did_listp = NULL;
25240Sstevel@tonic-gate 	mddrivenamelist_t	*dnlp;
25250Sstevel@tonic-gate 	mddrivename_t 		*dnp;
25260Sstevel@tonic-gate 	md_im_names_t		cnames = { 0, NULL};
25271945Sjeanm 	char			*nm = NULL, *shrnm = NULL;
25280Sstevel@tonic-gate 	char			*did_nm = NULL, *did_shrnm = NULL;
25290Sstevel@tonic-gate 	struct nm_rec		*nmp;
25301945Sjeanm 	struct nm_shr_rec	*snmp;
25310Sstevel@tonic-gate 	struct devid_shr_rec	*did_shrnmp;
25320Sstevel@tonic-gate 	struct devid_min_rec	*did_nmp;
25330Sstevel@tonic-gate 	int			extended_namespace = 0;
25340Sstevel@tonic-gate 	int			replicated = 0;
25351945Sjeanm 	int			partial = 0;
2536734Smw145384 	pnm_rec_t		*pnm = NULL; /* list of physical devs in set */
2537734Smw145384 	md_im_set_desc_t	*misp;
25380Sstevel@tonic-gate 
25390Sstevel@tonic-gate 	dnp = dp->drivenamep;
25400Sstevel@tonic-gate 
25410Sstevel@tonic-gate 	/*
25420Sstevel@tonic-gate 	 * Determine and open the replica slice
25430Sstevel@tonic-gate 	 */
25440Sstevel@tonic-gate 	if (meta_replicaslice(dnp, &s, ep) != 0) {
25450Sstevel@tonic-gate 		return (-1);
25460Sstevel@tonic-gate 	}
25470Sstevel@tonic-gate 
25480Sstevel@tonic-gate 	/*
25490Sstevel@tonic-gate 	 * Test for the size of replica slice in question. If
25500Sstevel@tonic-gate 	 * the size is zero, we know that this is not a disk that was
25510Sstevel@tonic-gate 	 * part of a set and it should be silently ignored for import.
25520Sstevel@tonic-gate 	 */
25530Sstevel@tonic-gate 	if (dnp->vtoc.parts[s].size == 0)
25540Sstevel@tonic-gate 		return (0);
25550Sstevel@tonic-gate 
25560Sstevel@tonic-gate 	if ((rsp = metaslicename(dnp, s, ep)) == NULL) {
25570Sstevel@tonic-gate 		return (-1);
25580Sstevel@tonic-gate 	}
25590Sstevel@tonic-gate 
25600Sstevel@tonic-gate 	if ((fd = open(rsp->rname, O_RDONLY|O_NDELAY)) < 0)
25610Sstevel@tonic-gate 		return (mdsyserror(ep, errno, rsp->cname));
25620Sstevel@tonic-gate 
25630Sstevel@tonic-gate 	/*
25640Sstevel@tonic-gate 	 * After the open() succeeds, we should return via the "out"
25650Sstevel@tonic-gate 	 * label to clean up after ourselves.  (Up 'til now, we can
25660Sstevel@tonic-gate 	 * just return directly, because there are no resources to
25670Sstevel@tonic-gate 	 * give back.)
25680Sstevel@tonic-gate 	 */
25690Sstevel@tonic-gate 
25700Sstevel@tonic-gate 	if ((rval = read_master_block(ep, fd, mbp, sizeof (mb))) <= 0)
25710Sstevel@tonic-gate 		goto out;
25720Sstevel@tonic-gate 
25730Sstevel@tonic-gate 	replicated = is_replicated(fd, mbp, 0, NULL);
25740Sstevel@tonic-gate 
25750Sstevel@tonic-gate 	if (!local_mb_ok && mbp->mb_setno == 0) {
25760Sstevel@tonic-gate 		rval = 0;
25770Sstevel@tonic-gate 		goto out;
25780Sstevel@tonic-gate 	}
25790Sstevel@tonic-gate 
25800Sstevel@tonic-gate 	if ((rval = read_locator_block(ep, fd, mbp, lbp, sizeof (lb))) <= 0)
25810Sstevel@tonic-gate 		goto out;
25820Sstevel@tonic-gate 
25830Sstevel@tonic-gate 	/*
25840Sstevel@tonic-gate 	 * Once the locator block has been read, we need to
25850Sstevel@tonic-gate 	 * check if the locator block commit count is zero.
25860Sstevel@tonic-gate 	 * If it is zero, we know that the replica we're dealing
25870Sstevel@tonic-gate 	 * with is on a disk that was deleted from the disk set;
25880Sstevel@tonic-gate 	 * and, it potentially has stale data. We need to quit
25890Sstevel@tonic-gate 	 * in that case
25900Sstevel@tonic-gate 	 */
25910Sstevel@tonic-gate 	if (lbp->lb_commitcnt == 0) {
25920Sstevel@tonic-gate 		rval = 0;
25930Sstevel@tonic-gate 		goto out;
25940Sstevel@tonic-gate 	}
25950Sstevel@tonic-gate 
25960Sstevel@tonic-gate 	/*
25970Sstevel@tonic-gate 	 * Make sure that the disk being imported has device id
25980Sstevel@tonic-gate 	 * namespace present for disksets. If a disk doesn't have
25990Sstevel@tonic-gate 	 * device id namespace, we skip reading the replica on that disk
26000Sstevel@tonic-gate 	 */
26010Sstevel@tonic-gate 	if (!(lbp->lb_flags & MDDB_DEVID_STYLE)) {
26020Sstevel@tonic-gate 		rval = 0;
26030Sstevel@tonic-gate 		goto out;
26040Sstevel@tonic-gate 	}
26050Sstevel@tonic-gate 
26060Sstevel@tonic-gate 	/*
26070Sstevel@tonic-gate 	 * Grab the locator block device id array. Allocate memory for the
26080Sstevel@tonic-gate 	 * array first.
26090Sstevel@tonic-gate 	 */
26100Sstevel@tonic-gate 	lbdid_size = dbtob(lbp->lb_didblkcnt);
26110Sstevel@tonic-gate 	lbdidp = Zalloc(lbdid_size);
26120Sstevel@tonic-gate 
26130Sstevel@tonic-gate 	if ((rval = read_locator_block_did(ep, fd, mbp, lbp, lbdidp,
26140Sstevel@tonic-gate 	    lbdid_size)) <= 0)
26150Sstevel@tonic-gate 		goto out;
26160Sstevel@tonic-gate 
26170Sstevel@tonic-gate 	/*
26180Sstevel@tonic-gate 	 * For a disk that has not been replicated, extract the device ids
26190Sstevel@tonic-gate 	 * stored in the locator block device id array and store them in
26200Sstevel@tonic-gate 	 * a list.
26210Sstevel@tonic-gate 	 *
26220Sstevel@tonic-gate 	 * If the disk has been replicated using replication software such
26230Sstevel@tonic-gate 	 * as HDS Truecopy/ShadowImage or EMC SRDF/BCV, the device ids in
26240Sstevel@tonic-gate 	 * the locator block are invalid and we need to build a list of
26250Sstevel@tonic-gate 	 * replicated disks.
26260Sstevel@tonic-gate 	 */
26271945Sjeanm 	if (imp_flags & META_IMP_PASS1) {
26281945Sjeanm 		/*
26291945Sjeanm 		 * We need to do this for both passes but
26301945Sjeanm 		 * replicated_disk_list_built is global so we need some way
26311945Sjeanm 		 * to determine which pass we're on. Set it to the appropriate
26321945Sjeanm 		 * pass's flag.
26331945Sjeanm 		 */
26341945Sjeanm 		replicated_disk_list_built = &replicated_disk_list_built_pass1;
26351945Sjeanm 	} else {
26361945Sjeanm 		replicated_disk_list_built = &replicated_disk_list_built_pass2;
26371945Sjeanm 	}
26381945Sjeanm 	if (replicated && !(*replicated_disk_list_built)) {
26390Sstevel@tonic-gate 		/*
26400Sstevel@tonic-gate 		 * if there's a replicated diskset involved, we need to
26410Sstevel@tonic-gate 		 * scan the system one more time and build a list of all
26420Sstevel@tonic-gate 		 * candidate disks that might be part of that replicated set
26430Sstevel@tonic-gate 		 */
26440Sstevel@tonic-gate 		if (meta_list_disks(ep, &cnames) != 0) {
26450Sstevel@tonic-gate 			rval = 0;
26460Sstevel@tonic-gate 			goto out;
26470Sstevel@tonic-gate 		}
26480Sstevel@tonic-gate 		dnlp = meta_prune_cnames(ep, &cnames, 0);
26490Sstevel@tonic-gate 		rval = build_replicated_disks_list(ep, dnlp);
26500Sstevel@tonic-gate 		if (rval == 0)
26510Sstevel@tonic-gate 			goto out;
26520Sstevel@tonic-gate 	}
26530Sstevel@tonic-gate 
26540Sstevel@tonic-gate 	/*
26550Sstevel@tonic-gate 	 * Until here, we've gotten away with fixed sizes for the
26560Sstevel@tonic-gate 	 * master block and locator block.  The locator names,
26570Sstevel@tonic-gate 	 * however, are sized (and therefore allocated) dynamically
26580Sstevel@tonic-gate 	 * according to information in the locator block.
26590Sstevel@tonic-gate 	 */
26600Sstevel@tonic-gate 	lnsize = dbtob(lbp->lb_lnblkcnt);
26610Sstevel@tonic-gate 	lnp = Zalloc(lnsize);
26620Sstevel@tonic-gate 
26630Sstevel@tonic-gate 	if ((rval = read_locator_names(ep, fd, mbp, lbp, lnp, lnsize)) <= 0)
26640Sstevel@tonic-gate 		goto out;
26650Sstevel@tonic-gate 
26661945Sjeanm 	rval = build_did_list(ep, fd, mbp, lbp, lbdidp, lnp, &did_listp,
26671945Sjeanm 	    replicated);
26681945Sjeanm 
26691945Sjeanm 	/*
26701945Sjeanm 	 * An rval of ENOTSUP means we have a partial diskset. We'll want
26711945Sjeanm 	 * to set the partial variable so we can pass this information
26721945Sjeanm 	 * set_append_wrapper later for placing on the misp list.
26731945Sjeanm 	 */
26741945Sjeanm 	if (rval == ENOTSUP)
26751945Sjeanm 		partial = MD_IM_PARTIAL_DISKSET;
26761945Sjeanm 
26771945Sjeanm 	if (rval < 0)
26781945Sjeanm 		goto out;
26791945Sjeanm 
26800Sstevel@tonic-gate 	/*
26810Sstevel@tonic-gate 	 * Read in the NM record
26820Sstevel@tonic-gate 	 * If no NM record was found, it still is a valid configuration
26830Sstevel@tonic-gate 	 * but it also means that we won't find any corresponding DID_NM
26840Sstevel@tonic-gate 	 * or DID_SHR_NM.
26850Sstevel@tonic-gate 	 */
26860Sstevel@tonic-gate 	if ((rval = read_nm_rec(ep, fd, mbp, lbp, &nm, MDDB_NM, rsp->cname))
26870Sstevel@tonic-gate 	    < 0)
26880Sstevel@tonic-gate 		goto out;
26890Sstevel@tonic-gate 	else if (rval == 0)
26900Sstevel@tonic-gate 		goto append;
26910Sstevel@tonic-gate 
26920Sstevel@tonic-gate 	/*
26930Sstevel@tonic-gate 	 * At this point, we have read in all of the blocks that form
26940Sstevel@tonic-gate 	 * the nm_rec.  We should at least detect the corner case
26950Sstevel@tonic-gate 	 * mentioned above, in which r_next_recid links to another
26960Sstevel@tonic-gate 	 * nm_rec. Extended namespace handling is left for Phase 2.
26970Sstevel@tonic-gate 	 *
26980Sstevel@tonic-gate 	 * What this should really be is a loop, each iteration of
2699734Smw145384 	 * which reads in a nm_rec and calls the set_append().
27000Sstevel@tonic-gate 	 */
27010Sstevel@tonic-gate 	/*LINTED*/
27020Sstevel@tonic-gate 	nmp = (struct nm_rec *)(nm + sizeof (mddb_rb_t));
27030Sstevel@tonic-gate 	if (nmp->r_rec_hdr.r_next_recid != (mddb_recid_t)0) {
27040Sstevel@tonic-gate 		extended_namespace = 1;
27050Sstevel@tonic-gate 		rval = 0;
27060Sstevel@tonic-gate 		goto out;
27070Sstevel@tonic-gate 	}
27080Sstevel@tonic-gate 
27091945Sjeanm 	if ((rval = read_nm_rec(ep, fd, mbp, lbp, &shrnm, MDDB_SHR_NM,
27101945Sjeanm 	    rsp->cname)) < 0)
27111945Sjeanm 		goto out;
27121945Sjeanm 	else if (rval == 0)
27131945Sjeanm 		goto append;
27141945Sjeanm 
27151945Sjeanm 	/*LINTED*/
27161945Sjeanm 	snmp = (struct nm_shr_rec *)(shrnm + sizeof (mddb_rb_t));
27171945Sjeanm 	if (snmp->sr_rec_hdr.r_next_recid != (mddb_recid_t)0) {
27181945Sjeanm 		extended_namespace = 1;
27191945Sjeanm 		rval = 0;
27201945Sjeanm 		goto out;
27211945Sjeanm 	}
27221945Sjeanm 
27230Sstevel@tonic-gate 	if ((rval = read_nm_rec(ep, fd, mbp, lbp, &did_nm,
27240Sstevel@tonic-gate 	    MDDB_DID_NM, rsp->cname)) < 0)
27250Sstevel@tonic-gate 		goto out;
27260Sstevel@tonic-gate 	else if (rval == 0)
27270Sstevel@tonic-gate 		goto append;
27280Sstevel@tonic-gate 
27290Sstevel@tonic-gate 	/*LINTED*/
273057Sjeanm 	did_nmp = (struct devid_min_rec *)(did_nm + sizeof (mddb_rb_t) -
273157Sjeanm 	    sizeof (int));
27320Sstevel@tonic-gate 	if (did_nmp->min_rec_hdr.r_next_recid != (mddb_recid_t)0) {
27330Sstevel@tonic-gate 		extended_namespace = 1;
27340Sstevel@tonic-gate 		rval = 0;
27350Sstevel@tonic-gate 		goto out;
27360Sstevel@tonic-gate 	}
27370Sstevel@tonic-gate 
27380Sstevel@tonic-gate 	if ((rval = read_nm_rec(ep, fd, mbp, lbp, &did_shrnm,
27390Sstevel@tonic-gate 	    MDDB_DID_SHR_NM, rsp->cname)) < 0)
27400Sstevel@tonic-gate 		goto out;
27410Sstevel@tonic-gate 	else if (rval == 0)
27420Sstevel@tonic-gate 		goto append;
27430Sstevel@tonic-gate 
27440Sstevel@tonic-gate 	/*LINTED*/
274557Sjeanm 	did_shrnmp = (struct devid_shr_rec *)(did_shrnm + sizeof (mddb_rb_t) -
274657Sjeanm 	    sizeof (int));
27470Sstevel@tonic-gate 	if (did_shrnmp->did_rec_hdr.r_next_recid != (mddb_recid_t)0) {
27480Sstevel@tonic-gate 		extended_namespace = 1;
27490Sstevel@tonic-gate 		rval = 0;
27500Sstevel@tonic-gate 		goto out;
27510Sstevel@tonic-gate 	}
27520Sstevel@tonic-gate 
275357Sjeanm 	/*
275457Sjeanm 	 * We need to check if all of the disks listed in the namespace
275557Sjeanm 	 * are actually available. If they aren't we'll return with
275657Sjeanm 	 * an ENOTSUP error which indicates a partial diskset.
275757Sjeanm 	 */
27581945Sjeanm 	rval = check_nm_disks(did_nmp, did_shrnmp);
27591945Sjeanm 
27601945Sjeanm 	/*
27611945Sjeanm 	 * An rval of ENOTSUP means we have a partial diskset. We'll want
27621945Sjeanm 	 * to set the partial variable so we can pass this information
27631945Sjeanm 	 * to set_append_wrapper later for placing on the misp list.
27641945Sjeanm 	 */
27651945Sjeanm 	if (rval == ENOTSUP)
27661945Sjeanm 		partial = MD_IM_PARTIAL_DISKSET;
27671945Sjeanm 
27681945Sjeanm 	if (rval < 0)
276957Sjeanm 		goto out;
277057Sjeanm 
27710Sstevel@tonic-gate append:
27720Sstevel@tonic-gate 	/* Finally, we've got what we need to process this replica. */
2773734Smw145384 	misp = set_append(mispp, did_listp, mbp, lbp,
27740Sstevel@tonic-gate 	    /*LINTED*/
27751945Sjeanm 	    (mddb_rb_t *)nm, (mddb_rb_t *)shrnm, &pnm, (mddb_rb_t *)did_nm,
27761945Sjeanm 	    /*LINTED*/
27771945Sjeanm 	    (mddb_rb_t *)did_shrnm, (imp_flags | partial | replicated), ep);
27781945Sjeanm 
27791945Sjeanm 	if (!(imp_flags & META_IMP_PASS1)) {
27801945Sjeanm 		*set_count += 1;
27811945Sjeanm 		rval = report_set_info(misp, mbp, lbp,
27821945Sjeanm 		    /*LINTED*/
27831945Sjeanm 		    (mddb_rb_t *)nm, &pnm, rsp, fd, imp_flags, *set_count,
27841945Sjeanm 		    overlap, overlap_disks, ep);
27851945Sjeanm 		if (rval < 0)
27861945Sjeanm 			goto out;
27871945Sjeanm 	}
27880Sstevel@tonic-gate 
27890Sstevel@tonic-gate 	/* Return the fact that we found at least one set */
27900Sstevel@tonic-gate 	rval = 1;
27910Sstevel@tonic-gate 
27920Sstevel@tonic-gate out:
27930Sstevel@tonic-gate 	if (fd >= 0)
27940Sstevel@tonic-gate 		(void) close(fd);
27950Sstevel@tonic-gate 	if (did_listp != NULL)
27960Sstevel@tonic-gate 		free_did_list(did_listp);
27970Sstevel@tonic-gate 	if (lnp != NULL)
27980Sstevel@tonic-gate 		Free(lnp);
27990Sstevel@tonic-gate 	if (nm != NULL)
28000Sstevel@tonic-gate 		Free(nm);
28010Sstevel@tonic-gate 	if (did_nm != NULL)
28020Sstevel@tonic-gate 		Free(did_nm);
28030Sstevel@tonic-gate 	if (did_shrnm != NULL)
28040Sstevel@tonic-gate 		Free(did_shrnm);
2805734Smw145384 	if (pnm != NULL)
2806734Smw145384 		free_pnm_rec_list(&pnm);
28070Sstevel@tonic-gate 
28080Sstevel@tonic-gate 	/*
28090Sstevel@tonic-gate 	 * If we are at the end of the list, we must free up
28100Sstevel@tonic-gate 	 * the replicated list too
28110Sstevel@tonic-gate 	 */
28120Sstevel@tonic-gate 	if (dp->next == NULL)
28130Sstevel@tonic-gate 		free_replicated_disks_list();
28140Sstevel@tonic-gate 
28150Sstevel@tonic-gate 	if (extended_namespace)
28160Sstevel@tonic-gate 		return (mddserror(ep, MDE_DS_EXTENDEDNM, MD_SET_BAD,
28170Sstevel@tonic-gate 		    mynode(), NULL, NULL));
28180Sstevel@tonic-gate 
28190Sstevel@tonic-gate 	return (rval);
28200Sstevel@tonic-gate }
28210Sstevel@tonic-gate 
28220Sstevel@tonic-gate /*
28230Sstevel@tonic-gate  * Return the minor name associated with a given disk slice
28240Sstevel@tonic-gate  */
28250Sstevel@tonic-gate static char *
meta_getminor_name(char * devname,md_error_t * ep)28260Sstevel@tonic-gate meta_getminor_name(
28270Sstevel@tonic-gate 	char *devname,
28280Sstevel@tonic-gate 	md_error_t *ep
28290Sstevel@tonic-gate )
28300Sstevel@tonic-gate {
28310Sstevel@tonic-gate 	int 	fd = -1;
28320Sstevel@tonic-gate 	char 	*minor_name = NULL;
28330Sstevel@tonic-gate 	char	*ret_minor_name = NULL;
28340Sstevel@tonic-gate 
28350Sstevel@tonic-gate 	if (devname == NULL)
28360Sstevel@tonic-gate 		return (NULL);
28370Sstevel@tonic-gate 
28380Sstevel@tonic-gate 	if ((fd = open(devname, O_RDONLY|O_NDELAY, 0)) < 0) {
28390Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, devname);
28400Sstevel@tonic-gate 		return (NULL);
28410Sstevel@tonic-gate 	}
28420Sstevel@tonic-gate 
28430Sstevel@tonic-gate 	if (devid_get_minor_name(fd, &minor_name) == 0) {
28440Sstevel@tonic-gate 		ret_minor_name = Strdup(minor_name);
28450Sstevel@tonic-gate 		devid_str_free(minor_name);
28460Sstevel@tonic-gate 	}
28470Sstevel@tonic-gate 
28480Sstevel@tonic-gate 	(void) close(fd);
28490Sstevel@tonic-gate 	return (ret_minor_name);
28500Sstevel@tonic-gate }
28510Sstevel@tonic-gate 
28521945Sjeanm /*
28531945Sjeanm  * meta_update_mb_did
28541945Sjeanm  *
28551945Sjeanm  * Update or create the master block with the new set number.
28561945Sjeanm  * If a non-null devid pointer is given, the devid in the
28571945Sjeanm  * master block will also be changed.
28581945Sjeanm  *
28591945Sjeanm  * This routine is called during the import of a diskset
28601945Sjeanm  * (meta_imp_update_mb) and during the take of a diskset that has
28611945Sjeanm  * some unresolved replicated drives (meta_unrslv_replicated_mb).
28621945Sjeanm  *
28631945Sjeanm  * Returns : nothing (void)
28641945Sjeanm  */
28651945Sjeanm static void
meta_update_mb_did(mdsetname_t * sp,mddrivename_t * dnp,void * new_devid,int new_devid_len,void * old_devid,int replica_present,int offset,md_error_t * ep)28661945Sjeanm meta_update_mb_did(
28671945Sjeanm 	mdsetname_t	*sp,
28681945Sjeanm 	mddrivename_t	*dnp,			/* raw name of drive with mb */
28691945Sjeanm 	void		*new_devid,		/* devid to be stored in mb */
28701945Sjeanm 	int		new_devid_len,
28711945Sjeanm 	void		*old_devid,		/* old devid stored in mb */
28721945Sjeanm 	int		replica_present,	/* does replica follow mb? */
28731945Sjeanm 	int		offset,
28741945Sjeanm 	md_error_t	*ep
28750Sstevel@tonic-gate )
28760Sstevel@tonic-gate {
28771945Sjeanm 	int			fd;
28781945Sjeanm 	struct mddb_mb		*mbp;
28791945Sjeanm 	uint_t			sliceno;
28801945Sjeanm 	mdname_t		*rsp;
28811945Sjeanm 
28821945Sjeanm 	/* determine the replica slice */
28831945Sjeanm 	if (meta_replicaslice(dnp, &sliceno, ep) != 0) {
28841945Sjeanm 		return;
28851945Sjeanm 	}
28861945Sjeanm 
28871945Sjeanm 	/*
28881945Sjeanm 	 * if the replica slice size is zero,
28891945Sjeanm 	 * don't bother opening
28901945Sjeanm 	 */
28911945Sjeanm 	if (dnp->vtoc.parts[sliceno].size == 0) {
28921945Sjeanm 		return;
28931945Sjeanm 	}
28941945Sjeanm 
28951945Sjeanm 	if ((rsp = metaslicename(dnp, sliceno, ep)) == NULL) {
28961945Sjeanm 		return;
28971945Sjeanm 	}
28981945Sjeanm 
28991945Sjeanm 	if ((fd = open(rsp->rname, O_RDWR | O_NDELAY)) < 0) {
29001945Sjeanm 		return;
29011945Sjeanm 	}
29021945Sjeanm 
29031945Sjeanm 	if (lseek(fd, (off_t)dbtob(offset), SEEK_SET) < 0)
29041945Sjeanm 		return;
29051945Sjeanm 
29061945Sjeanm 	mbp = Zalloc(DEV_BSIZE);
29071945Sjeanm 	if (read(fd, mbp, DEV_BSIZE) != DEV_BSIZE) {
29081945Sjeanm 		Free(mbp);
29091945Sjeanm 		return;
29101945Sjeanm 	}
29111945Sjeanm 
29121945Sjeanm 	/* If no replica on disk, check for dummy mb */
29131945Sjeanm 	if (replica_present == NULL) {
29141945Sjeanm 		/*
29151945Sjeanm 		 * Check to see if there is a dummy there. If not
29161945Sjeanm 		 * create one. This would happen if the set was
29171945Sjeanm 		 * created before the master block dummy code was
29181945Sjeanm 		 * implemented.
29191945Sjeanm 		 */
29201945Sjeanm 		if ((mbp->mb_magic != MDDB_MAGIC_DU) ||
29211945Sjeanm 		    (mbp->mb_revision != MDDB_REV_MB)) {
29221945Sjeanm 			meta_mkdummymaster(sp, fd, offset);
29231945Sjeanm 			Free(mbp);
29241945Sjeanm 			return;
29251945Sjeanm 		}
29261945Sjeanm 	}
29271945Sjeanm 
29281945Sjeanm 	mbp->mb_setno = sp->setno;
29291945Sjeanm 	if (meta_gettimeofday(&mbp->mb_timestamp) == -1) {
29301945Sjeanm 		Free(mbp);
29311945Sjeanm 		return;
29321945Sjeanm 	}
29331945Sjeanm 
29341945Sjeanm 	/*
29351945Sjeanm 	 * If a old_devid is non-NULL then we're are dealing with a
29361945Sjeanm 	 * replicated diskset and the devid needs to be updated.
29371945Sjeanm 	 */
29381945Sjeanm 	if (old_devid) {
29391945Sjeanm 		if (mbp->mb_devid_magic == MDDB_MAGIC_DE) {
29401945Sjeanm 			if (mbp->mb_devid_len)
29411945Sjeanm 				(void) memset(mbp->mb_devid, 0,
29421945Sjeanm 				    mbp->mb_devid_len);
29431945Sjeanm 			(void) memcpy(mbp->mb_devid,
29441945Sjeanm 			    (char *)new_devid, new_devid_len);
29451945Sjeanm 			mbp->mb_devid_len = new_devid_len;
29461945Sjeanm 		}
29471945Sjeanm 	}
29481945Sjeanm 
29491945Sjeanm 	crcgen((uchar_t *)mbp, (uint_t *)&mbp->mb_checksum,
29501945Sjeanm 	    (uint_t)DEV_BSIZE, (crc_skip_t *)NULL);
29511945Sjeanm 
29521945Sjeanm 	/*
29531945Sjeanm 	 * Now write out the changes to disk.
29541945Sjeanm 	 * If an error occurs, just continue on.
29551945Sjeanm 	 * Next take of set will register this drive as
29561945Sjeanm 	 * an unresolved replicated drive and will attempt
29571945Sjeanm 	 * to fix the master block again.
29581945Sjeanm 	 */
29591945Sjeanm 	if (lseek(fd, (off_t)dbtob(offset), SEEK_SET) < 0) {
29601945Sjeanm 		Free(mbp);
29611945Sjeanm 		return;
29621945Sjeanm 	}
29631945Sjeanm 	if (write(fd, mbp, DEV_BSIZE) != DEV_BSIZE) {
29641945Sjeanm 		Free(mbp);
29651945Sjeanm 		return;
29661945Sjeanm 	}
29671945Sjeanm 
29681945Sjeanm 	Free(mbp);
29691945Sjeanm 	(void) close(fd);
29701945Sjeanm }
29711945Sjeanm 
29721945Sjeanm 
29731945Sjeanm /*
29741945Sjeanm  * meta_imp_update_mb
29751945Sjeanm  *
29761945Sjeanm  * Update the master block information during an import.
29771945Sjeanm  * Takes an import set descriptor.
29781945Sjeanm  *
29791945Sjeanm  * Returns : nothing (void)
29801945Sjeanm  */
29811945Sjeanm void
meta_imp_update_mb(mdsetname_t * sp,md_im_set_desc_t * misp,md_error_t * ep)29821945Sjeanm meta_imp_update_mb(mdsetname_t *sp, md_im_set_desc_t *misp, md_error_t *ep)
29831945Sjeanm {
29840Sstevel@tonic-gate 	md_im_drive_info_t	*midp;
29850Sstevel@tonic-gate 	mddrivename_t		*dnp;
29861945Sjeanm 	int			offset = 16; /* default mb offset is 16 */
29871945Sjeanm 
29881945Sjeanm 	for (midp = misp->mis_drives; midp != NULL; midp = midp->mid_next) {
29891945Sjeanm 		/*
29901945Sjeanm 		 * If disk isn't available we can't update, so go to next
29911945Sjeanm 		 */
29921945Sjeanm 		if (midp->mid_available == MD_IM_DISK_NOT_AVAILABLE) {
29931945Sjeanm 			continue;
29941945Sjeanm 		}
29950Sstevel@tonic-gate 
29960Sstevel@tonic-gate 		dnp = midp->mid_dnp;
29970Sstevel@tonic-gate 
29981945Sjeanm 		if (midp->mid_replicas) {
29991945Sjeanm 			md_im_replica_info_t	*mirp;
30001945Sjeanm 
30011945Sjeanm 			/*
30021945Sjeanm 			 * If we have replicas on this disk we need to make
30031945Sjeanm 			 * sure that we update the master block on every
30041945Sjeanm 			 * replica on the disk.
30051945Sjeanm 			 */
30061945Sjeanm 			for (mirp = midp->mid_replicas; mirp != NULL;
30071945Sjeanm 			    mirp = mirp->mir_next) {
30081945Sjeanm 				offset = mirp->mir_offset;
30091945Sjeanm 				meta_update_mb_did(sp, dnp, midp->mid_devid,
30101945Sjeanm 				    midp->mid_devid_sz, midp->mid_o_devid,
30111945Sjeanm 				    1, offset, ep);
30121945Sjeanm 			}
30131945Sjeanm 		} else {
30141945Sjeanm 			/* No replicas, just update the one dummy mb */
30151945Sjeanm 			meta_update_mb_did(sp, dnp, midp->mid_devid,
30161945Sjeanm 			    midp->mid_devid_sz, midp->mid_o_devid,
30171945Sjeanm 			    0, offset, ep);
30181945Sjeanm 		}
30191945Sjeanm 		if (!mdisok(ep))
30201945Sjeanm 			return;
30211945Sjeanm 	}
30221945Sjeanm }
30231945Sjeanm 
30241945Sjeanm /*
30251945Sjeanm  * meta_unrslv_replicated_common
30261945Sjeanm  *
30271945Sjeanm  * Given a drive_desc and a drivenamelist pointer,
30281945Sjeanm  * return the devidp associated with the drive_desc,
30291945Sjeanm  * the replicated (new) devidp associated with the drive_desc
30301945Sjeanm  * and the specific mddrivename in the drivenamelist that
30311945Sjeanm  * matches the replicated (new) devidp.
30321945Sjeanm  *
30331945Sjeanm  * Typically the drivenamelist pointer would be setup by
30341945Sjeanm  * the meta_prune_cnames function.
30351945Sjeanm  *
30361945Sjeanm  * Calling function must free devidp using devid_free.
30371945Sjeanm  *
30381945Sjeanm  * Returns 0 - success, found new_devidp and dnp_new.
30391945Sjeanm  * Returns 1 - failure, didn't find new devid info
30401945Sjeanm  */
30411945Sjeanm static int
meta_unrslv_replicated_common(int myside,md_drive_desc * dd,mddrivenamelist_t * dnlp,ddi_devid_t * devidp,ddi_devid_t * new_devidp,mddrivename_t ** dnp_new,md_error_t * ep)30421945Sjeanm meta_unrslv_replicated_common(
30431945Sjeanm 	int			myside,
30441945Sjeanm 	md_drive_desc		*dd,	/* drive list for diskset */
30451945Sjeanm 	mddrivenamelist_t	*dnlp,	/* list of drives on current system */
30461945Sjeanm 	ddi_devid_t		*devidp,	/* old devid */
30471945Sjeanm 	ddi_devid_t		*new_devidp,	/* replicated (new) devid */
30481945Sjeanm 	mddrivename_t		**dnp_new,	/* replicated drive name */
30491945Sjeanm 	md_error_t		*ep
30501945Sjeanm )
30511945Sjeanm {
30521945Sjeanm 	mddrivename_t		*dnp;	/* drive name of old drive */
30531945Sjeanm 	mdsidenames_t		*sn = NULL;
30541945Sjeanm 	uint_t			rep_slice;
30551945Sjeanm 	mdname_t		*np;
30561945Sjeanm 	char			*minor_name = NULL;
30571945Sjeanm 	char			*devid_str = NULL;
30581945Sjeanm 	size_t			len;
30591945Sjeanm 	int			devid_sz;
30601945Sjeanm 	mddrivenamelist_t	*dp;
30611945Sjeanm 	ddi_devid_t		old_devid; /* devid of old drive */
30621945Sjeanm 	ddi_devid_t		new_devid; /* devid of new replicated drive */
30631945Sjeanm 	ddi_devid_t		dnp_new_devid; /* devid derived from drive */
30641945Sjeanm 						/* name of replicated drive */
30651945Sjeanm 
30661945Sjeanm 	dnp = dd->dd_dnp;
30671945Sjeanm 
30681945Sjeanm 	/* Get old devid from drive record */
30691945Sjeanm 	(void) devid_str_decode(dd->dd_dnp->devid,
30701945Sjeanm 	    &old_devid, NULL);
30711945Sjeanm 
30721945Sjeanm 	/* Look up replicated (new) devid */
30731945Sjeanm 	new_devid = replicated_list_lookup(
30741945Sjeanm 	    devid_sizeof(old_devid), old_devid);
30751945Sjeanm 
30761945Sjeanm 	devid_free(old_devid);
30771945Sjeanm 
30781945Sjeanm 	if (new_devid == NULL)
30791945Sjeanm 		return (1);
30801945Sjeanm 
30811945Sjeanm 	/*
30821945Sjeanm 	 * Using new_devid, find a drivename entry with a matching devid.
30831945Sjeanm 	 * Use the passed in dnlp since it has the new (replicated) disknames
30841945Sjeanm 	 * in it.
30851945Sjeanm 	 */
30861945Sjeanm 	for (dp = dnlp; dp != NULL; dp = dp->next) {
30871945Sjeanm 		(void) devid_str_decode(dp->drivenamep->devid,
30881945Sjeanm 		    &dnp_new_devid, NULL);
30891945Sjeanm 
30901945Sjeanm 		if (dnp_new_devid == NULL)
30911945Sjeanm 			continue;
30921945Sjeanm 
30931945Sjeanm 		if (devid_compare(new_devid, dnp_new_devid) == 0) {
30941945Sjeanm 			devid_free(dnp_new_devid);
30951945Sjeanm 			break;
30961945Sjeanm 		}
30971945Sjeanm 		devid_free(dnp_new_devid);
30981945Sjeanm 	}
30991945Sjeanm 
31001945Sjeanm 	/* If can't find new name for drive - nothing to update */
31011945Sjeanm 	if (dp == NULL)
31021945Sjeanm 		return (1);
31031945Sjeanm 
31041945Sjeanm 	/*
31051945Sjeanm 	 * Setup returned value to be the drivename structure associated
31061945Sjeanm 	 * with new (replicated) drive.
31071945Sjeanm 	 */
31081945Sjeanm 	*dnp_new = dp->drivenamep;
31091945Sjeanm 
31101945Sjeanm 	/*
31111945Sjeanm 	 * Need to return the new devid including the minor name.
31121945Sjeanm 	 * Find the minor_name here using the sidename or by
31131945Sjeanm 	 * looking in the namespace.
31141945Sjeanm 	 */
31151945Sjeanm 	for (sn = dnp->side_names; sn != NULL; sn = sn->next) {
31161945Sjeanm 		if (sn->sideno == myside)
31171945Sjeanm 			break;
31181945Sjeanm 	}
31191945Sjeanm 
31201945Sjeanm 	/*
31211945Sjeanm 	 * The disk has no side name information
31221945Sjeanm 	 */
31231945Sjeanm 	if (sn == NULL) {
31241945Sjeanm 		if ((meta_replicaslice(*dnp_new, &rep_slice, ep) != 0) ||
31251945Sjeanm 		    ((np = metaslicename(*dnp_new, rep_slice, ep))
31260Sstevel@tonic-gate 			== NULL)) {
31270Sstevel@tonic-gate 			mdclrerror(ep);
31281945Sjeanm 			return (1);
31291945Sjeanm 		}
31301945Sjeanm 
31311945Sjeanm 		if (np->dev == NODEV64)
31321945Sjeanm 			return (1);
31331945Sjeanm 
31341945Sjeanm 		/*
31351945Sjeanm 		 * minor_name will be NULL if dnp->devid == NULL
31361945Sjeanm 		 * - see metagetvtoc()
31371945Sjeanm 		 */
31381945Sjeanm 		if (np->minor_name == NULL)
31391945Sjeanm 			return (1);
31401945Sjeanm 		else
31411945Sjeanm 			minor_name = Strdup(np->minor_name);
31421945Sjeanm 
31431945Sjeanm 	} else {
31441945Sjeanm 		minor_name = meta_getdidminorbykey(
31451945Sjeanm 			    MD_LOCAL_SET, sn->sideno + SKEW,
31461945Sjeanm 			    dnp->side_names_key, ep);
31471945Sjeanm 		if (!mdisok(ep))
31481945Sjeanm 			return (1);
31491945Sjeanm 	}
31501945Sjeanm 	/*
31511945Sjeanm 	 * Now, use the old devid with minor name to lookup
31521945Sjeanm 	 * the replicated (new) devid that will also contain
31531945Sjeanm 	 * a minor name.
31541945Sjeanm 	 */
31551945Sjeanm 	len = strlen(dnp->devid) + strlen(minor_name) + 2;
31561945Sjeanm 	devid_str = (char *)Malloc(len);
31571945Sjeanm 	(void) snprintf(devid_str, len, "%s/%s", dnp->devid,
31581945Sjeanm 	    minor_name);
31591945Sjeanm 	(void) devid_str_decode(devid_str, devidp, NULL);
31601945Sjeanm 	Free(devid_str);
31611945Sjeanm 	devid_sz = devid_sizeof((ddi_devid_t)*devidp);
31621945Sjeanm 	*new_devidp = replicated_list_lookup(devid_sz, *devidp);
31631945Sjeanm 	return (0);
31641945Sjeanm }
31651945Sjeanm 
31661945Sjeanm /*
31671945Sjeanm  * meta_unrslv_replicated_mb
31681945Sjeanm  *
31691945Sjeanm  * Update the master block information during a take.
31701945Sjeanm  * Takes an md_drive_desc descriptor.
31711945Sjeanm  *
31721945Sjeanm  * Returns : nothing (void)
31731945Sjeanm  */
31741945Sjeanm void
meta_unrslv_replicated_mb(mdsetname_t * sp,md_drive_desc * dd,mddrivenamelist_t * dnlp,md_error_t * ep)31751945Sjeanm meta_unrslv_replicated_mb(
31761945Sjeanm 	mdsetname_t		*sp,
31771945Sjeanm 	md_drive_desc		*dd,	/* drive list for diskset */
31781945Sjeanm 	mddrivenamelist_t	*dnlp,	/* list of drives on current system */
31791945Sjeanm 	md_error_t		*ep
31801945Sjeanm )
31811945Sjeanm {
31821945Sjeanm 	md_drive_desc		*d = NULL, *d_save;
31831945Sjeanm 	mddrivename_t		*dnp;	   /* dnp of old drive */
31841945Sjeanm 	mddrivename_t		*dnp_new;  /* dnp of new (replicated) drive */
31851945Sjeanm 	mddrivename_t		*dnp_save; /* saved copy needed to restore */
31861945Sjeanm 	ddi_devid_t		devidp, new_devidp;
31871945Sjeanm 	int			myside;
31881945Sjeanm 
31891945Sjeanm 	if ((myside = getmyside(sp, ep)) == MD_SIDEWILD)
31901945Sjeanm 		return;
31911945Sjeanm 
31921945Sjeanm 	for (d = dd; d != NULL; d = d->dd_next) {
31931945Sjeanm 		dnp = d->dd_dnp;
31941945Sjeanm 		if (dnp == NULL)
31951945Sjeanm 			continue;
31961945Sjeanm 
31971945Sjeanm 		/* If don't need to update master block - skip it. */
31981945Sjeanm 		if (!(d->dd_flags & MD_DR_FIX_MB_DID))
31991945Sjeanm 			continue;
32001945Sjeanm 
32011945Sjeanm 		/*
32021945Sjeanm 		 * Get old and replicated (new) devids associated with this
32031945Sjeanm 		 * drive.  Also, get the new (replicated) drivename structure.
32041945Sjeanm 		 */
32051945Sjeanm 		if (meta_unrslv_replicated_common(myside, d, dnlp, &devidp,
32061945Sjeanm 		    &new_devidp, &dnp_new, ep) != 0) {
32071945Sjeanm 			mdclrerror(ep);
32080Sstevel@tonic-gate 			continue;
32090Sstevel@tonic-gate 		}
32100Sstevel@tonic-gate 
32111945Sjeanm 		if (new_devidp) {
32121945Sjeanm 			int	offset = 16; /* default mb offset is 16 */
32131945Sjeanm 			int	dbcnt;
32141945Sjeanm 
32151945Sjeanm 			if (d->dd_dbcnt) {
32161945Sjeanm 				/*
32171945Sjeanm 				 * Update each master block on the disk
32181945Sjeanm 				 */
32191945Sjeanm 				for (dbcnt = d->dd_dbcnt; dbcnt != 0; dbcnt--) {
32201945Sjeanm 					meta_update_mb_did(sp, dnp_new,
32211945Sjeanm 					    new_devidp,
32221945Sjeanm 					    devid_sizeof(new_devidp), devidp,
32231945Sjeanm 					    1, offset, ep);
32241945Sjeanm 					offset += d->dd_dbsize;
32251945Sjeanm 				}
32261945Sjeanm 			} else {
32271945Sjeanm 				/* update the one dummy mb */
32281945Sjeanm 				meta_update_mb_did(sp, dnp_new, new_devidp,
32291945Sjeanm 				    devid_sizeof(new_devidp), devidp,
32301945Sjeanm 				    0, offset, ep);
32311945Sjeanm 			}
32321945Sjeanm 			if (!mdisok(ep)) {
32331945Sjeanm 				devid_free(devidp);
32341945Sjeanm 				return;
32351945Sjeanm 			}
32361945Sjeanm 
32371945Sjeanm 			/* Set drive record flags to ok */
32381945Sjeanm 			/* Just update this one drive record. */
32391945Sjeanm 			d_save = d->dd_next;
32401945Sjeanm 			dnp_save = d->dd_dnp;
32411945Sjeanm 			d->dd_next = NULL;
32421945Sjeanm 			d->dd_dnp = dnp_new;
32431945Sjeanm 			/* Ignore failure since no bad effect. */
32441945Sjeanm 			(void) clnt_upd_dr_flags(mynode(), sp, d,
32451945Sjeanm 			    MD_DR_OK, ep);
32461945Sjeanm 			d->dd_next = d_save;
32471945Sjeanm 			d->dd_dnp = dnp_save;
32481945Sjeanm 		}
32491945Sjeanm 		devid_free(devidp);
32501945Sjeanm 	}
32511945Sjeanm }
32521945Sjeanm 
32531945Sjeanm /*
32541945Sjeanm  * meta_update_nm_rr_did
32551945Sjeanm  *
32561945Sjeanm  * Change a devid stored in the diskset namespace and in the local set
32571945Sjeanm  * namespace with the new devid.
32581945Sjeanm  *
32591945Sjeanm  * This routine is called during the import of a diskset
32601945Sjeanm  * (meta_imp_update_nn) and during the take of a diskset that has
32611945Sjeanm  * some unresolved replicated drives (meta_unrslv_replicated_nm).
32621945Sjeanm  *
32631945Sjeanm  * Returns : nothing (void)
32641945Sjeanm  */
32651945Sjeanm static void
meta_update_nm_rr_did(mdsetname_t * sp,void * old_devid,int old_devid_sz,void * new_devid,int new_devid_sz,int import_flag,md_error_t * ep)32661945Sjeanm meta_update_nm_rr_did(
32671945Sjeanm 	mdsetname_t	*sp,
32681945Sjeanm 	void		*old_devid,		/* old devid being replaced */
32691945Sjeanm 	int		old_devid_sz,
32701945Sjeanm 	void		*new_devid,		/* devid to be stored in nm */
32711945Sjeanm 	int		new_devid_sz,
32721945Sjeanm 	int		import_flag,		/* called during import? */
32731945Sjeanm 	md_error_t	*ep
32741945Sjeanm )
32751945Sjeanm {
32761945Sjeanm 	struct mddb_config	c;
32771945Sjeanm 
32781945Sjeanm 	(void) memset(&c, 0, sizeof (c));
32791945Sjeanm 	c.c_setno = sp->setno;
32801945Sjeanm 
32811945Sjeanm 	/* During import to NOT update the local namespace. */
32821945Sjeanm 	if (import_flag)
32831945Sjeanm 		c.c_flags = MDDB_C_IMPORT;
32841945Sjeanm 
32851945Sjeanm 	c.c_locator.l_devid = (uintptr_t)Malloc(new_devid_sz);
32861945Sjeanm 	(void) memcpy((void *)(uintptr_t)c.c_locator.l_devid,
32871945Sjeanm 	    new_devid, new_devid_sz);
32881945Sjeanm 	c.c_locator.l_devid_sz = new_devid_sz;
32891945Sjeanm 	c.c_locator.l_devid_flags =
32901945Sjeanm 	    MDDB_DEVID_VALID | MDDB_DEVID_SPACE | MDDB_DEVID_SZ;
32911945Sjeanm 	c.c_locator.l_old_devid = (uint64_t)(uintptr_t)Malloc(old_devid_sz);
32921945Sjeanm 	(void) memcpy((void *)(uintptr_t)c.c_locator.l_old_devid,
32931945Sjeanm 	    old_devid, old_devid_sz);
32941945Sjeanm 	c.c_locator.l_old_devid_sz = old_devid_sz;
32951945Sjeanm 	if (metaioctl(MD_IOCUPDATE_NM_RR_DID, &c, &c.c_mde, NULL) != 0) {
32961945Sjeanm 		(void) mdstealerror(ep, &c.c_mde);
32971945Sjeanm 	}
32981945Sjeanm 	Free((void *)(uintptr_t)c.c_locator.l_devid);
32991945Sjeanm 	Free((void *)(uintptr_t)c.c_locator.l_old_devid);
33001945Sjeanm }
33011945Sjeanm 
33021945Sjeanm /*
33031945Sjeanm  * meta_imp_update_nm
33041945Sjeanm  *
33051945Sjeanm  * Change a devid stored in the diskset namespace with the new devid.
33061945Sjeanm  * This routine is called during the import of a remotely replicated diskset.
33071945Sjeanm  *
33081945Sjeanm  * Returns : nothing (void)
33091945Sjeanm  */
33101945Sjeanm void
meta_imp_update_nm(mdsetname_t * sp,md_im_set_desc_t * misp,md_error_t * ep)33111945Sjeanm meta_imp_update_nm(mdsetname_t *sp, md_im_set_desc_t *misp, md_error_t *ep)
33121945Sjeanm {
33131945Sjeanm 	md_im_drive_info_t	*midp;
33141945Sjeanm 
33151945Sjeanm 	for (midp = misp->mis_drives; midp != NULL; midp = midp->mid_next) {
33161945Sjeanm 		/*
33171945Sjeanm 		 * If disk isn't available we can't update, so go to next
33181945Sjeanm 		 */
33191945Sjeanm 		if (midp->mid_available == MD_IM_DISK_NOT_AVAILABLE) {
33200Sstevel@tonic-gate 			continue;
33211945Sjeanm 		}
33221945Sjeanm 
33231945Sjeanm 		meta_update_nm_rr_did(sp, midp->mid_o_devid,
33241945Sjeanm 		    midp->mid_o_devid_sz, midp->mid_devid,
33251945Sjeanm 		    midp->mid_devid_sz, 1, ep);
33261945Sjeanm 		if (!mdisok(ep))
33271945Sjeanm 			return;
33281945Sjeanm 	}
33291945Sjeanm }
33301945Sjeanm 
33311945Sjeanm /*
33321945Sjeanm  * meta_unrslv_replicated_nm
33331945Sjeanm  *
33341945Sjeanm  * Change a devid stored in the diskset namespace and in the local set
33351945Sjeanm  * namespace with the new devid.
33361945Sjeanm  *
33371945Sjeanm  * This routine is called during the take of a diskset that has
33381945Sjeanm  * some unresolved replicated drives.
33391945Sjeanm  *
33401945Sjeanm  * Returns : nothing (void)
33411945Sjeanm  */
33421945Sjeanm void
meta_unrslv_replicated_nm(mdsetname_t * sp,md_drive_desc * dd,mddrivenamelist_t * dnlp,md_error_t * ep)33431945Sjeanm meta_unrslv_replicated_nm(
33441945Sjeanm 	mdsetname_t		*sp,
33451945Sjeanm 	md_drive_desc		*dd,	/* drive list for diskset */
33461945Sjeanm 	mddrivenamelist_t	*dnlp,	/* list of drives on current system */
33471945Sjeanm 	md_error_t		*ep
33481945Sjeanm )
33491945Sjeanm {
33501945Sjeanm 	md_drive_desc		*d = NULL;
33511945Sjeanm 	mddrivename_t		*dnp;	/* drive name of old drive */
33521945Sjeanm 	mddrivename_t		*dnp_new; /* drive name of new (repl) drive */
33531945Sjeanm 	ddi_devid_t		devidp, new_devidp;
33541945Sjeanm 	ddi_devid_t		old_devid;
33551945Sjeanm 	char			*devid_old_save;
33561945Sjeanm 	mdsetname_t		*local_sp = NULL;
33571945Sjeanm 	int			myside;
33581945Sjeanm 
33591945Sjeanm 	if ((myside = getmyside(sp, ep)) == MD_SIDEWILD)
33601945Sjeanm 		return;
33611945Sjeanm 
33621945Sjeanm 	for (d = dd; d != NULL; d = d->dd_next) {
33631945Sjeanm 		dnp = d->dd_dnp;
33641945Sjeanm 		if (dnp == NULL)
33651945Sjeanm 			continue;
33661945Sjeanm 
33671945Sjeanm 		/* If don't need to update namespace - skip it. */
33681945Sjeanm 		if (!(d->dd_flags & MD_DR_FIX_LB_NM_DID))
33691945Sjeanm 			continue;
33701945Sjeanm 
33711945Sjeanm 		/* Get old devid from drive record */
33721945Sjeanm 		(void) devid_str_decode(d->dd_dnp->devid,
33731945Sjeanm 		    &old_devid, NULL);
33740Sstevel@tonic-gate 
33750Sstevel@tonic-gate 		/*
33761945Sjeanm 		 * Get old and replicated (new) devids associated with this
33771945Sjeanm 		 * drive.  Also, get the new (replicated) drivename structure.
33780Sstevel@tonic-gate 		 */
33791945Sjeanm 		if (meta_unrslv_replicated_common(myside, d, dnlp, &devidp,
33801945Sjeanm 		    &new_devidp, &dnp_new, ep) != 0) {
33811945Sjeanm 			mdclrerror(ep);
33821945Sjeanm 			continue;
33830Sstevel@tonic-gate 		}
33841945Sjeanm 
33851945Sjeanm 		if (new_devidp) {
33861945Sjeanm 			meta_update_nm_rr_did(sp, devidp,
33871945Sjeanm 			    devid_sizeof(devidp), new_devidp,
33881945Sjeanm 			    devid_sizeof(new_devidp), 0, ep);
33891945Sjeanm 			if (!mdisok(ep)) {
33901945Sjeanm 				devid_free(devidp);
33911945Sjeanm 				return;
33921945Sjeanm 			}
33931945Sjeanm 		}
33941945Sjeanm 		devid_free(devidp);
33951945Sjeanm 
33961945Sjeanm 		/*
33971945Sjeanm 		 * Using the new devid, fix up the name.
33981945Sjeanm 		 * If meta_upd_ctdnames fails, the next take will re-resolve
33991945Sjeanm 		 * the name from the new devid.
34001945Sjeanm 		 */
34011945Sjeanm 		local_sp = metasetname(MD_LOCAL_NAME, ep);
34021945Sjeanm 		devid_old_save = dnp->devid;
34031945Sjeanm 		dnp->devid = dnp_new->devid;
34041945Sjeanm 		(void) meta_upd_ctdnames(&local_sp, 0, (myside + SKEW),
34051945Sjeanm 			dnp, NULL, ep);
34061945Sjeanm 		mdclrerror(ep);
34071945Sjeanm 		dnp->devid = devid_old_save;
34080Sstevel@tonic-gate 	}
34090Sstevel@tonic-gate }
34100Sstevel@tonic-gate 
34110Sstevel@tonic-gate static set_t
meta_imp_setno(md_error_t * ep)34120Sstevel@tonic-gate meta_imp_setno(
34130Sstevel@tonic-gate 	md_error_t *ep
34140Sstevel@tonic-gate )
34150Sstevel@tonic-gate {
34160Sstevel@tonic-gate 	set_t	max_sets, setno;
34170Sstevel@tonic-gate 	int	bool;
34180Sstevel@tonic-gate 
34190Sstevel@tonic-gate 	if ((max_sets = get_max_sets(ep)) == 0) {
34200Sstevel@tonic-gate 		return (MD_SET_BAD);
34210Sstevel@tonic-gate 	}
34220Sstevel@tonic-gate 
34230Sstevel@tonic-gate 	/*
34240Sstevel@tonic-gate 	 * This code needs to be expanded when we run in SunCluster
34250Sstevel@tonic-gate 	 * environment SunCluster obtains setno internally
34260Sstevel@tonic-gate 	 */
34270Sstevel@tonic-gate 	for (setno = 1; setno < max_sets; setno++) {
34280Sstevel@tonic-gate 		if (clnt_setnumbusy(mynode(), setno,
34290Sstevel@tonic-gate 			&bool, ep) == -1) {
34300Sstevel@tonic-gate 			setno = MD_SET_BAD;
34310Sstevel@tonic-gate 			break;
34320Sstevel@tonic-gate 		}
34330Sstevel@tonic-gate 		/*
34340Sstevel@tonic-gate 		 * found one available
34350Sstevel@tonic-gate 		 */
34360Sstevel@tonic-gate 		if (bool == FALSE)
34370Sstevel@tonic-gate 			break;
34380Sstevel@tonic-gate 	}
34390Sstevel@tonic-gate 
34400Sstevel@tonic-gate 	if (setno == max_sets) {
34410Sstevel@tonic-gate 		setno = MD_SET_BAD;
34420Sstevel@tonic-gate 	}
34430Sstevel@tonic-gate 
34440Sstevel@tonic-gate 	return (setno);
34450Sstevel@tonic-gate }
34460Sstevel@tonic-gate 
34470Sstevel@tonic-gate int
meta_imp_set(md_im_set_desc_t * misp,char * setname,int force,bool_t dry_run,md_error_t * ep)34480Sstevel@tonic-gate meta_imp_set(
34490Sstevel@tonic-gate 	md_im_set_desc_t *misp,
34500Sstevel@tonic-gate 	char		*setname,
34510Sstevel@tonic-gate 	int		force,
34520Sstevel@tonic-gate 	bool_t		dry_run,
34530Sstevel@tonic-gate 	md_error_t	*ep
34540Sstevel@tonic-gate )
34550Sstevel@tonic-gate {
34560Sstevel@tonic-gate 	md_timeval32_t		tp;
34570Sstevel@tonic-gate 	md_im_drive_info_t	*midp;
34580Sstevel@tonic-gate 	uint_t			rep_slice;
34590Sstevel@tonic-gate 	mddrivename_t		*dnp;
34600Sstevel@tonic-gate 	struct mddb_config	c;
34610Sstevel@tonic-gate 	mdname_t		*np;
34620Sstevel@tonic-gate 	md_im_replica_info_t	*mirp;
34631945Sjeanm 	set_t			setno;
34641945Sjeanm 	mdcinfo_t		*cinfo;
34651945Sjeanm 	mdsetname_t		*sp;
34661945Sjeanm 	mddrivenamelist_t	*dnlp = NULL;
34671945Sjeanm 	mddrivenamelist_t	**dnlpp = &dnlp;
34680Sstevel@tonic-gate 	char			*minor_name = NULL;
34691945Sjeanm 	int			stale_flag = 0;
34701945Sjeanm 	md_set_desc		*sd;
34711945Sjeanm 	int			partial_replicated_flag = 0;
34721945Sjeanm 	md_error_t		xep = mdnullerror;
34731945Sjeanm 	md_setkey_t		*cl_sk;
34740Sstevel@tonic-gate 
34750Sstevel@tonic-gate 	(void) memset(&c, 0, sizeof (c));
34760Sstevel@tonic-gate 	(void) strlcpy(c.c_setname, setname, sizeof (c.c_setname));
34770Sstevel@tonic-gate 	c.c_sideno = 0;
34780Sstevel@tonic-gate 	c.c_flags = MDDB_C_IMPORT;
34790Sstevel@tonic-gate 
34800Sstevel@tonic-gate 	/*
34810Sstevel@tonic-gate 	 * Check to see if the setname that the set is being imported into,
34820Sstevel@tonic-gate 	 * already exists.
34830Sstevel@tonic-gate 	 */
34840Sstevel@tonic-gate 	if (getsetbyname(c.c_setname, ep) != NULL) {
34850Sstevel@tonic-gate 		return (mddserror(ep, MDE_DS_SETNAMEBUSY, MD_SET_BAD,
34860Sstevel@tonic-gate 		    mynode(), NULL, c.c_setname));
34870Sstevel@tonic-gate 	}
34880Sstevel@tonic-gate 
34890Sstevel@tonic-gate 	/*
34900Sstevel@tonic-gate 	 * Find the next available set number
34910Sstevel@tonic-gate 	 */
34921945Sjeanm 	if ((setno = meta_imp_setno(ep)) == MD_SET_BAD) {
34930Sstevel@tonic-gate 		return (mddserror(ep, MDE_DS_SETNOTIMP, MD_SET_BAD,
34940Sstevel@tonic-gate 		    mynode(), NULL, c.c_setname));
34950Sstevel@tonic-gate 	}
34960Sstevel@tonic-gate 
34971945Sjeanm 	c.c_setno = setno;
34980Sstevel@tonic-gate 	if (meta_gettimeofday(&tp) == -1) {
34990Sstevel@tonic-gate 		return (mdsyserror(ep, errno, NULL));
35000Sstevel@tonic-gate 	}
35010Sstevel@tonic-gate 	c.c_timestamp = tp;
35020Sstevel@tonic-gate 
35030Sstevel@tonic-gate 	/* Check to see if replica quorum requirement is fulfilled */
35041945Sjeanm 	if (meta_replica_quorum(misp) == -1) {
35051945Sjeanm 		if (!force) {
35061945Sjeanm 			return (mddserror(ep, MDE_DS_INSUFQUORUM, MD_SET_BAD,
35071945Sjeanm 			    mynode(), NULL, c.c_setname));
35081945Sjeanm 		} else {
35091945Sjeanm 			stale_flag = MD_IMP_STALE_SET;
35101945Sjeanm 			/*
35111945Sjeanm 			 * If we have a stale diskset, the kernel will
35121945Sjeanm 			 * delete the replicas on the unavailable disks.
35131945Sjeanm 			 * To be consistent, we'll zero out the mirp on those
35141945Sjeanm 			 * disks here.
35151945Sjeanm 			 */
35161945Sjeanm 			for (midp = misp->mis_drives; midp != NULL;
35171945Sjeanm 			    midp = midp->mid_next) {
35181945Sjeanm 				if (midp->mid_available ==
35191945Sjeanm 				    MD_IM_DISK_NOT_AVAILABLE) {
35201945Sjeanm 					midp->mid_replicas = NULL;
35211945Sjeanm 				}
35221945Sjeanm 			}
35231945Sjeanm 		}
35241945Sjeanm 	}
35250Sstevel@tonic-gate 
35260Sstevel@tonic-gate 	for (midp = misp->mis_drives; midp != NULL;
35270Sstevel@tonic-gate 		midp = midp->mid_next) {
35281945Sjeanm 
35291945Sjeanm 		if ((misp->mis_flags & MD_IM_SET_REPLICATED) &&
35301945Sjeanm 		    (partial_replicated_flag == 0) &&
35311945Sjeanm 		    (midp->mid_available == MD_IM_DISK_NOT_AVAILABLE))
35321945Sjeanm 			partial_replicated_flag = MD_SR_UNRSLV_REPLICATED;
35330Sstevel@tonic-gate 
35340Sstevel@tonic-gate 		/*
35351945Sjeanm 		 * We pass the list of the drives in the
35361945Sjeanm 		 * set with replicas on them down to the kernel.
35370Sstevel@tonic-gate 		 */
35380Sstevel@tonic-gate 		dnp = midp->mid_dnp;
35391945Sjeanm 		mirp = midp->mid_replicas;
35401945Sjeanm 		if (!mirp) {
35411945Sjeanm 			/*
35421945Sjeanm 			 * No replicas on this disk, go to next disk.
35431945Sjeanm 			 */
35440Sstevel@tonic-gate 			continue;
35450Sstevel@tonic-gate 		}
35460Sstevel@tonic-gate 
35471945Sjeanm 		if (midp->mid_available == MD_IM_DISK_NOT_AVAILABLE) {
35481945Sjeanm 			/*
35491945Sjeanm 			 * The disk isn't there. We'll need to get the
35501945Sjeanm 			 * disk information from the midp list instead
35511945Sjeanm 			 * of going and looking for it. This means it
35521945Sjeanm 			 * will be information relative to the old
35531945Sjeanm 			 * system.
35541945Sjeanm 			 */
35551945Sjeanm 			minor_name = Strdup(midp->mid_minor_name);
35561945Sjeanm 			(void) strncpy(c.c_locator.l_driver,
35571945Sjeanm 			    midp->mid_driver_name,
35581945Sjeanm 			    sizeof (c.c_locator.l_driver));
35591945Sjeanm 			(void) strcpy(c.c_locator.l_devname, midp->mid_devname);
35601945Sjeanm 			c.c_locator.l_mnum = midp->mid_mnum;
35611945Sjeanm 
35621945Sjeanm 		} else {
35631945Sjeanm 			if ((meta_replicaslice(dnp, &rep_slice, ep) != 0) ||
35641945Sjeanm 			    ((np = metaslicename(dnp, rep_slice, ep))
35651945Sjeanm 			    == NULL)) {
35661945Sjeanm 				mdclrerror(ep);
35671945Sjeanm 				continue;
35681945Sjeanm 			}
35691945Sjeanm 			(void) strcpy(c.c_locator.l_devname, np->bname);
35701945Sjeanm 			c.c_locator.l_dev = meta_cmpldev(np->dev);
35711945Sjeanm 			c.c_locator.l_mnum = meta_getminor(np->dev);
35721945Sjeanm 			minor_name = meta_getminor_name(np->bname, ep);
35731945Sjeanm 			if ((cinfo = metagetcinfo(np, ep)) == NULL) {
35741945Sjeanm 				mdclrerror(ep);
35751945Sjeanm 				continue;
35761945Sjeanm 			}
35771945Sjeanm 
35781945Sjeanm 			if (cinfo->dname) {
35791945Sjeanm 				(void) strncpy(c.c_locator.l_driver,
35801945Sjeanm 				    cinfo->dname,
35811945Sjeanm 				    sizeof (c.c_locator.l_driver));
35821945Sjeanm 			}
35831945Sjeanm 		}
35841945Sjeanm 
35850Sstevel@tonic-gate 		c.c_locator.l_devid = (uintptr_t)Malloc(midp->mid_devid_sz);
358662Sjeanm 		(void) memcpy((void *)(uintptr_t)c.c_locator.l_devid,
358762Sjeanm 		    midp->mid_devid, midp->mid_devid_sz);
35880Sstevel@tonic-gate 		c.c_locator.l_devid_sz = midp->mid_devid_sz;
35890Sstevel@tonic-gate 		c.c_locator.l_devid_flags =
35900Sstevel@tonic-gate 		    MDDB_DEVID_VALID | MDDB_DEVID_SPACE | MDDB_DEVID_SZ;
35910Sstevel@tonic-gate 		if (midp->mid_o_devid) {
35920Sstevel@tonic-gate 			c.c_locator.l_old_devid =
359362Sjeanm 			    (uint64_t)(uintptr_t)Malloc(midp->mid_o_devid_sz);
359462Sjeanm 			(void) memcpy((void *)(uintptr_t)
359562Sjeanm 			    c.c_locator.l_old_devid,
35960Sstevel@tonic-gate 			    midp->mid_o_devid, midp->mid_o_devid_sz);
35970Sstevel@tonic-gate 			c.c_locator.l_old_devid_sz = midp->mid_o_devid_sz;
35980Sstevel@tonic-gate 		}
35991945Sjeanm 		if (minor_name) {
36001945Sjeanm 			(void) strncpy(c.c_locator.l_minor_name, minor_name,
36011945Sjeanm 			    sizeof (c.c_locator.l_minor_name));
36020Sstevel@tonic-gate 		}
36030Sstevel@tonic-gate 
36040Sstevel@tonic-gate 		do {
36051945Sjeanm 			c.c_locator.l_flags = 0;
36061945Sjeanm 			c.c_locator.l_blkno = mirp->mir_offset;
36070Sstevel@tonic-gate 			if (metaioctl(MD_DB_USEDEV, &c, &c.c_mde, NULL) != 0) {
360862Sjeanm 				Free((void *)(uintptr_t)c.c_locator.l_devid);
36090Sstevel@tonic-gate 				if (c.c_locator.l_old_devid)
361062Sjeanm 					Free((void *)(uintptr_t)
361162Sjeanm 					    c.c_locator.l_old_devid);
36120Sstevel@tonic-gate 				return (mdstealerror(ep, &c.c_mde));
36130Sstevel@tonic-gate 			}
36141945Sjeanm 			mirp = mirp->mir_next;
36150Sstevel@tonic-gate 		} while (mirp != NULL);
36160Sstevel@tonic-gate 	}
36170Sstevel@tonic-gate 
36180Sstevel@tonic-gate 	/*
36190Sstevel@tonic-gate 	 * If the dry run option was specified, flag success
36200Sstevel@tonic-gate 	 * and exit out
36210Sstevel@tonic-gate 	 */
36220Sstevel@tonic-gate 	if (dry_run == 1) {
36230Sstevel@tonic-gate 		md_eprintf("%s\n", dgettext(TEXT_DOMAIN,
36240Sstevel@tonic-gate 		    "import should be successful"));
362562Sjeanm 		Free((void *)(uintptr_t)c.c_locator.l_devid);
36260Sstevel@tonic-gate 		if (c.c_locator.l_old_devid)
362762Sjeanm 			Free((void *)(uintptr_t)c.c_locator.l_old_devid);
36280Sstevel@tonic-gate 		return (0);
36290Sstevel@tonic-gate 	}
36300Sstevel@tonic-gate 
36310Sstevel@tonic-gate 	/*
36321945Sjeanm 	 * Now the kernel should have all the information
36330Sstevel@tonic-gate 	 * regarding the import diskset replica.
36341945Sjeanm 	 * Tell the kernel to load them up and import the set
36350Sstevel@tonic-gate 	 */
36361945Sjeanm 	(void) memset(&c, 0, sizeof (c));
36371945Sjeanm 	c.c_flags = stale_flag;
36381945Sjeanm 	c.c_setno = setno;
36391945Sjeanm 	if (metaioctl(MD_IOCIMP_LOAD, &c, &c.c_mde, NULL) != 0) {
364062Sjeanm 		Free((void *)(uintptr_t)c.c_locator.l_devid);
36410Sstevel@tonic-gate 		if (c.c_locator.l_old_devid)
364262Sjeanm 			Free((void *)(uintptr_t)c.c_locator.l_old_devid);
36430Sstevel@tonic-gate 		return (mdstealerror(ep, &c.c_mde));
36440Sstevel@tonic-gate 	}
36450Sstevel@tonic-gate 
36462063Shshaw 	(void) meta_smf_enable(META_SMF_DISKSET, NULL);
36472063Shshaw 
36481945Sjeanm 	/*
36491945Sjeanm 	 * Create a set name for the set.
36501945Sjeanm 	 */
36511945Sjeanm 	sp = Zalloc(sizeof (*sp));
36521945Sjeanm 	sp->setname = Strdup(setname);
36531945Sjeanm 	sp->lockfd = MD_NO_LOCK;
36541945Sjeanm 	sp->setno = setno;
36551945Sjeanm 	sd = Zalloc(sizeof (*sd));
36561945Sjeanm 	(void) strcpy(sd->sd_nodes[0], mynode());
36571945Sjeanm 	sd->sd_ctime = tp;
36581945Sjeanm 	sd->sd_genid = 0;
36591945Sjeanm 
36601945Sjeanm 	if (misp->mis_flags & MD_IM_SET_REPLICATED) {
36611945Sjeanm 		/* Update the diskset namespace */
36621945Sjeanm 		meta_imp_update_nm(sp, misp, ep);
36631945Sjeanm 
36641945Sjeanm 		/* Release the diskset - even if update_nm failed */
36651945Sjeanm 		(void) memset(&c, 0, sizeof (c));
36661945Sjeanm 		c.c_setno = setno;
36671945Sjeanm 		/* Don't need device id information from this ioctl */
36681945Sjeanm 		c.c_locator.l_devid = (uint64_t)0;
36691945Sjeanm 		c.c_locator.l_devid_flags = 0;
36701945Sjeanm 		if (metaioctl(MD_RELEASE_SET, &c, &c.c_mde, NULL) != 0) {
36711945Sjeanm 			if (mdisok(ep))
36721945Sjeanm 				(void) mdstealerror(ep, &c.c_mde);
36731945Sjeanm 			Free(sd);
36741945Sjeanm 			Free(sp);
36751945Sjeanm 			return (-1);
36761945Sjeanm 		}
36771945Sjeanm 
36781945Sjeanm 		/* If update_nm failed, then fail the import. */
36791945Sjeanm 		if (!mdisok(ep)) {
36801945Sjeanm 			Free(sd);
36811945Sjeanm 			Free(sp);
36821945Sjeanm 			return (-1);
36831945Sjeanm 		}
36841945Sjeanm 	}
36851945Sjeanm 
36861945Sjeanm 	/*
36871945Sjeanm 	 * We'll need to update information in the master block due
36881945Sjeanm 	 * to the set number changing and if the case of a replicated
36891945Sjeanm 	 * diskset, the device id changing. May also need to create a
36901945Sjeanm 	 * dummy master block if it's not there.
36911945Sjeanm 	 */
36921945Sjeanm 	meta_imp_update_mb(sp, misp, ep);
36931945Sjeanm 	if (!mdisok(ep)) {
36941945Sjeanm 		Free(sd);
36951945Sjeanm 		Free(sp);
36961945Sjeanm 		return (-1);
36971945Sjeanm 	}
36980Sstevel@tonic-gate 
36990Sstevel@tonic-gate 	/*
37001945Sjeanm 	 * Create set record for diskset, but record is left in
37011945Sjeanm 	 * MD_SR_ADD state until after drives are added to set.
37020Sstevel@tonic-gate 	 */
37031945Sjeanm 	if (clnt_lock_set(mynode(), sp, ep)) {
37041945Sjeanm 		Free(sd);
37051945Sjeanm 		Free(sp);
37061945Sjeanm 		return (-1);
37071945Sjeanm 	}
37081945Sjeanm 
37091945Sjeanm 	if (clnt_createset(mynode(), sp, sd->sd_nodes,
37101945Sjeanm 	    sd->sd_ctime, sd->sd_genid, ep)) {
37111945Sjeanm 		cl_sk = cl_get_setkey(sp->setno, sp->setname);
37121945Sjeanm 		(void) clnt_unlock_set(mynode(), cl_sk, &xep);
37131945Sjeanm 		Free(sd);
37141945Sjeanm 		Free(sp);
37151945Sjeanm 		return (-1);
37160Sstevel@tonic-gate 	}
37170Sstevel@tonic-gate 
37181945Sjeanm 	Free(sd);
37191945Sjeanm 
37201945Sjeanm 	/*
37211945Sjeanm 	 * Create drive records for the disks in the set.
37221945Sjeanm 	 */
37231945Sjeanm 	for (midp = misp->mis_drives; midp != NULL; midp = midp->mid_next) {
37241945Sjeanm 		dnp = midp->mid_dnp;
37251945Sjeanm 		if (midp->mid_available & MD_IM_DISK_NOT_AVAILABLE) {
37261945Sjeanm 			/*
37271945Sjeanm 			 * If the disk isn't available, the dnp->devid is
37281945Sjeanm 			 * no good. It is either blank for the case where
37291945Sjeanm 			 * there is no disk with that devname, or it
37301945Sjeanm 			 * contains the devid for the real disk in the system
37311945Sjeanm 			 * with that name. The problem is, if the disk is
37321945Sjeanm 			 * unavailable, then the devid should be the devid
37331945Sjeanm 			 * of the missing disk. So we're faking a dnp for
37341945Sjeanm 			 * the import. This is needed for creating drive
37351945Sjeanm 			 * records.
37361945Sjeanm 			 */
37371945Sjeanm 			dnp = Zalloc(sizeof (mddrivename_t));
37381945Sjeanm 			dnp->side_names_key = midp->mid_dnp->side_names_key;
37391945Sjeanm 			dnp->type = midp->mid_dnp->type;
37401945Sjeanm 			dnp->cname = Strdup(midp->mid_dnp->cname);
37411945Sjeanm 			dnp->rname = Strdup(midp->mid_dnp->rname);
37421945Sjeanm 			dnp->devid = devid_str_encode(midp->mid_devid,
37431945Sjeanm 			    NULL);
37441945Sjeanm 			midp->mid_dnp = dnp;
37451945Sjeanm 		}
37461945Sjeanm 		dnlpp = meta_drivenamelist_append_wrapper(dnlpp, dnp);
37471945Sjeanm 	}
37481945Sjeanm 
37491945Sjeanm 	if (meta_imp_set_adddrives(sp, dnlp, misp, ep)) {
37501945Sjeanm 		Free(sp);
37511945Sjeanm 		return (mddserror(ep, MDE_DS_SETNOTIMP, MD_SET_BAD,
37521945Sjeanm 		    mynode(), NULL, c.c_setname));
37531945Sjeanm 	}
37541945Sjeanm 
37551945Sjeanm 	/* If drives were added without error, set set_record to OK */
37561945Sjeanm 	if (clnt_upd_sr_flags(mynode(), sp,
37571945Sjeanm 	    (partial_replicated_flag | MD_SR_OK | MD_SR_MB_DEVID), ep)) {
37581945Sjeanm 		Free(sp);
37591945Sjeanm 		return (mddserror(ep, MDE_DS_SETNOTIMP, MD_SET_BAD,
37601945Sjeanm 		    mynode(), NULL, c.c_setname));
37611945Sjeanm 	}
37621945Sjeanm 
37631945Sjeanm 	Free(sp);
37641945Sjeanm 
37651945Sjeanm 	cl_sk = cl_get_setkey(sp->setno, sp->setname);
37661945Sjeanm 	if (clnt_unlock_set(mynode(), cl_sk, ep)) {
37671945Sjeanm 		return (-1);
37681945Sjeanm 	}
37691945Sjeanm 	cl_set_setkey(NULL);
37700Sstevel@tonic-gate 
377162Sjeanm 	Free((void *)(uintptr_t)c.c_locator.l_devid);
37720Sstevel@tonic-gate 	if (c.c_locator.l_old_devid)
377362Sjeanm 		Free((void *)(uintptr_t)c.c_locator.l_old_devid);
37740Sstevel@tonic-gate 	return (0);
37750Sstevel@tonic-gate }
3776