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