1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <dlfcn.h>
30*0Sstevel@tonic-gate #include <meta.h>
31*0Sstevel@tonic-gate #include <metadyn.h>
32*0Sstevel@tonic-gate #include <ctype.h>
33*0Sstevel@tonic-gate #include <dirent.h>
34*0Sstevel@tonic-gate #include <devid.h>
35*0Sstevel@tonic-gate #include <sys/param.h>
36*0Sstevel@tonic-gate #include <sys/scsi/impl/uscsi.h>
37*0Sstevel@tonic-gate #include <sys/scsi/generic/commands.h>
38*0Sstevel@tonic-gate #include <sys/scsi/generic/inquiry.h>
39*0Sstevel@tonic-gate #include <sys/efi_partition.h>
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate #define	MD_EFI_FG_HEADS		128
42*0Sstevel@tonic-gate #define	MD_EFI_FG_SECTORS	256
43*0Sstevel@tonic-gate #define	MD_EFI_FG_RPM		7200
44*0Sstevel@tonic-gate #define	MD_EFI_FG_WRI		1
45*0Sstevel@tonic-gate #define	MD_EFI_FG_RRI		1
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate typedef struct ctlr_cache {
49*0Sstevel@tonic-gate 	char			*ctlr_nm;
50*0Sstevel@tonic-gate 	int			ctlr_ty;
51*0Sstevel@tonic-gate 	struct	ctlr_cache	*ctlr_nx;
52*0Sstevel@tonic-gate } ctlr_cache_t;
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate static	ctlr_cache_t	*ctlr_cache = NULL;
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate /*
58*0Sstevel@tonic-gate  * return set for a device
59*0Sstevel@tonic-gate  */
60*0Sstevel@tonic-gate mdsetname_t *
61*0Sstevel@tonic-gate metagetset(
62*0Sstevel@tonic-gate 	mdname_t	*np,
63*0Sstevel@tonic-gate 	int		bypass_daemon,
64*0Sstevel@tonic-gate 	md_error_t	*ep
65*0Sstevel@tonic-gate )
66*0Sstevel@tonic-gate {
67*0Sstevel@tonic-gate 	mdsetname_t	*sp;
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate 	/* metadevice */
70*0Sstevel@tonic-gate 	if (metaismeta(np))
71*0Sstevel@tonic-gate 		return (metasetnosetname(MD_MIN2SET(meta_getminor(np->dev)),
72*0Sstevel@tonic-gate 						ep));
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate 	/* regular device */
75*0Sstevel@tonic-gate 	if (meta_is_drive_in_anyset(np->drivenamep, &sp, bypass_daemon,
76*0Sstevel@tonic-gate 	    ep) != 0)
77*0Sstevel@tonic-gate 		return (NULL);
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate 	if (sp != NULL)
80*0Sstevel@tonic-gate 		return (sp);
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate 	return (metasetnosetname(MD_LOCAL_SET, ep));
83*0Sstevel@tonic-gate }
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate /*
86*0Sstevel@tonic-gate  * convert system to md types
87*0Sstevel@tonic-gate  */
88*0Sstevel@tonic-gate static void
89*0Sstevel@tonic-gate meta_geom_to_md(
90*0Sstevel@tonic-gate 	struct dk_geom	*gp,
91*0Sstevel@tonic-gate 	mdgeom_t	*mdgp
92*0Sstevel@tonic-gate )
93*0Sstevel@tonic-gate {
94*0Sstevel@tonic-gate 	(void) memset(mdgp, '\0', sizeof (*mdgp));
95*0Sstevel@tonic-gate 	mdgp->ncyl = gp->dkg_ncyl;
96*0Sstevel@tonic-gate 	mdgp->nhead = gp->dkg_nhead;
97*0Sstevel@tonic-gate 	mdgp->nsect = gp->dkg_nsect;
98*0Sstevel@tonic-gate 	mdgp->rpm = gp->dkg_rpm;
99*0Sstevel@tonic-gate 	mdgp->write_reinstruct = gp->dkg_write_reinstruct;
100*0Sstevel@tonic-gate 	mdgp->read_reinstruct = gp->dkg_read_reinstruct;
101*0Sstevel@tonic-gate 	mdgp->blk_sz = DEV_BSIZE;
102*0Sstevel@tonic-gate }
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate /*
105*0Sstevel@tonic-gate  * convert efi to md types
106*0Sstevel@tonic-gate  */
107*0Sstevel@tonic-gate static void
108*0Sstevel@tonic-gate meta_efi_to_mdgeom(struct dk_gpt *gpt, mdgeom_t	*mdgp)
109*0Sstevel@tonic-gate {
110*0Sstevel@tonic-gate 	(void) memset(mdgp, '\0', sizeof (*mdgp));
111*0Sstevel@tonic-gate 	mdgp->ncyl = (gpt->efi_last_u_lba - gpt->efi_first_u_lba) /
112*0Sstevel@tonic-gate 					(MD_EFI_FG_HEADS * MD_EFI_FG_SECTORS);
113*0Sstevel@tonic-gate 	mdgp->nhead = MD_EFI_FG_HEADS;
114*0Sstevel@tonic-gate 	mdgp->nsect = MD_EFI_FG_SECTORS;
115*0Sstevel@tonic-gate 	mdgp->rpm = MD_EFI_FG_RPM;
116*0Sstevel@tonic-gate 	mdgp->write_reinstruct = MD_EFI_FG_WRI;
117*0Sstevel@tonic-gate 	mdgp->read_reinstruct = MD_EFI_FG_RRI;
118*0Sstevel@tonic-gate 	mdgp->blk_sz = DEV_BSIZE;
119*0Sstevel@tonic-gate }
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate static void
122*0Sstevel@tonic-gate meta_efi_to_mdvtoc(struct dk_gpt *gpt, mdvtoc_t *mdvp)
123*0Sstevel@tonic-gate {
124*0Sstevel@tonic-gate 	char		typename[EFI_PART_NAME_LEN];
125*0Sstevel@tonic-gate 	uint_t		i;
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate 	(void) memset(mdvp, '\0', sizeof (*mdvp));
128*0Sstevel@tonic-gate 	mdvp->nparts = gpt->efi_nparts;
129*0Sstevel@tonic-gate 	if (mdvp->nparts > MD_MAX_PARTS)
130*0Sstevel@tonic-gate 		return;
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate 	mdvp->first_lba = gpt->efi_first_u_lba;
133*0Sstevel@tonic-gate 	mdvp->last_lba = gpt->efi_last_u_lba;
134*0Sstevel@tonic-gate 	mdvp->lbasize = gpt->efi_lbasize;
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate 	for (i = 0; (i < gpt->efi_nparts); ++i) {
137*0Sstevel@tonic-gate 		mdvp->parts[i].start = gpt->efi_parts[i].p_start;
138*0Sstevel@tonic-gate 		mdvp->parts[i].size = gpt->efi_parts[i].p_size;
139*0Sstevel@tonic-gate 		mdvp->parts[i].tag = gpt->efi_parts[i].p_tag;
140*0Sstevel@tonic-gate 		mdvp->parts[i].flag = gpt->efi_parts[i].p_flag;
141*0Sstevel@tonic-gate 		/*
142*0Sstevel@tonic-gate 		 * Due to the lack of a label for the entire partition table,
143*0Sstevel@tonic-gate 		 * we use p_name of the reserved partition
144*0Sstevel@tonic-gate 		 */
145*0Sstevel@tonic-gate 		if ((gpt->efi_parts[i].p_tag == V_RESERVED) &&
146*0Sstevel@tonic-gate 		    (gpt->efi_parts[i].p_name != NULL)) {
147*0Sstevel@tonic-gate 			(void) strlcpy(typename, gpt->efi_parts[i].p_name,
148*0Sstevel@tonic-gate 					EFI_PART_NAME_LEN);
149*0Sstevel@tonic-gate 			/* Stop at first (if any) space or tab */
150*0Sstevel@tonic-gate 			(void) strtok(typename, " \t");
151*0Sstevel@tonic-gate 			mdvp->typename = Strdup(typename);
152*0Sstevel@tonic-gate 		}
153*0Sstevel@tonic-gate 	}
154*0Sstevel@tonic-gate }
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate static void
157*0Sstevel@tonic-gate meta_mdvtoc_to_efi(mdvtoc_t *mdvp, struct dk_gpt **gpt)
158*0Sstevel@tonic-gate {
159*0Sstevel@tonic-gate 	char		typename[EFI_PART_NAME_LEN];
160*0Sstevel@tonic-gate 	uint_t		i;
161*0Sstevel@tonic-gate 	uint_t		lastpart;
162*0Sstevel@tonic-gate 	size_t		size;
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate 	/* first we count how many partitions we have to send */
165*0Sstevel@tonic-gate 	for (i = 0; i < MD_MAX_PARTS; i++) {
166*0Sstevel@tonic-gate 		if ((mdvp->parts[i].start == 0) &&
167*0Sstevel@tonic-gate 		    (mdvp->parts[i].size == 0) &&
168*0Sstevel@tonic-gate 		    (mdvp->parts[i].tag != V_RESERVED)) {
169*0Sstevel@tonic-gate 			continue;
170*0Sstevel@tonic-gate 		}
171*0Sstevel@tonic-gate 		/* if we are here, we know the partition is really used */
172*0Sstevel@tonic-gate 		lastpart = i;
173*0Sstevel@tonic-gate 	}
174*0Sstevel@tonic-gate 	size = sizeof (struct dk_gpt) + (sizeof (struct dk_part) * lastpart);
175*0Sstevel@tonic-gate 	*gpt = calloc(size, sizeof (char));
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate 	(*gpt)->efi_nparts = lastpart + 1;
178*0Sstevel@tonic-gate 	(*gpt)->efi_first_u_lba = mdvp->first_lba;
179*0Sstevel@tonic-gate 	(*gpt)->efi_last_u_lba = mdvp->last_lba;
180*0Sstevel@tonic-gate 	(*gpt)->efi_lbasize = mdvp->lbasize;
181*0Sstevel@tonic-gate 	for (i = 0; (i < (*gpt)->efi_nparts); ++i) {
182*0Sstevel@tonic-gate 		(*gpt)->efi_parts[i].p_start = mdvp->parts[i].start;
183*0Sstevel@tonic-gate 		(*gpt)->efi_parts[i].p_size = mdvp->parts[i].size;
184*0Sstevel@tonic-gate 		(*gpt)->efi_parts[i].p_tag = mdvp->parts[i].tag;
185*0Sstevel@tonic-gate 		(*gpt)->efi_parts[i].p_flag = mdvp->parts[i].flag;
186*0Sstevel@tonic-gate 		/*
187*0Sstevel@tonic-gate 		 * Due to the lack of a label for the entire partition table,
188*0Sstevel@tonic-gate 		 * we use p_name of the reserved partition
189*0Sstevel@tonic-gate 		 */
190*0Sstevel@tonic-gate 		if (((*gpt)->efi_parts[i].p_tag == V_RESERVED) &&
191*0Sstevel@tonic-gate 			(mdvp->typename != NULL)) {
192*0Sstevel@tonic-gate 			(void) strlcpy((*gpt)->efi_parts[i].p_name, typename,
193*0Sstevel@tonic-gate 				EFI_PART_NAME_LEN);
194*0Sstevel@tonic-gate 		}
195*0Sstevel@tonic-gate 	}
196*0Sstevel@tonic-gate }
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate void
200*0Sstevel@tonic-gate ctlr_cache_add(char *nm, int ty)
201*0Sstevel@tonic-gate {
202*0Sstevel@tonic-gate 	ctlr_cache_t	**ccpp;
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 	for (ccpp = &ctlr_cache; *ccpp != NULL; ccpp = &(*ccpp)->ctlr_nx)
205*0Sstevel@tonic-gate 		if (strcmp((*ccpp)->ctlr_nm, nm) == 0)
206*0Sstevel@tonic-gate 			return;
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 	*ccpp = Zalloc(sizeof (ctlr_cache_t));
209*0Sstevel@tonic-gate 	(*ccpp)->ctlr_nm = Strdup(nm);
210*0Sstevel@tonic-gate 	(*ccpp)->ctlr_ty = ty;
211*0Sstevel@tonic-gate }
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate int
214*0Sstevel@tonic-gate ctlr_cache_look(char *nm)
215*0Sstevel@tonic-gate {
216*0Sstevel@tonic-gate 	ctlr_cache_t	*tcp;
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 	for (tcp = ctlr_cache; tcp != NULL; tcp = tcp->ctlr_nx)
219*0Sstevel@tonic-gate 		if (strcmp(tcp->ctlr_nm, nm) == 0)
220*0Sstevel@tonic-gate 			return (tcp->ctlr_ty);
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate 	return (-1);
223*0Sstevel@tonic-gate }
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate void
227*0Sstevel@tonic-gate metaflushctlrcache(void)
228*0Sstevel@tonic-gate {
229*0Sstevel@tonic-gate 	ctlr_cache_t	*cp, *np;
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 	for (cp = ctlr_cache, np = NULL; cp != NULL; cp = np) {
232*0Sstevel@tonic-gate 		np = cp->ctlr_nx;
233*0Sstevel@tonic-gate 		Free(cp->ctlr_nm);
234*0Sstevel@tonic-gate 		Free(cp);
235*0Sstevel@tonic-gate 	}
236*0Sstevel@tonic-gate 	ctlr_cache = NULL;
237*0Sstevel@tonic-gate }
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate /*
240*0Sstevel@tonic-gate  * getdrvnode -- return the driver name based on mdname_t->bname
241*0Sstevel@tonic-gate  *	Need to free pointer when finished.
242*0Sstevel@tonic-gate  */
243*0Sstevel@tonic-gate char *
244*0Sstevel@tonic-gate getdrvnode(mdname_t *np, md_error_t *ep)
245*0Sstevel@tonic-gate {
246*0Sstevel@tonic-gate 	char	*devicespath,
247*0Sstevel@tonic-gate 		*drvnode,
248*0Sstevel@tonic-gate 		*cp;
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 	if ((devicespath = metagetdevicesname(np, ep)) == NULL)
251*0Sstevel@tonic-gate 		return (NULL);
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 	/*
254*0Sstevel@tonic-gate 	 * At this point devicespath should be like the following
255*0Sstevel@tonic-gate 	 * "/devices/<unknow_and_dont_care>/xxxx@vvvv"
256*0Sstevel@tonic-gate 	 *
257*0Sstevel@tonic-gate 	 * There's a couple of 'if' statements below which could
258*0Sstevel@tonic-gate 	 * return an error condition, but I've decide to allow
259*0Sstevel@tonic-gate 	 * a more open approach regarding the mapping so as to
260*0Sstevel@tonic-gate 	 * not restrict possible future projects.
261*0Sstevel@tonic-gate 	 */
262*0Sstevel@tonic-gate 	if (drvnode = strrchr(devicespath, '/'))
263*0Sstevel@tonic-gate 		/*
264*0Sstevel@tonic-gate 		 * drvnode now just "xxxx@vvvv"
265*0Sstevel@tonic-gate 		 */
266*0Sstevel@tonic-gate 		drvnode++;
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate 	if (cp = strrchr(drvnode, '@'))
269*0Sstevel@tonic-gate 		/*
270*0Sstevel@tonic-gate 		 * Now drvnode is just the driver name "xxxx"
271*0Sstevel@tonic-gate 		 */
272*0Sstevel@tonic-gate 		*cp = '\0';
273*0Sstevel@tonic-gate 
274*0Sstevel@tonic-gate 	cp = Strdup(drvnode);
275*0Sstevel@tonic-gate 	Free(devicespath);
276*0Sstevel@tonic-gate 	np->devicesname = NULL;
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	return (cp);
279*0Sstevel@tonic-gate }
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate /*
282*0Sstevel@tonic-gate  * meta_load_dl -- open dynamic library using LDLIBRARYPATH, a debug
283*0Sstevel@tonic-gate  *    environment variable METALDPATH, or the default location.
284*0Sstevel@tonic-gate  */
285*0Sstevel@tonic-gate static void *
286*0Sstevel@tonic-gate meta_load_dl(mdname_t *np, md_error_t *ep)
287*0Sstevel@tonic-gate {
288*0Sstevel@tonic-gate 	char	*drvnode,
289*0Sstevel@tonic-gate 		newpath[MAXPATHLEN],
290*0Sstevel@tonic-gate 		*p;
291*0Sstevel@tonic-gate 	void	*cookie;
292*0Sstevel@tonic-gate 
293*0Sstevel@tonic-gate 	if ((drvnode = getdrvnode(np, ep)) != NULL) {
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate 		/*
296*0Sstevel@tonic-gate 		 * Library seach algorithm:
297*0Sstevel@tonic-gate 		 * 1) Use LDLIBRARYPATH which is implied when a non-absolute
298*0Sstevel@tonic-gate 		 *    path name is passed to dlopen()
299*0Sstevel@tonic-gate 		 * 2) Use the value of METALDPATH as the directory. Mainly
300*0Sstevel@tonic-gate 		 *    used for debugging
301*0Sstevel@tonic-gate 		 * 3) Last search the default location of "/usr/lib"
302*0Sstevel@tonic-gate 		 */
303*0Sstevel@tonic-gate 		(void) snprintf(newpath, sizeof (newpath), "lib%s.so.1",
304*0Sstevel@tonic-gate 		    drvnode);
305*0Sstevel@tonic-gate 		if ((cookie = dlopen(newpath, RTLD_LAZY)) == NULL) {
306*0Sstevel@tonic-gate 			if ((p = getenv("METALDPATH")) == NULL)
307*0Sstevel@tonic-gate 				p = METALDPATH_DEFAULT;
308*0Sstevel@tonic-gate 			(void) snprintf(newpath, sizeof (newpath),
309*0Sstevel@tonic-gate 			    "%s/lib%s.so.1", p, drvnode);
310*0Sstevel@tonic-gate 			Free(drvnode);
311*0Sstevel@tonic-gate 			if ((cookie = dlopen(newpath, RTLD_LAZY)) != NULL) {
312*0Sstevel@tonic-gate 				/*
313*0Sstevel@tonic-gate 				 * Common failure here would be failing to
314*0Sstevel@tonic-gate 				 * find a libXX.so.1 such as libsd.so.1
315*0Sstevel@tonic-gate 				 * Some controllers will not have a library
316*0Sstevel@tonic-gate 				 * because there's no enclosure or name
317*0Sstevel@tonic-gate 				 * translation required.
318*0Sstevel@tonic-gate 				 */
319*0Sstevel@tonic-gate 				return (cookie);
320*0Sstevel@tonic-gate 			}
321*0Sstevel@tonic-gate 		} else {
322*0Sstevel@tonic-gate 			Free(drvnode);
323*0Sstevel@tonic-gate 			return (cookie);
324*0Sstevel@tonic-gate 		}
325*0Sstevel@tonic-gate 	}
326*0Sstevel@tonic-gate 	return (NULL);
327*0Sstevel@tonic-gate }
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate /*
330*0Sstevel@tonic-gate  * meta_match_names -- possibly convert the driver names returned by CINFO
331*0Sstevel@tonic-gate  */
332*0Sstevel@tonic-gate static void
333*0Sstevel@tonic-gate meta_match_names(mdname_t *np, struct dk_cinfo *cp, mdcinfo_t *mdcp,
334*0Sstevel@tonic-gate     md_error_t *ep)
335*0Sstevel@tonic-gate {
336*0Sstevel@tonic-gate 	void		*cookie;
337*0Sstevel@tonic-gate 	meta_convert_e	((*fptr)(mdname_t *, struct dk_cinfo *, mdcinfo_t *,
338*0Sstevel@tonic-gate 			    md_error_t *));
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 	if ((cookie = meta_load_dl(np, ep)) != NULL) {
341*0Sstevel@tonic-gate 		fptr = (meta_convert_e (*)(mdname_t *, struct dk_cinfo *,
342*0Sstevel@tonic-gate 		    mdcinfo_t *, md_error_t *))dlsym(cookie, "convert_path");
343*0Sstevel@tonic-gate 		if (fptr != NULL)
344*0Sstevel@tonic-gate 			(void) (*fptr)(np, cp, mdcp, ep);
345*0Sstevel@tonic-gate 		(void) dlclose(cookie);
346*0Sstevel@tonic-gate 	}
347*0Sstevel@tonic-gate }
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate /*
350*0Sstevel@tonic-gate  * meta_match_enclosure -- return any enclosure info if found
351*0Sstevel@tonic-gate  */
352*0Sstevel@tonic-gate int
353*0Sstevel@tonic-gate meta_match_enclosure(mdname_t *np, mdcinfo_t *mdcp, md_error_t *ep)
354*0Sstevel@tonic-gate {
355*0Sstevel@tonic-gate 	meta_enclosure_e	e,
356*0Sstevel@tonic-gate 				((*fptr)(mdname_t *, mdcinfo_t *,
357*0Sstevel@tonic-gate 				    md_error_t *));
358*0Sstevel@tonic-gate 	void			*cookie;
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 	if ((cookie = meta_load_dl(np, ep)) != NULL) {
361*0Sstevel@tonic-gate 		fptr = (meta_enclosure_e (*)(mdname_t *, mdcinfo_t *,
362*0Sstevel@tonic-gate 		    md_error_t *))dlsym(cookie, "get_enclosure");
363*0Sstevel@tonic-gate 		if (fptr != NULL) {
364*0Sstevel@tonic-gate 			e = (*fptr)(np, mdcp, ep);
365*0Sstevel@tonic-gate 			switch (e) {
366*0Sstevel@tonic-gate 			case Enclosure_Error:
367*0Sstevel@tonic-gate 				/*
368*0Sstevel@tonic-gate 				 * Looks like this library wanted to handle
369*0Sstevel@tonic-gate 				 * our device and had an internal error.
370*0Sstevel@tonic-gate 				 */
371*0Sstevel@tonic-gate 				return (1);
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 			case Enclosure_Okay:
374*0Sstevel@tonic-gate 				/*
375*0Sstevel@tonic-gate 				 * Found a library to handle the request so
376*0Sstevel@tonic-gate 				 * just return with data provided.
377*0Sstevel@tonic-gate 				 */
378*0Sstevel@tonic-gate 				return (0);
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate 			case Enclosure_Noop:
381*0Sstevel@tonic-gate 				/*
382*0Sstevel@tonic-gate 				 * Need to continue the search
383*0Sstevel@tonic-gate 				 */
384*0Sstevel@tonic-gate 				break;
385*0Sstevel@tonic-gate 			}
386*0Sstevel@tonic-gate 		}
387*0Sstevel@tonic-gate 		(void) dlclose(cookie);
388*0Sstevel@tonic-gate 	}
389*0Sstevel@tonic-gate 	return (0);
390*0Sstevel@tonic-gate }
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate static int
393*0Sstevel@tonic-gate meta_cinfo_to_md(mdname_t *np, struct dk_cinfo *cp, mdcinfo_t *mdcp,
394*0Sstevel@tonic-gate     md_error_t *ep)
395*0Sstevel@tonic-gate {
396*0Sstevel@tonic-gate 	/* default */
397*0Sstevel@tonic-gate 	(void) memset(mdcp, '\0', sizeof (*mdcp));
398*0Sstevel@tonic-gate 	(void) strncpy(mdcp->cname, cp->dki_cname,
399*0Sstevel@tonic-gate 	    min((sizeof (mdcp->cname) - 1), sizeof (cp->dki_cname)));
400*0Sstevel@tonic-gate 	mdcp->ctype = MHD_CTLR_GENERIC;
401*0Sstevel@tonic-gate 	mdcp->cnum = cp->dki_cnum;
402*0Sstevel@tonic-gate 	(void) strncpy(mdcp->dname, cp->dki_dname,
403*0Sstevel@tonic-gate 	    min((sizeof (mdcp->dname) - 1), sizeof (cp->dki_dname)));
404*0Sstevel@tonic-gate 	mdcp->unit = cp->dki_unit;
405*0Sstevel@tonic-gate 	mdcp->maxtransfer = cp->dki_maxtransfer;
406*0Sstevel@tonic-gate 
407*0Sstevel@tonic-gate 	/*
408*0Sstevel@tonic-gate 	 * See if the driver name returned from DKIOCINFO
409*0Sstevel@tonic-gate 	 * is valid or not. In somecases, such as the ap_dmd
410*0Sstevel@tonic-gate 	 * driver, we need to modify the name that's return
411*0Sstevel@tonic-gate 	 * for everything to work.
412*0Sstevel@tonic-gate 	 */
413*0Sstevel@tonic-gate 	meta_match_names(np, cp, mdcp, ep);
414*0Sstevel@tonic-gate 
415*0Sstevel@tonic-gate 	if (meta_match_enclosure(np, mdcp, ep))
416*0Sstevel@tonic-gate 		return (-1);
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate 	/* return success */
419*0Sstevel@tonic-gate 	return (0);
420*0Sstevel@tonic-gate }
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate static void
423*0Sstevel@tonic-gate meta_vtoc_to_md(
424*0Sstevel@tonic-gate 	struct vtoc	*vp,
425*0Sstevel@tonic-gate 	mdvtoc_t	*mdvp
426*0Sstevel@tonic-gate )
427*0Sstevel@tonic-gate {
428*0Sstevel@tonic-gate 	char		typename[sizeof (vp->v_asciilabel) + 1];
429*0Sstevel@tonic-gate 	uint_t		i;
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 	(void) memset(mdvp, '\0', sizeof (*mdvp));
432*0Sstevel@tonic-gate 	(void) strncpy(typename, vp->v_asciilabel,
433*0Sstevel@tonic-gate 	    sizeof (vp->v_asciilabel));
434*0Sstevel@tonic-gate 	typename[sizeof (typename) - 1] = '\0';
435*0Sstevel@tonic-gate 	for (i = 0; ((i < sizeof (typename)) && (typename[i] != '\0')); ++i) {
436*0Sstevel@tonic-gate 		if ((typename[i] == ' ') || (typename[i] == '\t')) {
437*0Sstevel@tonic-gate 			typename[i] = '\0';
438*0Sstevel@tonic-gate 			break;
439*0Sstevel@tonic-gate 		}
440*0Sstevel@tonic-gate 	}
441*0Sstevel@tonic-gate 	mdvp->typename = Strdup(typename);
442*0Sstevel@tonic-gate 	mdvp->nparts = vp->v_nparts;
443*0Sstevel@tonic-gate 	for (i = 0; (i < vp->v_nparts); ++i) {
444*0Sstevel@tonic-gate 		mdvp->parts[i].start = vp->v_part[i].p_start;
445*0Sstevel@tonic-gate 		mdvp->parts[i].size = vp->v_part[i].p_size;
446*0Sstevel@tonic-gate 		mdvp->parts[i].tag = vp->v_part[i].p_tag;
447*0Sstevel@tonic-gate 		mdvp->parts[i].flag = vp->v_part[i].p_flag;
448*0Sstevel@tonic-gate 		if (vp->v_part[i].p_start == 0 && vp->v_part[i].p_size > 0)
449*0Sstevel@tonic-gate 			mdvp->parts[i].label = btodb(DK_LABEL_SIZE);
450*0Sstevel@tonic-gate 	}
451*0Sstevel@tonic-gate }
452*0Sstevel@tonic-gate 
453*0Sstevel@tonic-gate /*
454*0Sstevel@tonic-gate  * free allocations in vtoc
455*0Sstevel@tonic-gate  */
456*0Sstevel@tonic-gate void
457*0Sstevel@tonic-gate metafreevtoc(
458*0Sstevel@tonic-gate 	mdvtoc_t	*vtocp
459*0Sstevel@tonic-gate )
460*0Sstevel@tonic-gate {
461*0Sstevel@tonic-gate 	if (vtocp->typename != NULL)
462*0Sstevel@tonic-gate 		Free(vtocp->typename);
463*0Sstevel@tonic-gate 	(void) memset(vtocp, 0, sizeof (*vtocp));
464*0Sstevel@tonic-gate }
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate /*
467*0Sstevel@tonic-gate  * return md types
468*0Sstevel@tonic-gate  */
469*0Sstevel@tonic-gate mdvtoc_t *
470*0Sstevel@tonic-gate metagetvtoc(
471*0Sstevel@tonic-gate 	mdname_t	*np,	/* only rname, drivenamep, are setup */
472*0Sstevel@tonic-gate 	int		nocache,
473*0Sstevel@tonic-gate 	uint_t		*partnop,
474*0Sstevel@tonic-gate 	md_error_t	*ep
475*0Sstevel@tonic-gate )
476*0Sstevel@tonic-gate {
477*0Sstevel@tonic-gate 	mddrivename_t	*dnp = np->drivenamep;
478*0Sstevel@tonic-gate 	struct dk_geom	geom;
479*0Sstevel@tonic-gate 	char		*minor_name = NULL;
480*0Sstevel@tonic-gate 	char		*rname = np->rname;
481*0Sstevel@tonic-gate 	int		fd;
482*0Sstevel@tonic-gate 	int		partno;
483*0Sstevel@tonic-gate 	int		err = 0;	    /* saves errno from ioctl */
484*0Sstevel@tonic-gate 	ddi_devid_t	devid;
485*0Sstevel@tonic-gate 	char		*p;
486*0Sstevel@tonic-gate 
487*0Sstevel@tonic-gate 	/* short circuit */
488*0Sstevel@tonic-gate 	if ((! nocache) && (dnp->vtoc.nparts != 0)) {
489*0Sstevel@tonic-gate 		if (partnop != NULL) {
490*0Sstevel@tonic-gate 			/*
491*0Sstevel@tonic-gate 			 * the following assigment works because the
492*0Sstevel@tonic-gate 			 * mdname_t structs are always created as part
493*0Sstevel@tonic-gate 			 * of the drivenamep struct.  When a user
494*0Sstevel@tonic-gate 			 * creates an mdname_t struct it either
495*0Sstevel@tonic-gate 			 * uses an existing drivenamep struct or creates
496*0Sstevel@tonic-gate 			 * a new one and then adds the mdname_t struct
497*0Sstevel@tonic-gate 			 * as part of its parts_val array.  So what is
498*0Sstevel@tonic-gate 			 * being computed below is the slice offset in
499*0Sstevel@tonic-gate 			 * the parts_val array.
500*0Sstevel@tonic-gate 			 */
501*0Sstevel@tonic-gate 			*partnop = np - np->drivenamep->parts.parts_val;
502*0Sstevel@tonic-gate 			assert(*partnop < dnp->parts.parts_len);
503*0Sstevel@tonic-gate 		}
504*0Sstevel@tonic-gate 		return (&dnp->vtoc);
505*0Sstevel@tonic-gate 	}
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate 	/* can't get vtoc */
508*0Sstevel@tonic-gate 	if (! nocache) {
509*0Sstevel@tonic-gate 		switch (dnp->type) {
510*0Sstevel@tonic-gate 		case MDT_ACCES:
511*0Sstevel@tonic-gate 		case MDT_UNKNOWN:
512*0Sstevel@tonic-gate 			(void) mdsyserror(ep, dnp->errnum, rname);
513*0Sstevel@tonic-gate 			return (NULL);
514*0Sstevel@tonic-gate 		}
515*0Sstevel@tonic-gate 	}
516*0Sstevel@tonic-gate 
517*0Sstevel@tonic-gate 	/* get all the info */
518*0Sstevel@tonic-gate 	if ((fd = open(rname, (O_RDONLY|O_NDELAY), 0)) < 0) {
519*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, rname);
520*0Sstevel@tonic-gate 		return (NULL);
521*0Sstevel@tonic-gate 	}
522*0Sstevel@tonic-gate 
523*0Sstevel@tonic-gate 	/*
524*0Sstevel@tonic-gate 	 * The disk is open so this is a good point to get the devid
525*0Sstevel@tonic-gate 	 * otherwise it will need to be done at another time which
526*0Sstevel@tonic-gate 	 * means reopening it.
527*0Sstevel@tonic-gate 	 */
528*0Sstevel@tonic-gate 	if (devid_get(fd, &devid) != 0) {
529*0Sstevel@tonic-gate 		/* there is no devid for the disk */
530*0Sstevel@tonic-gate 		if (((p = getenv("MD_DEBUG")) != NULL) &&
531*0Sstevel@tonic-gate 		    (strstr(p, "DEVID") != NULL)) {
532*0Sstevel@tonic-gate 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
533*0Sstevel@tonic-gate 			    "%s has no device id\n"), np->rname);
534*0Sstevel@tonic-gate 		}
535*0Sstevel@tonic-gate 		np->minor_name = (char *)NULL;
536*0Sstevel@tonic-gate 		dnp->devid = NULL;
537*0Sstevel@tonic-gate 	} else {
538*0Sstevel@tonic-gate 		(void) devid_get_minor_name(fd, &minor_name);
539*0Sstevel@tonic-gate 		/*
540*0Sstevel@tonic-gate 		 * The minor name could be NULL if the underlying
541*0Sstevel@tonic-gate 		 * device driver does not support 'minor names'.
542*0Sstevel@tonic-gate 		 * This means we do not use devid's for this device.
543*0Sstevel@tonic-gate 		 * SunCluster did driver does not support minor names.
544*0Sstevel@tonic-gate 		 */
545*0Sstevel@tonic-gate 		if (minor_name != NULL) {
546*0Sstevel@tonic-gate 			np->minor_name = Strdup(minor_name);
547*0Sstevel@tonic-gate 			devid_str_free(minor_name);
548*0Sstevel@tonic-gate 			dnp->devid = devid_str_encode(devid, NULL);
549*0Sstevel@tonic-gate 		} else {
550*0Sstevel@tonic-gate 			np->minor_name = (char *)NULL;
551*0Sstevel@tonic-gate 			dnp->devid = NULL;
552*0Sstevel@tonic-gate 
553*0Sstevel@tonic-gate 			if (((p = getenv("MD_DEBUG")) != NULL) &&
554*0Sstevel@tonic-gate 			    (strstr(p, "DEVID") != NULL)) {
555*0Sstevel@tonic-gate 				(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
556*0Sstevel@tonic-gate 				    "%s no minor name (no devid)\n"),
557*0Sstevel@tonic-gate 				    np->rname);
558*0Sstevel@tonic-gate 			}
559*0Sstevel@tonic-gate 		}
560*0Sstevel@tonic-gate 		devid_free(devid);
561*0Sstevel@tonic-gate 	}
562*0Sstevel@tonic-gate 
563*0Sstevel@tonic-gate 	/*
564*0Sstevel@tonic-gate 	 * if our drivenamep points to a device not supporting DKIOCGGEOM,
565*0Sstevel@tonic-gate 	 * it's likely to have an EFI label.
566*0Sstevel@tonic-gate 	 */
567*0Sstevel@tonic-gate 	(void) memset(&geom, 0, sizeof (geom));
568*0Sstevel@tonic-gate 	if (ioctl(fd, DKIOCGGEOM, &geom) != 0) {
569*0Sstevel@tonic-gate 		err = errno;
570*0Sstevel@tonic-gate 		if (err == ENOTTY) {
571*0Sstevel@tonic-gate 			(void) mddeverror(ep, MDE_NOT_DISK, NODEV, rname);
572*0Sstevel@tonic-gate 			(void) close(fd);
573*0Sstevel@tonic-gate 			return (NULL);
574*0Sstevel@tonic-gate 		} else if (err != ENOTSUP) {
575*0Sstevel@tonic-gate 			(void) mdsyserror(ep, err, rname);
576*0Sstevel@tonic-gate 			(void) close(fd);
577*0Sstevel@tonic-gate 			return (NULL);
578*0Sstevel@tonic-gate 		}
579*0Sstevel@tonic-gate 
580*0Sstevel@tonic-gate 	}
581*0Sstevel@tonic-gate 	/*
582*0Sstevel@tonic-gate 	 * If we are here, there was either no failure on DKIOCGGEOM or
583*0Sstevel@tonic-gate 	 * the failure was ENOTSUP
584*0Sstevel@tonic-gate 	 */
585*0Sstevel@tonic-gate 	if (err == ENOTSUP) {
586*0Sstevel@tonic-gate 		/* DKIOCGGEOM yielded ENOTSUP => try efi_alloc_and_read */
587*0Sstevel@tonic-gate 		struct dk_gpt	*gpt;
588*0Sstevel@tonic-gate 		int		save_errno;
589*0Sstevel@tonic-gate 
590*0Sstevel@tonic-gate 		/* this also sets errno */
591*0Sstevel@tonic-gate 		partno = efi_alloc_and_read(fd, &gpt);
592*0Sstevel@tonic-gate 		save_errno = errno;
593*0Sstevel@tonic-gate 		(void) close(fd);
594*0Sstevel@tonic-gate 		if (partno < 0) {
595*0Sstevel@tonic-gate 			efi_free(gpt);
596*0Sstevel@tonic-gate 			(void) mdsyserror(ep, save_errno, rname);
597*0Sstevel@tonic-gate 			return (NULL);
598*0Sstevel@tonic-gate 		}
599*0Sstevel@tonic-gate 		if (partno >= gpt->efi_nparts) {
600*0Sstevel@tonic-gate 			efi_free(gpt);
601*0Sstevel@tonic-gate 			(void) mddeverror(ep, MDE_INVALID_PART, NODEV64,
602*0Sstevel@tonic-gate 						rname);
603*0Sstevel@tonic-gate 			return (NULL);
604*0Sstevel@tonic-gate 		}
605*0Sstevel@tonic-gate 
606*0Sstevel@tonic-gate 		/* convert to our format */
607*0Sstevel@tonic-gate 		metafreevtoc(&dnp->vtoc);
608*0Sstevel@tonic-gate 		meta_efi_to_mdvtoc(gpt, &dnp->vtoc);
609*0Sstevel@tonic-gate 		if (dnp->vtoc.nparts > MD_MAX_PARTS) {
610*0Sstevel@tonic-gate 			(void) mddeverror(ep, MDE_TOO_MANY_PARTS, NODEV64,
611*0Sstevel@tonic-gate 			    rname);
612*0Sstevel@tonic-gate 			return (NULL);
613*0Sstevel@tonic-gate 		}
614*0Sstevel@tonic-gate 		/*
615*0Sstevel@tonic-gate 		 * libmeta needs at least V_NUMPAR partitions.
616*0Sstevel@tonic-gate 		 * If we have an EFI partition with less than V_NUMPAR slices,
617*0Sstevel@tonic-gate 		 * we nevertheless reserve space for V_NUMPAR
618*0Sstevel@tonic-gate 		 */
619*0Sstevel@tonic-gate 
620*0Sstevel@tonic-gate 		if (dnp->vtoc.nparts < V_NUMPAR) {
621*0Sstevel@tonic-gate 			dnp->vtoc.nparts = V_NUMPAR;
622*0Sstevel@tonic-gate 		}
623*0Sstevel@tonic-gate 		meta_efi_to_mdgeom(gpt, &dnp->geom);
624*0Sstevel@tonic-gate 		efi_free(gpt);
625*0Sstevel@tonic-gate 	} else {
626*0Sstevel@tonic-gate 		/* no error on DKIOCGGEOM, try meta_getvtoc */
627*0Sstevel@tonic-gate 		struct vtoc	vtoc;
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 		if (meta_getvtoc(fd, np->cname, &vtoc, &partno, ep) < 0) {
630*0Sstevel@tonic-gate 			(void) close(fd);
631*0Sstevel@tonic-gate 			return (NULL);
632*0Sstevel@tonic-gate 		}
633*0Sstevel@tonic-gate 		(void) close(fd);
634*0Sstevel@tonic-gate 
635*0Sstevel@tonic-gate 		/* convert to our format */
636*0Sstevel@tonic-gate 		meta_geom_to_md(&geom, &dnp->geom);
637*0Sstevel@tonic-gate 		metafreevtoc(&dnp->vtoc);
638*0Sstevel@tonic-gate 		meta_vtoc_to_md(&vtoc, &dnp->vtoc);
639*0Sstevel@tonic-gate 	}
640*0Sstevel@tonic-gate 
641*0Sstevel@tonic-gate 	/* fix up any drives which are now accessible */
642*0Sstevel@tonic-gate 	if ((nocache) && (dnp->type == MDT_ACCES) &&
643*0Sstevel@tonic-gate 	    (dnp->vtoc.nparts == dnp->parts.parts_len)) {
644*0Sstevel@tonic-gate 		dnp->type = MDT_COMP;
645*0Sstevel@tonic-gate 		dnp->errnum = 0;
646*0Sstevel@tonic-gate 	}
647*0Sstevel@tonic-gate 
648*0Sstevel@tonic-gate 	/* save partno */
649*0Sstevel@tonic-gate 	assert(partno < dnp->vtoc.nparts);
650*0Sstevel@tonic-gate 	if (partnop != NULL)
651*0Sstevel@tonic-gate 		*partnop = partno;
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate 	/* return info */
654*0Sstevel@tonic-gate 	return (&dnp->vtoc);
655*0Sstevel@tonic-gate }
656*0Sstevel@tonic-gate 
657*0Sstevel@tonic-gate static void
658*0Sstevel@tonic-gate meta_mdvtoc_to_vtoc(
659*0Sstevel@tonic-gate 	mdvtoc_t	*mdvp,
660*0Sstevel@tonic-gate 	struct vtoc	*vp
661*0Sstevel@tonic-gate )
662*0Sstevel@tonic-gate {
663*0Sstevel@tonic-gate 	uint_t		i;
664*0Sstevel@tonic-gate 
665*0Sstevel@tonic-gate 	(void) memset(&vp->v_part, '\0', sizeof (vp->v_part));
666*0Sstevel@tonic-gate 	vp->v_nparts = (ushort_t)mdvp->nparts;
667*0Sstevel@tonic-gate 	for (i = 0; (i < mdvp->nparts); ++i) {
668*0Sstevel@tonic-gate 		vp->v_part[i].p_start = (daddr32_t)mdvp->parts[i].start;
669*0Sstevel@tonic-gate 		vp->v_part[i].p_size  = (daddr32_t)mdvp->parts[i].size;
670*0Sstevel@tonic-gate 		vp->v_part[i].p_tag   = mdvp->parts[i].tag;
671*0Sstevel@tonic-gate 		vp->v_part[i].p_flag  = mdvp->parts[i].flag;
672*0Sstevel@tonic-gate 	}
673*0Sstevel@tonic-gate }
674*0Sstevel@tonic-gate 
675*0Sstevel@tonic-gate /*
676*0Sstevel@tonic-gate  * Set the vtoc, but use the cached copy to get the info from.
677*0Sstevel@tonic-gate  * We write np->drivenamep->vtoc to disk.
678*0Sstevel@tonic-gate  * Before we can do this we read the vtoc in.
679*0Sstevel@tonic-gate  * if we're dealing with a metadevice and this metadevice is a 64 bit device
680*0Sstevel@tonic-gate  *	we can use meta_getmdvtoc/meta_setmdvtoc
681*0Sstevel@tonic-gate  * else
682*0Sstevel@tonic-gate  * 	we use meta_getvtoc/meta_setvtoc but than we first have to convert
683*0Sstevel@tonic-gate  *	dnp->vtoc (actually being a mdvtoc_t) into a vtoc_t
684*0Sstevel@tonic-gate  */
685*0Sstevel@tonic-gate int
686*0Sstevel@tonic-gate metasetvtoc(
687*0Sstevel@tonic-gate 	mdname_t	*np,
688*0Sstevel@tonic-gate 	md_error_t	*ep
689*0Sstevel@tonic-gate )
690*0Sstevel@tonic-gate {
691*0Sstevel@tonic-gate 	char		*rname = np->rname;
692*0Sstevel@tonic-gate 	mddrivename_t	*dnp = np->drivenamep;
693*0Sstevel@tonic-gate 	int		fd;
694*0Sstevel@tonic-gate 	int		err;
695*0Sstevel@tonic-gate 	int 		save_errno;
696*0Sstevel@tonic-gate 	struct dk_geom	geom;
697*0Sstevel@tonic-gate 
698*0Sstevel@tonic-gate 	if ((fd = open(rname, (O_RDONLY | O_NDELAY), 0)) < 0)
699*0Sstevel@tonic-gate 		return (mdsyserror(ep, errno, rname));
700*0Sstevel@tonic-gate 
701*0Sstevel@tonic-gate 	err = ioctl(fd, DKIOCGGEOM, &geom);
702*0Sstevel@tonic-gate 	save_errno = errno;
703*0Sstevel@tonic-gate 	if (err == 0) {
704*0Sstevel@tonic-gate 		struct vtoc	vtoc;
705*0Sstevel@tonic-gate 
706*0Sstevel@tonic-gate 		if (meta_getvtoc(fd, np->cname, &vtoc, NULL, ep) < 0) {
707*0Sstevel@tonic-gate 			(void) close(fd);
708*0Sstevel@tonic-gate 			return (-1);
709*0Sstevel@tonic-gate 		}
710*0Sstevel@tonic-gate 
711*0Sstevel@tonic-gate 		meta_mdvtoc_to_vtoc(&dnp->vtoc, &vtoc);
712*0Sstevel@tonic-gate 
713*0Sstevel@tonic-gate 		if (meta_setvtoc(fd, np->cname, &vtoc, ep) < 0) {
714*0Sstevel@tonic-gate 			(void) close(fd);
715*0Sstevel@tonic-gate 			return (-1);
716*0Sstevel@tonic-gate 		}
717*0Sstevel@tonic-gate 	} else if (save_errno == ENOTSUP) {
718*0Sstevel@tonic-gate 		struct dk_gpt	*gpt;
719*0Sstevel@tonic-gate 		int		ret;
720*0Sstevel@tonic-gate 
721*0Sstevel@tonic-gate 		/* allocation of gpt is done in meta_mdvtoc_to_efi */
722*0Sstevel@tonic-gate 		meta_mdvtoc_to_efi(&dnp->vtoc, &gpt);
723*0Sstevel@tonic-gate 
724*0Sstevel@tonic-gate 		ret = efi_write(fd, gpt);
725*0Sstevel@tonic-gate 		save_errno = errno;
726*0Sstevel@tonic-gate 		free(gpt);
727*0Sstevel@tonic-gate 		if (ret != 0) {
728*0Sstevel@tonic-gate 			(void) close(fd);
729*0Sstevel@tonic-gate 			return (mdsyserror(ep, save_errno, rname));
730*0Sstevel@tonic-gate 		} else {
731*0Sstevel@tonic-gate 			(void) close(fd);
732*0Sstevel@tonic-gate 			return (0);
733*0Sstevel@tonic-gate 		}
734*0Sstevel@tonic-gate 
735*0Sstevel@tonic-gate 	} else {
736*0Sstevel@tonic-gate 		(void) close(fd);
737*0Sstevel@tonic-gate 		return (mdsyserror(ep, save_errno, rname));
738*0Sstevel@tonic-gate 	}
739*0Sstevel@tonic-gate 
740*0Sstevel@tonic-gate 	(void) close(fd);
741*0Sstevel@tonic-gate 
742*0Sstevel@tonic-gate 	return (0);
743*0Sstevel@tonic-gate }
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate mdgeom_t *
746*0Sstevel@tonic-gate metagetgeom(
747*0Sstevel@tonic-gate 	mdname_t	*np,	/* only rname, drivenamep, are setup */
748*0Sstevel@tonic-gate 	md_error_t	*ep
749*0Sstevel@tonic-gate )
750*0Sstevel@tonic-gate {
751*0Sstevel@tonic-gate 	if (metagetvtoc(np, FALSE, NULL, ep) == NULL)
752*0Sstevel@tonic-gate 		return (NULL);
753*0Sstevel@tonic-gate 	return (&np->drivenamep->geom);
754*0Sstevel@tonic-gate }
755*0Sstevel@tonic-gate 
756*0Sstevel@tonic-gate mdcinfo_t *
757*0Sstevel@tonic-gate metagetcinfo(
758*0Sstevel@tonic-gate 	mdname_t	*np,	/* only rname, drivenamep, are setup */
759*0Sstevel@tonic-gate 	md_error_t	*ep
760*0Sstevel@tonic-gate )
761*0Sstevel@tonic-gate {
762*0Sstevel@tonic-gate 	char			*rname = np->rname;
763*0Sstevel@tonic-gate 	mddrivename_t		*dnp = np->drivenamep;
764*0Sstevel@tonic-gate 	int			fd;
765*0Sstevel@tonic-gate 	struct dk_cinfo		cinfo;
766*0Sstevel@tonic-gate 
767*0Sstevel@tonic-gate 	/* short circuit */
768*0Sstevel@tonic-gate 	if (dnp->cinfo.cname[0] != '\0')
769*0Sstevel@tonic-gate 		return (&dnp->cinfo);
770*0Sstevel@tonic-gate 
771*0Sstevel@tonic-gate 	/* get controller info */
772*0Sstevel@tonic-gate 	if ((fd = open(rname, (O_RDONLY|O_NDELAY), 0)) < 0) {
773*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, rname);
774*0Sstevel@tonic-gate 		return (NULL);
775*0Sstevel@tonic-gate 	}
776*0Sstevel@tonic-gate 	if (ioctl(fd, DKIOCINFO, &cinfo) != 0) {
777*0Sstevel@tonic-gate 		int	save = errno;
778*0Sstevel@tonic-gate 
779*0Sstevel@tonic-gate 		(void) close(fd);
780*0Sstevel@tonic-gate 		if (save == ENOTTY) {
781*0Sstevel@tonic-gate 			(void) mddeverror(ep, MDE_NOT_DISK, NODEV64, rname);
782*0Sstevel@tonic-gate 		} else {
783*0Sstevel@tonic-gate 			(void) mdsyserror(ep, save, rname);
784*0Sstevel@tonic-gate 		}
785*0Sstevel@tonic-gate 		return (NULL);
786*0Sstevel@tonic-gate 	}
787*0Sstevel@tonic-gate 	(void) close(fd);	/* sd/ssd bug */
788*0Sstevel@tonic-gate 
789*0Sstevel@tonic-gate 	/* convert to our format */
790*0Sstevel@tonic-gate 	if (meta_cinfo_to_md(np, &cinfo, &dnp->cinfo, ep) != 0)
791*0Sstevel@tonic-gate 		return (NULL);
792*0Sstevel@tonic-gate 
793*0Sstevel@tonic-gate 	/* return info */
794*0Sstevel@tonic-gate 	return (&dnp->cinfo);
795*0Sstevel@tonic-gate }
796*0Sstevel@tonic-gate 
797*0Sstevel@tonic-gate /*
798*0Sstevel@tonic-gate  * get partition number
799*0Sstevel@tonic-gate  */
800*0Sstevel@tonic-gate int
801*0Sstevel@tonic-gate metagetpartno(
802*0Sstevel@tonic-gate 	mdname_t	*np,
803*0Sstevel@tonic-gate 	md_error_t	*ep
804*0Sstevel@tonic-gate )
805*0Sstevel@tonic-gate {
806*0Sstevel@tonic-gate 	mdvtoc_t	*vtocp;
807*0Sstevel@tonic-gate 	uint_t		partno;
808*0Sstevel@tonic-gate 
809*0Sstevel@tonic-gate 	if ((vtocp = metagetvtoc(np, FALSE, &partno, ep)) == NULL)
810*0Sstevel@tonic-gate 		return (-1);
811*0Sstevel@tonic-gate 	assert(partno < vtocp->nparts);
812*0Sstevel@tonic-gate 	return (partno);
813*0Sstevel@tonic-gate }
814*0Sstevel@tonic-gate 
815*0Sstevel@tonic-gate /*
816*0Sstevel@tonic-gate  * get size of device
817*0Sstevel@tonic-gate  */
818*0Sstevel@tonic-gate diskaddr_t
819*0Sstevel@tonic-gate metagetsize(
820*0Sstevel@tonic-gate 	mdname_t	*np,
821*0Sstevel@tonic-gate 	md_error_t	*ep
822*0Sstevel@tonic-gate )
823*0Sstevel@tonic-gate {
824*0Sstevel@tonic-gate 	mdvtoc_t	*vtocp;
825*0Sstevel@tonic-gate 	uint_t		partno;
826*0Sstevel@tonic-gate 
827*0Sstevel@tonic-gate 	if ((vtocp = metagetvtoc(np, FALSE, &partno, ep)) == NULL)
828*0Sstevel@tonic-gate 		return (MD_DISKADDR_ERROR);
829*0Sstevel@tonic-gate 	assert(partno < vtocp->nparts);
830*0Sstevel@tonic-gate 	return (vtocp->parts[partno].size);
831*0Sstevel@tonic-gate }
832*0Sstevel@tonic-gate 
833*0Sstevel@tonic-gate /*
834*0Sstevel@tonic-gate  * get label of device
835*0Sstevel@tonic-gate  */
836*0Sstevel@tonic-gate diskaddr_t
837*0Sstevel@tonic-gate metagetlabel(
838*0Sstevel@tonic-gate 	mdname_t	*np,
839*0Sstevel@tonic-gate 	md_error_t	*ep
840*0Sstevel@tonic-gate )
841*0Sstevel@tonic-gate {
842*0Sstevel@tonic-gate 	mdvtoc_t	*vtocp;
843*0Sstevel@tonic-gate 	uint_t		partno;
844*0Sstevel@tonic-gate 
845*0Sstevel@tonic-gate 	if ((vtocp = metagetvtoc(np, FALSE, &partno, ep)) == NULL)
846*0Sstevel@tonic-gate 		return (MD_DISKADDR_ERROR);
847*0Sstevel@tonic-gate 	assert(partno < vtocp->nparts);
848*0Sstevel@tonic-gate 	return (vtocp->parts[partno].label);
849*0Sstevel@tonic-gate }
850*0Sstevel@tonic-gate 
851*0Sstevel@tonic-gate /*
852*0Sstevel@tonic-gate  * find out where database replicas end
853*0Sstevel@tonic-gate  */
854*0Sstevel@tonic-gate static int
855*0Sstevel@tonic-gate mddb_getendblk(
856*0Sstevel@tonic-gate 	mdsetname_t		*sp,
857*0Sstevel@tonic-gate 	mdname_t		*np,
858*0Sstevel@tonic-gate 	diskaddr_t		*endblkp,
859*0Sstevel@tonic-gate 	md_error_t		*ep
860*0Sstevel@tonic-gate )
861*0Sstevel@tonic-gate {
862*0Sstevel@tonic-gate 	md_replicalist_t	*rlp = NULL;
863*0Sstevel@tonic-gate 	md_replicalist_t	*rl;
864*0Sstevel@tonic-gate 
865*0Sstevel@tonic-gate 	/* make sure we have a component */
866*0Sstevel@tonic-gate 	*endblkp = 0;
867*0Sstevel@tonic-gate 	if (metaismeta(np))
868*0Sstevel@tonic-gate 		return (0);
869*0Sstevel@tonic-gate 
870*0Sstevel@tonic-gate 	/* get replicas, quit if none */
871*0Sstevel@tonic-gate 	if (metareplicalist(sp, MD_BASICNAME_OK | PRINT_FAST, &rlp, ep) < 0) {
872*0Sstevel@tonic-gate 		if (! mdismddberror(ep, MDE_DB_NODB))
873*0Sstevel@tonic-gate 			return (-1);
874*0Sstevel@tonic-gate 		mdclrerror(ep);
875*0Sstevel@tonic-gate 		return (0);
876*0Sstevel@tonic-gate 	} else if (rlp == NULL)
877*0Sstevel@tonic-gate 		return (0);
878*0Sstevel@tonic-gate 
879*0Sstevel@tonic-gate 	/* go through all the replicas */
880*0Sstevel@tonic-gate 	for (rl = rlp; (rl != NULL); rl = rl->rl_next) {
881*0Sstevel@tonic-gate 		md_replica_t	*rp = rl->rl_repp;
882*0Sstevel@tonic-gate 		mdname_t	*repnamep = rp->r_namep;
883*0Sstevel@tonic-gate 		diskaddr_t	dbend;
884*0Sstevel@tonic-gate 
885*0Sstevel@tonic-gate 		if (np->dev != repnamep->dev)
886*0Sstevel@tonic-gate 			continue;
887*0Sstevel@tonic-gate 		dbend = rp->r_blkno + rp->r_nblk - 1;
888*0Sstevel@tonic-gate 		if (dbend > *endblkp)
889*0Sstevel@tonic-gate 			*endblkp = dbend;
890*0Sstevel@tonic-gate 	}
891*0Sstevel@tonic-gate 
892*0Sstevel@tonic-gate 	/* cleanup, return success */
893*0Sstevel@tonic-gate 	metafreereplicalist(rlp);
894*0Sstevel@tonic-gate 	return (0);
895*0Sstevel@tonic-gate }
896*0Sstevel@tonic-gate 
897*0Sstevel@tonic-gate /*
898*0Sstevel@tonic-gate  * return cached start block
899*0Sstevel@tonic-gate  */
900*0Sstevel@tonic-gate static diskaddr_t
901*0Sstevel@tonic-gate metagetend(
902*0Sstevel@tonic-gate 	mdsetname_t	*sp,
903*0Sstevel@tonic-gate 	mdname_t	*np,
904*0Sstevel@tonic-gate 	md_error_t	*ep
905*0Sstevel@tonic-gate )
906*0Sstevel@tonic-gate {
907*0Sstevel@tonic-gate 	diskaddr_t	end_blk = MD_DISKADDR_ERROR;
908*0Sstevel@tonic-gate 
909*0Sstevel@tonic-gate 	/* short circuit */
910*0Sstevel@tonic-gate 	if (np->end_blk != MD_DISKADDR_ERROR)
911*0Sstevel@tonic-gate 		return (np->end_blk);
912*0Sstevel@tonic-gate 
913*0Sstevel@tonic-gate 	/* look for database locations */
914*0Sstevel@tonic-gate 	if (mddb_getendblk(sp, np, &end_blk, ep) != 0)
915*0Sstevel@tonic-gate 		return (MD_DISKADDR_ERROR);
916*0Sstevel@tonic-gate 
917*0Sstevel@tonic-gate 	/* success */
918*0Sstevel@tonic-gate 	np->end_blk = end_blk;
919*0Sstevel@tonic-gate 	return (end_blk);
920*0Sstevel@tonic-gate }
921*0Sstevel@tonic-gate 
922*0Sstevel@tonic-gate /*
923*0Sstevel@tonic-gate  * does device have a metadb
924*0Sstevel@tonic-gate  */
925*0Sstevel@tonic-gate int
926*0Sstevel@tonic-gate metahasmddb(
927*0Sstevel@tonic-gate 	mdsetname_t	*sp,
928*0Sstevel@tonic-gate 	mdname_t	*np,
929*0Sstevel@tonic-gate 	md_error_t	*ep
930*0Sstevel@tonic-gate )
931*0Sstevel@tonic-gate {
932*0Sstevel@tonic-gate 	if (metagetend(sp, np, ep) == MD_DISKADDR_ERROR)
933*0Sstevel@tonic-gate 		return (-1);
934*0Sstevel@tonic-gate 	else if (np->end_blk > 0)
935*0Sstevel@tonic-gate 		return (1);
936*0Sstevel@tonic-gate 	else
937*0Sstevel@tonic-gate 		return (0);
938*0Sstevel@tonic-gate }
939*0Sstevel@tonic-gate 
940*0Sstevel@tonic-gate /*
941*0Sstevel@tonic-gate  * return cached start block
942*0Sstevel@tonic-gate  */
943*0Sstevel@tonic-gate diskaddr_t
944*0Sstevel@tonic-gate metagetstart(
945*0Sstevel@tonic-gate 	mdsetname_t	*sp,
946*0Sstevel@tonic-gate 	mdname_t	*np,
947*0Sstevel@tonic-gate 	md_error_t	*ep
948*0Sstevel@tonic-gate )
949*0Sstevel@tonic-gate {
950*0Sstevel@tonic-gate 	diskaddr_t	start_blk = MD_DISKADDR_ERROR;
951*0Sstevel@tonic-gate 
952*0Sstevel@tonic-gate 	/* short circuit */
953*0Sstevel@tonic-gate 	if (np->start_blk != MD_DISKADDR_ERROR)
954*0Sstevel@tonic-gate 		return (np->start_blk);
955*0Sstevel@tonic-gate 
956*0Sstevel@tonic-gate 	/* look for database locations */
957*0Sstevel@tonic-gate 	if ((start_blk = metagetend(sp, np, ep)) == MD_DISKADDR_ERROR)
958*0Sstevel@tonic-gate 		return (MD_DISKADDR_ERROR);
959*0Sstevel@tonic-gate 
960*0Sstevel@tonic-gate 	/* check for label */
961*0Sstevel@tonic-gate 	if (start_blk == 0) {
962*0Sstevel@tonic-gate 		start_blk = metagetlabel(np, ep);
963*0Sstevel@tonic-gate 		if (start_blk == MD_DISKADDR_ERROR) {
964*0Sstevel@tonic-gate 			return (MD_DISKADDR_ERROR);
965*0Sstevel@tonic-gate 		}
966*0Sstevel@tonic-gate 	}
967*0Sstevel@tonic-gate 
968*0Sstevel@tonic-gate 	/* roundup to next cylinder */
969*0Sstevel@tonic-gate 	if (start_blk != 0) {
970*0Sstevel@tonic-gate 		mdgeom_t	*geomp;
971*0Sstevel@tonic-gate 
972*0Sstevel@tonic-gate 		if ((geomp = metagetgeom(np, ep)) == NULL)
973*0Sstevel@tonic-gate 			return (MD_DISKADDR_ERROR);
974*0Sstevel@tonic-gate 		start_blk = roundup(start_blk, (geomp->nhead * geomp->nsect));
975*0Sstevel@tonic-gate 	}
976*0Sstevel@tonic-gate 
977*0Sstevel@tonic-gate 	/* success */
978*0Sstevel@tonic-gate 	np->start_blk = start_blk;
979*0Sstevel@tonic-gate 	return (start_blk);
980*0Sstevel@tonic-gate }
981*0Sstevel@tonic-gate 
982*0Sstevel@tonic-gate /*
983*0Sstevel@tonic-gate  * return cached devices name
984*0Sstevel@tonic-gate  */
985*0Sstevel@tonic-gate char *
986*0Sstevel@tonic-gate metagetdevicesname(
987*0Sstevel@tonic-gate 	mdname_t	*np,
988*0Sstevel@tonic-gate 	md_error_t	*ep
989*0Sstevel@tonic-gate )
990*0Sstevel@tonic-gate {
991*0Sstevel@tonic-gate 	char		path[MAXPATHLEN + 1];
992*0Sstevel@tonic-gate 	int		len;
993*0Sstevel@tonic-gate 
994*0Sstevel@tonic-gate 	/* short circuit */
995*0Sstevel@tonic-gate 	if (np->devicesname != NULL)
996*0Sstevel@tonic-gate 		return (np->devicesname);
997*0Sstevel@tonic-gate 
998*0Sstevel@tonic-gate 	/* follow symlink */
999*0Sstevel@tonic-gate 	if ((len = readlink(np->bname, path, (sizeof (path) - 1))) < 0) {
1000*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, np->bname);
1001*0Sstevel@tonic-gate 		return (NULL);
1002*0Sstevel@tonic-gate 	} else if (len >= sizeof (path)) {
1003*0Sstevel@tonic-gate 		(void) mdsyserror(ep, ENAMETOOLONG, np->bname);
1004*0Sstevel@tonic-gate 		return (NULL);
1005*0Sstevel@tonic-gate 	}
1006*0Sstevel@tonic-gate 	path[len] = '\0';
1007*0Sstevel@tonic-gate 	if ((len = strfind(path, "/devices/")) < 0) {
1008*0Sstevel@tonic-gate 		(void) mddeverror(ep, MDE_DEVICES_NAME, np->dev, np->bname);
1009*0Sstevel@tonic-gate 		return (NULL);
1010*0Sstevel@tonic-gate 	}
1011*0Sstevel@tonic-gate 
1012*0Sstevel@tonic-gate 	/* return name */
1013*0Sstevel@tonic-gate 	np->devicesname = Strdup(path + len + strlen("/devices"));
1014*0Sstevel@tonic-gate 	return (np->devicesname);
1015*0Sstevel@tonic-gate }
1016*0Sstevel@tonic-gate 
1017*0Sstevel@tonic-gate /*
1018*0Sstevel@tonic-gate  * get metadevice misc name
1019*0Sstevel@tonic-gate  */
1020*0Sstevel@tonic-gate char *
1021*0Sstevel@tonic-gate metagetmiscname(
1022*0Sstevel@tonic-gate 	mdname_t		*np,
1023*0Sstevel@tonic-gate 	md_error_t		*ep
1024*0Sstevel@tonic-gate )
1025*0Sstevel@tonic-gate {
1026*0Sstevel@tonic-gate 	mddrivename_t		*dnp = np->drivenamep;
1027*0Sstevel@tonic-gate 	md_i_driverinfo_t	mid;
1028*0Sstevel@tonic-gate 
1029*0Sstevel@tonic-gate 	/* short circuit */
1030*0Sstevel@tonic-gate 	if (dnp->miscname != NULL)
1031*0Sstevel@tonic-gate 		return (dnp->miscname);
1032*0Sstevel@tonic-gate 	if (metachkmeta(np, ep) != 0)
1033*0Sstevel@tonic-gate 		return (NULL);
1034*0Sstevel@tonic-gate 
1035*0Sstevel@tonic-gate 	/* get misc module from driver */
1036*0Sstevel@tonic-gate 	(void) memset(&mid, 0, sizeof (mid));
1037*0Sstevel@tonic-gate 	mid.mnum = meta_getminor(np->dev);
1038*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCGET_DRVNM, &mid, &mid.mde, np->cname) != 0) {
1039*0Sstevel@tonic-gate 		(void) mdstealerror(ep, &mid.mde);
1040*0Sstevel@tonic-gate 		return (NULL);
1041*0Sstevel@tonic-gate 	}
1042*0Sstevel@tonic-gate 
1043*0Sstevel@tonic-gate 	/* return miscname */
1044*0Sstevel@tonic-gate 	dnp->miscname = Strdup(MD_PNTDRIVERNAME(&mid));
1045*0Sstevel@tonic-gate 	return (dnp->miscname);
1046*0Sstevel@tonic-gate }
1047*0Sstevel@tonic-gate 
1048*0Sstevel@tonic-gate /*
1049*0Sstevel@tonic-gate  * get unit structure from driver
1050*0Sstevel@tonic-gate  */
1051*0Sstevel@tonic-gate md_unit_t *
1052*0Sstevel@tonic-gate meta_get_mdunit(
1053*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1054*0Sstevel@tonic-gate 	mdname_t	*np,
1055*0Sstevel@tonic-gate 	md_error_t	*ep
1056*0Sstevel@tonic-gate )
1057*0Sstevel@tonic-gate {
1058*0Sstevel@tonic-gate 	md_i_get_t	mig;
1059*0Sstevel@tonic-gate 	char		*miscname = NULL;
1060*0Sstevel@tonic-gate 
1061*0Sstevel@tonic-gate 	/* should have a set */
1062*0Sstevel@tonic-gate 	assert(sp != NULL);
1063*0Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(np->dev)));
1064*0Sstevel@tonic-gate 
1065*0Sstevel@tonic-gate 	/* get size of unit structure */
1066*0Sstevel@tonic-gate 	if (metachkmeta(np, ep) != 0)
1067*0Sstevel@tonic-gate 		return (NULL);
1068*0Sstevel@tonic-gate 	if ((miscname = metagetmiscname(np, ep)) == NULL)
1069*0Sstevel@tonic-gate 		return (NULL);
1070*0Sstevel@tonic-gate 	(void) memset(&mig, '\0', sizeof (mig));
1071*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&mig, miscname, sp->setno);
1072*0Sstevel@tonic-gate 	mig.id = meta_getminor(np->dev);
1073*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCGET, &mig, &mig.mde, np->cname) != 0) {
1074*0Sstevel@tonic-gate 		(void) mdstealerror(ep, &mig.mde);
1075*0Sstevel@tonic-gate 		return (NULL);
1076*0Sstevel@tonic-gate 	}
1077*0Sstevel@tonic-gate 
1078*0Sstevel@tonic-gate 	/* get actual unit structure */
1079*0Sstevel@tonic-gate 	assert(mig.size > 0);
1080*0Sstevel@tonic-gate 	mig.mdp = (uintptr_t)Zalloc(mig.size);
1081*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCGET, &mig, &mig.mde, np->cname) != 0) {
1082*0Sstevel@tonic-gate 		(void) mdstealerror(ep, &mig.mde);
1083*0Sstevel@tonic-gate 		Free((void *)mig.mdp);
1084*0Sstevel@tonic-gate 		return (NULL);
1085*0Sstevel@tonic-gate 	}
1086*0Sstevel@tonic-gate 
1087*0Sstevel@tonic-gate 	return ((md_unit_t *)mig.mdp);
1088*0Sstevel@tonic-gate }
1089*0Sstevel@tonic-gate 
1090*0Sstevel@tonic-gate /*
1091*0Sstevel@tonic-gate  * free metadevice unit
1092*0Sstevel@tonic-gate  */
1093*0Sstevel@tonic-gate void
1094*0Sstevel@tonic-gate meta_free_unit(
1095*0Sstevel@tonic-gate 	mddrivename_t	*dnp
1096*0Sstevel@tonic-gate )
1097*0Sstevel@tonic-gate {
1098*0Sstevel@tonic-gate 	if (dnp->unitp != NULL) {
1099*0Sstevel@tonic-gate 		switch (dnp->unitp->type) {
1100*0Sstevel@tonic-gate 		case MD_DEVICE:
1101*0Sstevel@tonic-gate 			meta_free_stripe((md_stripe_t *)dnp->unitp);
1102*0Sstevel@tonic-gate 			break;
1103*0Sstevel@tonic-gate 		case MD_METAMIRROR:
1104*0Sstevel@tonic-gate 			meta_free_mirror((md_mirror_t *)dnp->unitp);
1105*0Sstevel@tonic-gate 			break;
1106*0Sstevel@tonic-gate 		case MD_METATRANS:
1107*0Sstevel@tonic-gate 			meta_free_trans((md_trans_t *)dnp->unitp);
1108*0Sstevel@tonic-gate 			break;
1109*0Sstevel@tonic-gate 		case MD_METARAID:
1110*0Sstevel@tonic-gate 			meta_free_raid((md_raid_t *)dnp->unitp);
1111*0Sstevel@tonic-gate 			break;
1112*0Sstevel@tonic-gate 		case MD_METASP:
1113*0Sstevel@tonic-gate 			meta_free_sp((md_sp_t *)dnp->unitp);
1114*0Sstevel@tonic-gate 			break;
1115*0Sstevel@tonic-gate 		default:
1116*0Sstevel@tonic-gate 			assert(0);
1117*0Sstevel@tonic-gate 			break;
1118*0Sstevel@tonic-gate 		}
1119*0Sstevel@tonic-gate 		dnp->unitp = NULL;
1120*0Sstevel@tonic-gate 	}
1121*0Sstevel@tonic-gate }
1122*0Sstevel@tonic-gate 
1123*0Sstevel@tonic-gate /*
1124*0Sstevel@tonic-gate  * free metadevice name info
1125*0Sstevel@tonic-gate  */
1126*0Sstevel@tonic-gate void
1127*0Sstevel@tonic-gate meta_invalidate_name(
1128*0Sstevel@tonic-gate 	mdname_t	*namep
1129*0Sstevel@tonic-gate )
1130*0Sstevel@tonic-gate {
1131*0Sstevel@tonic-gate 	mddrivename_t	*dnp = namep->drivenamep;
1132*0Sstevel@tonic-gate 
1133*0Sstevel@tonic-gate 	/* get rid of cached name info */
1134*0Sstevel@tonic-gate 	if (namep->devicesname != NULL) {
1135*0Sstevel@tonic-gate 		Free(namep->devicesname);
1136*0Sstevel@tonic-gate 		namep->devicesname = NULL;
1137*0Sstevel@tonic-gate 	}
1138*0Sstevel@tonic-gate 	namep->key = MD_KEYBAD;
1139*0Sstevel@tonic-gate 	namep->start_blk = -1;
1140*0Sstevel@tonic-gate 	namep->end_blk = -1;
1141*0Sstevel@tonic-gate 
1142*0Sstevel@tonic-gate 	/* get rid of cached drivename info */
1143*0Sstevel@tonic-gate 	(void) memset(&dnp->geom, 0, sizeof (dnp->geom));
1144*0Sstevel@tonic-gate 	(void) memset(&dnp->cinfo, 0, sizeof (dnp->cinfo));
1145*0Sstevel@tonic-gate 	metafreevtoc(&dnp->vtoc);
1146*0Sstevel@tonic-gate 	metaflushsidenames(dnp);
1147*0Sstevel@tonic-gate 	dnp->side_names_key = MD_KEYBAD;
1148*0Sstevel@tonic-gate 	if (dnp->miscname != NULL) {
1149*0Sstevel@tonic-gate 		Free(dnp->miscname);
1150*0Sstevel@tonic-gate 		dnp->miscname = NULL;
1151*0Sstevel@tonic-gate 	}
1152*0Sstevel@tonic-gate 	meta_free_unit(dnp);
1153*0Sstevel@tonic-gate }
1154*0Sstevel@tonic-gate 
1155*0Sstevel@tonic-gate /*
1156*0Sstevel@tonic-gate  * get metadevice unit
1157*0Sstevel@tonic-gate  */
1158*0Sstevel@tonic-gate md_common_t *
1159*0Sstevel@tonic-gate meta_get_unit(
1160*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1161*0Sstevel@tonic-gate 	mdname_t	*np,
1162*0Sstevel@tonic-gate 	md_error_t	*ep
1163*0Sstevel@tonic-gate )
1164*0Sstevel@tonic-gate {
1165*0Sstevel@tonic-gate 	char		*miscname;
1166*0Sstevel@tonic-gate 
1167*0Sstevel@tonic-gate 	/* short circuit */
1168*0Sstevel@tonic-gate 	if (np->drivenamep->unitp != NULL)
1169*0Sstevel@tonic-gate 		return (np->drivenamep->unitp);
1170*0Sstevel@tonic-gate 	if (metachkmeta(np, ep) != 0)
1171*0Sstevel@tonic-gate 		return (NULL);
1172*0Sstevel@tonic-gate 
1173*0Sstevel@tonic-gate 	/* dispatch */
1174*0Sstevel@tonic-gate 	if ((miscname = metagetmiscname(np, ep)) == NULL)
1175*0Sstevel@tonic-gate 		return (NULL);
1176*0Sstevel@tonic-gate 	else if (strcmp(miscname, MD_STRIPE) == 0)
1177*0Sstevel@tonic-gate 		return ((md_common_t *)meta_get_stripe(sp, np, ep));
1178*0Sstevel@tonic-gate 	else if (strcmp(miscname, MD_MIRROR) == 0)
1179*0Sstevel@tonic-gate 		return ((md_common_t *)meta_get_mirror(sp, np, ep));
1180*0Sstevel@tonic-gate 	else if (strcmp(miscname, MD_TRANS) == 0)
1181*0Sstevel@tonic-gate 		return ((md_common_t *)meta_get_trans(sp, np, ep));
1182*0Sstevel@tonic-gate 	else if (strcmp(miscname, MD_RAID) == 0)
1183*0Sstevel@tonic-gate 		return ((md_common_t *)meta_get_raid(sp, np, ep));
1184*0Sstevel@tonic-gate 	else if (strcmp(miscname, MD_SP) == 0)
1185*0Sstevel@tonic-gate 		return ((md_common_t *)meta_get_sp(sp, np, ep));
1186*0Sstevel@tonic-gate 	else {
1187*0Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_UNKNOWN_TYPE, meta_getminor(np->dev),
1188*0Sstevel@tonic-gate 		    np->cname);
1189*0Sstevel@tonic-gate 		return (NULL);
1190*0Sstevel@tonic-gate 	}
1191*0Sstevel@tonic-gate }
1192*0Sstevel@tonic-gate 
1193*0Sstevel@tonic-gate 
1194*0Sstevel@tonic-gate int
1195*0Sstevel@tonic-gate meta_isopen(
1196*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1197*0Sstevel@tonic-gate 	mdname_t	*np,
1198*0Sstevel@tonic-gate 	md_error_t	*ep,
1199*0Sstevel@tonic-gate 	mdcmdopts_t	options
1200*0Sstevel@tonic-gate )
1201*0Sstevel@tonic-gate {
1202*0Sstevel@tonic-gate 	md_isopen_t	d;
1203*0Sstevel@tonic-gate 
1204*0Sstevel@tonic-gate 	if (metachkmeta(np, ep) != 0)
1205*0Sstevel@tonic-gate 		return (-1);
1206*0Sstevel@tonic-gate 
1207*0Sstevel@tonic-gate 	(void) memset(&d, '\0', sizeof (d));
1208*0Sstevel@tonic-gate 	d.dev = np->dev;
1209*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCISOPEN, &d, &d.mde, np->cname) != 0)
1210*0Sstevel@tonic-gate 		return (mdstealerror(ep, &d.mde));
1211*0Sstevel@tonic-gate 
1212*0Sstevel@tonic-gate 	/*
1213*0Sstevel@tonic-gate 	 * shortcut: if the device is open, no need to check on other nodes,
1214*0Sstevel@tonic-gate 	 * even in case of a mn metadevice
1215*0Sstevel@tonic-gate 	 * Also return in case we're told not to check on other nodes.
1216*0Sstevel@tonic-gate 	 */
1217*0Sstevel@tonic-gate 	if ((d.isopen != 0) || ((options & MDCMD_MN_OPEN_CHECK) == 0)) {
1218*0Sstevel@tonic-gate 		return (d.isopen);
1219*0Sstevel@tonic-gate 	}
1220*0Sstevel@tonic-gate 
1221*0Sstevel@tonic-gate 	/*
1222*0Sstevel@tonic-gate 	 * If the device is closed locally, but it's a mn device,
1223*0Sstevel@tonic-gate 	 * check on all other nodes, too
1224*0Sstevel@tonic-gate 	 */
1225*0Sstevel@tonic-gate 	if (sp->setno != MD_LOCAL_SET) {
1226*0Sstevel@tonic-gate 		(void) metaget_setdesc(sp, ep); /* not supposed to fail */
1227*0Sstevel@tonic-gate 		if (sp->setdesc->sd_flags & MD_SR_MN) {
1228*0Sstevel@tonic-gate 			int		err = 0;
1229*0Sstevel@tonic-gate 			md_mn_result_t *resp;
1230*0Sstevel@tonic-gate 			/*
1231*0Sstevel@tonic-gate 			 * This message is never directly issued.
1232*0Sstevel@tonic-gate 			 * So we launch it with a suspend override flag.
1233*0Sstevel@tonic-gate 			 * If the commd is suspended, and this message comes
1234*0Sstevel@tonic-gate 			 * along it must be sent due to replaying a metainit or
1235*0Sstevel@tonic-gate 			 * similar. In that case we don't want this message to
1236*0Sstevel@tonic-gate 			 * be blocked.
1237*0Sstevel@tonic-gate 			 * If the commd is not suspended, the flag does no harm.
1238*0Sstevel@tonic-gate 			 * Additionally we don't want the result of the message
1239*0Sstevel@tonic-gate 			 * cached in the MCT, because we want uptodate results,
1240*0Sstevel@tonic-gate 			 * and the message doesn't need being logged either.
1241*0Sstevel@tonic-gate 			 * Hence NO_LOG and NO_MCT
1242*0Sstevel@tonic-gate 			 */
1243*0Sstevel@tonic-gate 			err = mdmn_send_message(
1244*0Sstevel@tonic-gate 				sp->setno,
1245*0Sstevel@tonic-gate 				MD_MN_MSG_CLU_CHECK,
1246*0Sstevel@tonic-gate 				MD_MSGF_NO_MCT | MD_MSGF_STOP_ON_ERROR |
1247*0Sstevel@tonic-gate 				MD_MSGF_NO_LOG | MD_MSGF_OVERRIDE_SUSPEND,
1248*0Sstevel@tonic-gate 				(char *)&d, sizeof (md_isopen_t),
1249*0Sstevel@tonic-gate 				&resp, ep);
1250*0Sstevel@tonic-gate 			if (err == 0) {
1251*0Sstevel@tonic-gate 				d.isopen = resp->mmr_exitval;
1252*0Sstevel@tonic-gate 			} else {
1253*0Sstevel@tonic-gate 				/*
1254*0Sstevel@tonic-gate 				 * in case some error occurred,
1255*0Sstevel@tonic-gate 				 * we better say the device is open
1256*0Sstevel@tonic-gate 				 */
1257*0Sstevel@tonic-gate 				d.isopen = 1;
1258*0Sstevel@tonic-gate 			}
1259*0Sstevel@tonic-gate 			if (resp != (md_mn_result_t *)NULL) {
1260*0Sstevel@tonic-gate 				free_result(resp);
1261*0Sstevel@tonic-gate 			}
1262*0Sstevel@tonic-gate 
1263*0Sstevel@tonic-gate 		}
1264*0Sstevel@tonic-gate 	}
1265*0Sstevel@tonic-gate 
1266*0Sstevel@tonic-gate 	return (d.isopen);
1267*0Sstevel@tonic-gate }
1268