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 2006 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 goto out; 209 } 210 if (meta_getdevs(sp, devnp, nlpp, ep) != 0) 211 goto out; 212 } 213 214 /* success */ 215 rval = 0; 216 217 /* cleanup, return error */ 218 out: 219 if (mydevs != NULL) 220 Free(mydevs); 221 return (rval); 222 } 223 224 /* 225 * get all dev_t for a set 226 */ 227 int 228 meta_getalldevs( 229 mdsetname_t *sp, /* set to look in */ 230 mdnamelist_t **nlpp, /* returned devices */ 231 int check_db, 232 md_error_t *ep 233 ) 234 { 235 md_replicalist_t *rlp, *rp; 236 mdnamelist_t *nlp, *np; 237 mdhspnamelist_t *hspnlp, *hspp; 238 int rval = 0; 239 240 assert(sp != NULL); 241 242 /* 243 * Get a replica namelist, 244 * and then get all the devs within the replicas. 245 */ 246 if (check_db == TRUE) { 247 rlp = NULL; 248 if (metareplicalist(sp, MD_BASICNAME_OK, &rlp, ep) < 0) 249 rval = -1; 250 for (rp = rlp; (rp != NULL); rp = rp->rl_next) { 251 if (meta_getdevs(sp, rp->rl_repp->r_namep, 252 nlpp, ep) != 0) 253 rval = -1; 254 } 255 metafreereplicalist(rlp); 256 } 257 258 /* 259 * Get a stripe namelist, 260 * and then get all the devs within the stripes. 261 */ 262 nlp = NULL; 263 if (meta_get_stripe_names(sp, &nlp, 0, ep) < 0) 264 rval = -1; 265 for (np = nlp; (np != NULL); np = np->next) { 266 if (meta_getdevs(sp, np->namep, nlpp, ep) != 0) 267 rval = -1; 268 } 269 metafreenamelist(nlp); 270 271 /* 272 * Get a mirror namelist, 273 * and then get all the devs within the mirrors. 274 */ 275 nlp = NULL; 276 if (meta_get_mirror_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 trans namelist, 286 * and then get all the devs within the trans. 287 */ 288 nlp = NULL; 289 290 if (meta_get_trans_names(sp, &nlp, 0, ep) < 0) 291 rval = -1; 292 for (np = nlp; (np != NULL); np = np->next) { 293 if (meta_getdevs(sp, np->namep, nlpp, ep) != 0) 294 rval = -1; 295 } 296 metafreenamelist(nlp); 297 298 /* 299 * Get a hot spare pool namelist, 300 * and then get all the devs within the hot spare pools. 301 */ 302 hspnlp = NULL; 303 if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0) 304 rval = -1; 305 for (hspp = hspnlp; (hspp != NULL); hspp = hspp->next) { 306 md_hsp_t *hsp; 307 uint_t i; 308 309 if ((hsp = meta_get_hsp(sp, hspp->hspnamep, ep)) == NULL) 310 rval = -1; 311 else for (i = 0; (i < hsp->hotspares.hotspares_len); ++i) { 312 md_hs_t *hs = &hsp->hotspares.hotspares_val[i]; 313 314 if (meta_getdevs(sp, hs->hsnamep, nlpp, ep) != 0) 315 rval = -1; 316 } 317 } 318 metafreehspnamelist(hspnlp); 319 320 /* 321 * Get a raid namelist, 322 * and then get all the devs within the raids. 323 */ 324 nlp = NULL; 325 if (meta_get_raid_names(sp, &nlp, 0, ep) < 0) 326 rval = -1; 327 for (np = nlp; (np != NULL); np = np->next) { 328 if (meta_getdevs(sp, np->namep, nlpp, ep) != 0) 329 rval = -1; 330 } 331 metafreenamelist(nlp); 332 333 /* 334 * Get a soft partition namelist, 335 * and then get all the devs within the softpartitions 336 */ 337 nlp = NULL; 338 if (meta_get_sp_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 return (rval); 347 } 348 349 /* 350 * get vtoc from a device already opened. 351 * returns 352 * 0 on success, 353 * -1 on error. If the error was ENOTSUP, partno will be set to 354 * VT_ENOTSUP if possible. 355 */ 356 int 357 meta_getvtoc( 358 int fd, /* fd for named device */ 359 char *devname, /* name of device */ 360 struct vtoc *vtocbufp, /* vtoc buffer to fill */ 361 int *partno, /* return partno here */ 362 md_error_t *ep 363 ) 364 { 365 int part; 366 367 (void) memset(vtocbufp, 0, sizeof (*vtocbufp)); 368 if ((part = read_vtoc(fd, vtocbufp)) < 0) { 369 int err = errno; 370 371 if (ioctl(fd, MHIOCSTATUS, NULL) == 1) 372 err = EACCES; 373 else if (part == VT_EINVAL) 374 err = EINVAL; 375 else if (part == VT_EIO) 376 err = EIO; 377 else if (part == VT_ENOTSUP) { 378 if (partno) { 379 *partno = VT_ENOTSUP; 380 return (-1); 381 } 382 } 383 return (mdsyserror(ep, err, devname)); 384 } 385 386 /* Slice number for *p0 partition (whole disk on x86) is 16 */ 387 if (part >= V_NUMPAR) 388 return (mdsyserror(ep, EINVAL, devname)); 389 390 if (partno) 391 *partno = part; 392 return (0); 393 } 394 /* 395 * set mdvtoc for a meta devices 396 */ 397 int 398 meta_setmdvtoc( 399 int fd, /* fd for named device */ 400 char *devname, /* name of device */ 401 mdvtoc_t *mdvtocp, /* mdvtoc buffer to fill */ 402 md_error_t *ep 403 ) 404 { 405 uint_t i; 406 407 /* 408 * Sanity-check the mdvtoc 409 */ 410 411 if (mdvtocp->nparts > V_NUMPAR) { 412 return (-1); 413 } 414 415 /* 416 * since many drivers won't allow opening a device make sure 417 * all partitions aren't being set to zero. If all are zero then 418 * we have no way to set them to something else 419 */ 420 421 for (i = 0; i < mdvtocp->nparts; i++) 422 if (mdvtocp->parts[i].size > 0) 423 break; 424 if (i == mdvtocp->nparts) 425 return (-1); 426 427 /* 428 * Write the mdvtoc 429 */ 430 if (ioctl(fd, DKIOCSVTOC, (caddr_t)mdvtocp) == -1) { 431 return (mdsyserror(ep, errno, devname)); 432 } 433 434 return (0); 435 } 436 437 /* 438 * set vtoc 439 */ 440 int 441 meta_setvtoc( 442 int fd, /* fd for named device */ 443 char *devname, /* name of device */ 444 struct vtoc *vtocbufp, /* vtoc buffer to fill */ 445 md_error_t *ep 446 ) 447 { 448 int part; 449 int err; 450 451 if ((part = write_vtoc(fd, vtocbufp)) < 0) { 452 if (part == VT_EINVAL) 453 err = EINVAL; 454 else if (part == VT_EIO) 455 err = EIO; 456 else 457 err = errno; 458 return (mdsyserror(ep, err, devname)); 459 } 460 461 return (0); 462 } 463 464 /* 465 * FUNCTION: meta_get_names() 466 * INPUT: drivername - char string containing the driver name 467 * sp - the set name to get soft partitions from 468 * options - options from the command line 469 * OUTPUT: nlpp - list of all soft partition names 470 * ep - return error pointer 471 * RETURNS: int - -1 if error, 0 success 472 * PURPOSE: returns a list of all specified devices in the metadb 473 * for all devices in the specified set 474 */ 475 int 476 meta_get_names( 477 char *drivername, 478 mdsetname_t *sp, 479 mdnamelist_t **nlpp, 480 mdprtopts_t options, 481 md_error_t *ep 482 ) 483 { 484 md_i_getnum_t gn; /* MD_IOCGET_NUM params */ 485 mdnamelist_t **tailpp = nlpp; 486 minor_t *minors = NULL; 487 minor_t *m_ptr; 488 int i; 489 490 (void) memset(&gn, '\0', sizeof (gn)); 491 MD_SETDRIVERNAME(&gn, drivername, sp->setno); 492 493 /* get number of devices */ 494 if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) { 495 if (mdiserror(&gn.mde, MDE_UNIT_NOT_FOUND)) { 496 mdclrerror(&gn.mde); 497 } else { 498 (void) mdstealerror(ep, &gn.mde); 499 return (-1); 500 } 501 } 502 503 if (gn.size > 0) { 504 /* malloc minor number buffer to be filled by ioctl */ 505 if ((minors = (minor_t *)malloc( 506 gn.size * sizeof (minor_t))) == 0) { 507 return (ENOMEM); 508 } 509 gn.minors = (uintptr_t)minors; 510 if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) { 511 (void) mdstealerror(ep, &gn.mde); 512 free(minors); 513 return (-1); 514 } 515 m_ptr = minors; 516 for (i = 0; i < gn.size; i++) { 517 mdname_t *np; 518 519 /* get name */ 520 np = metamnumname(&sp, *m_ptr, 521 ((options & PRINT_FAST) ? 1 : 0), ep); 522 if (np == NULL) 523 goto out; 524 525 tailpp = meta_namelist_append_wrapper( 526 tailpp, np); 527 528 /* next device */ 529 m_ptr++; 530 } 531 free(minors); 532 } 533 return (gn.size); 534 535 out: 536 if (minors != NULL) 537 free(minors); 538 metafreenamelist(*nlpp); 539 *nlpp = NULL; 540 return (-1); 541 } 542 543 /* 544 * Wrap lib/libdevid/devid_deviceid_to_nmlist. We want to take the 545 * results from that function and filter out the c[t]dp style names that 546 * we typically see on x86 so that we never see them. 547 */ 548 int 549 meta_deviceid_to_nmlist(char *search_path, ddi_devid_t devid, char *minor_name, 550 devid_nmlist_t **retlist) 551 { 552 int res; 553 devid_nmlist_t *dp; 554 devid_nmlist_t *tmp_retlist; 555 int i = 1; 556 devid_nmlist_t *rp; 557 558 res = devid_deviceid_to_nmlist(search_path, devid, minor_name, retlist); 559 if (res != 0) { 560 return (res); 561 } 562 563 564 /* first count the number of non c[t]dp items in retlist */ 565 for (dp = *retlist; dp->dev != NODEV; dp++) { 566 uint_t s; 567 568 /* Check if this is a c[t]dp style name. */ 569 if (parse_ctd(basename(dp->devname), &s) != 1) { 570 i++; 571 } 572 } 573 574 /* create an array to hold the non c[t]dp items */ 575 tmp_retlist = Malloc(sizeof (devid_nmlist_t) * i); 576 /* copy the non c[t]dp items to the array */ 577 for (dp = *retlist, rp = tmp_retlist; dp->dev != NODEV; dp++) { 578 uint_t s; 579 580 /* Check if this is a c[t]dp style name. */ 581 if (parse_ctd(basename(dp->devname), &s) != 1) { 582 /* nope, so copy and go to the next */ 583 rp->dev = dp->dev; 584 rp->devname = Strdup(dp->devname); 585 rp++; 586 } 587 /* if it is c[t]dp, just skip the element */ 588 } 589 /* copy the list terminator */ 590 rp->dev = NODEV; 591 rp->devname = NULL; 592 devid_free_nmlist (*retlist); 593 *retlist = tmp_retlist; 594 return (res); 595 } 596