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