xref: /onnv-gate/usr/src/uts/common/io/lvm/md/md_ioctl.c (revision 5684:b3786baf60e8)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Driver for Virtual Disk.
30  */
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/buf.h>
34 #include <sys/conf.h>
35 #include <sys/user.h>
36 #include <sys/uio.h>
37 #include <sys/proc.h>
38 #include <sys/t_lock.h>
39 #include <sys/dkio.h>
40 #include <sys/kmem.h>
41 #include <sys/utsname.h>
42 #include <sys/debug.h>
43 #include <sys/sysmacros.h>
44 #include <sys/types.h>
45 #include <sys/mkdev.h>
46 #include <sys/vtoc.h>
47 #include <sys/efi_partition.h>
48 #include <sys/open.h>
49 #include <sys/file.h>
50 #include <sys/ddi.h>
51 #include <sys/sunddi.h>
52 #include <sys/lvm/mdmn_commd.h>
53 
54 #include <sys/lvm/mdvar.h>
55 #include <sys/lvm/md_rename.h>
56 #include <sys/lvm/md_names.h>
57 #include <sys/lvm/md_hotspares.h>
58 
59 extern md_ops_t		**md_ops;
60 extern unit_t		md_nunits;
61 extern set_t		md_nsets;
62 extern int		md_nmedh;
63 extern md_set_t		md_set[];
64 extern md_set_io_t	md_set_io[];
65 extern int		md_status;
66 extern int		md_ioctl_cnt;
67 extern int		md_in_upgrade;
68 extern major_t		md_major;
69 
70 /* md.c */
71 extern kmutex_t		md_mx;
72 extern kcondvar_t	md_cv;
73 
74 /* md_hotspares.c */
75 extern	hot_spare_pool_t *find_hot_spare_pool(set_t setno, int hsp_id);
76 
77 /* md_med.c */
78 extern int		med_addr_tab_nents;
79 extern int		med_get_t_size_ioctl(mddb_med_t_parm_t *tpp, int mode);
80 extern int		med_get_t_ioctl(mddb_med_t_parm_t *tpp, int mode);
81 extern int		med_set_t_ioctl(mddb_med_t_parm_t *tpp, int mode);
82 extern unit_t		md_get_nextunit(set_t setno);
83 
84 static int		md_mn_commd_present;
85 
86 /* md_mddb.c */
87 extern mddb_set_t	*mddb_setenter(set_t setno, int flag, int *errorcodep);
88 extern void		mddb_setexit(mddb_set_t *s);
89 extern md_krwlock_t	nm_lock;
90 
91 /*
92  * md_mn_is_commd_present:
93  * ----------------------
94  * Determine if commd is running on this node.
95  *
96  * Returns:
97  *	1	if commd has been started
98  *	0	if commd has not been started or has exited
99  */
100 int
101 md_mn_is_commd_present(void)
102 {
103 	return (md_mn_commd_present ? 1 : 0);
104 }
105 
106 /*
107  * md_mn_clear_commd_present:
108  * -------------------------
109  * Clear the commd_present flag. Called only from a CPR request to suspend /
110  * terminate a resync thread. We clear the md_mn_commd_present flag so that
111  * any RPC request that was in transit can complete with a failure and _not_
112  * result in an unexpected system panic.
113  */
114 void
115 md_mn_clear_commd_present()
116 {
117 	md_mn_commd_present = 0;
118 }
119 
120 /*
121  * It is possible to pass in a minor number via the ioctl interface
122  * and this minor number is used to reference elements in arrays.
123  * Therefore we need to make sure that the value passed in is
124  * correct within the array sizes, and array dereference. Not
125  * doing so allows for incorrect values which may result in panics.
126  */
127 static int
128 verify_minor(minor_t mnum)
129 {
130 	set_t	setno = MD_MIN2SET(mnum);
131 
132 	/*
133 	 * Check the bounds.
134 	 */
135 	if (setno >= md_nsets || (MD_MIN2UNIT(mnum) >= md_nunits)) {
136 		return (EINVAL);
137 	}
138 
139 	/* has the set been initialised ? */
140 	if ((md_get_setstatus(setno) & MD_SET_SNARFED) == 0)
141 		return (ENODEV);
142 
143 	return (0);
144 }
145 
146 static int
147 get_lb_inittime_ioctl(
148 	mddb_config_t	*cp
149 )
150 {
151 	set_t		setno = cp->c_setno;
152 	int		err;
153 	mddb_set_t	*s;
154 
155 	if (setno >= md_nsets)
156 		return (-1);
157 
158 	if ((s = mddb_setenter(setno, MDDB_MUSTEXIST, &err)) == NULL)
159 		return (-1);
160 
161 	if (s->s_lbp == NULL) {
162 		mddb_setexit(s);
163 		return (-1);
164 	}
165 
166 	cp->c_timestamp = s->s_lbp->lb_inittime;
167 
168 	mddb_setexit(s);
169 	return (0);
170 }
171 
172 static int
173 setnm_ioctl(mdnm_params_t *nm, int mode)
174 {
175 	char 	*name, *minorname = NULL;
176 	side_t	side;
177 	int	err = 0;
178 	void	*devid = NULL;
179 	int	devid_sz;
180 
181 	/*
182 	 * Don't allow addition of new names to namespace during upgrade.
183 	 */
184 	if (MD_UPGRADE)  {
185 		return (EAGAIN);
186 	}
187 
188 	mdclrerror(&nm->mde);
189 
190 	if ((mode & FWRITE) == 0)
191 		return (EACCES);
192 
193 	if (md_snarf_db_set(MD_LOCAL_SET, &nm->mde) != 0)
194 		return (0);
195 
196 	if ((md_get_setstatus(nm->setno) & MD_SET_SNARFED) == 0)
197 		return (ENODEV);
198 
199 	if (md_get_setstatus(nm->setno) & MD_SET_STALE)
200 		return (mdmddberror(&nm->mde, MDE_DB_STALE, NODEV32,
201 		    nm->setno));
202 
203 	name = kmem_alloc(MAXPATHLEN, KM_SLEEP);
204 
205 	err = ddi_copyin((caddr_t)(uintptr_t)nm->devname, name,
206 	    (size_t)nm->devname_len, mode);
207 	if (err) {
208 		err = EFAULT;
209 		goto out;
210 	}
211 
212 	if (nm->imp_flag) {
213 		if ((nm->devid == NULL) || (nm->minorname == NULL)) {
214 			err = EINVAL;
215 			goto out;
216 		}
217 		if (nm->devid) {
218 			devid_sz = nm->devid_size;
219 			devid = kmem_zalloc(devid_sz, KM_SLEEP);
220 			err = ddi_copyin((caddr_t)(uintptr_t)nm->devid,
221 			    devid, devid_sz, mode);
222 			if (err) {
223 				err = EFAULT;
224 				goto out;
225 			}
226 		}
227 		if (nm->minorname) {
228 			if (nm->minorname_len > MAXPATHLEN) {
229 				err = EINVAL;
230 				goto out;
231 			}
232 			minorname = kmem_zalloc(nm->minorname_len, KM_SLEEP);
233 			err = ddi_copyin((caddr_t)(uintptr_t)nm->minorname,
234 			    minorname, (size_t)nm->minorname_len, mode);
235 			if (err) {
236 				err = EFAULT;
237 				goto out;
238 			}
239 		}
240 	}
241 
242 	if (nm->side == -1)
243 		side = mddb_getsidenum(nm->setno);
244 	else
245 		side = nm->side;
246 
247 	if (strcmp(nm->drvnm, "") == 0) {
248 		char *drvnm;
249 		drvnm = ddi_major_to_name(nm->major);
250 		(void) strncpy(nm->drvnm, drvnm, sizeof (nm->drvnm));
251 	}
252 
253 	nm->key = md_setdevname(nm->setno, side, nm->key, nm->drvnm,
254 	    nm->mnum, name, nm->imp_flag, (ddi_devid_t)devid, minorname,
255 	    0, &nm->mde);
256 	/*
257 	 * If we got an error from md_setdevname & md_setdevname did not
258 	 * set the error code, we'll default to MDE_DB_NOSPACE.
259 	 */
260 	if ((((int)nm->key) < 0) && mdisok(&nm->mde)) {
261 		err = mdmddberror(&nm->mde, MDE_DB_NOSPACE, NODEV32, nm->setno);
262 		goto out;
263 	}
264 
265 out:
266 	kmem_free(name, MAXPATHLEN);
267 	if (devid) {
268 		kmem_free(devid, devid_sz);
269 	}
270 	if (minorname)
271 		kmem_free(minorname, nm->minorname_len);
272 	return (err);
273 }
274 
275 static int
276 getnm_ioctl(
277 	mdnm_params_t	*nm,
278 	int		mode
279 )
280 {
281 	char		*name;
282 	side_t		side;
283 	md_dev64_t	dev = NODEV64;
284 	mdc_unit_t	*un;
285 	uint_t		id;
286 	char		*setname;
287 	int		err = 0;
288 
289 	mdclrerror(&nm->mde);
290 
291 	if (md_snarf_db_set(MD_LOCAL_SET, &nm->mde) != 0)
292 		return (0);
293 
294 	if ((md_get_setstatus(nm->setno) & MD_SET_SNARFED) == 0)
295 		return (ENODEV);
296 
297 
298 	name = kmem_alloc(MAXPATHLEN, KM_SLEEP);
299 
300 	if (nm->side == -1)
301 		side = mddb_getsidenum(nm->setno);
302 	else
303 		side = nm->side;
304 
305 	if (nm->drvnm[0] == '\0') {
306 		char *drvnm;
307 
308 		if (MD_UPGRADE)
309 			drvnm = md_targ_major_to_name(nm->major);
310 		else
311 			drvnm = ddi_major_to_name(nm->major);
312 		if (drvnm != NULL)
313 			(void) strncpy(nm->drvnm, drvnm, sizeof (nm->drvnm));
314 	}
315 
316 	if (nm->drvnm[0] != '\0') {
317 		if (MD_UPGRADE)
318 			dev = md_makedevice(md_targ_name_to_major(nm->drvnm),
319 			    nm->mnum);
320 		else
321 			dev = md_makedevice(ddi_name_to_major(nm->drvnm),
322 			    nm->mnum);
323 	}
324 
325 	/*
326 	 * With the introduction of friendly names, all friendly named
327 	 * metadevices will have an entry in the name space. However,
328 	 * systems upgraded from pre-friendly name to a friendly name
329 	 * release won't have name space entries for pre-friendly name
330 	 * top level metadevices.
331 	 *
332 	 * So we search the name space for the our entry with either the
333 	 * given dev_t or key. If we can't find the entry, we'll try the
334 	 * un array to get information for our target metadevice. Note
335 	 * we only use the un array when searching by dev_t since a
336 	 * key implies an existing device which should have been
337 	 * found in the name space with the call md_getdevname.
338 	 */
339 	if (md_getdevname(nm->setno, side, nm->key, dev, name,
340 	    MAXPATHLEN) == 0) {
341 		err = md_getnment(nm->setno, side, nm->key, dev, nm->drvnm,
342 		    sizeof (nm->drvnm), &nm->major, &nm->mnum, &nm->retkey);
343 		if (err) {
344 			if (err < 0)
345 				err = EINVAL;
346 			goto out;
347 		}
348 	} else {
349 		if ((nm->key != MD_KEYWILD) ||
350 		    (md_set[MD_MIN2SET(nm->mnum)].s_un == NULL) ||
351 		    (MD_UNIT(nm->mnum) == NULL)) {
352 			err = ENOENT;
353 			goto out;
354 		}
355 
356 		/*
357 		 * We're here because the mnum is of a pre-friendly
358 		 * name device. Make sure the major value is for
359 		 * metadevices.
360 		 */
361 		if (nm->major != md_major) {
362 			err = ENOENT;
363 			goto out;
364 		}
365 
366 		/*
367 		 * get the unit number and setname to construct the
368 		 * fully qualified name for the metadevice.
369 		 */
370 		un = MD_UNIT(nm->mnum);
371 		id =  MD_MIN2UNIT(un->un_self_id);
372 		if (nm->setno != MD_LOCAL_SET) {
373 			setname = mddb_getsetname(nm->setno);
374 			(void) snprintf(name, MAXPATHLEN,
375 			    "/dev/md/%s/dsk/d%u", setname, id);
376 		} else {
377 			(void) snprintf(name, MAXPATHLEN,
378 			    "/dev/md/dsk/d%u", id);
379 		}
380 	}
381 
382 	err = ddi_copyout(name, (caddr_t)(uintptr_t)nm->devname,
383 	    strlen(name) + 1, mode);
384 	if (err) {
385 		err = EFAULT;
386 		goto out;
387 	}
388 
389 out:
390 	kmem_free(name, MAXPATHLEN);
391 	return (err);
392 }
393 
394 static int
395 gethspnm_ioctl(
396 	mdhspnm_params_t	*nm,
397 	int			mode
398 )
399 {
400 	char			*name;
401 	char			*tmpname;
402 	char			*setname = NULL;
403 	side_t			side;
404 	hot_spare_pool_t	*hsp = NULL;
405 	mdkey_t			key = MD_KEYWILD;
406 	int			err = 0;
407 
408 	mdclrerror(&nm->mde);
409 
410 	if (md_snarf_db_set(MD_LOCAL_SET, &nm->mde) != 0)
411 		return (0);
412 
413 	if ((md_get_setstatus(nm->setno) & MD_SET_SNARFED) == 0)
414 		return (ENODEV);
415 
416 	name = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
417 
418 	if (nm->side == -1)
419 		side = mddb_getsidenum(nm->setno);
420 	else
421 		side = nm->side;
422 
423 	/*
424 	 * Get the key from input hspid, use different macros
425 	 * since the hspid could be either a FN or pre-FN hspid.
426 	 */
427 	if (nm->hspid != MD_HSPID_WILD) {
428 		if (HSP_ID_IS_FN(nm->hspid))
429 			key = HSP_ID_TO_KEY(nm->hspid);
430 		else
431 			key = HSP_ID(nm->hspid);
432 	}
433 
434 	/*
435 	 * Get the input name if we're searching by hsp name. Check
436 	 * that the input name length is less than MAXPATHLEN.
437 	 */
438 	if ((nm->hspid == MD_HSPID_WILD) &&
439 	    (nm->hspname_len <= MAXPATHLEN)) {
440 		err = ddi_copyin((caddr_t)(uintptr_t)nm->hspname,
441 		    name, (sizeof (char)) * nm->hspname_len, mode);
442 
443 		/* Stop if ddi_copyin failed. */
444 		if (err) {
445 			err = EFAULT;
446 			goto out;
447 		}
448 	}
449 
450 	/* Must have either a valid hspid or a name to continue */
451 	if ((nm->hspid == MD_HSPID_WILD) && (name[0] == '\0')) {
452 		err = EINVAL;
453 		goto out;
454 	}
455 
456 	/*
457 	 * Try to find the hsp namespace entry corresponds to either
458 	 * the given hspid or name. If we can't find it, the hsp maybe
459 	 * a pre-friendly name hsp so we'll try to find it in the
460 	 * s_hsp array.
461 	 */
462 	if ((nm->hspid == MD_HSPID_WILD) || (HSP_ID_IS_FN(nm->hspid))) {
463 
464 		if (md_gethspinfo(nm->setno, side, key, nm->drvnm,
465 		    &nm->ret_hspid, name) != 0) {
466 			/*
467 			 * If we were given a key for a FN hsp and
468 			 * couldn't find its entry, simply errored
469 			 * out.
470 			 */
471 			if (HSP_ID_IS_FN(nm->hspid)) {
472 				err = ENOENT;
473 				goto out;
474 			}
475 
476 			/*
477 			 * Since md_gethspinfo failed and the hspid is
478 			 * not a FN hspid,  we must have a name for a
479 			 * pre-FN hotspare pool
480 			 */
481 			if (name[0] == '\0') {
482 				err = EINVAL;
483 				goto out;
484 			}
485 
486 			tmpname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
487 			if (nm->setno != MD_LOCAL_SET)
488 				setname = mddb_getsetname(nm->setno);
489 
490 			hsp = (hot_spare_pool_t *)md_set[nm->setno].s_hsp;
491 			while (hsp != NULL) {
492 				/* Only use the pre-friendly name hsp */
493 				if (!(hsp->hsp_revision & MD_FN_META_DEV)) {
494 
495 					if (setname != NULL) {
496 						(void) snprintf(tmpname,
497 						    MAXPATHLEN,
498 						    "%s/hsp%03u", setname,
499 						    HSP_ID(hsp->hsp_self_id));
500 					} else {
501 						(void) snprintf(tmpname,
502 						    MAXPATHLEN, "hsp%03u",
503 						    HSP_ID(hsp->hsp_self_id));
504 					}
505 
506 					if (strcmp(name, tmpname) == 0)
507 						break;
508 				}
509 
510 				hsp = hsp->hsp_next;
511 			}
512 			kmem_free(tmpname, MAXPATHLEN);
513 
514 			if (hsp == NULL) {
515 				err = ENOENT;
516 				goto out;
517 			}
518 
519 			/* Return hsp_self_id */
520 			nm->ret_hspid = hsp->hsp_self_id;
521 		}
522 
523 	} else {
524 		/*
525 		 * We have a hspid for a pre-FN hotspare pool. Let's
526 		 * try to find the matching hsp using the given
527 		 * hspid.
528 		 */
529 		if (nm->hspid == MD_HSPID_WILD) {
530 			err = ENOENT;
531 			goto out;
532 		}
533 
534 		hsp = (hot_spare_pool_t *)md_set[nm->setno].s_hsp;
535 		while (hsp != NULL) {
536 			if (hsp->hsp_self_id == nm->hspid)
537 				break;
538 			hsp = hsp->hsp_next;
539 		}
540 
541 		if (hsp == NULL) {
542 			err = ENOENT;
543 			goto out;
544 		}
545 
546 		/* Prepare a name to return */
547 		if (nm->setno != MD_LOCAL_SET)
548 			setname = mddb_getsetname(nm->setno);
549 
550 		if (setname != NULL) {
551 			(void) snprintf(name, MAXPATHLEN, "%s/hsp%03u",
552 			    setname, HSP_ID(hsp->hsp_self_id));
553 		} else {
554 			(void) snprintf(name, MAXPATHLEN, "hsp%03u",
555 			    HSP_ID(hsp->hsp_self_id));
556 		}
557 
558 		nm->ret_hspid = hsp->hsp_self_id;
559 	}
560 
561 	if (nm->hspid != MD_HSPID_WILD) {
562 		if ((strlen(name) + 1) > nm->hspname_len) {
563 			err = EINVAL;
564 			goto out;
565 		}
566 		err = ddi_copyout(name, (caddr_t)
567 		    (uintptr_t)nm->hspname, strlen(name)+1, mode);
568 	}
569 
570 	if (err) {
571 		if (err < 0)
572 			err = EINVAL;
573 	}
574 
575 out:
576 	kmem_free(name, MAXPATHLEN);
577 	return (err);
578 }
579 
580 
581 /*ARGSUSED*/
582 static int
583 update_loc_namespace_ioctl(
584 	mdnm_params_t	*nm,
585 	char		*dname,
586 	char		*pname,
587 	int		mode
588 )
589 {
590 
591 	side_t		side;
592 
593 	mdclrerror(&nm->mde);
594 
595 	if (md_snarf_db_set(MD_LOCAL_SET, &nm->mde) != 0)
596 		return (0);
597 
598 	if (MD_MNSET_SETNO(nm->setno))
599 		return (0);
600 
601 	if ((md_get_setstatus(nm->setno) & MD_SET_STALE))
602 		return (0);
603 
604 	if ((md_get_setstatus(nm->setno) & MD_SET_SNARFED) == 0)
605 		return (ENODEV);
606 
607 	if (nm->side == -1)
608 		side = mddb_getsidenum(nm->setno);
609 	else
610 		side = nm->side;
611 
612 	return (md_update_locator_namespace(nm->setno, side, dname,
613 	    pname, nm->devt));
614 }
615 
616 /*ARGSUSED*/
617 static int
618 update_namespace_did_ioctl(
619 	mdnm_params_t	*nm,
620 	int		mode
621 )
622 {
623 	side_t		side;
624 
625 	mdclrerror(&nm->mde);
626 
627 	if (md_snarf_db_set(MD_LOCAL_SET, &nm->mde) != 0)
628 		return (0);
629 
630 	if (MD_MNSET_SETNO(nm->setno))
631 		return (0);
632 
633 	if ((md_get_setstatus(nm->setno) & MD_SET_STALE))
634 		return (0);
635 
636 	if ((md_get_setstatus(nm->setno) & MD_SET_SNARFED) == 0)
637 		return (ENODEV);
638 
639 	if (nm->side == -1)
640 		side = mddb_getsidenum(nm->setno);
641 	else
642 		side = nm->side;
643 
644 	return (md_update_namespace_did(nm->setno, side, nm->key, &nm->mde));
645 }
646 
647 /*ARGSUSED*/
648 static int
649 update_namespace_ioctl(
650 	mdnm_params_t	*nm,
651 	char		*dname,
652 	char		*pname,
653 	int		mode
654 )
655 {
656 	side_t		side;
657 
658 	mdclrerror(&nm->mde);
659 
660 	if (md_snarf_db_set(MD_LOCAL_SET, &nm->mde) != 0)
661 		return (0);
662 
663 	if (MD_MNSET_SETNO(nm->setno))
664 		return (0);
665 
666 	if ((md_get_setstatus(nm->setno) & MD_SET_STALE))
667 		return (0);
668 
669 	if ((md_get_setstatus(nm->setno) & MD_SET_SNARFED) == 0)
670 		return (ENODEV);
671 
672 	if (nm->side == -1)
673 		side = mddb_getsidenum(nm->setno);
674 	else
675 		side = nm->side;
676 
677 	return (md_update_namespace(nm->setno, side, nm->key,
678 	    dname, pname, nm->mnum));
679 
680 }
681 
682 /*ARGSUSED*/
683 static int
684 getnextkey_ioctl(
685 	mdnm_params_t	*nm,
686 	int		mode
687 )
688 {
689 	side_t		side;
690 
691 	mdclrerror(&nm->mde);
692 
693 	if (md_snarf_db_set(MD_LOCAL_SET, &nm->mde) != 0)
694 		return (0);
695 
696 	if (nm->setno >= md_nsets)
697 		return (EINVAL);
698 
699 	if ((md_get_setstatus(nm->setno) & MD_SET_SNARFED) == 0)
700 		return (ENODEV);
701 
702 	if (nm->side == -1)
703 		side = mddb_getsidenum(nm->setno);
704 	else
705 		side = nm->side;
706 
707 	nm->key = md_getnextkey(nm->setno, side, nm->key, &nm->ref_count);
708 	return (0);
709 }
710 
711 /*ARGSUSED*/
712 static int
713 remnm_ioctl(mdnm_params_t *nm, int mode)
714 {
715 	side_t	side;
716 
717 	mdclrerror(&nm->mde);
718 
719 	if (md_snarf_db_set(MD_LOCAL_SET, &nm->mde) != 0)
720 		return (0);
721 
722 	if ((md_get_setstatus(nm->setno) & MD_SET_SNARFED) == 0)
723 		return (ENODEV);
724 
725 	if (nm->side == -1)
726 		side = mddb_getsidenum(nm->setno);
727 	else
728 		side = nm->side;
729 
730 	return (md_remdevname(nm->setno, side, nm->key));
731 }
732 
733 
734 /*ARGSUSED*/
735 static int
736 getdrvnm_ioctl(md_dev64_t dev, md_i_driverinfo_t *di, int mode)
737 {
738 	mdi_unit_t 	*ui;
739 	minor_t		mnum = di->mnum;
740 	set_t		setno = MD_MIN2SET(mnum);
741 
742 	mdclrerror(&di->mde);
743 
744 	if (md_snarf_db_set(MD_LOCAL_SET, &di->mde) != 0)
745 		return (0);
746 
747 	ui = MDI_UNIT(mnum);
748 	if (ui == NULL) {
749 		return (mdmderror(&di->mde, MDE_UNIT_NOT_SETUP, mnum));
750 	}
751 
752 	MD_SETDRIVERNAME(di, md_ops[ui->ui_opsindex]->md_driver.md_drivername,
753 	    setno);
754 
755 	return (0);
756 }
757 
758 /*ARGSUSED*/
759 static int
760 getnext_ioctl(md_i_getnext_t *gn, int mode)
761 {
762 	int		modindex;
763 	md_link_t	*next;
764 	uint_t		id;
765 	int		found = 0;
766 	set_t		setno = gn->md_driver.md_setno;
767 
768 	mdclrerror(&gn->mde);
769 
770 	if (md_snarf_db_set(MD_LOCAL_SET, &gn->mde) != 0)
771 		return (0);
772 
773 	if ((md_get_setstatus(setno) & MD_SET_SNARFED) == 0) {
774 		if (md_get_setstatus(setno) & MD_SET_TAGDATA)
775 			return (mdmddberror(&gn->mde, MDE_DB_TAGDATA,
776 			    NODEV32, setno));
777 		else
778 			return (mderror(&gn->mde, MDE_UNIT_NOT_FOUND));
779 	}
780 
781 	modindex = md_getmodindex((md_driver_t *)gn, 1, 0);
782 	if (modindex == -1) {
783 		return (mderror(&gn->mde, MDE_UNIT_NOT_FOUND));
784 	}
785 
786 	rw_enter(&md_ops[modindex]->md_link_rw.lock, RW_READER);
787 	id = gn->id;
788 	next = md_ops[modindex]->md_head;
789 	while (next) {
790 		if ((next->ln_setno == setno) && (next->ln_id == id)) {
791 			gn->id = id;
792 			found = 1;
793 			break;
794 		}
795 
796 		if ((next->ln_setno == setno) &&(next->ln_id > id) &&
797 		    (! found || (next->ln_id < gn->id))) {
798 			gn->id = next->ln_id;
799 			found = 1;
800 			/* continue looking for smallest */
801 		}
802 		next = next->ln_next;
803 	}
804 	rw_exit(&md_ops[modindex]->md_link_rw.lock);
805 
806 	if (! found)
807 		return (mderror(&gn->mde, MDE_UNIT_NOT_FOUND));
808 
809 	return (0);
810 }
811 
812 /*ARGSUSED*/
813 static int
814 getnum_ioctl(void *d, int mode)
815 {
816 	int		modindex;
817 	md_link_t	*next;
818 	int		sz;
819 	minor_t		*minors;
820 	minor_t		*m_ptr;
821 	set_t		setno;
822 	int		err = 0;
823 	md_error_t	*mdep;
824 	int		minor_array_length;
825 	md_driver_t	*driver;
826 	int		count = 0;
827 	struct md_i_getnum	*gn = d;
828 
829 
830 	/* number of specified devices in specified set - if 0 return count */
831 	minor_array_length = gn->size;
832 	if (minor_array_length > md_nunits)
833 		return (EINVAL);
834 
835 	mdep = &gn->mde;
836 	driver = &gn->md_driver;
837 	setno = driver->md_setno;
838 
839 	mdclrerror(mdep);
840 
841 	if (md_snarf_db_set(MD_LOCAL_SET, mdep) != 0)
842 		return (0);
843 
844 	if ((md_get_setstatus(setno) & MD_SET_SNARFED) == 0) {
845 		if (md_get_setstatus(setno) & MD_SET_TAGDATA) {
846 			return (mdmddberror(mdep, MDE_DB_TAGDATA,
847 			    NODEV32, setno));
848 		} else {
849 			return (mderror(mdep, MDE_UNIT_NOT_FOUND));
850 		}
851 	}
852 
853 	modindex = md_getmodindex(driver, 0, 0);
854 	if (modindex == -1) {
855 
856 		return (mderror(mdep, MDE_UNIT_NOT_FOUND));
857 	}
858 
859 	rw_enter(&md_ops[modindex]->md_link_rw.lock, RW_READER);
860 	/* if array length is not 0 then allocate the output buffers */
861 	if (minor_array_length != 0) {
862 		sz = minor_array_length * ((int)sizeof (minor_t));
863 		minors = kmem_zalloc(sz, KM_SLEEP);
864 		m_ptr = minors;
865 	}
866 
867 	next = md_ops[modindex]->md_head;
868 	count = 0;
869 	while (next) {
870 		if (next->ln_setno == setno) {
871 			if ((minor_array_length > 0) &&
872 			    (count < minor_array_length)) {
873 				*m_ptr = next->ln_id;
874 				m_ptr++;
875 			}
876 			count++;
877 		}
878 		next = next->ln_next;
879 	}
880 	rw_exit(&md_ops[modindex]->md_link_rw.lock);
881 
882 	gn->size = count;
883 	/* now copy the array back */
884 	if (minor_array_length > 0) {
885 		err = ddi_copyout(minors,
886 		    (caddr_t)(uintptr_t)gn->minors, sz, mode);
887 		kmem_free(minors, sz);
888 	}
889 
890 	return (err);
891 }
892 
893 /*ARGSUSED*/
894 static int
895 didstat_ioctl(
896 	md_i_didstat_t	*ds
897 )
898 {
899 	int		cnt = 0;
900 	int		err = 0;
901 
902 	mdclrerror(&ds->mde);
903 
904 	if (md_snarf_db_set(MD_LOCAL_SET, &ds->mde) != 0)
905 		return (0);
906 
907 	if (ds->setno >= md_nsets) {
908 		return (EINVAL);
909 	}
910 
911 	if ((md_get_setstatus(ds->setno) & MD_SET_SNARFED) == 0)
912 		return (ENODEV);
913 
914 	if (ds->mode == MD_FIND_INVDID) {
915 		cnt = md_validate_devid(ds->setno, ds->side, &ds->maxsz);
916 		if (cnt == -1)
917 			err = -1;
918 		ds->cnt = cnt;
919 	} else if (ds->mode == MD_GET_INVDID) {
920 		if (md_get_invdid(ds->setno, ds->side, ds->cnt, ds->maxsz,
921 		    (caddr_t)(uintptr_t)ds->ctdp) == -1) {
922 			err = -1;
923 		}
924 	} else {
925 		/* invalid mode */
926 		err = EINVAL;
927 	}
928 
929 	return (err);
930 }
931 
932 /*ARGSUSED*/
933 static int
934 getdid_ioctl(
935 	mdnm_params_t	*nm,
936 	int		mode
937 )
938 {
939 	int		err = 0;
940 	ddi_devid_t	did = NULL;
941 
942 	mdclrerror(&nm->mde);
943 
944 	if (md_snarf_db_set(MD_LOCAL_SET, &nm->mde) != 0)
945 		return (0);
946 
947 	if (nm->setno >= md_nsets) {
948 		return (EINVAL);
949 	}
950 
951 	if ((md_get_setstatus(nm->setno) & MD_SET_SNARFED) == 0)
952 		return (ENODEV);
953 
954 	/*
955 	 * Tell user that replica is not in devid mode
956 	 */
957 	if (!(((mddb_set_t *)md_set[nm->setno].s_db)->s_lbp->lb_flags
958 	    & MDDB_DEVID_STYLE) && md_keep_repl_state) {
959 		return (mdsyserror(&nm->mde, MDDB_F_NODEVID));
960 	}
961 
962 	/*
963 	 * If user is prepared to receive the devid allocate a kernel buffer.
964 	 */
965 	if (nm->devid_size != 0) {
966 		/* check for bogus value of devid_size */
967 		if (nm->devid_size > MAXPATHLEN) {
968 			return (EINVAL);
969 		}
970 		did = kmem_alloc(nm->devid_size, KM_SLEEP);
971 	}
972 
973 	err = md_getdevid(nm->setno, nm->side, nm->key, did, &nm->devid_size);
974 
975 	if (err) {
976 		if (err < 0)
977 			err = EINVAL;
978 		goto out;
979 	}
980 
981 	/*
982 	 * If devid size was already known to user then give them the devid.
983 	 */
984 	if (did != NULL)
985 		err = ddi_copyout(did,
986 		    (caddr_t)(uintptr_t)nm->devid, nm->devid_size, mode);
987 
988 out:
989 	if (did != NULL)
990 		kmem_free(did, nm->devid_size);
991 	return (err);
992 }
993 
994 int
995 mddb_setmaster_ioctl(mddb_setmaster_config_t *info)
996 {
997 	/* Verify that setno is in valid range */
998 	if (info->c_setno >= md_nsets)
999 		return (EINVAL);
1000 
1001 	/*
1002 	 * When adding the first disk to a MN diskset, the master
1003 	 * needs to be set (in order to write out the mddb)
1004 	 * before the set is snarfed or even before the set
1005 	 * is marked as a MNset in the md_set structure.
1006 	 * So, don't check for MNset or SNARFED and don't call
1007 	 * mddb_setenter. In order to discourage bad ioctl calls,
1008 	 * verify that magic field in structure is set correctly.
1009 	 */
1010 	if (info->c_magic != MDDB_SETMASTER_MAGIC)
1011 		return (EINVAL);
1012 
1013 	if (info->c_current_host_master)
1014 		md_set[info->c_setno].s_am_i_master = 1;
1015 	else
1016 		md_set[info->c_setno].s_am_i_master = 0;
1017 
1018 	return (0);
1019 }
1020 
1021 /*
1022  * Set the devid for the namespace record identified by the tuple
1023  * [setno, sideno, key]. The key is the namespace key. The md_getdevnum()
1024  * function is used to actually regenerate the devid.
1025  */
1026 /*ARGSUSED*/
1027 static int
1028 setdid_ioctl(
1029 	mdnm_params_t	*nm,
1030 	int		mode
1031 )
1032 {
1033 	dev_t		devt;
1034 
1035 	/*
1036 	 * If upgrading do not allow modification of the namespace.
1037 	 */
1038 	if (MD_UPGRADE)
1039 		return (EAGAIN);
1040 
1041 	mdclrerror(&nm->mde);
1042 
1043 	if (md_snarf_db_set(MD_LOCAL_SET, &nm->mde) != 0)
1044 		return (0);
1045 
1046 	if (nm->setno >= md_nsets)
1047 		return (EINVAL);
1048 
1049 	if (MD_MNSET_SETNO(nm->setno))
1050 		return (0);
1051 
1052 	if ((md_get_setstatus(nm->setno) & MD_SET_SNARFED) == 0)
1053 		return (ENODEV);
1054 
1055 	devt = md_dev64_to_dev(
1056 	    md_getdevnum(nm->setno, nm->side, nm->key, MD_TRUST_DEVT));
1057 
1058 	if (devt == NODEV)
1059 		return (ENODEV);
1060 
1061 	return (0);
1062 }
1063 
1064 /*ARGSUSED*/
1065 static int
1066 getdidmin_ioctl(
1067 	mdnm_params_t   *nm,
1068 	int		mode
1069 )
1070 {
1071 	int	err = 0;
1072 	char	*minorname = NULL;
1073 
1074 	mdclrerror(&nm->mde);
1075 
1076 	if (md_snarf_db_set(MD_LOCAL_SET, &nm->mde) != 0)
1077 		return (0);
1078 
1079 	if (nm->setno >= md_nsets)
1080 		return (EINVAL);
1081 
1082 	if (MD_MNSET_SETNO(nm->setno))
1083 		return (0);
1084 
1085 	if ((md_get_setstatus(nm->setno) & MD_SET_SNARFED) == 0)
1086 		return (ENODEV);
1087 
1088 	minorname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1089 
1090 	if (nm->side == -1) {
1091 		err = EINVAL;
1092 		goto out;
1093 	}
1094 
1095 	err = md_getdevidminor(nm->setno, nm->side, nm->key, minorname,
1096 	    MAXPATHLEN);
1097 
1098 	if (err) {
1099 		if (err < 0)
1100 			err = EINVAL;
1101 		goto out;
1102 	}
1103 
1104 	err = ddi_copyout(minorname, (caddr_t)(uintptr_t)nm->minorname,
1105 	    strlen(minorname) + 1, mode);
1106 
1107 out:
1108 
1109 	kmem_free(minorname, MAXPATHLEN);
1110 	return (err);
1111 }
1112 
1113 static int
1114 mddb_userreq_ioctl(mddb_userreq_t *ur, int mode)
1115 {
1116 	void			*data;
1117 	int			status;
1118 	mddb_recid_t		*recids;
1119 	int			flags;
1120 
1121 	if (ur->ur_setno >= md_nsets)
1122 		return (EINVAL);
1123 
1124 	mdclrerror(&ur->ur_mde);
1125 
1126 	if (md_snarf_db_set(MD_LOCAL_SET, &ur->ur_mde) != 0)
1127 		return (0);
1128 
1129 	if ((md_get_setstatus(ur->ur_setno) & MD_SET_SNARFED) == 0)
1130 		return (ENODEV);
1131 
1132 	switch (ur->ur_cmd) {
1133 	case MD_DB_GETNEXTREC:
1134 		if (ur->ur_recid == 0)
1135 			ur->ur_recid = mddb_makerecid(ur->ur_setno, 0);
1136 		/*
1137 		 * Is ur_recid a valid one ?
1138 		 */
1139 		if (DBSET(ur->ur_recid) < 0 || DBSET(ur->ur_recid) >= md_nsets)
1140 			return (EINVAL);
1141 
1142 		ur->ur_recid = mddb_getnextrec(ur->ur_recid, ur->ur_type,
1143 		    ur->ur_type2);
1144 		if (ur->ur_recid > 0) {
1145 			ur->ur_type = mddb_getrectype1(ur->ur_recid);
1146 			ur->ur_type2 = mddb_getrectype2(ur->ur_recid);
1147 			ur->ur_recstat = mddb_getrecstatus(ur->ur_recid);
1148 		}
1149 		break;
1150 
1151 	case MD_DB_COMMIT_ONE:
1152 		/*
1153 		 * Is ur_recid a valid one?
1154 		 */
1155 		if (DBSET(ur->ur_recid) < 0 || DBSET(ur->ur_recid) >= md_nsets)
1156 			return (EINVAL);
1157 
1158 		ur->ur_recstat = mddb_getrecstatus(ur->ur_recid);
1159 		if (ur->ur_recstat == MDDB_NORECORD)
1160 			return (ENXIO);
1161 		status = mddb_commitrec(ur->ur_recid);
1162 		/*
1163 		 * For MN sets we panic if there are too few database replicas
1164 		 * and we're attempting to add entries to the log.
1165 		 */
1166 		if (status != 0) {
1167 			if ((MD_MNSET_SETNO(ur->ur_setno) &&
1168 			    (ur->ur_type2 == MDDB_UR_LR)) &&
1169 			    (md_get_setstatus(ur->ur_setno) & MD_SET_TOOFEW)) {
1170 				cmn_err(CE_PANIC,
1171 				    "md: Panic due to lack of DiskSuite state\n"
1172 				    " database replicas. Fewer than 50%% of "
1173 				    "the total were available,\n so panic to "
1174 				    "ensure data integrity.");
1175 			}
1176 			return (mddbstatus2error(&ur->ur_mde, status, NODEV32,
1177 			    ur->ur_setno));
1178 		}
1179 		break;
1180 
1181 	case MD_DB_COMMIT_MANY:
1182 		if (ur->ur_size <= 0)
1183 			return (EINVAL);
1184 
1185 		data = kmem_alloc(ur->ur_size, KM_SLEEP);
1186 
1187 		if (ddi_copyin((caddr_t)(uintptr_t)ur->ur_data, data,
1188 		    (size_t)ur->ur_size, mode)) {
1189 			kmem_free(data, ur->ur_size);
1190 			return (EFAULT);
1191 		}
1192 
1193 		recids = (mddb_recid_t *)data;
1194 		while (*recids != 0) {
1195 			/*
1196 			 * Is recid a valid ?
1197 			 */
1198 			if (DBSET(*recids) < 0 || DBSET(*recids) >= md_nsets) {
1199 				kmem_free(data, ur->ur_size);
1200 				return (EINVAL);
1201 			}
1202 			ur->ur_recstat = mddb_getrecstatus(*recids++);
1203 			if (ur->ur_recstat == MDDB_NORECORD) {
1204 				kmem_free(data, ur->ur_size);
1205 				return (ENXIO);
1206 			}
1207 		}
1208 		status = mddb_commitrecs(data);
1209 		kmem_free(data, ur->ur_size);
1210 		/*
1211 		 * For MN sets we panic if there are too few database replicas
1212 		 * and we're attempting to add entries to the log.
1213 		 */
1214 		if (status != 0) {
1215 			if ((MD_MNSET_SETNO(ur->ur_setno) &&
1216 			    (ur->ur_type2 == MDDB_UR_LR)) &&
1217 			    (md_get_setstatus(ur->ur_setno) & MD_SET_TOOFEW)) {
1218 				cmn_err(CE_PANIC,
1219 				    "md: Panic due to lack of DiskSuite state\n"
1220 				    " database replicas. Fewer than 50%% of "
1221 				    "the total were available,\n so panic to "
1222 				    "ensure data integrity.");
1223 			}
1224 			return (mddbstatus2error(&ur->ur_mde, status, NODEV32,
1225 			    ur->ur_setno));
1226 		}
1227 		break;
1228 
1229 	case MD_DB_GETDATA:
1230 		/*
1231 		 * Check ur_recid
1232 		 */
1233 		if (DBSET(ur->ur_recid) < 0 || DBSET(ur->ur_recid) >= md_nsets)
1234 			return (EINVAL);
1235 
1236 		ur->ur_recstat = mddb_getrecstatus(ur->ur_recid);
1237 		if (ur->ur_recstat == MDDB_NORECORD ||
1238 		    ur->ur_recstat == MDDB_NODATA)
1239 			return (ENXIO);
1240 
1241 		if (ur->ur_size > mddb_getrecsize(ur->ur_recid))
1242 			return (EINVAL);
1243 
1244 		data = mddb_getrecaddr(ur->ur_recid);
1245 		if (ddi_copyout(data, (caddr_t)(uintptr_t)ur->ur_data,
1246 		    (size_t)ur->ur_size, mode)) {
1247 			return (EFAULT);
1248 		}
1249 		break;
1250 
1251 	case MD_DB_SETDATA:
1252 		if (DBSET(ur->ur_recid) < 0 || DBSET(ur->ur_recid) >= md_nsets)
1253 			return (EINVAL);
1254 
1255 		ur->ur_recstat = mddb_getrecstatus(ur->ur_recid);
1256 		if (ur->ur_recstat == MDDB_NORECORD)
1257 			return (ENXIO);
1258 
1259 		if (ur->ur_size > mddb_getrecsize(ur->ur_recid))
1260 			return (EINVAL);
1261 
1262 		data = mddb_getrecaddr(ur->ur_recid);
1263 		if (ddi_copyin((caddr_t)(uintptr_t)ur->ur_data, data,
1264 		    (size_t)ur->ur_size, mode)) {
1265 			return (EFAULT);
1266 		}
1267 		break;
1268 
1269 	case MD_DB_DELETE:
1270 		if (DBSET(ur->ur_recid) < 0 || DBSET(ur->ur_recid) >= md_nsets)
1271 			return (EINVAL);
1272 
1273 		ur->ur_recstat = mddb_getrecstatus(ur->ur_recid);
1274 		if (ur->ur_recstat == MDDB_NORECORD)
1275 			return (ENXIO);
1276 		status = mddb_deleterec(ur->ur_recid);
1277 		if (status < 0)
1278 			return (mddbstatus2error(&ur->ur_mde, status, NODEV32,
1279 			    ur->ur_setno));
1280 		break;
1281 
1282 	case MD_DB_CREATE:
1283 	{
1284 		int	mn_set = 0;
1285 
1286 		if (md_get_setstatus(ur->ur_setno) & MD_SET_MNSET)
1287 			mn_set = 1;
1288 
1289 		if (ur->ur_setno >= md_nsets)
1290 			return (EINVAL);
1291 		if ((mn_set) && (ur->ur_type2 == MDDB_UR_LR))
1292 			flags = MD_CRO_32BIT | MD_CRO_CHANGELOG;
1293 		else
1294 			flags = MD_CRO_32BIT;
1295 		ur->ur_recid = mddb_createrec(ur->ur_size, ur->ur_type,
1296 		    ur->ur_type2, flags, ur->ur_setno);
1297 		if (ur->ur_recid < 0)
1298 			return (mddbstatus2error(&ur->ur_mde, ur->ur_recid,
1299 			    NODEV32, ur->ur_setno));
1300 		break;
1301 	}
1302 
1303 	case MD_DB_GETSTATUS:
1304 		if (DBSET(ur->ur_recid) < 0 || DBSET(ur->ur_recid) >= md_nsets)
1305 			return (EINVAL);
1306 		ur->ur_recstat = mddb_getrecstatus(ur->ur_recid);
1307 		break;
1308 
1309 	case MD_DB_GETSIZE:
1310 		if (DBSET(ur->ur_recid) < 0 || DBSET(ur->ur_recid) >= md_nsets)
1311 			return (EINVAL);
1312 		ur->ur_size = mddb_getrecsize(ur->ur_recid);
1313 		break;
1314 
1315 	case MD_DB_MAKEID:
1316 		if (ur->ur_setno >= md_nsets)
1317 			return (EINVAL);
1318 		ur->ur_recid = mddb_makerecid(ur->ur_setno, ur->ur_recid);
1319 		break;
1320 
1321 	default:
1322 		return (EINVAL);
1323 	}
1324 	return (0);
1325 }
1326 
1327 static int
1328 setuserflags(
1329 	md_set_userflags_t	*msu,
1330 	IOLOCK			*lock
1331 )
1332 {
1333 	minor_t			mnum = msu->mnum;
1334 	set_t			setno = MD_MIN2SET(mnum);
1335 	md_unit_t		*un;
1336 	mdi_unit_t		*ui;
1337 
1338 	mdclrerror(&msu->mde);
1339 
1340 	if (md_get_setstatus(setno) & MD_SET_STALE)
1341 		return (mdmddberror(&msu->mde, MDE_DB_STALE, mnum, setno));
1342 
1343 	if ((ui = MDI_UNIT(mnum)) == NULL) {
1344 		return (mdmderror(&msu->mde, MDE_UNIT_NOT_SETUP, mnum));
1345 	}
1346 
1347 	un = (md_unit_t *)md_ioctl_writerlock(lock, ui);
1348 
1349 	un->c.un_user_flags = msu->userflags;
1350 	mddb_commitrec_wrapper(un->c.un_record_id);
1351 
1352 	return (0);
1353 }
1354 
1355 /*
1356  * mddb_didstat_from_user -- called for DIDSTAT ioctl. 2 different calling
1357  * 	scenarios.
1358  * 	1) data->mode == MD_FIND_INVDID
1359  *	   when user is inquiring about the existence of invalid device id's.
1360  *	   Upon return to the user d->cnt may have a value in it.
1361  *	2) data->mode == MD_GET_INVDID
1362  *	   when the user wants a list of the invalid device id's.
1363  *	   In this case d->ctdp is non Null and cnt has	a value in it.
1364  *
1365  * Basically this routine along with mddb_didstat_to_user can be eliminated
1366  * by pushing ddi_copyout down to lower level interfaces.  To minimize impact
1367  * just keep the current implementation intact.
1368  */
1369 static int
1370 mddb_didstat_from_user(
1371 	void		**d,
1372 	caddr_t		data,
1373 	int		mode,
1374 	caddr_t		*ds_ctd_addr
1375 )
1376 {
1377 	size_t		sz1 = 0, sz2 = 0;
1378 	md_i_didstat_t	*d1;
1379 	void		*d2;
1380 	*ds_ctd_addr	= 0;
1381 
1382 	sz1 = sizeof (md_i_didstat_t);
1383 	d1 = (md_i_didstat_t *)kmem_zalloc(sz1, KM_SLEEP);
1384 
1385 	if (ddi_copyin(data, (void *)d1, sz1, mode) != 0) {
1386 		kmem_free((void *)d1, sz1);
1387 		return (EFAULT);
1388 	}
1389 
1390 	/*
1391 	 * ds_ctd_addr has actual user ctdp
1392 	 */
1393 	*ds_ctd_addr = (caddr_t)(uintptr_t)d1->ctdp;
1394 	if (d1->mode == MD_GET_INVDID) {
1395 		sz2 = (d1->cnt * d1->maxsz) + 1;
1396 		if (sz2 <= 0) {
1397 			kmem_free(d1, sz1);
1398 			return (EINVAL);
1399 		}
1400 		d2 = kmem_zalloc(sz2, KM_SLEEP);
1401 		d1->ctdp = (uint64_t)(uintptr_t)d2;
1402 	} else if (d1->mode != MD_FIND_INVDID) {
1403 		kmem_free(d1, sz1);
1404 		return (EINVAL);
1405 	}
1406 	*d = (void *)d1;
1407 	return (0);
1408 }
1409 
1410 /*
1411  * mddb_didstat_to_user -- see comment for mddb_didstat_from_user. In this
1412  * 		case d->cnt could have a value in it for either usage of
1413  *		the ioctl.
1414  */
1415 /*ARGSUSED*/
1416 static int
1417 mddb_didstat_to_user(
1418 	void 		*d,
1419 	caddr_t		data,
1420 	int		mode,
1421 	caddr_t		ds_ctd_addr
1422 )
1423 {
1424 	size_t		sz1 = 0, sz2 = 0;
1425 	md_i_didstat_t		*d1;
1426 	void			*d2;
1427 
1428 
1429 	d1 = (md_i_didstat_t *)d;
1430 	sz1 = sizeof (md_i_didstat_t);
1431 
1432 	sz2 = (d1->cnt * d1->maxsz) + 1;
1433 	d2 = (caddr_t)(uintptr_t)d1->ctdp;
1434 	if (d2 && sz2) {
1435 		/*
1436 		 * Copy out from kernel ctdp to user ctdp area
1437 		 */
1438 		if (ddi_copyout(d2, (caddr_t)ds_ctd_addr, sz2, mode) != 0) {
1439 			kmem_free(d1, sz1);
1440 			kmem_free(d2, sz2);
1441 			return (EFAULT);
1442 		}
1443 		d1->ctdp = (uint64_t)(uintptr_t)ds_ctd_addr;
1444 	}
1445 	if (ddi_copyout(d1, data, sz1, mode) != 0) {
1446 		kmem_free(d1, sz1);
1447 		if (sz2 && d2)
1448 			kmem_free(d2, sz2);
1449 		return (EFAULT);
1450 	}
1451 	kmem_free(d1, sz1);
1452 	if (sz2 && d2)
1453 		kmem_free(d2, sz2);
1454 	return (0);
1455 }
1456 
1457 
1458 static int
1459 mddb_config_from_user(
1460 	void 		**d,
1461 	caddr_t 	data,
1462 	int 		mode,
1463 	caddr_t 	*c_devid_addr,
1464 	caddr_t		*c_old_devid_addr
1465 )
1466 {
1467 	size_t		sz1 = 0, sz2 = 0, sz3 = 0;
1468 	mddb_config_t	*d1;
1469 	void		*d2;
1470 	void 		*d3;
1471 
1472 	*c_devid_addr = 0;
1473 
1474 	sz1 = sizeof (mddb_config_t);
1475 	d1 = (mddb_config_t *)kmem_zalloc(sz1, KM_SLEEP);
1476 
1477 	if (ddi_copyin(data, (void *)d1, sz1, mode) != 0) {
1478 		kmem_free((void *)d1, sz1);
1479 		return (EFAULT);
1480 	}
1481 	*c_devid_addr = (caddr_t)(uintptr_t)d1->c_locator.l_devid;
1482 
1483 	if (d1->c_locator.l_devid_flags & MDDB_DEVID_SPACE) {
1484 		sz2 = d1->c_locator.l_devid_sz;
1485 		if (d1->c_locator.l_devid_sz <= 0 ||
1486 		    d1->c_locator.l_devid_sz > MAXPATHLEN) {
1487 			kmem_free((void *)d1, sz1);
1488 			return (EINVAL);
1489 		}
1490 		d2 = kmem_zalloc(sz2, KM_SLEEP);
1491 		if (ddi_copyin((caddr_t)(uintptr_t)d1->c_locator.l_devid,
1492 		    d2, sz2, mode) != 0) {
1493 			kmem_free(d1, sz1);
1494 			kmem_free(d2, sz2);
1495 			return (EFAULT);
1496 		}
1497 		d1->c_locator.l_devid = (uint64_t)(uintptr_t)d2;
1498 
1499 		if ((caddr_t)(uintptr_t)d1->c_locator.l_old_devid) {
1500 			*c_old_devid_addr = (caddr_t)(uintptr_t)
1501 			    d1->c_locator.l_old_devid;
1502 
1503 			sz3 = d1->c_locator.l_old_devid_sz;
1504 			if (d1->c_locator.l_old_devid_sz <= 0 ||
1505 			    d1->c_locator.l_old_devid_sz > MAXPATHLEN) {
1506 				kmem_free((void *)d1, sz1);
1507 				kmem_free(d2, sz2);
1508 				return (EINVAL);
1509 			}
1510 			d3 = kmem_zalloc(sz3, KM_SLEEP);
1511 			if (ddi_copyin(
1512 			    (caddr_t)(uintptr_t)d1->c_locator.l_old_devid,
1513 			    d3, sz3, mode) != 0) {
1514 				kmem_free((void *)d1, sz1);
1515 				kmem_free(d2, sz2);
1516 				kmem_free(d3, sz3);
1517 				return (EFAULT);
1518 			}
1519 			d1->c_locator.l_old_devid = (uintptr_t)d3;
1520 		}
1521 	} else {
1522 		d1->c_locator.l_devid = (uint64_t)0;
1523 		d1->c_locator.l_old_devid = (uint64_t)0;
1524 	}
1525 
1526 	*d = (void *)d1;
1527 	return (0);
1528 }
1529 
1530 /*ARGSUSED*/
1531 static int
1532 mddb_config_to_user(
1533 	void 		*d,
1534 	caddr_t 	data,
1535 	int 		mode,
1536 	caddr_t 	c_devid_addr,
1537 	caddr_t		c_old_devid_addr
1538 )
1539 {
1540 	size_t		sz1 = 0, sz2 = 0, sz3 = 0;
1541 	mddb_config_t		*d1;
1542 	void			*d2;
1543 	void			*d3;
1544 
1545 	d1 = (mddb_config_t *)d;
1546 	sz1 = sizeof (mddb_config_t);
1547 
1548 	if (d1->c_locator.l_devid_flags & MDDB_DEVID_SPACE) {
1549 		sz2 = d1->c_locator.l_devid_sz;
1550 		d2 = (caddr_t)(uintptr_t)d1->c_locator.l_devid;
1551 		/* Only copyout devid if valid */
1552 		if (d1->c_locator.l_devid_flags & MDDB_DEVID_VALID) {
1553 			if (ddi_copyout(d2, (caddr_t)c_devid_addr,
1554 			    sz2, mode) != 0) {
1555 				kmem_free(d1, sz1);
1556 				kmem_free(d2, sz2);
1557 				return (EFAULT);
1558 			}
1559 		}
1560 	}
1561 
1562 	d1->c_locator.l_devid = (uint64_t)(uintptr_t)c_devid_addr;
1563 
1564 	if (d1->c_locator.l_old_devid) {
1565 		sz3 = d1->c_locator.l_old_devid_sz;
1566 		d3 = (caddr_t)(uintptr_t)d1->c_locator.l_old_devid;
1567 		if (ddi_copyout(d3, (caddr_t)c_old_devid_addr,
1568 		    sz3, mode) != 0) {
1569 			kmem_free(d1, sz1);
1570 			kmem_free(d2, sz2);
1571 			kmem_free(d3, sz3);
1572 		}
1573 	}
1574 	d1->c_locator.l_old_devid = (uintptr_t)c_old_devid_addr;
1575 
1576 	if (ddi_copyout(d1, data, sz1, mode) != 0) {
1577 		kmem_free(d1, sz1);
1578 		if (sz2)
1579 			kmem_free(d2, sz2);
1580 		if (sz3)
1581 			kmem_free(d3, sz3);
1582 		return (EFAULT);
1583 	}
1584 
1585 	if (d1)
1586 		kmem_free(d1, sz1);
1587 	if (sz2)
1588 		kmem_free(d2, sz2);
1589 	if (sz3)
1590 		kmem_free(d3, sz3);
1591 
1592 	return (0);
1593 }
1594 
1595 /*
1596  * NAME:	get_tstate
1597  * PURPOSE:	Return unit's transient error state to user.
1598  * INPUT:	device node (set + metadevice number)
1599  * OUTPUT:	gu->tstate
1600  * RETURNS:	0 on success
1601  *		EINVAL on failure
1602  */
1603 static int
1604 get_tstate(md_i_get_tstate_t *gu, IOLOCK *lock)
1605 {
1606 	mdi_unit_t	*ui;
1607 
1608 	ui = MDI_UNIT(gu->id);
1609 	if (ui == (mdi_unit_t *)NULL) {
1610 		(void) mdmderror(&gu->mde, MDE_UNIT_NOT_SETUP, gu->id);
1611 		return (EINVAL);
1612 	}
1613 
1614 	(void) md_ioctl_readerlock(lock, ui);
1615 	gu->tstate = ui->ui_tstate;
1616 	md_ioctl_readerexit(lock);
1617 
1618 	return (0);
1619 }
1620 
1621 /*
1622  * NAME:	md_clu_ioctl
1623  * PURPOSE:	depending on clu_cmd:
1624  *		- Check open state,
1625  *		- lock opens and check open state
1626  *		- unlock opens again
1627  * INPUT:	metadevice and clu_cmd
1628  * OUTPUT:	open state (for MD_MN_LCU_UNLOCK always 0)
1629  * RETURNS:	0 on success
1630  *		EINVAL on failure
1631  */
1632 int
1633 md_clu_ioctl(md_clu_open_t *clu)
1634 {
1635 	mdi_unit_t	*ui;
1636 	minor_t		mnum;
1637 
1638 	if ((clu->clu_dev <= 0) ||
1639 	    (md_getmajor(clu->clu_dev)) != md_major) {
1640 		return (EINVAL);
1641 	}
1642 
1643 	mnum = md_getminor(clu->clu_dev);
1644 	if ((ui = MDI_UNIT(mnum)) == NULL) {
1645 		return (mdmderror(&clu->clu_mde, MDE_UNIT_NOT_SETUP, mnum));
1646 	}
1647 
1648 	switch (clu->clu_cmd) {
1649 	case MD_MN_LCU_CHECK:
1650 		/* No lock here, just checking */
1651 		clu->clu_isopen = md_unit_isopen(ui);
1652 		break;
1653 	case MD_MN_LCU_LOCK:
1654 		/* This inhibits later opens to succeed */
1655 		ui->ui_tstate |= MD_OPENLOCKED;
1656 		clu->clu_isopen = md_unit_isopen(ui);
1657 		/* In case the md is opened, reset the lock immediately */
1658 		if (clu->clu_isopen != 0) {
1659 			ui->ui_tstate &= ~MD_OPENLOCKED;
1660 		}
1661 		break;
1662 	case MD_MN_LCU_UNLOCK:
1663 		ui->ui_tstate &= ~MD_OPENLOCKED;
1664 		clu->clu_isopen = 0;	/* always sucess */
1665 		break;
1666 	}
1667 	return (0);
1668 }
1669 
1670 /*
1671  * NAME:	mkdev_ioctl
1672  * PURPOSE:	Create device node for specified set / metadevice tuple
1673  * INPUT:	device tuple (set number + metadevice number)
1674  * OUTPUT:	None
1675  * RETURNS:	0 on success
1676  *		EINVAL on failure
1677  */
1678 static int
1679 mkdev_ioctl(md_mkdev_params_t *p)
1680 {
1681 	set_t	setno = p->md_driver.md_setno;
1682 	unit_t	un;
1683 
1684 	mdclrerror(&p->mde);
1685 
1686 	/* Validate arguments passed in to ioctl */
1687 	if (setno >= MD_MAXSETS) {
1688 		(void) mderror(&p->mde, MDE_NO_SET);
1689 		return (EINVAL);
1690 	}
1691 
1692 	/*
1693 	 * Get the next available unit number in this set
1694 	 */
1695 	un = md_get_nextunit(setno);
1696 	if (un == MD_UNITBAD) {
1697 		(void) mdmderror(&p->mde, MDE_UNIT_NOT_SETUP, un);
1698 		return (ENODEV);
1699 	}
1700 
1701 	/* Create the device node */
1702 	if (md_create_minor_node(setno, un)) {
1703 		(void) mdmderror(&p->mde, MDE_UNIT_NOT_SETUP, un);
1704 		return (ENODEV);
1705 	}
1706 
1707 	/* Return the minor number */
1708 	p->un = un;
1709 
1710 	return (0);
1711 }
1712 
1713 /*
1714  * admin device ioctls
1715  */
1716 static int
1717 md_base_ioctl(md_dev64_t dev, int cmd, caddr_t data, int mode, IOLOCK *lockp)
1718 {
1719 	size_t		sz = 0;
1720 	void		*d = NULL;
1721 	mddb_config_t	*cp;
1722 	set_t		setno;
1723 	int		err = 0;
1724 	int		err_to_user = 0;
1725 	int		mddb_config_case = 0;
1726 	int		mddb_didstat_case = 0;
1727 	caddr_t		c_devid_addr = 0;
1728 	caddr_t		c_old_devid_addr = 0;
1729 	caddr_t		ds_ctd_addr = 0;
1730 	mddb_set_node_params_t	*snp;
1731 
1732 	/* For now we can only handle 32-bit clients for internal commands */
1733 	if ((cmd != DKIOCINFO) &&
1734 	    ((mode & DATAMODEL_MASK) != DATAMODEL_ILP32)) {
1735 		return (EINVAL);
1736 	}
1737 
1738 	switch (cmd) {
1739 
1740 	case DKIOCINFO:
1741 	{
1742 		if (! (mode & FREAD))
1743 			return (EACCES);
1744 
1745 		sz = sizeof (struct dk_cinfo);
1746 		d = kmem_alloc(sz, KM_SLEEP);
1747 
1748 		get_info((struct dk_cinfo *)d, md_getminor(dev));
1749 		break;
1750 	}
1751 
1752 	case MD_DB_USEDEV:
1753 	{
1754 		if (! (mode & FWRITE))
1755 			return (EACCES);
1756 
1757 		mddb_config_case = 1;
1758 
1759 		err = mddb_config_from_user(&d, data, mode, &c_devid_addr,
1760 		    &c_old_devid_addr);
1761 
1762 		if (err)
1763 			return (err);
1764 
1765 		err = mddb_configure(MDDB_USEDEV, (mddb_config_t *)d);
1766 		break;
1767 	}
1768 
1769 	case MD_DB_GETDEV:
1770 	{
1771 		if (! (mode & FREAD))
1772 			return (EACCES);
1773 
1774 		mddb_config_case = 1;
1775 
1776 		err = mddb_config_from_user(&d, data, mode, &c_devid_addr,
1777 		    &c_old_devid_addr);
1778 
1779 		if (err)
1780 			return (err);
1781 
1782 		err = mddb_configure(MDDB_GETDEV, (mddb_config_t *)d);
1783 		break;
1784 	}
1785 
1786 	case MD_DB_GETDRVNM:
1787 	{
1788 		if (! (mode & FREAD))
1789 			return (EACCES);
1790 
1791 		mddb_config_case = 1;
1792 
1793 		err = mddb_config_from_user(&d, data, mode, &c_devid_addr,
1794 		    &c_old_devid_addr);
1795 
1796 		if (err)
1797 			return (err);
1798 
1799 		err = mddb_configure(MDDB_GETDRVRNAME, (mddb_config_t *)d);
1800 		break;
1801 	}
1802 
1803 	case MD_DB_ENDDEV:
1804 	{
1805 		if (! (mode & FREAD))
1806 			return (EACCES);
1807 
1808 		mddb_config_case = 1;
1809 
1810 		err = mddb_config_from_user(&d, data, mode, &c_devid_addr,
1811 		    &c_old_devid_addr);
1812 
1813 		if (err)
1814 			return (err);
1815 
1816 		err = mddb_configure(MDDB_ENDDEV, (mddb_config_t *)d);
1817 		break;
1818 	}
1819 
1820 	case MD_DB_DELDEV:
1821 	{
1822 		if (! (mode & FWRITE))
1823 			return (EACCES);
1824 
1825 		mddb_config_case = 1;
1826 
1827 		err = mddb_config_from_user(&d, data, mode, &c_devid_addr,
1828 		    &c_old_devid_addr);
1829 
1830 		if (err)
1831 			return (err);
1832 
1833 		cp = (mddb_config_t *)d;
1834 		setno = cp->c_setno;
1835 		err = mddb_configure(MDDB_DELDEV, cp);
1836 		if (! mdisok(&cp->c_mde))
1837 			break;
1838 
1839 		if (setno == MD_LOCAL_SET)
1840 			break;
1841 
1842 		if (cp->c_dbcnt != 0)
1843 			break;
1844 
1845 		/*
1846 		 * if the last db replica of a diskset is deleted
1847 		 * unload everything.
1848 		 */
1849 
1850 		/* Requesting a release, clean up everything */
1851 		md_clr_setstatus(setno, MD_SET_KEEPTAG);
1852 
1853 		err = release_set(cp, mode);
1854 
1855 		break;
1856 	}
1857 
1858 	case MD_DB_NEWDEV:
1859 	{
1860 		if (! (mode & FWRITE))
1861 			return (EACCES);
1862 
1863 		mddb_config_case = 1;
1864 
1865 		err = mddb_config_from_user(&d, data, mode, &c_devid_addr,
1866 		    &c_old_devid_addr);
1867 
1868 		if (err)
1869 			return (err);
1870 
1871 		cp = (mddb_config_t *)d;
1872 		setno = cp->c_setno;
1873 		err = mddb_configure(MDDB_NEWDEV, cp);
1874 		if (! err && mdisok(&cp->c_mde))
1875 			(void) md_snarf_db_set(setno, &cp->c_mde);
1876 		break;
1877 	}
1878 
1879 	case MD_DB_NEWSIDE:
1880 	{
1881 		if (! (mode & FWRITE))
1882 			return (EACCES);
1883 
1884 		mddb_config_case = 1;
1885 
1886 		err = mddb_config_from_user(&d, data, mode, &c_devid_addr,
1887 		    &c_old_devid_addr);
1888 
1889 		if (err)
1890 			return (err);
1891 
1892 		err = mddb_configure(MDDB_NEWSIDE, (mddb_config_t *)d);
1893 		break;
1894 	}
1895 
1896 	case MD_DB_DELSIDE:
1897 	{
1898 		if (! (mode & FWRITE))
1899 			return (EACCES);
1900 
1901 		mddb_config_case = 1;
1902 
1903 		err = mddb_config_from_user(&d, data, mode, &c_devid_addr,
1904 		    &c_old_devid_addr);
1905 
1906 		if (err)
1907 			return (err);
1908 
1909 		err = mddb_configure(MDDB_DELSIDE, (mddb_config_t *)d);
1910 		break;
1911 	}
1912 
1913 	case MD_DB_SETDID:
1914 	{
1915 		if (!(mode & FWRITE)) {
1916 			return (EACCES);
1917 		}
1918 
1919 		mddb_config_case = 1;
1920 
1921 		err = mddb_config_from_user(&d, data, mode, &c_devid_addr,
1922 		    &c_old_devid_addr);
1923 
1924 		if (err) {
1925 			return (err);
1926 		}
1927 
1928 		err = mddb_configure(MDDB_SETDID, (mddb_config_t *)d);
1929 
1930 		break;
1931 	}
1932 
1933 	case MD_GRAB_SET:
1934 	{
1935 		if (! (mode & FWRITE))
1936 			return (EACCES);
1937 
1938 		mddb_config_case = 1;
1939 
1940 		err = mddb_config_from_user(&d, data, mode, &c_devid_addr,
1941 		    &c_old_devid_addr);
1942 
1943 		if (err)
1944 			return (err);
1945 
1946 		cp = (mddb_config_t *)d;
1947 		setno = cp->c_setno;
1948 
1949 		err = take_set(cp, mode);
1950 
1951 		if (err || ! mdisok(&cp->c_mde))
1952 			break;
1953 
1954 		if (md_get_setstatus(setno) & MD_SET_ACCOK)
1955 			err = mdmddberror(&cp->c_mde, MDE_DB_ACCOK, NODEV32,
1956 			    setno);
1957 
1958 		md_unblock_setio(setno);
1959 		break;
1960 	}
1961 
1962 	case MD_RELEASE_SET:
1963 	{
1964 		if (! (mode & FWRITE))
1965 			return (EACCES);
1966 
1967 		mddb_config_case = 1;
1968 
1969 		err = mddb_config_from_user(&d, data, mode, &c_devid_addr,
1970 		    &c_old_devid_addr);
1971 
1972 		if (err)
1973 			return (err);
1974 
1975 		/* shorthand */
1976 		cp = (mddb_config_t *)d;
1977 		setno = cp->c_setno;
1978 
1979 		/* If the user requests a release, clean up everything */
1980 		md_clr_setstatus(setno, MD_SET_KEEPTAG);
1981 
1982 		/* Block incoming I/Os during release_set operation */
1983 		if (MD_MNSET_SETNO(setno)) {
1984 			/*
1985 			 * md_tas_block_setio will block the set if
1986 			 * there are no outstanding I/O requests,
1987 			 * otherwise it returns -1.
1988 			 */
1989 			if (md_tas_block_setio(setno) != 1) {
1990 				err = EBUSY;
1991 				break;
1992 			}
1993 		} else {
1994 			/*
1995 			 * Should not return something other than 1
1996 			 */
1997 			if (md_block_setio(setno) != 1) {
1998 				md_clearblock_setio(setno);
1999 				err = EACCES;
2000 				break;
2001 			}
2002 		}
2003 
2004 		err = release_set(cp, mode);
2005 
2006 		/* Always unblock I/O even if release_set fails */
2007 		md_clearblock_setio(setno);
2008 
2009 		break;
2010 	}
2011 
2012 	case MD_DB_GETOPTLOC:
2013 	{
2014 		if (! (mode & FREAD))
2015 			return (EACCES);
2016 
2017 		sz = sizeof (mddb_optloc_t);
2018 		d = kmem_alloc(sz, KM_SLEEP);
2019 
2020 		if (ddi_copyin(data, d, sz, mode) != 0) {
2021 			err = EFAULT;
2022 			break;
2023 		}
2024 
2025 		err = mddb_getoptloc((mddb_optloc_t *)d);
2026 		break;
2027 	}
2028 
2029 	case MD_HALT:
2030 	{
2031 		if (! (mode & FWRITE))
2032 			return (EACCES);
2033 
2034 		/* already have the ioctl lock */
2035 		return (md_halt(MD_GBL_IOCTL_LOCK));
2036 	}
2037 
2038 	case MD_IOCSET_NM:
2039 	{
2040 		if (! (mode & FREAD))
2041 			return (EACCES);
2042 
2043 		sz = sizeof (mdnm_params_t);
2044 		d = kmem_alloc(sz, KM_SLEEP);
2045 
2046 		if (ddi_copyin(data, d, sz, mode) != 0) {
2047 			err = EFAULT;
2048 			break;
2049 		}
2050 
2051 		/* check data integrity */
2052 		if (((mdnm_params_t *)d)->setno >= md_nsets) {
2053 			err = EINVAL;
2054 			break;
2055 		}
2056 
2057 		if ((((mdnm_params_t *)d)->devname_len == 0) ||
2058 		    (((mdnm_params_t *)d)->devname_len > MAXPATHLEN)) {
2059 			err = EINVAL;
2060 			break;
2061 		}
2062 
2063 		if (((mdnm_params_t *)d)->devname == NULL) {
2064 			err = EINVAL;
2065 			break;
2066 		}
2067 
2068 		err = setnm_ioctl((mdnm_params_t *)d, mode);
2069 		break;
2070 	}
2071 
2072 	case MD_IOCGET_NM:
2073 	{
2074 		if (! (mode & FREAD))
2075 			return (EACCES);
2076 
2077 		sz = sizeof (mdnm_params_t);
2078 		d = kmem_alloc(sz, KM_SLEEP);
2079 
2080 		if (ddi_copyin(data, d, sz, mode) != 0) {
2081 			err = EFAULT;
2082 			break;
2083 		}
2084 
2085 		/* check data integrity */
2086 		if (((mdnm_params_t *)d)->setno >= md_nsets) {
2087 			err = EINVAL;
2088 			break;
2089 		}
2090 		if (((mdnm_params_t *)d)->devname == NULL) {
2091 			err = EINVAL;
2092 			break;
2093 		}
2094 
2095 		err = getnm_ioctl((mdnm_params_t *)d, mode);
2096 		break;
2097 	}
2098 
2099 	case MD_IOCGET_HSP_NM:
2100 	{
2101 		if (! (mode & FREAD))
2102 			return (EACCES);
2103 
2104 		sz = sizeof (mdhspnm_params_t);
2105 		d = kmem_alloc(sz, KM_SLEEP);
2106 
2107 		if (ddi_copyin(data, d, sz, mode) != 0) {
2108 			err = EFAULT;
2109 			break;
2110 		}
2111 
2112 		/* check data integrity */
2113 		if (((mdhspnm_params_t *)d)->setno >= md_nsets) {
2114 			err = EINVAL;
2115 			break;
2116 		}
2117 		if (((mdhspnm_params_t *)d)->hspname == NULL) {
2118 			err = EINVAL;
2119 			break;
2120 		}
2121 
2122 		err = gethspnm_ioctl((mdhspnm_params_t *)d, mode);
2123 		break;
2124 	}
2125 
2126 	case MD_IOCNXTKEY_NM:
2127 	{
2128 		if (! (mode & FREAD))
2129 			return (EACCES);
2130 
2131 		sz = sizeof (mdnm_params_t);
2132 		d = kmem_alloc(sz, KM_SLEEP);
2133 
2134 		if (ddi_copyin(data, d, sz, mode) != 0) {
2135 			err = EFAULT;
2136 			break;
2137 		}
2138 
2139 		err = getnextkey_ioctl((mdnm_params_t *)d, mode);
2140 		break;
2141 	}
2142 
2143 	case MD_IOCREM_NM:
2144 	{
2145 		if (! (mode & FREAD))
2146 			return (EACCES);
2147 
2148 		sz = sizeof (mdnm_params_t);
2149 		d = kmem_alloc(sz, KM_SLEEP);
2150 
2151 		if (ddi_copyin(data, d, sz, mode) != 0) {
2152 			err = EFAULT;
2153 			break;
2154 		}
2155 
2156 		/* check data integrity */
2157 		if (((mdnm_params_t *)d)->setno >= md_nsets) {
2158 			err = EINVAL;
2159 			break;
2160 		}
2161 
2162 		err = remnm_ioctl((mdnm_params_t *)d, mode);
2163 		break;
2164 	}
2165 
2166 	case MD_IOCGET_TSTATE:
2167 	{
2168 		md_i_get_tstate_t	*p;
2169 
2170 		if (! (mode & FREAD))
2171 			return (EACCES);
2172 
2173 		sz = sizeof (md_i_get_tstate_t);
2174 		d = kmem_alloc(sz, KM_SLEEP);
2175 
2176 		if (ddi_copyin(data, d, sz, mode) != 0) {
2177 			err = EFAULT;
2178 			break;
2179 		}
2180 
2181 		p = (md_i_get_tstate_t *)d;
2182 
2183 		if ((err = verify_minor(p->id)) != 0) {
2184 			if (err == EINVAL)
2185 				(void) mdmderror(&p->mde, MDE_INVAL_UNIT,
2186 				    p->id);
2187 			break;
2188 		}
2189 
2190 		err = get_tstate(p, lockp);
2191 		break;
2192 	}
2193 
2194 	case MD_IOCGET_DRVNM:
2195 	{
2196 		md_i_driverinfo_t	*p;
2197 
2198 		if (! (mode & FREAD))
2199 			return (EACCES);
2200 
2201 		sz = sizeof (md_i_driverinfo_t);
2202 		d = kmem_alloc(sz, KM_SLEEP);
2203 
2204 		if (ddi_copyin(data, d, sz, mode) != 0) {
2205 			err = EFAULT;
2206 			break;
2207 		}
2208 
2209 		p = (md_i_driverinfo_t *)d;
2210 
2211 		/* check data integrity */
2212 		if (p->md_driver.md_drivername == NULL) {
2213 			err = EINVAL;
2214 			break;
2215 		}
2216 
2217 		if ((err = verify_minor(p->mnum)) != 0) {
2218 			if (err == EINVAL)
2219 				(void) mdmderror(&p->mde, MDE_INVAL_UNIT,
2220 				    p->mnum);
2221 			break;
2222 		}
2223 
2224 		err = getdrvnm_ioctl(dev, p, mode);
2225 		break;
2226 	}
2227 
2228 	case MD_IOCGET_NEXT:
2229 	{
2230 		if (! (mode & FREAD))
2231 			return (EACCES);
2232 
2233 		sz = sizeof (md_i_getnext_t);
2234 		d = kmem_alloc(sz, KM_SLEEP);
2235 
2236 		if (ddi_copyin(data, d, sz, mode) != 0) {
2237 			err = EFAULT;
2238 			break;
2239 		}
2240 
2241 		/* check data integrity */
2242 		if (((md_i_getnext_t *)d)->md_driver.md_setno >= md_nsets) {
2243 			err = EINVAL;
2244 			break;
2245 		}
2246 
2247 		err = getnext_ioctl((md_i_getnext_t *)d, mode);
2248 		break;
2249 	}
2250 
2251 	case MD_DB_USERREQ:
2252 	case MD_MN_DB_USERREQ:
2253 	{
2254 		if (! (mode & FREAD))
2255 			return (EACCES);
2256 
2257 		sz = sizeof (mddb_userreq_t);
2258 		d = kmem_alloc(sz, KM_SLEEP);
2259 
2260 		if (ddi_copyin(data, d, sz, mode) != 0) {
2261 			err = EFAULT;
2262 			break;
2263 		}
2264 		err = mddb_userreq_ioctl((mddb_userreq_t *)d, mode);
2265 		break;
2266 	}
2267 
2268 	case MD_IOCGET_NUM:
2269 	{
2270 		if (! (mode & FREAD))
2271 			return (EACCES);
2272 
2273 		sz = sizeof (md_i_getnum_t);
2274 		d = kmem_alloc(sz, KM_SLEEP);
2275 
2276 		if (ddi_copyin(data, d, sz, mode) != 0) {
2277 			err = EFAULT;
2278 			break;
2279 		}
2280 
2281 		err = getnum_ioctl(d, mode);
2282 		break;
2283 	}
2284 
2285 	case MD_DB_OWNSET:
2286 	{
2287 		if (! (mode & FREAD))
2288 			return (EACCES);
2289 
2290 		sz = sizeof (mddb_ownset_t);
2291 		d = kmem_alloc(sz, KM_SLEEP);
2292 
2293 		if (ddi_copyin(data, d, sz, mode) != 0) {
2294 			err = EFAULT;
2295 			break;
2296 		}
2297 
2298 		if (((mddb_ownset_t *)d)->setno >= md_nsets) {
2299 			err = EINVAL;
2300 			break;
2301 		}
2302 
2303 		((mddb_ownset_t *)d)->owns_set =
2304 		    mddb_ownset(((mddb_ownset_t *)d)->setno);
2305 
2306 		break;
2307 	}
2308 
2309 	case MD_IOCGETNSET:
2310 	{
2311 		if (! (mode & FREAD))
2312 			return (EACCES);
2313 
2314 		if (ddi_copyout((caddr_t)&md_nsets, data,
2315 		    sizeof (set_t), mode) != 0) {
2316 			err = EFAULT;
2317 			break;
2318 		}
2319 		break;
2320 	}
2321 
2322 	case MD_IOCGETNUNITS:
2323 	{
2324 		if (! (mode & FREAD))
2325 			return (EACCES);
2326 
2327 		if (ddi_copyout((caddr_t)&md_nunits, data,
2328 		    sizeof (set_t), mode) != 0) {
2329 			err = EFAULT;
2330 			break;
2331 		}
2332 		break;
2333 	}
2334 
2335 	case MD_IOCGVERSION:
2336 	{
2337 		uint_t	dversion = MD_DVERSION;
2338 
2339 		if (! (mode & FREAD))
2340 			return (EACCES);
2341 
2342 		if (ddi_copyout((caddr_t)&dversion, data,
2343 		    sizeof (dversion), mode) != 0) {
2344 			err = EFAULT;
2345 			break;
2346 		}
2347 		break;
2348 	}
2349 
2350 	case MD_IOCSET_FLAGS:
2351 	{
2352 		md_set_userflags_t	*p;
2353 
2354 		if (! (mode & FWRITE))
2355 			return (EACCES);
2356 
2357 		sz = sizeof (md_set_userflags_t);
2358 		d = kmem_alloc(sz, KM_SLEEP);
2359 
2360 		if (ddi_copyin(data, d, sz, mode)) {
2361 			err = EFAULT;
2362 			break;
2363 		}
2364 
2365 		p = (md_set_userflags_t *)d;
2366 
2367 		if ((err = verify_minor(p->mnum)) != 0) {
2368 			if (err == EINVAL)
2369 				(void) mdmderror(&p->mde, MDE_INVAL_UNIT,
2370 				    p->mnum);
2371 			break;
2372 		}
2373 
2374 		err = setuserflags(p, lockp);
2375 		break;
2376 	}
2377 
2378 	case MD_IOCRENAME:
2379 	{
2380 		md_rename_t	*p;
2381 
2382 		if (! (mode & FWRITE)) {
2383 			return (EACCES);
2384 		}
2385 
2386 		sz = sizeof (md_rename_t);
2387 		d = kmem_alloc(sz, KM_SLEEP);
2388 
2389 		if (ddi_copyin(data, d, sz, mode)) {
2390 			err = EFAULT;
2391 			break;
2392 		}
2393 
2394 		p = (md_rename_t *)d;
2395 
2396 		if ((err = verify_minor(p->to.mnum)) != 0) {
2397 			if (err == EINVAL)
2398 				(void) mdmderror(&p->mde, MDE_INVAL_UNIT,
2399 				    p->to.mnum);
2400 			break;
2401 		}
2402 
2403 		if ((err = verify_minor(p->from.mnum)) != 0) {
2404 			if (err == EINVAL)
2405 				(void) mdmderror(&p->mde, MDE_INVAL_UNIT,
2406 				    p->from.mnum);
2407 			break;
2408 		}
2409 
2410 		err = md_rename(p, lockp);
2411 		break;
2412 	}
2413 
2414 	case MD_IOCISOPEN:
2415 	{
2416 		md_isopen_t	*p;
2417 		mdi_unit_t	*ui;
2418 		minor_t		mnum;
2419 
2420 		if (! (mode & FREAD))
2421 			return (EACCES);
2422 
2423 		sz = sizeof (md_isopen_t);
2424 		d = kmem_alloc(sz, KM_SLEEP);
2425 
2426 		if (ddi_copyin(data, d, sz, mode)) {
2427 			err = EFAULT;
2428 			break;
2429 		}
2430 
2431 		p = (md_isopen_t *)d;
2432 		if ((p->dev <= 0) || (md_getmajor(p->dev)) != md_major) {
2433 			err = EINVAL;
2434 			break;
2435 		}
2436 
2437 		mnum = md_getminor(p->dev);
2438 
2439 		if ((err = verify_minor(mnum)) != 0) {
2440 			if (err == EINVAL)
2441 				(void) mdmderror(&p->mde, MDE_INVAL_UNIT, mnum);
2442 			break;
2443 		}
2444 
2445 		if ((ui = MDI_UNIT(mnum)) == NULL) {
2446 			(void) mdmderror(&p->mde, MDE_UNIT_NOT_SETUP, mnum);
2447 			err = EINVAL;
2448 			break;
2449 		}
2450 
2451 		p->isopen = md_unit_isopen(ui);
2452 		break;
2453 	}
2454 
2455 	case MD_MED_GET_LST:
2456 	{
2457 		mddb_med_parm_t		*medpp;
2458 
2459 		if (! (mode & FREAD))
2460 			return (EACCES);
2461 
2462 		sz = sizeof (mddb_med_parm_t);
2463 		d = kmem_alloc(sz, KM_SLEEP);
2464 
2465 		if (ddi_copyin(data, d, sz, mode) != 0) {
2466 			err = EFAULT;
2467 			break;
2468 		}
2469 
2470 		medpp = (mddb_med_parm_t *)d;
2471 
2472 		err = getmed_ioctl(medpp, mode);
2473 		break;
2474 	}
2475 
2476 	case MD_MED_SET_LST:
2477 	{
2478 		mddb_med_parm_t		*medpp;
2479 
2480 		if (! (mode & FWRITE))
2481 			return (EACCES);
2482 
2483 		sz = sizeof (mddb_med_parm_t);
2484 		d = kmem_alloc(sz, KM_SLEEP);
2485 
2486 		if (ddi_copyin(data, d, sz, mode) != 0) {
2487 			err = EFAULT;
2488 			break;
2489 		}
2490 
2491 		medpp = (mddb_med_parm_t *)d;
2492 
2493 		err = setmed_ioctl(medpp, mode);
2494 
2495 		break;
2496 	}
2497 
2498 	case MD_MED_UPD_MED:
2499 	{
2500 		if (! (mode & FWRITE))
2501 			return (EACCES);
2502 
2503 		sz = sizeof (mddb_med_upd_parm_t);
2504 		d = kmem_alloc(sz, KM_SLEEP);
2505 
2506 		if (ddi_copyin(data, d, sz, mode) != 0) {
2507 			err = EFAULT;
2508 			break;
2509 		}
2510 
2511 		err = updmed_ioctl((mddb_med_upd_parm_t *)d, mode);
2512 
2513 		break;
2514 	}
2515 
2516 	case MD_MED_GET_NMED:
2517 	{
2518 		if (! (mode & FREAD))
2519 			return (EACCES);
2520 
2521 		if (ddi_copyout((caddr_t)&md_nmedh, data,
2522 		    sizeof (int), mode) != 0) {
2523 			err = EFAULT;
2524 			break;
2525 		}
2526 		break;
2527 	}
2528 
2529 	case MD_MED_GET_TAG:
2530 	{
2531 		if (! (mode & FREAD))
2532 			return (EACCES);
2533 
2534 		sz = sizeof (mddb_dtag_get_parm_t);
2535 		d = kmem_alloc(sz, KM_SLEEP);
2536 
2537 		if (ddi_copyin(data, d, sz, mode) != 0) {
2538 			err = EFAULT;
2539 			break;
2540 		}
2541 
2542 		err = gettag_ioctl((mddb_dtag_get_parm_t *)d, mode);
2543 
2544 		break;
2545 	}
2546 
2547 	case MD_MED_USE_TAG:
2548 	{
2549 		if (! (mode & FWRITE))
2550 			return (EACCES);
2551 
2552 		sz = sizeof (mddb_dtag_use_parm_t);
2553 		d = kmem_alloc(sz, KM_SLEEP);
2554 
2555 		if (ddi_copyin(data, d, sz, mode) != 0) {
2556 			err = EFAULT;
2557 			break;
2558 		}
2559 
2560 		err = usetag_ioctl((mddb_dtag_use_parm_t *)d, mode);
2561 
2562 		break;
2563 	}
2564 
2565 	case MD_MED_ACCEPT:
2566 	{
2567 		if (! (mode & FWRITE))
2568 			return (EACCES);
2569 
2570 		sz = sizeof (mddb_accept_parm_t);
2571 		d = kmem_alloc(sz, KM_SLEEP);
2572 
2573 		if (ddi_copyin(data, d, sz, mode) != 0) {
2574 			err = EFAULT;
2575 			break;
2576 		}
2577 
2578 		err = accept_ioctl((mddb_accept_parm_t *)d, mode);
2579 
2580 		break;
2581 	}
2582 
2583 	case MD_MED_GET_TLEN:
2584 	{
2585 		if (! (mode & FREAD))
2586 			return (EACCES);
2587 
2588 		sz = sizeof (mddb_med_t_parm_t);
2589 		d = kmem_alloc(sz, KM_SLEEP);
2590 
2591 		if (ddi_copyin(data, d, sz, mode) != 0) {
2592 			err = EFAULT;
2593 			break;
2594 		}
2595 
2596 		err = med_get_t_size_ioctl((mddb_med_t_parm_t *)d, mode);
2597 
2598 		break;
2599 	}
2600 
2601 	case MD_MED_GET_T:
2602 	{
2603 		if (! (mode & FREAD))
2604 			return (EACCES);
2605 
2606 		sz = (sizeof (mddb_med_t_parm_t) - sizeof (mddb_med_t_ent_t)) +
2607 		    (sizeof (mddb_med_t_ent_t) * med_addr_tab_nents);
2608 		d = kmem_alloc(sz, KM_SLEEP);
2609 
2610 		if (ddi_copyin(data, d, sz, mode) != 0) {
2611 			err = EFAULT;
2612 			break;
2613 		}
2614 
2615 		err = med_get_t_ioctl((mddb_med_t_parm_t *)d, mode);
2616 
2617 		break;
2618 	}
2619 
2620 	case MD_MED_SET_T:
2621 	{
2622 		if (! (mode & FWRITE))
2623 			return (EACCES);
2624 
2625 		sz = (sizeof (mddb_med_t_parm_t) - sizeof (mddb_med_t_ent_t)) +
2626 		    (sizeof (mddb_med_t_ent_t) * med_addr_tab_nents);
2627 		d = kmem_alloc(sz, KM_SLEEP);
2628 
2629 		if (ddi_copyin(data, d, sz, mode) != 0) {
2630 			err = EFAULT;
2631 			break;
2632 		}
2633 
2634 		err = med_set_t_ioctl((mddb_med_t_parm_t *)d, mode);
2635 
2636 		break;
2637 	}
2638 
2639 	case  MD_GET_SETSTAT:
2640 	{
2641 		md_gs_stat_parm_t	*gsp;
2642 
2643 		if (! (mode & FREAD))
2644 			return (EACCES);
2645 
2646 		sz = sizeof (md_gs_stat_parm_t);
2647 		d = kmem_alloc(sz, KM_SLEEP);
2648 
2649 		if (ddi_copyin(data, d, sz, mode) != 0) {
2650 			err = EFAULT;
2651 			break;
2652 		}
2653 
2654 		gsp = (md_gs_stat_parm_t *)d;
2655 
2656 		if (gsp->gs_setno > (md_nsets - 1)) {
2657 			err = EINVAL;
2658 			break;
2659 		}
2660 
2661 		gsp->gs_status = md_set[gsp->gs_setno].s_status;
2662 
2663 		break;
2664 	}
2665 
2666 	case  MD_SETNMDID:
2667 	{
2668 		if (!(mode & FREAD))
2669 			return (EACCES);
2670 
2671 		sz = sizeof (mdnm_params_t);
2672 		d = kmem_alloc(sz, KM_SLEEP);
2673 
2674 		if (ddi_copyin(data, d, sz, mode) != 0) {
2675 			err = EFAULT;
2676 			break;
2677 		}
2678 
2679 		err = update_namespace_did_ioctl((mdnm_params_t *)d, mode);
2680 		break;
2681 
2682 	}
2683 	case  MD_IOCUPD_NM:
2684 	{
2685 		char *dname;
2686 		char *pname;
2687 		uint_t	devnamelen, pathnamelen;
2688 
2689 		if (!(mode & FREAD))
2690 			return (EACCES);
2691 
2692 		sz = sizeof (mdnm_params_t);
2693 		d = kmem_alloc(sz, KM_SLEEP);
2694 
2695 		if (ddi_copyin(data, d, sz, mode) != 0) {
2696 			err = EFAULT;
2697 			break;
2698 		}
2699 
2700 		devnamelen = ((mdnm_params_t *)d)->devname_len;
2701 		pathnamelen = ((mdnm_params_t *)d)->pathname_len;
2702 
2703 		if ((devnamelen > MAXPATHLEN) || (pathnamelen > MAXPATHLEN) ||
2704 		    (devnamelen == 0) || (pathnamelen == 0)) {
2705 			kmem_free(d, sz);
2706 			return (EINVAL);
2707 		}
2708 
2709 		/* alloc memory for devname */
2710 		dname = kmem_alloc(devnamelen + 1, KM_SLEEP);
2711 
2712 		if (ddi_copyin(
2713 		    (void *)(uintptr_t)((mdnm_params_t *)d)->devname,
2714 		    (void *)dname, devnamelen + 1, mode) != 0) {
2715 			err = EFAULT;
2716 			kmem_free(dname, devnamelen + 1);
2717 			break;
2718 		}
2719 
2720 		pname = kmem_alloc(pathnamelen + 1, KM_SLEEP);
2721 
2722 		if (ddi_copyin(
2723 		    (void *)(uintptr_t)((mdnm_params_t *)d)->pathname,
2724 		    (void *)pname, pathnamelen + 1, mode) != 0) {
2725 			err = EFAULT;
2726 			kmem_free(dname, devnamelen + 1);
2727 			kmem_free(pname, pathnamelen + 1);
2728 			break;
2729 		}
2730 
2731 		err = update_namespace_ioctl((mdnm_params_t *)d, dname, pname,
2732 		    mode);
2733 
2734 		kmem_free(dname, devnamelen + 1);
2735 		kmem_free(pname, pathnamelen + 1);
2736 		break;
2737 	}
2738 
2739 	case	MD_IOCUPD_LOCNM:
2740 	{
2741 		char *dname;
2742 		char *pname;
2743 		uint_t	devnamelen, pathnamelen;
2744 
2745 		if (!(mode & FREAD))
2746 			return (EACCES);
2747 
2748 		sz = sizeof (mdnm_params_t);
2749 		d = kmem_alloc(sz, KM_SLEEP);
2750 
2751 		if (ddi_copyin(data, d, sz, mode) != 0) {
2752 			err = EFAULT;
2753 			break;
2754 		}
2755 
2756 		devnamelen = ((mdnm_params_t *)d)->devname_len;
2757 		pathnamelen = ((mdnm_params_t *)d)->pathname_len;
2758 
2759 		if ((devnamelen > MAXPATHLEN) || (pathnamelen > MAXPATHLEN) ||
2760 		    (devnamelen == 0) || (pathnamelen == 0)) {
2761 			kmem_free(d, sz);
2762 			return (EINVAL);
2763 		}
2764 
2765 		/* alloc memory for devname */
2766 		dname = kmem_alloc(devnamelen + 1, KM_SLEEP);
2767 
2768 		if (ddi_copyin(
2769 		    (void *)(uintptr_t)((mdnm_params_t *)d)->devname,
2770 		    (void *)dname, devnamelen + 1, mode) != 0) {
2771 			err = EFAULT;
2772 			kmem_free(dname, devnamelen + 1);
2773 			break;
2774 		}
2775 
2776 		pname = kmem_alloc(pathnamelen + 1, KM_SLEEP);
2777 
2778 		if (ddi_copyin(
2779 		    (void *)(uintptr_t)((mdnm_params_t *)d)->pathname,
2780 		    (void *)pname, pathnamelen + 1, mode) != 0) {
2781 			err = EFAULT;
2782 			kmem_free(dname, devnamelen + 1);
2783 			kmem_free(pname, pathnamelen + 1);
2784 			break;
2785 		}
2786 
2787 		err = update_loc_namespace_ioctl((mdnm_params_t *)d, dname,
2788 		    pname, mode);
2789 
2790 		kmem_free(dname, devnamelen + 1);
2791 		kmem_free(pname, pathnamelen + 1);
2792 		break;
2793 	}
2794 
2795 	case  MD_SET_SETSTAT:
2796 	{
2797 #ifdef DEBUG
2798 		/* Can be used to set the s_status flags from user code */
2799 		md_gs_stat_parm_t	*gsp;
2800 
2801 		if (! (mode & FWRITE))
2802 			return (EACCES);
2803 
2804 		sz = sizeof (md_gs_stat_parm_t);
2805 		d = kmem_alloc(sz, KM_SLEEP);
2806 
2807 		if (ddi_copyin(data, d, sz, mode) != 0) {
2808 			err = EFAULT;
2809 			break;
2810 		}
2811 
2812 		gsp = (md_gs_stat_parm_t *)d;
2813 
2814 		if (gsp->gs_setno > (md_nsets - 1)) {
2815 			err = EINVAL;
2816 			break;
2817 		}
2818 
2819 		md_set[gsp->gs_setno].s_status = gsp->gs_status;
2820 
2821 #endif	/* DEBUG */
2822 		break;
2823 	}
2824 
2825 	case MD_IOCGET_DID:
2826 	{
2827 		if (! (mode & FREAD))
2828 			return (EACCES);
2829 
2830 		sz = sizeof (mdnm_params_t);
2831 		d = kmem_alloc(sz, KM_SLEEP);
2832 
2833 		if (ddi_copyin(data, d, sz, mode) != 0) {
2834 			err = EFAULT;
2835 			break;
2836 		}
2837 
2838 		err = getdid_ioctl((mdnm_params_t *)d, mode);
2839 		break;
2840 	}
2841 
2842 	case MD_IOCSET_DID:
2843 	{
2844 		if (! (mode & FWRITE))
2845 			return (EACCES);
2846 
2847 		sz = sizeof (mdnm_params_t);
2848 		d = kmem_alloc(sz, KM_SLEEP);
2849 
2850 		if (ddi_copyin(data, d, sz, mode) != 0) {
2851 			err = EFAULT;
2852 			break;
2853 		}
2854 
2855 		err = setdid_ioctl((mdnm_params_t *)d, mode);
2856 		break;
2857 	}
2858 
2859 	case MD_IOCGET_DIDMIN:
2860 	{
2861 		if (! (mode & FREAD))
2862 			return (EACCES);
2863 
2864 		sz = sizeof (mdnm_params_t);
2865 		d = kmem_alloc(sz, KM_SLEEP);
2866 
2867 		if (ddi_copyin(data, d, sz, mode) != 0) {
2868 			err = EFAULT;
2869 			break;
2870 		}
2871 
2872 		if (((mdnm_params_t *)d)->setno >= md_nsets) {
2873 			err = EINVAL;
2874 			break;
2875 		}
2876 
2877 		err = getdidmin_ioctl((mdnm_params_t *)d, mode);
2878 		break;
2879 	}
2880 
2881 	case MD_IOCDID_STAT:
2882 	{
2883 		if (!(mode & FREAD))
2884 			return (EACCES);
2885 
2886 		mddb_didstat_case = 1;
2887 
2888 		err = mddb_didstat_from_user(&d, data, mode, &ds_ctd_addr);
2889 
2890 		if (err) {
2891 			return (err);
2892 		}
2893 
2894 		err = didstat_ioctl((md_i_didstat_t *)d);
2895 		break;
2896 	}
2897 
2898 	case MD_UPGRADE_STAT:
2899 	{
2900 		if (! (mode & FREAD))
2901 			return (EACCES);
2902 
2903 		if (ddi_copyout((caddr_t)&md_in_upgrade, data,
2904 		    sizeof (int), mode) != 0) {
2905 			err = EFAULT;
2906 			break;
2907 		}
2908 		break;
2909 	}
2910 
2911 	case MD_SETMASTER:
2912 	{
2913 		if (! (mode & FREAD))
2914 			return (EACCES);
2915 
2916 		sz = sizeof (mddb_setmaster_config_t);
2917 		d = kmem_alloc(sz, KM_SLEEP);
2918 
2919 		if (ddi_copyin(data, d, sz, mode) != 0) {
2920 			err = EFAULT;
2921 			break;
2922 		}
2923 
2924 		err = mddb_setmaster_ioctl((mddb_setmaster_config_t *)d);
2925 		break;
2926 	}
2927 
2928 	case MD_MN_SET_DOORH:
2929 	{
2930 	/* This ioctl sets the global kernel variable mdmn_door_handle */
2931 		if (ddi_copyin(data, &mdmn_door_did, sizeof (int), mode) != 0) {
2932 			err = EFAULT;
2933 		} else {
2934 			err = 0;
2935 		}
2936 		mdmn_door_handle = door_ki_lookup(mdmn_door_did);
2937 
2938 		break;
2939 	}
2940 
2941 #ifdef DEBUG
2942 	case MD_MN_CHECK_DOOR1:
2943 	{
2944 	/* This ioctl sends a message through a previously opened door */
2945 		int		ret;
2946 		int		msg_test = 11111111;
2947 		int		nloops = 0;
2948 		set_t		setno;
2949 		md_mn_kresult_t	*result;
2950 		uint_t		flags = MD_MSGF_NO_LOG | MD_MSGF_NO_BCAST;
2951 
2952 		result = kmem_zalloc(sizeof (md_mn_kresult_t), KM_SLEEP);
2953 		if (ddi_copyin(data, &nloops, sizeof (int), mode) != 0) {
2954 			err = EFAULT;
2955 		} else {
2956 			err = 0;
2957 		}
2958 
2959 		/*
2960 		 * This is a way to tell ksend_message() to use different sets.
2961 		 * Odd numbers go to set 1 even numbers go to set 2
2962 		 */
2963 		if (nloops & 0x1) {
2964 			setno = 1;
2965 		} else {
2966 			setno = 2;
2967 		}
2968 		while (nloops--)  {
2969 			ret = mdmn_ksend_message(
2970 			    setno,
2971 			    MD_MN_MSG_TEST1,
2972 			    flags,
2973 			    (char *)&msg_test,
2974 			    sizeof (msg_test),
2975 			    result);
2976 
2977 			if (ret != 0) {
2978 				printf("mdmn_ksend_message failed (%d)\n", ret);
2979 			}
2980 		}
2981 		kmem_free(result, sizeof (md_mn_kresult_t));
2982 
2983 		break;
2984 	}
2985 
2986 	case MD_MN_CHECK_DOOR2:
2987 	{
2988 	/* This ioctl sends a message through a previously opened door */
2989 		int		ret;
2990 		int		msg_test = 22222222;
2991 		int		nloops = 0;
2992 		md_mn_kresult_t	*result;
2993 		set_t		setno;
2994 		uint_t		flags = MD_MSGF_NO_LOG;
2995 
2996 		result = kmem_zalloc(sizeof (md_mn_kresult_t), KM_SLEEP);
2997 		if (ddi_copyin(data, &nloops, sizeof (int), mode) != 0) {
2998 			err = EFAULT;
2999 		} else {
3000 			err = 0;
3001 		}
3002 		/*
3003 		 * This is a way to tell ksend_message() to use different sets.
3004 		 * Odd numbers go to set 1 even numbers go to set 2
3005 		 */
3006 		if (nloops & 0x1) {
3007 			setno = 1;
3008 		} else {
3009 			setno = 2;
3010 		}
3011 		while (nloops--)  {
3012 			ret = mdmn_ksend_message(
3013 			    setno,
3014 			    MD_MN_MSG_TEST2,
3015 			    flags,
3016 			    (char *)&msg_test,
3017 			    sizeof (msg_test),
3018 			    result);
3019 
3020 			if (ret != 0) {
3021 				printf("mdmn_ksend_message failed (%d)\n", ret);
3022 			}
3023 		}
3024 		kmem_free(result, sizeof (md_mn_kresult_t));
3025 
3026 		break;
3027 	}
3028 #endif
3029 
3030 	case MD_MN_OPEN_TEST:
3031 	{
3032 		md_clu_open_t	*p;
3033 		minor_t		mnum;
3034 
3035 		sz = sizeof (md_clu_open_t);
3036 		d = kmem_alloc(sz, KM_SLEEP);
3037 
3038 		if (ddi_copyin(data, d, sizeof (md_clu_open_t), mode) != 0) {
3039 			err = EFAULT;
3040 			break;
3041 		}
3042 
3043 		p = (md_clu_open_t *)d;
3044 		mnum = md_getminor(p->clu_dev);
3045 
3046 		if ((err = verify_minor(mnum)) != 0) {
3047 			if (err == EINVAL)
3048 				(void) mdmderror(&p->clu_mde, MDE_INVAL_UNIT,
3049 				    mnum);
3050 			break;
3051 		}
3052 		err = md_clu_ioctl(p);
3053 		break;
3054 	}
3055 
3056 	case MD_MN_SET_NODEID:
3057 	{
3058 		if (! (mode & FWRITE))
3059 			return (EACCES);
3060 
3061 		sz = sizeof (mddb_set_node_params_t);
3062 		d = kmem_alloc(sz, KM_SLEEP);
3063 
3064 		if (ddi_copyin(data, d, sz, mode) != 0) {
3065 			err = EFAULT;
3066 			break;
3067 		}
3068 		snp = (mddb_set_node_params_t *)d;
3069 
3070 		if (snp->sn_setno >= md_nsets) {
3071 			err = EINVAL;
3072 			break;
3073 		}
3074 
3075 		md_set[snp->sn_setno].s_nodeid = snp->sn_nodeid;
3076 
3077 		if (md_mn_mynode_id == MD_MN_INVALID_NID)
3078 			md_mn_mynode_id = snp->sn_nodeid;
3079 #ifdef DEBUG
3080 		else if (md_mn_mynode_id != snp->sn_nodeid)
3081 			cmn_err(CE_WARN, "Previously set nodeid 0x%x for this"
3082 			    "node doesn't match nodeid being set 0x%x\n",
3083 			    md_mn_mynode_id, snp->sn_nodeid);
3084 #endif /* DEBUG */
3085 		err = 0;
3086 		break;
3087 	}
3088 	case MD_IOCGUNIQMSGID:
3089 	{
3090 		md_mn_msgid_t msgid;
3091 		struct timeval32 tv;
3092 
3093 		if (! (mode & FREAD))
3094 			return (EACCES);
3095 
3096 		uniqtime32(&tv);
3097 
3098 		/* high 32 bits are the seconds */
3099 		msgid.mid_time = (u_longlong_t)tv.tv_sec << 32;
3100 		/* low 32 bits are the micro secs */
3101 		msgid.mid_time |= tv.tv_usec;
3102 
3103 		msgid.mid_nid = md_mn_mynode_id;
3104 		/*
3105 		 * This is never called for submessages, so we better
3106 		 * null out the submessage ID
3107 		 */
3108 		msgid.mid_smid = 0;
3109 
3110 		if (ddi_copyout((caddr_t)&msgid, data, sizeof (msgid), mode)
3111 		    != 0) {
3112 			err = EFAULT;
3113 			break;
3114 		}
3115 		break;
3116 	}
3117 
3118 	/*
3119 	 * suspend the IO's for a given set number.
3120 	 *
3121 	 * If setno = 0 is specified, try operation on all snarfed MN disksets.
3122 	 * If there are no snarfed MN disksets, then return success.
3123 	 *
3124 	 * If a specific set number is given, then return EINVAL if unable
3125 	 * to perform operation.
3126 	 */
3127 	case MD_MN_SUSPEND_SET:
3128 	{
3129 		set_t	setno;
3130 		int	rval = 0;
3131 		int	i;
3132 
3133 		if (! (mode & FWRITE))
3134 			return (EACCES);
3135 
3136 		if (ddi_copyin(data, &setno, sizeof (set_t), mode) != 0) {
3137 			return (EFAULT);
3138 		}
3139 		if (setno >= MD_MAXSETS) {
3140 			return (EINVAL);
3141 		}
3142 
3143 		mutex_enter(&md_mx);
3144 		if (setno == 0) {
3145 			/* if set number is 0, we walk all sets */
3146 			for (i = 1; i <= (MD_MAXSETS - 1); i++) {
3147 				if ((md_set[i].s_status &
3148 				    (MD_SET_SNARFED|MD_SET_MNSET)) ==
3149 				    (MD_SET_SNARFED|MD_SET_MNSET)) {
3150 					md_set[i].s_status |= MD_SET_HALTED;
3151 				}
3152 			}
3153 		} else {
3154 			/* If unable to halt specified set, set EINVAL */
3155 			if ((md_set[setno].s_status &
3156 			    (MD_SET_SNARFED|MD_SET_MNSET)) ==
3157 			    (MD_SET_SNARFED|MD_SET_MNSET)) {
3158 				md_set[setno].s_status |= MD_SET_HALTED;
3159 			} else {
3160 				rval = EINVAL;
3161 			}
3162 		}
3163 		mutex_exit(&md_mx);
3164 		return (rval);
3165 	}
3166 
3167 	/*
3168 	 * resume the IO's for a given set number.
3169 	 *
3170 	 * If setno = 0 is specified, try operation on all snarfed MN disksets.
3171 	 * If there are no snarfed MN disksets, then return success.
3172 	 *
3173 	 * If a specific set number is given, then return EINVAL if unable
3174 	 * to perform operation.
3175 	 */
3176 	case MD_MN_RESUME_SET:
3177 	{
3178 		set_t	setno;
3179 		int	resumed_set = 0;
3180 		int	rval = 0;
3181 		int	i;
3182 
3183 		if (! (mode & FWRITE))
3184 			return (EACCES);
3185 
3186 		if (ddi_copyin(data, &setno, sizeof (set_t), mode) != 0) {
3187 			return (EFAULT);
3188 		}
3189 		if (setno >= MD_MAXSETS) {
3190 			return (EINVAL);
3191 		}
3192 
3193 		/* if 0 is specified as the set number, we walk all sets */
3194 		mutex_enter(&md_mx);
3195 		if (setno == 0) {
3196 			/* if set number is 0, we walk all sets */
3197 			for (i = 1; i <= (MD_MAXSETS - 1); i++) {
3198 				if ((md_set[i].s_status &
3199 				    (MD_SET_SNARFED|MD_SET_MNSET)) ==
3200 				    (MD_SET_SNARFED|MD_SET_MNSET)) {
3201 					md_set[i].s_status &= ~MD_SET_HALTED;
3202 					resumed_set = 1;
3203 				}
3204 			}
3205 		} else {
3206 			/* If unable to resume specified set, set EINVAL */
3207 			if ((md_set[setno].s_status &
3208 			    (MD_SET_SNARFED|MD_SET_MNSET)) ==
3209 			    (MD_SET_SNARFED|MD_SET_MNSET)) {
3210 				md_set[setno].s_status &= ~MD_SET_HALTED;
3211 				resumed_set = 1;
3212 			} else {
3213 				rval = EINVAL;
3214 			}
3215 		}
3216 
3217 		/*
3218 		 * In case we actually resumed at least one set,
3219 		 * Inform all threads waiting for this change
3220 		 */
3221 		if (resumed_set == 1) {
3222 			cv_broadcast(&md_cv);
3223 		}
3224 
3225 		mutex_exit(&md_mx);
3226 		return (rval);
3227 	}
3228 
3229 	case MD_MN_MDDB_PARSE:
3230 	{
3231 		if (! (mode & FWRITE))
3232 			return (EACCES);
3233 
3234 		sz = sizeof (mddb_parse_parm_t);
3235 		d = kmem_alloc(sz, KM_SLEEP);
3236 
3237 		if (ddi_copyin(data, d, sz, mode) != 0) {
3238 			err = EFAULT;
3239 			break;
3240 		}
3241 		err = mddb_parse((mddb_parse_parm_t *)d);
3242 		break;
3243 
3244 	}
3245 
3246 	case MD_MN_MDDB_BLOCK:
3247 	{
3248 		if (! (mode & FWRITE))
3249 			return (EACCES);
3250 
3251 		sz = sizeof (mddb_block_parm_t);
3252 		d = kmem_alloc(sz, KM_SLEEP);
3253 
3254 		if (ddi_copyin(data, d, sz, mode) != 0) {
3255 			err = EFAULT;
3256 			break;
3257 		}
3258 		err = mddb_block((mddb_block_parm_t *)d);
3259 		break;
3260 
3261 	}
3262 
3263 	case MD_MN_MDDB_OPTRECFIX:
3264 	{
3265 		if (! (mode & FWRITE))
3266 			return (EACCES);
3267 
3268 		sz = sizeof (mddb_optrec_parm_t);
3269 		d = kmem_alloc(sz, KM_SLEEP);
3270 
3271 		if (ddi_copyin(data, d, sz, mode) != 0) {
3272 			err = EFAULT;
3273 			break;
3274 		}
3275 		err = mddb_optrecfix((mddb_optrec_parm_t *)d);
3276 		break;
3277 
3278 	}
3279 
3280 	case MD_MN_CHK_WRT_MDDB:
3281 	{
3282 		if (! (mode & FWRITE))
3283 			return (EACCES);
3284 
3285 		sz = sizeof (mddb_config_t);
3286 		d = kmem_alloc(sz, KM_SLEEP);
3287 
3288 		if (ddi_copyin(data, d, sz, mode) != 0) {
3289 			err = EFAULT;
3290 			break;
3291 		}
3292 
3293 		err = mddb_check_write_ioctl((mddb_config_t *)d);
3294 		break;
3295 	}
3296 
3297 	case MD_MN_SET_SETFLAGS:
3298 	case MD_MN_GET_SETFLAGS:
3299 	{
3300 		if (! (mode & FREAD))
3301 			return (EACCES);
3302 
3303 		sz = sizeof (mddb_setflags_config_t);
3304 		d = kmem_alloc(sz, KM_SLEEP);
3305 
3306 		if (ddi_copyin(data, d, sz, mode) != 0) {
3307 			err = EFAULT;
3308 			break;
3309 		}
3310 
3311 		err = mddb_setflags_ioctl((mddb_setflags_config_t *)d);
3312 		break;
3313 	}
3314 
3315 	case MD_MN_COMMD_ERR:
3316 	{
3317 		md_mn_commd_err_t *cmp;
3318 		char *msg;
3319 
3320 		sz = sizeof (md_mn_commd_err_t);
3321 		d = kmem_zalloc(sz, KM_SLEEP);
3322 
3323 		if (ddi_copyin(data, d, sz, mode) != 0) {
3324 			err = EFAULT;
3325 			break;
3326 		}
3327 
3328 		cmp = (md_mn_commd_err_t *)d;
3329 		if (cmp->size > MAXPATHLEN) {
3330 			err = EINVAL;
3331 			break;
3332 		}
3333 
3334 		msg = (char *)kmem_zalloc(cmp->size + 1, KM_SLEEP);
3335 		if (ddi_copyin((caddr_t)(uintptr_t)cmp->md_message, msg,
3336 		    cmp->size, mode) != 0) {
3337 			kmem_free(msg, cmp->size + 1);
3338 			err = EFAULT;
3339 			break;
3340 		}
3341 		cmn_err(CE_WARN, "%s\n", msg);
3342 		kmem_free(msg, cmp->size + 1);
3343 		break;
3344 	}
3345 
3346 	case MD_IOCMAKE_DEV:
3347 	{
3348 		if (! (mode & FWRITE))
3349 			return (EACCES);
3350 
3351 		sz = sizeof (md_mkdev_params_t);
3352 
3353 		if ((d = kmem_alloc(sz, KM_NOSLEEP)) == NULL)
3354 			return (ENOMEM);
3355 
3356 		if (ddi_copyin(data, d, sz, mode) != 0) {
3357 			err = EFAULT;
3358 			break;
3359 		}
3360 
3361 		err = mkdev_ioctl((md_mkdev_params_t *)d);
3362 		break;
3363 	}
3364 
3365 	case MD_IOCREM_DEV:
3366 	{
3367 		set_t	setno;
3368 
3369 		if (! (mode & FWRITE))
3370 			return (EACCES);
3371 
3372 		sz = sizeof (minor_t);
3373 
3374 		d = kmem_zalloc(sz, KM_SLEEP);
3375 
3376 		if (ddi_copyin(data, d, sz, mode) != 0) {
3377 			err = EFAULT;
3378 			break;
3379 		}
3380 
3381 		/*
3382 		 * This ioctl is called to cleanup the device name
3383 		 * space when metainit fails or -n is invoked
3384 		 * In this case, reclaim the dispatched un slot
3385 		 */
3386 		setno = MD_MIN2SET(*(minor_t *)d);
3387 		if (setno >= md_nsets) {
3388 			err = EINVAL;
3389 			break;
3390 		} else if (md_set[setno].s_un_next <= 0) {
3391 			err = EFAULT;
3392 			break;
3393 		} else {
3394 			md_set[setno].s_un_next--;
3395 		}
3396 
3397 		/*
3398 		 * Attempt to remove the assocated device node
3399 		 */
3400 		md_remove_minor_node(*(minor_t *)d);
3401 		break;
3402 	}
3403 
3404 	/*
3405 	 * Update md_mn_commd_present global to reflect presence or absence of
3406 	 * /usr/sbin/rpc.mdcommd. This allows us to determine if an RPC failure
3407 	 * is expected during a mdmn_ksend_message() handshake. If the commd is
3408 	 * not present then an RPC failure is acceptable. If the commd _is_
3409 	 * present then an RPC failure means we have an inconsistent view across
3410 	 * the cluster.
3411 	 */
3412 	case MD_MN_SET_COMMD_RUNNING:
3413 	{
3414 		if (! (mode & FWRITE))
3415 			return (EACCES);
3416 
3417 		md_mn_commd_present = (int)(intptr_t)data;
3418 		err = 0;
3419 		break;
3420 	}
3421 
3422 	case MD_IOCIMP_LOAD:
3423 	{
3424 		if (! (mode & FWRITE))
3425 			return (EACCES);
3426 
3427 		mddb_config_case = 1;
3428 
3429 		err = mddb_config_from_user(&d, data, mode, &c_devid_addr,
3430 		    &c_old_devid_addr);
3431 
3432 		if (err) {
3433 			return (err);
3434 		}
3435 
3436 		err = md_imp_snarf_set((mddb_config_t *)d);
3437 		break;
3438 
3439 	}
3440 
3441 	case MD_DB_LBINITTIME:
3442 	{
3443 		if (! (mode & FWRITE))
3444 			return (EACCES);
3445 
3446 		mddb_config_case = 1;
3447 
3448 		err = mddb_config_from_user(&d, data, mode, &c_devid_addr,
3449 		    &c_old_devid_addr);
3450 
3451 		if (err)
3452 			return (err);
3453 
3454 		err = get_lb_inittime_ioctl((mddb_config_t *)d);
3455 		break;
3456 	}
3457 	case MD_IOCUPDATE_NM_RR_DID:
3458 	{
3459 		if (! (mode & FWRITE))
3460 			return (EACCES);
3461 
3462 		mddb_config_case = 1;
3463 
3464 		err = mddb_config_from_user(&d, data, mode, &c_devid_addr,
3465 		    &c_old_devid_addr);
3466 
3467 		if (err)
3468 			return (err);
3469 
3470 		err = md_update_nm_rr_did_ioctl((mddb_config_t *)d);
3471 		break;
3472 	}
3473 	default:
3474 		return (ENOTTY);	/* used by next level up */
3475 	}
3476 
3477 	/*
3478 	 * copyout and free any args
3479 	 */
3480 	if (mddb_config_case) {
3481 		err_to_user = mddb_config_to_user(d, data, mode, c_devid_addr,
3482 		    c_old_devid_addr);
3483 	} else if (mddb_didstat_case) {
3484 		err_to_user = mddb_didstat_to_user(d, data, mode, ds_ctd_addr);
3485 	} else if (sz != 0) {
3486 		if (ddi_copyout(d, data, sz, mode) != 0) {
3487 			err = EFAULT;
3488 		}
3489 		kmem_free(d, sz);
3490 	}
3491 
3492 	if (err)
3493 		return (err);
3494 	return (err_to_user);
3495 }
3496 
3497 int
3498 md_admin_ioctl(md_dev64_t dev, int cmd, caddr_t data, int mode, IOLOCK *lockp)
3499 {
3500 	md_driver_t	drv;
3501 	int		modindex;
3502 	int		err;
3503 
3504 	/*
3505 	 * see if we can do this without involving the subdriver
3506 	 */
3507 	if ((err = md_base_ioctl(dev, cmd, data, mode, lockp)) != ENOTTY)
3508 		return (err);
3509 
3510 	/*
3511 	 * see what subdriver we need
3512 	 */
3513 	if (! ISMDIOC(cmd))
3514 		return (ENOTTY);
3515 
3516 	if ((!NODBNEEDED(cmd)) && md_snarf_db_set(MD_LOCAL_SET, NULL) != 0)
3517 		return (ENODEV);
3518 
3519 	if (ddi_copyin(data, (caddr_t)&drv, sizeof (drv), mode) != 0)
3520 		return (EFAULT);
3521 
3522 	/*
3523 	 * load subdriver if not already loaded
3524 	 */
3525 	if (((modindex = md_getmodindex(&drv, 0, NODBNEEDED(cmd))) == -1) ||
3526 	    (md_ops[modindex]->md_ioctl == NULL))
3527 		return (ENOTTY);
3528 
3529 	/*
3530 	 * dispatch to subdriver
3531 	 */
3532 	return ((*md_ops[modindex]->md_ioctl)(md_dev64_to_dev(dev), cmd, data,
3533 	    mode, lockp));
3534 }
3535 
3536 void
3537 md_get_geom(
3538 	md_unit_t	*un,
3539 	struct dk_geom	*gp
3540 )
3541 {
3542 	diskaddr_t		tb = un->c.un_total_blocks;
3543 	uint_t			cylsize = un->c.un_nhead * un->c.un_nsect;
3544 
3545 	bzero((caddr_t)gp, sizeof (*gp));
3546 	gp->dkg_nhead = un->c.un_nhead;
3547 	gp->dkg_nsect = un->c.un_nsect;
3548 	gp->dkg_rpm = un->c.un_rpm;
3549 	gp->dkg_write_reinstruct = un->c.un_wr_reinstruct;
3550 	gp->dkg_read_reinstruct = un->c.un_rd_reinstruct;
3551 	gp->dkg_ncyl = (ushort_t)(tb / cylsize);
3552 	if (! (un->c.un_flag & MD_LABELED))	/* skip first cyl */
3553 		gp->dkg_ncyl += 1;
3554 	gp->dkg_pcyl = gp->dkg_ncyl;
3555 }
3556 
3557 void
3558 md_get_vtoc(md_unit_t *un, struct vtoc *vtoc)
3559 {
3560 	caddr_t			v;
3561 	mddb_recstatus_t	status;
3562 	struct vtoc32		*vt32;
3563 
3564 	/*
3565 	 * Return vtoc structure fields in the provided VTOC area, addressed
3566 	 * by *vtoc.
3567 	 *
3568 	 */
3569 
3570 	if (un->c.un_vtoc_id) {
3571 		status = mddb_getrecstatus(un->c.un_vtoc_id);
3572 		if (status == MDDB_OK) {
3573 			v = mddb_getrecaddr(un->c.un_vtoc_id);
3574 			/* if this seems to be a sane vtoc, just copy it ... */
3575 			if (((struct vtoc *)v)->v_sanity == VTOC_SANE) {
3576 				bcopy(v, (caddr_t)vtoc, sizeof (struct vtoc));
3577 			} else {
3578 				/* ... else assume a vtoc32 was stored here */
3579 				vt32 = (struct vtoc32 *)v;
3580 				vtoc32tovtoc((*vt32), (*vtoc));
3581 			}
3582 			if (un->c.un_flag & MD_LABELED)
3583 				vtoc->v_part[0].p_start = 0;
3584 			else
3585 				vtoc->v_part[0].p_start =
3586 				    un->c.un_nhead * un->c.un_nsect;
3587 			vtoc->v_part[0].p_size = un->c.un_total_blocks;
3588 			vtoc->v_version = V_VERSION;
3589 			vtoc->v_sectorsz = DEV_BSIZE;
3590 			return;
3591 		}
3592 
3593 		un->c.un_vtoc_id = 0;
3594 		mddb_commitrec_wrapper(un->c.un_record_id);
3595 	}
3596 
3597 	bzero((caddr_t)vtoc, sizeof (struct vtoc));
3598 	vtoc->v_sanity = VTOC_SANE;
3599 	vtoc->v_nparts = 1;
3600 	vtoc->v_version = V_VERSION;
3601 	vtoc->v_sectorsz = DEV_BSIZE;
3602 	if (un->c.un_flag & MD_LABELED)
3603 		vtoc->v_part[0].p_start = 0;
3604 	else
3605 		vtoc->v_part[0].p_start = un->c.un_nhead * un->c.un_nsect;
3606 	vtoc->v_part[0].p_size = un->c.un_total_blocks;
3607 }
3608 
3609 int
3610 md_set_vtoc(md_unit_t *un, struct vtoc *vtoc)
3611 {
3612 
3613 	struct partition	*vpart;
3614 	int			i;
3615 	mddb_recid_t		recid;
3616 	mddb_recid_t		recids[3];
3617 	mddb_recstatus_t	status;
3618 	caddr_t			v;
3619 	daddr_t			sb;
3620 
3621 	/*
3622 	 * Sanity-check the vtoc
3623 	 */
3624 	if (vtoc->v_sanity != VTOC_SANE || vtoc->v_nparts != 1)
3625 		return (EINVAL);
3626 
3627 	/* don't allow to create a vtoc for a big metadevice */
3628 	if (un->c.un_revision & MD_64BIT_META_DEV)
3629 		return (ENOTSUP);
3630 	/*
3631 	 * Validate the partition table
3632 	 */
3633 	vpart = vtoc->v_part;
3634 	for (i = 0; i < V_NUMPAR; i++, vpart++) {
3635 		if (i == 0) {
3636 			if (un->c.un_flag & MD_LABELED)
3637 				sb = 0;
3638 			else
3639 				sb = un->c.un_nhead * un->c.un_nsect;
3640 			if (vpart->p_start != sb)
3641 				return (EINVAL);
3642 			if (vpart->p_size != (long)un->c.un_total_blocks)
3643 				return (EINVAL);
3644 			continue;
3645 		}
3646 		/* all other partitions must be zero */
3647 		if (vpart->p_start != 0)
3648 			return (EINVAL);
3649 		if (vpart->p_size != 0)
3650 			return (EINVAL);
3651 	}
3652 
3653 	if (un->c.un_vtoc_id) {
3654 		recid = un->c.un_vtoc_id;
3655 		status = mddb_getrecstatus(recid);
3656 		if (status == MDDB_OK) {
3657 			/*
3658 			 * If there's enough space in the record, and the
3659 			 * existing record is a vtoc record (not EFI),
3660 			 * we just can use the existing space.
3661 			 * Otherwise, we create a new MDDB_VTOC record for
3662 			 * this unit.
3663 			 */
3664 			if ((mddb_getrecsize(recid) >= sizeof (struct vtoc)) &&
3665 			    ((un->c.un_flag & MD_EFILABEL) == 0)) {
3666 				v = mddb_getrecaddr(recid);
3667 				bcopy((caddr_t)vtoc, v, sizeof (struct vtoc));
3668 				mddb_commitrec_wrapper(recid);
3669 				recids[0] = recid;
3670 				recids[1] = un->c.un_record_id;
3671 				recids[2] = 0;
3672 				un->c.un_flag &= ~MD_EFILABEL;
3673 				mddb_commitrecs_wrapper(recids);
3674 				return (0);
3675 			}
3676 
3677 			un->c.un_vtoc_id = 0;
3678 			mddb_commitrec_wrapper(un->c.un_record_id);
3679 			mddb_deleterec_wrapper(recid);
3680 		}
3681 	}
3682 
3683 	recid = mddb_createrec(sizeof (struct vtoc), MDDB_VTOC, 0,
3684 	    MD_CRO_32BIT, MD_UN2SET(un));
3685 
3686 	if (recid < 0) {
3687 		return (ENOSPC);
3688 	}
3689 
3690 	recids[0] = recid;
3691 	recids[1] = un->c.un_record_id;
3692 	recids[2] = 0;
3693 	v = mddb_getrecaddr(recid);
3694 	bcopy((caddr_t)vtoc, v, sizeof (struct vtoc));
3695 
3696 	un->c.un_vtoc_id = recid;
3697 	un->c.un_flag &= ~MD_EFILABEL;
3698 	mddb_commitrecs_wrapper(recids);
3699 	return (0);
3700 }
3701 
3702 
3703 void
3704 md_get_cgapart(md_unit_t *un, struct dk_map *dkmapp)
3705 {
3706 
3707 	/* skip the first cyl */
3708 	dkmapp->dkl_cylno = 1;
3709 
3710 	dkmapp->dkl_nblk = (daddr_t)un->c.un_total_blocks;
3711 }
3712 
3713 static struct uuid md_efi_reserved = EFI_RESERVED;
3714 
3715 /*
3716  * md_get_efi
3717  * INPUT:
3718  *	un; the md_unit
3719  *	buf; the buffer that is preallocated by the calling routine and
3720  *		capable of taking the EFI label for this unit
3721  * OUTPUT:
3722  *	A filled buffer, containing one struct efi_gpt followed by one
3723  *		struct efi_gpe, because a md efi only has one valid partition
3724  *		We fetch that date either from the mddb (like vtoc)
3725  *		or we a fake an EFI label.
3726  *
3727  * NOTES:
3728  *	We do not provide for any global unique identifiers,
3729  *	We also use the field c.un_vtoc_id, as the semantic is very similar
3730  *	When we are called, it's already checked, that this unit has an EFI
3731  *		label and not a vtoc
3732  */
3733 
3734 void
3735 md_get_efi(md_unit_t *un, char *buf)
3736 {
3737 	caddr_t		v;
3738 	efi_gpt_t	*efi_header = (efi_gpt_t *)buf;
3739 	efi_gpe_t	*efi_part = (efi_gpe_t *)(buf + sizeof (efi_gpt_t));
3740 	mddb_recstatus_t	status;
3741 
3742 	/* first comes the header */
3743 	efi_header->efi_gpt_Signature = LE_64(EFI_SIGNATURE);
3744 	efi_header->efi_gpt_HeaderSize = LE_32(sizeof (efi_gpt_t));
3745 	efi_header->efi_gpt_NumberOfPartitionEntries = LE_32(1);
3746 	efi_header->efi_gpt_SizeOfPartitionEntry = LE_32(sizeof (efi_gpe_t));
3747 	efi_header->efi_gpt_LastUsableLBA = LE_64(un->c.un_total_blocks - 1);
3748 	efi_header->efi_gpt_FirstUsableLBA = 0;
3749 	efi_header->efi_gpt_Revision = LE_32(EFI_VERSION_CURRENT);
3750 
3751 	/*
3752 	 * We don't fill out any of these:
3753 	 *
3754 	 * efi_header->efi_gpt_HeaderCRC32;
3755 	 * efi_header->efi_gpt_DiskGUID;
3756 	 * efi_header->efi_gpt_PartitionEntryArrayCRC32;
3757 	 * efi_header->efi_gpt_Reserved1;
3758 	 * efi_header->efi_gpt_MyLBA;
3759 	 * efi_header->efi_gpt_AlternateLBA;
3760 	 * efi_header->efi_gpt_Reserved2[LEN_EFI_PAD];
3761 	 * efi_header->efi_gpt_PartitionEntryLBA;
3762 	 */
3763 
3764 	/*
3765 	 * We copy back one partition, of type reserved,
3766 	 * which may contain the name of the metadevice
3767 	 * (this is what was used to be v_volume for a vtoc device)
3768 	 * if no name is stored in the vtoc record, we hand an empty name
3769 	 * to the user
3770 	 */
3771 
3772 	UUID_LE_CONVERT(efi_part->efi_gpe_PartitionTypeGUID, md_efi_reserved);
3773 	if (un->c.un_flag & MD_LABELED)
3774 		efi_part->efi_gpe_StartingLBA = LE_64(1ULL);
3775 	else
3776 		efi_part->efi_gpe_StartingLBA = 0;
3777 
3778 	efi_part->efi_gpe_EndingLBA = LE_64(un->c.un_total_blocks - 1);
3779 
3780 	if (un->c.un_vtoc_id) {
3781 		status = mddb_getrecstatus(un->c.un_vtoc_id);
3782 		if (status == MDDB_OK) {
3783 			v = mddb_getrecaddr(un->c.un_vtoc_id);
3784 			bcopy(v, (caddr_t)&(efi_part->efi_gpe_PartitionName),
3785 			    MD_EFI_PARTNAME_BYTES);
3786 			return;
3787 		}
3788 		un->c.un_vtoc_id = 0;
3789 		mddb_commitrec_wrapper(un->c.un_record_id);
3790 	}
3791 
3792 	/*
3793 	 * We don't fill out any of these
3794 	 * efi_part->efi_gpe_UniquePartitionGUID
3795 	 * efi_part->efi_gpe_Attributes
3796 	 */
3797 }
3798 
3799 
3800 /*
3801  * md_set_efi
3802  * INPUT:
3803  *	un; a md_unit
3804  *	buf; a buffer that is holding an EFI label for this unit
3805  *
3806  * PURPOSE:
3807  *	Perform some sanity checks on the EFI label provided,
3808  *	Then store efi_gpe_PartitionName in the mddb
3809  *	and link the unit's c.un_vtoc_id field to it.
3810  *
3811  * RETURN:
3812  *	EINVAL if any of the sanity checks fail
3813  *	0 on succes
3814  *
3815  * NOTES:
3816  *	We do not provide for any global unique identifiers,
3817  *	We also use the field c.un_vtoc_id, as the semantic is very similar
3818  *	When we are called, it's already checked, that this unit has an EFI
3819  *		label and not a vtoc
3820  */
3821 
3822 
3823 int
3824 md_set_efi(md_unit_t *un, char *buf)
3825 {
3826 
3827 	mddb_recid_t		recid;
3828 	mddb_recid_t		recids[3];
3829 	mddb_recstatus_t	status;
3830 	caddr_t			v;
3831 	efi_gpt_t	*efi_header = (efi_gpt_t *)buf;
3832 	efi_gpe_t	*efi_part = (efi_gpe_t *)(buf + sizeof (efi_gpt_t));
3833 	struct uuid	md_efi_reserved_le;
3834 
3835 	/*
3836 	 * Sanity-check the EFI label
3837 	 */
3838 	if ((efi_header->efi_gpt_Signature != LE_64(EFI_SIGNATURE)) ||
3839 	    (efi_header->efi_gpt_NumberOfPartitionEntries != LE_32(1)))
3840 		return (EINVAL);
3841 
3842 	UUID_LE_CONVERT(md_efi_reserved_le, md_efi_reserved);
3843 
3844 	/*
3845 	 * Validate the partition
3846 	 */
3847 	if (efi_part->efi_gpe_StartingLBA != 0 ||
3848 	    efi_part->efi_gpe_EndingLBA != LE_64(un->c.un_total_blocks - 1) ||
3849 	    bcmp(&efi_part->efi_gpe_PartitionTypeGUID, &md_efi_reserved_le,
3850 	    sizeof (struct uuid))) {
3851 		return (EINVAL);
3852 	}
3853 	/*
3854 	 * If no name is specified, we have nothing to do and return success.
3855 	 * because efi_gpe_PartitionName is in unicode form, we have to
3856 	 * check the first two bytes of efi_gpe_PartitionName.
3857 	 */
3858 	if (((char *)(uintptr_t)efi_part->efi_gpe_PartitionName[0] == NULL) &&
3859 	    ((char *)(uintptr_t)efi_part->efi_gpe_PartitionName[1] == NULL)) {
3860 		return (0);
3861 	}
3862 
3863 	if (un->c.un_vtoc_id) {
3864 		recid = un->c.un_vtoc_id;
3865 		status = mddb_getrecstatus(recid);
3866 		if (status == MDDB_OK) {
3867 			/*
3868 			 * If there's enough space in the record, and the
3869 			 * existing record is an EFI record (not vtoc),
3870 			 * we just can use the existing space.
3871 			 * Otherwise, we create a new MDDB_EFILABEL record for
3872 			 * this unit.
3873 			 */
3874 			if ((mddb_getrecsize(recid) >= MD_EFI_PARTNAME_BYTES) &&
3875 			    (un->c.un_flag & MD_EFILABEL))  {
3876 				v = mddb_getrecaddr(recid);
3877 				bcopy((caddr_t)&efi_part->efi_gpe_PartitionName,
3878 				    v, MD_EFI_PARTNAME_BYTES);
3879 				mddb_commitrec_wrapper(recid);
3880 				return (0);
3881 			}
3882 
3883 			un->c.un_vtoc_id = 0;
3884 			mddb_commitrec_wrapper(un->c.un_record_id);
3885 			mddb_deleterec_wrapper(recid);
3886 		}
3887 	}
3888 
3889 	recid = mddb_createrec(MD_EFI_PARTNAME_BYTES, MDDB_EFILABEL, 0,
3890 	    MD_CRO_32BIT, MD_UN2SET(un));
3891 
3892 	if (recid < 0) {
3893 		return (ENOSPC);
3894 	}
3895 
3896 	recids[0] = recid;
3897 	recids[1] = un->c.un_record_id;
3898 	recids[2] = 0;
3899 	v = mddb_getrecaddr(recid);
3900 	bcopy((caddr_t)&efi_part->efi_gpe_PartitionName, v,
3901 	    MD_EFI_PARTNAME_BYTES);
3902 
3903 	un->c.un_vtoc_id = recid;
3904 	un->c.un_flag |= MD_EFILABEL;
3905 	mddb_commitrecs_wrapper(recids);
3906 	return (0);
3907 }
3908 
3909 int
3910 md_dkiocgetefi(minor_t mnum, void *data, int mode)
3911 {
3912 	dk_efi_t	efi;
3913 	caddr_t		*buf;
3914 	int		rval = 0;
3915 	mdi_unit_t	*ui;
3916 	md_unit_t	*mdun;
3917 
3918 	if (!(mode & FREAD))
3919 		return (EACCES);
3920 
3921 	if (ddi_copyin(data, &efi, sizeof (dk_efi_t), mode))
3922 		return (EFAULT);
3923 
3924 	efi.dki_data = (void *)(uintptr_t)efi.dki_data_64;
3925 
3926 	/*
3927 	 * If the user specified a zero length or a null pointer, we give them
3928 	 * the number of bytes to alloc in user land.
3929 	 */
3930 	if (efi.dki_length == 0 || efi.dki_data == NULL) {
3931 		efi.dki_length = MD_EFI_LABEL_SIZE;
3932 		if (ddi_copyout(&efi, data, sizeof (dk_efi_t), mode))
3933 			return (EFAULT);
3934 		return (0);
3935 	}
3936 	/* Bad size specified, better not answer to that query */
3937 	if (efi.dki_length < MD_EFI_LABEL_SIZE)
3938 		return (EINVAL);
3939 
3940 	if ((ui = MDI_UNIT(mnum)) == NULL)
3941 		return (ENXIO);
3942 
3943 	/*
3944 	 * We don't want to allocate as much bytes as we are told,
3945 	 * because we know the good size is MD_EFI_LABEL_SIZE
3946 	 */
3947 	efi.dki_length = MD_EFI_LABEL_SIZE;
3948 	buf = kmem_zalloc(MD_EFI_LABEL_SIZE, KM_SLEEP);
3949 
3950 	mdun = (md_unit_t *)md_unit_readerlock(ui);
3951 	md_get_efi(mdun, (char *)buf);
3952 	md_unit_readerexit(ui);
3953 
3954 	if (ddi_copyout(buf, efi.dki_data, efi.dki_length, mode))
3955 		rval = EFAULT;
3956 
3957 	kmem_free(buf, MD_EFI_LABEL_SIZE);
3958 	return (rval);
3959 }
3960 
3961 int
3962 md_dkiocsetefi(minor_t mnum, void *data, int mode)
3963 {
3964 	dk_efi_t	efi;
3965 	caddr_t		*buf;
3966 	int		rval = 0;
3967 	mdi_unit_t	*ui;
3968 	md_unit_t	*mdun;
3969 
3970 	if (!(mode & FREAD))
3971 		return (EACCES);
3972 
3973 	if ((ui = MDI_UNIT(mnum)) == NULL)
3974 		return (ENXIO);
3975 
3976 	if (ddi_copyin(data, &efi, sizeof (dk_efi_t), mode))
3977 		return (EFAULT);
3978 
3979 	efi.dki_data = (void *)(uintptr_t)efi.dki_data_64;
3980 
3981 	/* Sanity check of the skeleton */
3982 	if ((efi.dki_length > sizeof (efi_gpt_t) + EFI_MIN_ARRAY_SIZE) ||
3983 	    (efi.dki_length < sizeof (efi_gpt_t) + sizeof (efi_gpe_t)) ||
3984 	    (efi.dki_data == NULL))
3985 		return (EINVAL);
3986 
3987 	/*
3988 	 * It's only a real EFI label if the location is 1
3989 	 * in all other cases, we do nothing but say we did.
3990 	 */
3991 	if (efi.dki_lba != 1)
3992 		return (0);	/* success */
3993 
3994 	buf = kmem_alloc(efi.dki_length, KM_SLEEP);
3995 	/* And here we copy in the real data */
3996 	if (ddi_copyin(efi.dki_data, buf, efi.dki_length, mode)) {
3997 		rval = EFAULT;
3998 	} else {
3999 		mdun = (md_unit_t *)md_unit_readerlock(ui);
4000 		rval = md_set_efi(mdun, (char *)buf);
4001 		md_unit_readerexit(ui);
4002 	}
4003 
4004 	kmem_free(buf, efi.dki_length);
4005 	return (rval);
4006 }
4007 
4008 /*
4009  * md_dkiocpartition()
4010  * Return the appropriate partition64 structure for a given metadevice.
4011  *
4012  * Actually the only real information being returned is the number of blocks
4013  * of the specified metadevice.
4014  * The starting block is always 0, and so is the partition number, because
4015  * metadevices don't have slices.
4016  *
4017  * This function is generic for all types of metadevices.
4018  */
4019 int
4020 md_dkiocpartition(minor_t mnum, void *data, int mode)
4021 {
4022 	struct partition64	p64;
4023 	mdi_unit_t		*ui;
4024 	md_unit_t		*un;
4025 	int			rval = 0;
4026 
4027 	if (!(mode & FREAD))
4028 		return (EACCES);
4029 
4030 
4031 	if ((ui = MDI_UNIT(mnum)) == NULL)
4032 		return (ENXIO);
4033 
4034 	if (ddi_copyin(data, &p64, sizeof (struct partition64), mode))
4035 		return (EFAULT);
4036 
4037 	if (p64.p_partno != 0)
4038 		return (ESRCH);
4039 
4040 	un = (md_unit_t *)md_unit_readerlock(ui);
4041 	/* All metadevices share the same PartitionTypeGUID (see md_get_efi) */
4042 	UUID_LE_CONVERT(p64.p_type, md_efi_reserved);
4043 
4044 	p64.p_partno = 0;
4045 	p64.p_start = 0;
4046 	p64.p_size = un->c.un_total_blocks;
4047 	md_unit_readerexit(ui);
4048 
4049 	if (ddi_copyout(&p64, data, sizeof (struct partition64), mode)) {
4050 		rval = EFAULT;
4051 	}
4052 
4053 	return (rval);
4054 }
4055 
4056 
4057 /*
4058  * Remove device node
4059  */
4060 void
4061 md_remove_minor_node(minor_t mnum)
4062 {
4063 	char			name[16];
4064 	extern dev_info_t	*md_devinfo;
4065 
4066 	/*
4067 	 * Attempt release of its minor node
4068 	 */
4069 	(void) snprintf(name, sizeof (name), "%d,%d,blk", MD_MIN2SET(mnum),
4070 	    MD_MIN2UNIT(mnum));
4071 	ddi_remove_minor_node(md_devinfo, name);
4072 
4073 	(void) snprintf(name, sizeof (name), "%d,%d,raw", MD_MIN2SET(mnum),
4074 	    MD_MIN2UNIT(mnum));
4075 	ddi_remove_minor_node(md_devinfo, name);
4076 }
4077