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 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * get dev_t list
29 */
30
31 #include <meta.h>
32
33 #include <sys/mhd.h>
34 #include <strings.h>
35
36 /*
37 * private version of minor(), able to handle 64 bit and 32 bit devices.
38 * print a warning out in case a 32 bit dev is specified.
39 */
40 minor_t
meta_getminor(md_dev64_t dev64)41 meta_getminor(md_dev64_t dev64)
42 {
43 /* check if it's a real 64 bit dev */
44 if ((dev64 >> NBITSMAJOR64) > 0) {
45 return ((minor_t)(dev64 & MAXMIN64));
46 } else {
47 if (getenv("META_DEBUG"))
48 (void) printf(
49 "meta_getminor called with 32 bit dev: 0x%llx\n",
50 dev64);
51 return ((minor_t)(dev64 & MAXMIN32));
52 }
53 }
54
55 /*
56 * private version of major(), able to handle 64 bit and 32 bit devices.
57 * print a warning out in case a 32 bit dev is specified.
58 */
59 major_t
meta_getmajor(md_dev64_t dev64)60 meta_getmajor(md_dev64_t dev64)
61 {
62 /* check if it's a real 64 bit dev */
63 if ((dev64 >> NBITSMAJOR64) > 0) {
64 return ((major_t)((dev64 >> NBITSMINOR64) & MAXMAJ64));
65 } else {
66 if (getenv("META_DEBUG"))
67 (void) printf(
68 "meta_getmajor called with 32 bit dev: 0x%llx\n",
69 dev64);
70 return ((major_t)((dev64 >> NBITSMINOR32) & MAXMAJ32));
71 }
72 }
73
74 /*
75 * private version of cmpldev(), able to handle 64 bit and 32 bit devices.
76 */
77 dev32_t
meta_cmpldev(md_dev64_t dev64)78 meta_cmpldev(md_dev64_t dev64)
79 {
80 minor_t minor;
81 major_t major;
82
83 major = (major_t)(dev64 >> NBITSMAJOR64);
84 if (major == 0) {
85 return ((dev32_t)dev64);
86 }
87 minor = (dev32_t)dev64 & MAXMIN32;
88 return ((major << NBITSMINOR32) | minor);
89 }
90
91 /*
92 * private version of expldev(), able to handle 64 bit and 32 bit devices.
93 */
94 md_dev64_t
meta_expldev(md_dev64_t dev64)95 meta_expldev(md_dev64_t dev64)
96 {
97 minor_t minor;
98 major_t major;
99
100 major = (major_t)(dev64 >> NBITSMAJOR64);
101 if (major > 0) { /* a 64 bit device was given, return unchanged */
102 return (dev64);
103 }
104 minor = (minor_t)(dev64) & MAXMIN32;
105 major = ((major_t)dev64 >> NBITSMINOR32) & MAXMAJ32;
106 return (((md_dev64_t)major << NBITSMINOR64) | minor);
107 }
108
109 /*
110 * get underlying devices (recursively)
111 */
112 int
meta_getdevs(mdsetname_t * sp,mdname_t * namep,mdnamelist_t ** nlpp,md_error_t * ep)113 meta_getdevs(
114 mdsetname_t *sp,
115 mdname_t *namep,
116 mdnamelist_t **nlpp,
117 md_error_t *ep
118 )
119 {
120 char *miscname;
121 md_dev64_t *mydevs = NULL;
122 md_getdevs_params_t mgd;
123 size_t i;
124 int rval = -1;
125 md_sys_error_t *ip;
126
127 /* must have local set */
128 assert(sp != NULL);
129
130 /* if no valid name then return an error */
131 if (namep == NULL)
132 return (-1);
133
134 /* just add regular devices */
135 if (! metaismeta(namep)) {
136 mdnamelist_t *p;
137
138 /*
139 * If the dev_t is in the array already
140 * then let's continue.
141 */
142 for (p = *nlpp; (p != NULL); p = p->next) {
143 if (strcmp(namep->bname, p->namep->bname) == 0) {
144 rval = 0;
145 goto out;
146 }
147 }
148
149 /* add to list */
150 (void) metanamelist_append(nlpp, namep);
151 rval = 0;
152 goto out;
153 }
154
155 /* get MD misc module */
156 if ((miscname = metagetmiscname(namep, ep)) == NULL)
157 goto out;
158
159 /* get count of underlying devices */
160 (void) memset(&mgd, '\0', sizeof (mgd));
161 MD_SETDRIVERNAME(&mgd, miscname, sp->setno);
162 mgd.mnum = meta_getminor(namep->dev);
163 mgd.cnt = 0;
164 mgd.devs = NULL;
165 if (metaioctl(MD_IOCGET_DEVS, &mgd, &mgd.mde, namep->cname) != 0) {
166 if (mgd.mde.info.errclass == MDEC_SYS) {
167 ip = &mgd.mde.info.md_error_info_t_u.sys_error;
168 if (ip->errnum == ENODEV) {
169 rval = 0;
170 goto out;
171 }
172 }
173 (void) mdstealerror(ep, &mgd.mde);
174 goto out;
175 } else if (mgd.cnt <= 0) {
176 assert(mgd.cnt >= 0);
177 rval = 0;
178 goto out;
179 }
180
181 /* get underlying devices */
182 mydevs = Zalloc(sizeof (*mydevs) * mgd.cnt);
183 mgd.devs = (uintptr_t)mydevs;
184 if (metaioctl(MD_IOCGET_DEVS, &mgd, &mgd.mde, namep->cname) != 0) {
185 if (mgd.mde.info.errclass == MDEC_SYS) {
186 ip = &mgd.mde.info.md_error_info_t_u.sys_error;
187 if (ip->errnum == ENODEV) {
188 rval = 0;
189 goto out;
190 }
191 }
192 (void) mdstealerror(ep, &mgd.mde);
193 goto out;
194 } else if (mgd.cnt <= 0) {
195 assert(mgd.cnt >= 0);
196 rval = 0;
197 goto out;
198 }
199 /* recurse */
200 for (i = 0; (i < mgd.cnt); ++i) {
201 mdname_t *devnp;
202
203 if (mydevs[i] == NODEV64) {
204 continue;
205 }
206 if ((devnp = metadevname(&sp, mydevs[i], ep)) == NULL) {
207 if (mdissyserror(ep, ENOENT)) {
208 mdclrerror(ep);
209 /*
210 * If the device doesn't exist, it could be
211 * that we have a wrong dev_t/name
212 * combination in the namespace, so
213 * meta_fix_compnames try to check this
214 * with the unit structure and fix this.
215 */
216 if (meta_fix_compnames(sp, namep,
217 mydevs[i], ep) == 0)
218 continue;
219 }
220 goto out;
221 }
222 if (meta_getdevs(sp, devnp, nlpp, ep) != 0)
223 goto out;
224 }
225
226 /* success */
227 rval = 0;
228
229 /* cleanup, return error */
230 out:
231 if (mydevs != NULL)
232 Free(mydevs);
233 return (rval);
234 }
235
236 /*
237 * get all dev_t for a set
238 */
239 int
meta_getalldevs(mdsetname_t * sp,mdnamelist_t ** nlpp,int check_db,md_error_t * ep)240 meta_getalldevs(
241 mdsetname_t *sp, /* set to look in */
242 mdnamelist_t **nlpp, /* returned devices */
243 int check_db,
244 md_error_t *ep
245 )
246 {
247 md_replicalist_t *rlp, *rp;
248 mdnamelist_t *nlp, *np;
249 mdhspnamelist_t *hspnlp, *hspp;
250 int rval = 0;
251
252 assert(sp != NULL);
253
254 /*
255 * Get a replica namelist,
256 * and then get all the devs within the replicas.
257 */
258 if (check_db == TRUE) {
259 rlp = NULL;
260 if (metareplicalist(sp, MD_BASICNAME_OK, &rlp, ep) < 0)
261 rval = -1;
262 for (rp = rlp; (rp != NULL); rp = rp->rl_next) {
263 if (meta_getdevs(sp, rp->rl_repp->r_namep,
264 nlpp, ep) != 0)
265 rval = -1;
266 }
267 metafreereplicalist(rlp);
268 }
269
270 /*
271 * Get a stripe namelist,
272 * and then get all the devs within the stripes.
273 */
274 nlp = NULL;
275 if (meta_get_stripe_names(sp, &nlp, 0, ep) < 0)
276 rval = -1;
277 for (np = nlp; (np != NULL); np = np->next) {
278 if (meta_getdevs(sp, np->namep, nlpp, ep) != 0)
279 rval = -1;
280 }
281 metafreenamelist(nlp);
282
283 /*
284 * Get a mirror namelist,
285 * and then get all the devs within the mirrors.
286 */
287 nlp = NULL;
288 if (meta_get_mirror_names(sp, &nlp, 0, ep) < 0)
289 rval = -1;
290 for (np = nlp; (np != NULL); np = np->next) {
291 if (meta_getdevs(sp, np->namep, nlpp, ep) != 0)
292 rval = -1;
293 }
294 metafreenamelist(nlp);
295
296 /*
297 * Get a trans namelist,
298 * and then get all the devs within the trans.
299 */
300 nlp = NULL;
301
302 if (meta_get_trans_names(sp, &nlp, 0, ep) < 0)
303 rval = -1;
304 for (np = nlp; (np != NULL); np = np->next) {
305 if (meta_getdevs(sp, np->namep, nlpp, ep) != 0)
306 rval = -1;
307 }
308 metafreenamelist(nlp);
309
310 /*
311 * Get a hot spare pool namelist,
312 * and then get all the devs within the hot spare pools.
313 */
314 hspnlp = NULL;
315 if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
316 rval = -1;
317 for (hspp = hspnlp; (hspp != NULL); hspp = hspp->next) {
318 md_hsp_t *hsp;
319 uint_t i;
320
321 if ((hsp = meta_get_hsp(sp, hspp->hspnamep, ep)) == NULL)
322 rval = -1;
323 else for (i = 0; (i < hsp->hotspares.hotspares_len); ++i) {
324 md_hs_t *hs = &hsp->hotspares.hotspares_val[i];
325
326 if (meta_getdevs(sp, hs->hsnamep, nlpp, ep) != 0)
327 rval = -1;
328 }
329 }
330 metafreehspnamelist(hspnlp);
331
332 /*
333 * Get a raid namelist,
334 * and then get all the devs within the raids.
335 */
336 nlp = NULL;
337 if (meta_get_raid_names(sp, &nlp, 0, ep) < 0)
338 rval = -1;
339 for (np = nlp; (np != NULL); np = np->next) {
340 if (meta_getdevs(sp, np->namep, nlpp, ep) != 0)
341 rval = -1;
342 }
343 metafreenamelist(nlp);
344
345 /*
346 * Get a soft partition namelist,
347 * and then get all the devs within the softpartitions
348 */
349 nlp = NULL;
350 if (meta_get_sp_names(sp, &nlp, 0, ep) < 0)
351 rval = -1;
352 for (np = nlp; (np != NULL); np = np->next) {
353 if (meta_getdevs(sp, np->namep, nlpp, ep) != 0)
354 rval = -1;
355 }
356 metafreenamelist(nlp);
357
358 return (rval);
359 }
360
361 /*
362 * get vtoc from a device already opened.
363 * returns
364 * 0 on success,
365 * -1 on error. If the error was ENOTSUP, partno will be set to
366 * VT_ENOTSUP if possible.
367 */
368 int
meta_getvtoc(int fd,char * devname,struct extvtoc * vtocbufp,int * partno,md_error_t * ep)369 meta_getvtoc(
370 int fd, /* fd for named device */
371 char *devname, /* name of device */
372 struct extvtoc *vtocbufp, /* vtoc buffer to fill */
373 int *partno, /* return partno here */
374 md_error_t *ep
375 )
376 {
377 int part;
378
379 (void) memset(vtocbufp, 0, sizeof (*vtocbufp));
380 if ((part = read_extvtoc(fd, vtocbufp)) < 0) {
381 int err = errno;
382
383 if (ioctl(fd, MHIOCSTATUS, NULL) == 1)
384 err = EACCES;
385 else if (part == VT_EINVAL)
386 err = EINVAL;
387 else if (part == VT_EIO)
388 err = EIO;
389 else if (part == VT_ENOTSUP) {
390 if (partno) {
391 *partno = VT_ENOTSUP;
392 return (-1);
393 }
394 }
395 return (mdsyserror(ep, err, devname));
396 }
397
398 /* Slice number for *p0 partition (whole disk on x86) is 16 */
399 if (part >= V_NUMPAR)
400 return (mdsyserror(ep, EINVAL, devname));
401
402 /* Slice number for *p0 partition (whole disk on x86) is 16 */
403 if (part >= V_NUMPAR)
404 return (mdsyserror(ep, EINVAL, devname));
405
406 if (partno)
407 *partno = part;
408 return (0);
409 }
410 /*
411 * set mdvtoc for a meta devices
412 */
413 int
meta_setmdvtoc(int fd,char * devname,mdvtoc_t * mdvtocp,md_error_t * ep)414 meta_setmdvtoc(
415 int fd, /* fd for named device */
416 char *devname, /* name of device */
417 mdvtoc_t *mdvtocp, /* mdvtoc buffer to fill */
418 md_error_t *ep
419 )
420 {
421 uint_t i;
422
423 /*
424 * Sanity-check the mdvtoc
425 */
426
427 if (mdvtocp->nparts > V_NUMPAR) {
428 return (-1);
429 }
430
431 /*
432 * since many drivers won't allow opening a device make sure
433 * all partitions aren't being set to zero. If all are zero then
434 * we have no way to set them to something else
435 */
436
437 for (i = 0; i < mdvtocp->nparts; i++)
438 if (mdvtocp->parts[i].size > 0)
439 break;
440 if (i == mdvtocp->nparts)
441 return (-1);
442
443 /*
444 * Write the mdvtoc
445 */
446 if (ioctl(fd, DKIOCSVTOC, (caddr_t)mdvtocp) == -1) {
447 return (mdsyserror(ep, errno, devname));
448 }
449
450 return (0);
451 }
452
453 /*
454 * set vtoc
455 */
456 int
meta_setvtoc(int fd,char * devname,struct extvtoc * vtocbufp,md_error_t * ep)457 meta_setvtoc(
458 int fd, /* fd for named device */
459 char *devname, /* name of device */
460 struct extvtoc *vtocbufp, /* vtoc buffer to fill */
461 md_error_t *ep
462 )
463 {
464 int part;
465 int err;
466
467 if ((part = write_extvtoc(fd, vtocbufp)) < 0) {
468 if (part == VT_EINVAL)
469 err = EINVAL;
470 else if (part == VT_EIO)
471 err = EIO;
472 else
473 err = errno;
474 return (mdsyserror(ep, err, devname));
475 }
476
477 return (0);
478 }
479
480 /*
481 * FUNCTION: meta_get_names()
482 * INPUT: drivername - char string containing the driver name
483 * sp - the set name to get soft partitions from
484 * options - options from the command line
485 * OUTPUT: nlpp - list of all soft partition names
486 * ep - return error pointer
487 * RETURNS: int - -1 if error, 0 success
488 * PURPOSE: returns a list of all specified devices in the metadb
489 * for all devices in the specified set
490 */
491 int
meta_get_names(char * drivername,mdsetname_t * sp,mdnamelist_t ** nlpp,mdprtopts_t options,md_error_t * ep)492 meta_get_names(
493 char *drivername,
494 mdsetname_t *sp,
495 mdnamelist_t **nlpp,
496 mdprtopts_t options,
497 md_error_t *ep
498 )
499 {
500 md_i_getnum_t gn; /* MD_IOCGET_NUM params */
501 mdnamelist_t **tailpp = nlpp;
502 minor_t *minors = NULL;
503 minor_t *m_ptr;
504 int i;
505
506 (void) memset(&gn, '\0', sizeof (gn));
507 MD_SETDRIVERNAME(&gn, drivername, sp->setno);
508
509 /* get number of devices */
510 if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) {
511 if (mdiserror(&gn.mde, MDE_UNIT_NOT_FOUND)) {
512 mdclrerror(&gn.mde);
513 } else {
514 (void) mdstealerror(ep, &gn.mde);
515 return (-1);
516 }
517 }
518
519 if (gn.size > 0) {
520 /* malloc minor number buffer to be filled by ioctl */
521 if ((minors = (minor_t *)malloc(
522 gn.size * sizeof (minor_t))) == 0) {
523 return (ENOMEM);
524 }
525 gn.minors = (uintptr_t)minors;
526 if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) {
527 (void) mdstealerror(ep, &gn.mde);
528 free(minors);
529 return (-1);
530 }
531 m_ptr = minors;
532 for (i = 0; i < gn.size; i++) {
533 mdname_t *np;
534
535 /* get name */
536 np = metamnumname(&sp, *m_ptr,
537 ((options & PRINT_FAST) ? 1 : 0), ep);
538
539 /*
540 * np can be NULL if the /dev/md namespace entries
541 * do not exist. This could have happened due to
542 * devfsadmd not having created them.
543 * Therefore assume devfsadmd has not run and tell
544 * it to run for the specific device that is missing.
545 * Ignore any error return from meta_update_devtree
546 * as a failure to create the device nodes will be
547 * picked up in the metamnumname() call. Note that
548 * the call to meta_update_devtree should not return
549 * until the /dev/md links have been created or if
550 * there has been a failure of some sort.
551 */
552 if (np == NULL) {
553 (void) meta_update_devtree(*m_ptr);
554 np = metamnumname(&sp, *m_ptr,
555 ((options & PRINT_FAST) ? 1 : 0), ep);
556 }
557
558 if (np == NULL)
559 goto out;
560
561 tailpp = meta_namelist_append_wrapper(tailpp, np);
562
563 /* next device */
564 m_ptr++;
565 }
566 free(minors);
567 }
568 return (gn.size);
569
570 out:
571 if (minors != NULL)
572 free(minors);
573 metafreenamelist(*nlpp);
574 *nlpp = NULL;
575 return (-1);
576 }
577
578 /*
579 * Wrap lib/libdevid/devid_deviceid_to_nmlist. We want to take the
580 * results from that function and filter out the c[t]dp style names that
581 * we typically see on x86 so that we never see them.
582 */
583 int
meta_deviceid_to_nmlist(char * search_path,ddi_devid_t devid,char * minor_name,devid_nmlist_t ** retlist)584 meta_deviceid_to_nmlist(char *search_path, ddi_devid_t devid, char *minor_name,
585 devid_nmlist_t **retlist)
586 {
587 int res;
588 devid_nmlist_t *dp;
589 devid_nmlist_t *tmp_retlist;
590 int i = 1;
591 devid_nmlist_t *rp;
592
593 res = devid_deviceid_to_nmlist(search_path, devid, minor_name, retlist);
594 if (res != 0) {
595 return (res);
596 }
597
598
599 /* first count the number of non c[t]dp items in retlist */
600 for (dp = *retlist; dp->dev != NODEV; dp++) {
601 uint_t s;
602
603 /* Check if this is a c[t]dp style name. */
604 if (parse_ctd(basename(dp->devname), &s) != 1) {
605 i++;
606 }
607 }
608
609 /* create an array to hold the non c[t]dp items */
610 tmp_retlist = Malloc(sizeof (devid_nmlist_t) * i);
611 /* copy the non c[t]dp items to the array */
612 for (dp = *retlist, rp = tmp_retlist; dp->dev != NODEV; dp++) {
613 uint_t s;
614
615 /* Check if this is a c[t]dp style name. */
616 if (parse_ctd(basename(dp->devname), &s) != 1) {
617 /* nope, so copy and go to the next */
618 rp->dev = dp->dev;
619 rp->devname = Strdup(dp->devname);
620 rp++;
621 }
622 /* if it is c[t]dp, just skip the element */
623 }
624 /* copy the list terminator */
625 rp->dev = NODEV;
626 rp->devname = NULL;
627 devid_free_nmlist (*retlist);
628 *retlist = tmp_retlist;
629 return (res);
630 }
631
632 /*
633 * Check each real device that makes up a metadevice so that
634 * un_dev entries can be matched against the entries in the
635 * namespace.
636 *
637 * RETURN:
638 * -1 error
639 * 0 success
640 */
641 int
meta_fix_compnames(mdsetname_t * sp,mdname_t * namep,md_dev64_t dev,md_error_t * ep)642 meta_fix_compnames(
643 mdsetname_t *sp,
644 mdname_t *namep,
645 md_dev64_t dev,
646 md_error_t *ep
647 )
648 {
649 int ret = 0;
650 char *miscname;
651
652 /* get miscname and unit */
653 if ((miscname = metagetmiscname(namep, ep)) == NULL)
654 return (-1);
655 if (strcmp(miscname, MD_STRIPE) == 0) {
656 if (meta_stripe_check_component(sp, namep, dev, ep) < 0) {
657 ret = -1;
658 }
659 } else if (strcmp(miscname, MD_SP) == 0) {
660 if (meta_sp_check_component(sp, namep, ep) < 0) {
661 ret = -1;
662 }
663 } else if (strcmp(miscname, MD_RAID) == 0) {
664 if (meta_raid_check_component(sp, namep, dev, ep) < 0) {
665 ret = -1;
666 }
667 } else {
668 (void) mdmderror(ep, MDE_INVAL_UNIT, 0, namep->cname);
669 return (-1);
670 }
671 return (ret);
672 }
673