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