meta_nameinfo.c revision 8452:89d32dfdae6e
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#include <dlfcn.h> 28#include <meta.h> 29#include <metadyn.h> 30#include <ctype.h> 31#include <dirent.h> 32#include <devid.h> 33#include <sys/param.h> 34#include <sys/scsi/impl/uscsi.h> 35#include <sys/scsi/generic/commands.h> 36#include <sys/scsi/generic/inquiry.h> 37#include <sys/efi_partition.h> 38 39typedef struct ctlr_cache { 40 char *ctlr_nm; 41 int ctlr_ty; 42 struct ctlr_cache *ctlr_nx; 43} ctlr_cache_t; 44 45static ctlr_cache_t *ctlr_cache = NULL; 46 47 48/* 49 * return set for a device 50 */ 51mdsetname_t * 52metagetset( 53 mdname_t *np, 54 int bypass_daemon, 55 md_error_t *ep 56) 57{ 58 mdsetname_t *sp; 59 60 /* metadevice */ 61 if (metaismeta(np)) 62 return (metasetnosetname(MD_MIN2SET(meta_getminor(np->dev)), 63 ep)); 64 65 /* regular device */ 66 if (meta_is_drive_in_anyset(np->drivenamep, &sp, bypass_daemon, 67 ep) != 0) 68 return (NULL); 69 70 if (sp != NULL) 71 return (sp); 72 73 return (metasetnosetname(MD_LOCAL_SET, ep)); 74} 75 76/* 77 * convert system to md types 78 */ 79static void 80meta_geom_to_md( 81 struct dk_geom *gp, 82 mdgeom_t *mdgp 83) 84{ 85 (void) memset(mdgp, '\0', sizeof (*mdgp)); 86 mdgp->ncyl = gp->dkg_ncyl; 87 mdgp->nhead = gp->dkg_nhead; 88 mdgp->nsect = gp->dkg_nsect; 89 mdgp->rpm = gp->dkg_rpm; 90 mdgp->write_reinstruct = gp->dkg_write_reinstruct; 91 mdgp->read_reinstruct = gp->dkg_read_reinstruct; 92 mdgp->blk_sz = DEV_BSIZE; 93} 94 95/* 96 * convert efi to md types 97 */ 98static void 99meta_efi_to_mdgeom(struct dk_gpt *gpt, mdgeom_t *mdgp) 100{ 101 (void) memset(mdgp, '\0', sizeof (*mdgp)); 102 mdgp->ncyl = (gpt->efi_last_u_lba - gpt->efi_first_u_lba) / 103 (MD_EFI_FG_HEADS * MD_EFI_FG_SECTORS); 104 mdgp->nhead = MD_EFI_FG_HEADS; 105 mdgp->nsect = MD_EFI_FG_SECTORS; 106 mdgp->rpm = MD_EFI_FG_RPM; 107 mdgp->write_reinstruct = MD_EFI_FG_WRI; 108 mdgp->read_reinstruct = MD_EFI_FG_RRI; 109 mdgp->blk_sz = DEV_BSIZE; 110} 111 112static void 113meta_efi_to_mdvtoc(struct dk_gpt *gpt, mdvtoc_t *mdvp) 114{ 115 char typename[EFI_PART_NAME_LEN]; 116 uint_t i; 117 118 (void) memset(mdvp, '\0', sizeof (*mdvp)); 119 mdvp->nparts = gpt->efi_nparts; 120 if (mdvp->nparts > MD_MAX_PARTS) 121 return; 122 123 mdvp->first_lba = gpt->efi_first_u_lba; 124 mdvp->last_lba = gpt->efi_last_u_lba; 125 mdvp->lbasize = gpt->efi_lbasize; 126 127 for (i = 0; (i < gpt->efi_nparts); ++i) { 128 mdvp->parts[i].start = gpt->efi_parts[i].p_start; 129 mdvp->parts[i].size = gpt->efi_parts[i].p_size; 130 mdvp->parts[i].tag = gpt->efi_parts[i].p_tag; 131 mdvp->parts[i].flag = gpt->efi_parts[i].p_flag; 132 /* 133 * It is possible to present an efi label but be using vtoc 134 * disks to create a > 1 TB metadevice. In case the first 135 * disk in the underlying metadevice is a vtoc disk and starts 136 * at the beginning of the disk it is necessary to convey this 137 * information to the user. 138 */ 139 if (mdvp->parts[i].size > 0 && 140 mdvp->parts[i].start != 0 && mdvp->nparts == 1) { 141 mdvp->parts[i].label = btodb(DK_LABEL_SIZE); 142 mdvp->parts[i].start = 0; 143 } 144 145 /* 146 * Due to the lack of a label for the entire partition table, 147 * we use p_name of the reserved partition 148 */ 149 if ((gpt->efi_parts[i].p_tag == V_RESERVED) && 150 (gpt->efi_parts[i].p_name != NULL)) { 151 (void) strlcpy(typename, gpt->efi_parts[i].p_name, 152 EFI_PART_NAME_LEN); 153 /* Stop at first (if any) space or tab */ 154 (void) strtok(typename, " \t"); 155 mdvp->typename = Strdup(typename); 156 } 157 } 158} 159 160static void 161meta_mdvtoc_to_efi(mdvtoc_t *mdvp, struct dk_gpt **gpt) 162{ 163 char typename[EFI_PART_NAME_LEN]; 164 uint_t i; 165 uint_t lastpart; 166 size_t size; 167 168 /* first we count how many partitions we have to send */ 169 for (i = 0; i < MD_MAX_PARTS; i++) { 170 if ((mdvp->parts[i].start == 0) && 171 (mdvp->parts[i].size == 0) && 172 (mdvp->parts[i].tag != V_RESERVED)) { 173 continue; 174 } 175 /* if we are here, we know the partition is really used */ 176 lastpart = i; 177 } 178 size = sizeof (struct dk_gpt) + (sizeof (struct dk_part) * lastpart); 179 *gpt = calloc(size, sizeof (char)); 180 181 (*gpt)->efi_nparts = lastpart + 1; 182 (*gpt)->efi_first_u_lba = mdvp->first_lba; 183 (*gpt)->efi_last_u_lba = mdvp->last_lba; 184 (*gpt)->efi_lbasize = mdvp->lbasize; 185 for (i = 0; (i < (*gpt)->efi_nparts); ++i) { 186 (*gpt)->efi_parts[i].p_start = mdvp->parts[i].start; 187 (*gpt)->efi_parts[i].p_size = mdvp->parts[i].size; 188 (*gpt)->efi_parts[i].p_tag = mdvp->parts[i].tag; 189 (*gpt)->efi_parts[i].p_flag = mdvp->parts[i].flag; 190 /* 191 * Due to the lack of a label for the entire partition table, 192 * we use p_name of the reserved partition 193 */ 194 if (((*gpt)->efi_parts[i].p_tag == V_RESERVED) && 195 (mdvp->typename != NULL)) { 196 (void) strlcpy((*gpt)->efi_parts[i].p_name, typename, 197 EFI_PART_NAME_LEN); 198 } 199 } 200} 201 202 203void 204ctlr_cache_add(char *nm, int ty) 205{ 206 ctlr_cache_t **ccpp; 207 208 for (ccpp = &ctlr_cache; *ccpp != NULL; ccpp = &(*ccpp)->ctlr_nx) 209 if (strcmp((*ccpp)->ctlr_nm, nm) == 0) 210 return; 211 212 *ccpp = Zalloc(sizeof (ctlr_cache_t)); 213 (*ccpp)->ctlr_nm = Strdup(nm); 214 (*ccpp)->ctlr_ty = ty; 215} 216 217int 218ctlr_cache_look(char *nm) 219{ 220 ctlr_cache_t *tcp; 221 222 for (tcp = ctlr_cache; tcp != NULL; tcp = tcp->ctlr_nx) 223 if (strcmp(tcp->ctlr_nm, nm) == 0) 224 return (tcp->ctlr_ty); 225 226 return (-1); 227} 228 229 230void 231metaflushctlrcache(void) 232{ 233 ctlr_cache_t *cp, *np; 234 235 for (cp = ctlr_cache, np = NULL; cp != NULL; cp = np) { 236 np = cp->ctlr_nx; 237 Free(cp->ctlr_nm); 238 Free(cp); 239 } 240 ctlr_cache = NULL; 241} 242 243/* 244 * getdrvnode -- return the driver name based on mdname_t->bname 245 * Need to free pointer when finished. 246 */ 247char * 248getdrvnode(mdname_t *np, md_error_t *ep) 249{ 250 char *devicespath; 251 char *drvnode; 252 char *cp; 253 254 if ((devicespath = metagetdevicesname(np, ep)) == NULL) 255 return (NULL); 256 257 /* 258 * At this point devicespath should be like the following 259 * "/devices/<unknow_and_dont_care>/xxxx@vvvv" 260 * 261 * There's a couple of 'if' statements below which could 262 * return an error condition, but I've decide to allow 263 * a more open approach regarding the mapping so as to 264 * not restrict possible future projects. 265 */ 266 if (drvnode = strrchr(devicespath, '/')) 267 /* 268 * drvnode now just "xxxx@vvvv" 269 */ 270 drvnode++; 271 272 if (cp = strrchr(drvnode, '@')) 273 /* 274 * Now drvnode is just the driver name "xxxx" 275 */ 276 *cp = '\0'; 277 278 cp = Strdup(drvnode); 279 Free(devicespath); 280 np->devicesname = NULL; 281 282 return (cp); 283} 284 285/* 286 * meta_load_dl -- open dynamic library using LDLIBRARYPATH, a debug 287 * environment variable METALDPATH, or the default location. 288 */ 289static void * 290meta_load_dl(mdname_t *np, md_error_t *ep) 291{ 292 char *drvnode; 293 char newpath[MAXPATHLEN]; 294 char *p; 295 void *cookie; 296 297 if ((drvnode = getdrvnode(np, ep)) != NULL) { 298 299 /* 300 * Library seach algorithm: 301 * 1) Use LDLIBRARYPATH which is implied when a non-absolute 302 * path name is passed to dlopen() 303 * 2) Use the value of METALDPATH as the directory. Mainly 304 * used for debugging 305 * 3) Last search the default location of "/usr/lib" 306 */ 307 (void) snprintf(newpath, sizeof (newpath), "lib%s.so.1", 308 drvnode); 309 if ((cookie = dlopen(newpath, RTLD_LAZY)) == NULL) { 310 if ((p = getenv("METALDPATH")) == NULL) 311 p = METALDPATH_DEFAULT; 312 (void) snprintf(newpath, sizeof (newpath), 313 "%s/lib%s.so.1", p, drvnode); 314 Free(drvnode); 315 if ((cookie = dlopen(newpath, RTLD_LAZY)) != NULL) { 316 /* 317 * Common failure here would be failing to 318 * find a libXX.so.1 such as libsd.so.1 319 * Some controllers will not have a library 320 * because there's no enclosure or name 321 * translation required. 322 */ 323 return (cookie); 324 } 325 } else { 326 Free(drvnode); 327 return (cookie); 328 } 329 } 330 return (NULL); 331} 332 333/* 334 * meta_match_names -- possibly convert the driver names returned by CINFO 335 */ 336static void 337meta_match_names(mdname_t *np, struct dk_cinfo *cp, mdcinfo_t *mdcp, 338 md_error_t *ep) 339{ 340 void *cookie; 341 meta_convert_e ((*fptr)(mdname_t *, struct dk_cinfo *, mdcinfo_t *, 342 md_error_t *)); 343 344 if ((cookie = meta_load_dl(np, ep)) != NULL) { 345 fptr = (meta_convert_e (*)(mdname_t *, struct dk_cinfo *, 346 mdcinfo_t *, md_error_t *))dlsym(cookie, "convert_path"); 347 if (fptr != NULL) 348 (void) (*fptr)(np, cp, mdcp, ep); 349 (void) dlclose(cookie); 350 } 351} 352 353/* 354 * meta_match_enclosure -- return any enclosure info if found 355 */ 356int 357meta_match_enclosure(mdname_t *np, mdcinfo_t *mdcp, md_error_t *ep) 358{ 359 meta_enclosure_e e; 360 meta_enclosure_e ((*fptr)(mdname_t *, mdcinfo_t *, 361 md_error_t *)); 362 void *cookie; 363 364 if ((cookie = meta_load_dl(np, ep)) != NULL) { 365 fptr = (meta_enclosure_e (*)(mdname_t *, mdcinfo_t *, 366 md_error_t *))dlsym(cookie, "get_enclosure"); 367 if (fptr != NULL) { 368 e = (*fptr)(np, mdcp, ep); 369 switch (e) { 370 case Enclosure_Error: 371 /* 372 * Looks like this library wanted to handle 373 * our device and had an internal error. 374 */ 375 return (1); 376 377 case Enclosure_Okay: 378 /* 379 * Found a library to handle the request so 380 * just return with data provided. 381 */ 382 return (0); 383 384 case Enclosure_Noop: 385 /* 386 * Need to continue the search 387 */ 388 break; 389 } 390 } 391 (void) dlclose(cookie); 392 } 393 return (0); 394} 395 396static int 397meta_cinfo_to_md(mdname_t *np, struct dk_cinfo *cp, mdcinfo_t *mdcp, 398 md_error_t *ep) 399{ 400 /* default */ 401 (void) memset(mdcp, '\0', sizeof (*mdcp)); 402 (void) strncpy(mdcp->cname, cp->dki_cname, 403 min((sizeof (mdcp->cname) - 1), sizeof (cp->dki_cname))); 404 mdcp->ctype = MHD_CTLR_GENERIC; 405 mdcp->cnum = cp->dki_cnum; 406 (void) strncpy(mdcp->dname, cp->dki_dname, 407 min((sizeof (mdcp->dname) - 1), sizeof (cp->dki_dname))); 408 mdcp->unit = cp->dki_unit; 409 mdcp->maxtransfer = cp->dki_maxtransfer; 410 411 /* 412 * See if the driver name returned from DKIOCINFO 413 * is valid or not. In somecases, such as the ap_dmd 414 * driver, we need to modify the name that's return 415 * for everything to work. 416 */ 417 meta_match_names(np, cp, mdcp, ep); 418 419 if (meta_match_enclosure(np, mdcp, ep)) 420 return (-1); 421 422 /* return success */ 423 return (0); 424} 425 426static void 427meta_vtoc_to_md( 428 struct extvtoc *vp, 429 mdvtoc_t *mdvp 430) 431{ 432 char typename[sizeof (vp->v_asciilabel) + 1]; 433 uint_t i; 434 435 (void) memset(mdvp, '\0', sizeof (*mdvp)); 436 (void) strncpy(typename, vp->v_asciilabel, 437 sizeof (vp->v_asciilabel)); 438 typename[sizeof (typename) - 1] = '\0'; 439 for (i = 0; ((i < sizeof (typename)) && (typename[i] != '\0')); ++i) { 440 if ((typename[i] == ' ') || (typename[i] == '\t')) { 441 typename[i] = '\0'; 442 break; 443 } 444 } 445 mdvp->typename = Strdup(typename); 446 mdvp->nparts = vp->v_nparts; 447 for (i = 0; (i < vp->v_nparts); ++i) { 448 mdvp->parts[i].start = vp->v_part[i].p_start; 449 mdvp->parts[i].size = vp->v_part[i].p_size; 450 mdvp->parts[i].tag = vp->v_part[i].p_tag; 451 mdvp->parts[i].flag = vp->v_part[i].p_flag; 452 if (vp->v_part[i].p_start == 0 && vp->v_part[i].p_size > 0) 453 mdvp->parts[i].label = btodb(DK_LABEL_SIZE); 454 } 455} 456 457/* 458 * free allocations in vtoc 459 */ 460void 461metafreevtoc( 462 mdvtoc_t *vtocp 463) 464{ 465 if (vtocp->typename != NULL) 466 Free(vtocp->typename); 467 (void) memset(vtocp, 0, sizeof (*vtocp)); 468} 469 470/* 471 * return md types 472 */ 473mdvtoc_t * 474metagetvtoc( 475 mdname_t *np, /* only rname, drivenamep, are setup */ 476 int nocache, 477 uint_t *partnop, 478 md_error_t *ep 479) 480{ 481 mddrivename_t *dnp = np->drivenamep; 482 struct dk_geom geom; 483 char *minor_name = NULL; 484 char *rname = np->rname; 485 int fd; 486 int partno; 487 int err = 0; /* saves errno from ioctl */ 488 ddi_devid_t devid; 489 char *p; 490 491 /* short circuit */ 492 if ((! nocache) && (dnp->vtoc.nparts != 0)) { 493 if (partnop != NULL) { 494 /* 495 * the following assigment works because the 496 * mdname_t structs are always created as part 497 * of the drivenamep struct. When a user 498 * creates an mdname_t struct it either 499 * uses an existing drivenamep struct or creates 500 * a new one and then adds the mdname_t struct 501 * as part of its parts_val array. So what is 502 * being computed below is the slice offset in 503 * the parts_val array. 504 */ 505 *partnop = np - np->drivenamep->parts.parts_val; 506 assert(*partnop < dnp->parts.parts_len); 507 } 508 return (&dnp->vtoc); 509 } 510 511 /* can't get vtoc */ 512 if (! nocache) { 513 switch (dnp->type) { 514 case MDT_ACCES: 515 case MDT_UNKNOWN: 516 (void) mdsyserror(ep, dnp->errnum, rname); 517 return (NULL); 518 } 519 } 520 521 /* get all the info */ 522 if ((fd = open(rname, (O_RDONLY|O_NDELAY), 0)) < 0) { 523 (void) mdsyserror(ep, errno, rname); 524 return (NULL); 525 } 526 527 /* 528 * The disk is open so this is a good point to get the devid 529 * otherwise it will need to be done at another time which 530 * means reopening it. 531 */ 532 if (devid_get(fd, &devid) != 0) { 533 /* there is no devid for the disk */ 534 if (((p = getenv("MD_DEBUG")) != NULL) && 535 (strstr(p, "DEVID") != NULL)) { 536 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 537 "%s has no device id\n"), np->rname); 538 } 539 np->minor_name = (char *)NULL; 540 dnp->devid = NULL; 541 } else { 542 (void) devid_get_minor_name(fd, &minor_name); 543 /* 544 * The minor name could be NULL if the underlying 545 * device driver does not support 'minor names'. 546 * This means we do not use devid's for this device. 547 * SunCluster did driver does not support minor names. 548 */ 549 if (minor_name != NULL) { 550 np->minor_name = Strdup(minor_name); 551 devid_str_free(minor_name); 552 dnp->devid = devid_str_encode(devid, NULL); 553 } else { 554 np->minor_name = (char *)NULL; 555 dnp->devid = NULL; 556 557 if (((p = getenv("MD_DEBUG")) != NULL) && 558 (strstr(p, "DEVID") != NULL)) { 559 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 560 "%s no minor name (no devid)\n"), 561 np->rname); 562 } 563 } 564 devid_free(devid); 565 } 566 567 /* 568 * if our drivenamep points to a device not supporting DKIOCGGEOM, 569 * it's likely to have an EFI label. 570 */ 571 (void) memset(&geom, 0, sizeof (geom)); 572 if (ioctl(fd, DKIOCGGEOM, &geom) != 0) { 573 err = errno; 574 if (err == ENOTTY) { 575 (void) mddeverror(ep, MDE_NOT_DISK, NODEV, rname); 576 (void) close(fd); 577 return (NULL); 578 } else if (err != ENOTSUP) { 579 (void) mdsyserror(ep, err, rname); 580 (void) close(fd); 581 return (NULL); 582 } 583 584 } 585 /* 586 * If we are here, there was either no failure on DKIOCGGEOM or 587 * the failure was ENOTSUP 588 */ 589 if (err == ENOTSUP) { 590 /* DKIOCGGEOM yielded ENOTSUP => try efi_alloc_and_read */ 591 struct dk_gpt *gpt; 592 int save_errno; 593 594 /* this also sets errno */ 595 partno = efi_alloc_and_read(fd, &gpt); 596 save_errno = errno; 597 (void) close(fd); 598 if (partno < 0) { 599 efi_free(gpt); 600 (void) mdsyserror(ep, save_errno, rname); 601 return (NULL); 602 } 603 if (partno >= gpt->efi_nparts) { 604 efi_free(gpt); 605 (void) mddeverror(ep, MDE_INVALID_PART, NODEV64, 606 rname); 607 return (NULL); 608 } 609 610 /* convert to our format */ 611 metafreevtoc(&dnp->vtoc); 612 meta_efi_to_mdvtoc(gpt, &dnp->vtoc); 613 if (dnp->vtoc.nparts > MD_MAX_PARTS) { 614 (void) mddeverror(ep, MDE_TOO_MANY_PARTS, NODEV64, 615 rname); 616 return (NULL); 617 } 618 /* 619 * libmeta needs at least V_NUMPAR partitions. 620 * If we have an EFI partition with less than V_NUMPAR slices, 621 * we nevertheless reserve space for V_NUMPAR 622 */ 623 624 if (dnp->vtoc.nparts < V_NUMPAR) { 625 dnp->vtoc.nparts = V_NUMPAR; 626 } 627 meta_efi_to_mdgeom(gpt, &dnp->geom); 628 efi_free(gpt); 629 } else { 630 /* no error on DKIOCGGEOM, try meta_getvtoc */ 631 struct extvtoc vtoc; 632 633 if (meta_getvtoc(fd, np->cname, &vtoc, &partno, ep) < 0) { 634 (void) close(fd); 635 return (NULL); 636 } 637 (void) close(fd); 638 639 /* convert to our format */ 640 meta_geom_to_md(&geom, &dnp->geom); 641 metafreevtoc(&dnp->vtoc); 642 meta_vtoc_to_md(&vtoc, &dnp->vtoc); 643 } 644 645 /* fix up any drives which are now accessible */ 646 if ((nocache) && (dnp->type == MDT_ACCES) && 647 (dnp->vtoc.nparts == dnp->parts.parts_len)) { 648 dnp->type = MDT_COMP; 649 dnp->errnum = 0; 650 } 651 652 /* save partno */ 653 assert(partno < dnp->vtoc.nparts); 654 if (partnop != NULL) 655 *partnop = partno; 656 657 /* return info */ 658 return (&dnp->vtoc); 659} 660 661static void 662meta_mdvtoc_to_vtoc( 663 mdvtoc_t *mdvp, 664 struct extvtoc *vp 665) 666{ 667 uint_t i; 668 669 (void) memset(&vp->v_part, '\0', sizeof (vp->v_part)); 670 vp->v_nparts = (ushort_t)mdvp->nparts; 671 for (i = 0; (i < mdvp->nparts); ++i) { 672 vp->v_part[i].p_start = mdvp->parts[i].start; 673 vp->v_part[i].p_size = mdvp->parts[i].size; 674 vp->v_part[i].p_tag = mdvp->parts[i].tag; 675 vp->v_part[i].p_flag = mdvp->parts[i].flag; 676 } 677} 678 679/* 680 * Set the vtoc, but use the cached copy to get the info from. 681 * We write np->drivenamep->vtoc to disk. 682 * Before we can do this we read the vtoc in. 683 * if we're dealing with a metadevice and this metadevice is a 64 bit device 684 * we can use meta_getmdvtoc/meta_setmdvtoc 685 * else 686 * we use meta_getvtoc/meta_setvtoc but than we first have to convert 687 * dnp->vtoc (actually being a mdvtoc_t) into a vtoc_t 688 */ 689int 690metasetvtoc( 691 mdname_t *np, 692 md_error_t *ep 693) 694{ 695 char *rname = np->rname; 696 mddrivename_t *dnp = np->drivenamep; 697 int fd; 698 int err; 699 int save_errno; 700 struct dk_geom geom; 701 702 if ((fd = open(rname, (O_RDONLY | O_NDELAY), 0)) < 0) 703 return (mdsyserror(ep, errno, rname)); 704 705 err = ioctl(fd, DKIOCGGEOM, &geom); 706 save_errno = errno; 707 if (err == 0) { 708 struct extvtoc vtoc; 709 710 if (meta_getvtoc(fd, np->cname, &vtoc, NULL, ep) < 0) { 711 (void) close(fd); 712 return (-1); 713 } 714 715 meta_mdvtoc_to_vtoc(&dnp->vtoc, &vtoc); 716 717 if (meta_setvtoc(fd, np->cname, &vtoc, ep) < 0) { 718 (void) close(fd); 719 return (-1); 720 } 721 } else if (save_errno == ENOTSUP) { 722 struct dk_gpt *gpt; 723 int ret; 724 725 /* allocation of gpt is done in meta_mdvtoc_to_efi */ 726 meta_mdvtoc_to_efi(&dnp->vtoc, &gpt); 727 728 ret = efi_write(fd, gpt); 729 save_errno = errno; 730 free(gpt); 731 if (ret != 0) { 732 (void) close(fd); 733 return (mdsyserror(ep, save_errno, rname)); 734 } else { 735 (void) close(fd); 736 return (0); 737 } 738 739 } else { 740 (void) close(fd); 741 return (mdsyserror(ep, save_errno, rname)); 742 } 743 744 (void) close(fd); 745 746 return (0); 747} 748 749mdgeom_t * 750metagetgeom( 751 mdname_t *np, /* only rname, drivenamep, are setup */ 752 md_error_t *ep 753) 754{ 755 if (metagetvtoc(np, FALSE, NULL, ep) == NULL) 756 return (NULL); 757 return (&np->drivenamep->geom); 758} 759 760mdcinfo_t * 761metagetcinfo( 762 mdname_t *np, /* only rname, drivenamep, are setup */ 763 md_error_t *ep 764) 765{ 766 char *rname = np->rname; 767 mddrivename_t *dnp = np->drivenamep; 768 int fd; 769 struct dk_cinfo cinfo; 770 771 /* short circuit */ 772 if (dnp->cinfo.cname[0] != '\0') 773 return (&dnp->cinfo); 774 775 /* get controller info */ 776 if ((fd = open(rname, (O_RDONLY|O_NDELAY), 0)) < 0) { 777 (void) mdsyserror(ep, errno, rname); 778 return (NULL); 779 } 780 if (ioctl(fd, DKIOCINFO, &cinfo) != 0) { 781 int save = errno; 782 783 (void) close(fd); 784 if (save == ENOTTY) { 785 (void) mddeverror(ep, MDE_NOT_DISK, NODEV64, rname); 786 } else { 787 (void) mdsyserror(ep, save, rname); 788 } 789 return (NULL); 790 } 791 (void) close(fd); /* sd/ssd bug */ 792 793 /* convert to our format */ 794 if (meta_cinfo_to_md(np, &cinfo, &dnp->cinfo, ep) != 0) 795 return (NULL); 796 797 /* return info */ 798 return (&dnp->cinfo); 799} 800 801/* 802 * get partition number 803 */ 804int 805metagetpartno( 806 mdname_t *np, 807 md_error_t *ep 808) 809{ 810 mdvtoc_t *vtocp; 811 uint_t partno; 812 813 if ((vtocp = metagetvtoc(np, FALSE, &partno, ep)) == NULL) 814 return (-1); 815 assert(partno < vtocp->nparts); 816 return (partno); 817} 818 819/* 820 * get size of device 821 */ 822diskaddr_t 823metagetsize( 824 mdname_t *np, 825 md_error_t *ep 826) 827{ 828 mdvtoc_t *vtocp; 829 uint_t partno; 830 831 if ((vtocp = metagetvtoc(np, FALSE, &partno, ep)) == NULL) 832 return (MD_DISKADDR_ERROR); 833 assert(partno < vtocp->nparts); 834 return (vtocp->parts[partno].size); 835} 836 837/* 838 * get label of device 839 */ 840diskaddr_t 841metagetlabel( 842 mdname_t *np, 843 md_error_t *ep 844) 845{ 846 mdvtoc_t *vtocp; 847 uint_t partno; 848 849 if ((vtocp = metagetvtoc(np, FALSE, &partno, ep)) == NULL) 850 return (MD_DISKADDR_ERROR); 851 assert(partno < vtocp->nparts); 852 return (vtocp->parts[partno].label); 853} 854 855/* 856 * find out where database replicas end 857 */ 858static int 859mddb_getendblk( 860 mdsetname_t *sp, 861 mdname_t *np, 862 diskaddr_t *endblkp, 863 md_error_t *ep 864) 865{ 866 md_replicalist_t *rlp = NULL; 867 md_replicalist_t *rl; 868 869 /* make sure we have a component */ 870 *endblkp = 0; 871 if (metaismeta(np)) 872 return (0); 873 874 /* get replicas, quit if none */ 875 if (metareplicalist(sp, MD_BASICNAME_OK | PRINT_FAST, &rlp, ep) < 0) { 876 if (! mdismddberror(ep, MDE_DB_NODB)) 877 return (-1); 878 mdclrerror(ep); 879 return (0); 880 } else if (rlp == NULL) 881 return (0); 882 883 /* go through all the replicas */ 884 for (rl = rlp; (rl != NULL); rl = rl->rl_next) { 885 md_replica_t *rp = rl->rl_repp; 886 mdname_t *repnamep = rp->r_namep; 887 diskaddr_t dbend; 888 889 if (np->dev != repnamep->dev) 890 continue; 891 dbend = rp->r_blkno + rp->r_nblk - 1; 892 if (dbend > *endblkp) 893 *endblkp = dbend; 894 } 895 896 /* cleanup, return success */ 897 metafreereplicalist(rlp); 898 return (0); 899} 900 901/* 902 * return cached start block 903 */ 904static diskaddr_t 905metagetend( 906 mdsetname_t *sp, 907 mdname_t *np, 908 md_error_t *ep 909) 910{ 911 diskaddr_t end_blk = MD_DISKADDR_ERROR; 912 913 /* short circuit */ 914 if (np->end_blk != MD_DISKADDR_ERROR) 915 return (np->end_blk); 916 917 /* look for database locations */ 918 if (mddb_getendblk(sp, np, &end_blk, ep) != 0) 919 return (MD_DISKADDR_ERROR); 920 921 /* success */ 922 np->end_blk = end_blk; 923 return (end_blk); 924} 925 926/* 927 * does device have a metadb 928 */ 929int 930metahasmddb( 931 mdsetname_t *sp, 932 mdname_t *np, 933 md_error_t *ep 934) 935{ 936 if (metagetend(sp, np, ep) == MD_DISKADDR_ERROR) 937 return (-1); 938 else if (np->end_blk > 0) 939 return (1); 940 else 941 return (0); 942} 943 944/* 945 * return cached start block 946 */ 947diskaddr_t 948metagetstart( 949 mdsetname_t *sp, 950 mdname_t *np, 951 md_error_t *ep 952) 953{ 954 diskaddr_t start_blk = MD_DISKADDR_ERROR; 955 956 /* short circuit */ 957 if (np->start_blk != MD_DISKADDR_ERROR) 958 return (np->start_blk); 959 960 /* look for database locations */ 961 if ((start_blk = metagetend(sp, np, ep)) == MD_DISKADDR_ERROR) 962 return (MD_DISKADDR_ERROR); 963 964 /* check for label */ 965 if (start_blk == 0) { 966 start_blk = metagetlabel(np, ep); 967 if (start_blk == MD_DISKADDR_ERROR) { 968 return (MD_DISKADDR_ERROR); 969 } 970 } 971 972 /* roundup to next cylinder */ 973 if (start_blk != 0) { 974 mdgeom_t *geomp; 975 976 if ((geomp = metagetgeom(np, ep)) == NULL) 977 return (MD_DISKADDR_ERROR); 978 start_blk = roundup(start_blk, (geomp->nhead * geomp->nsect)); 979 } 980 981 /* success */ 982 np->start_blk = start_blk; 983 return (start_blk); 984} 985 986/* 987 * return cached devices name 988 */ 989char * 990metagetdevicesname( 991 mdname_t *np, 992 md_error_t *ep 993) 994{ 995 char path[MAXPATHLEN + 1]; 996 int len; 997 998 /* short circuit */ 999 if (np->devicesname != NULL) 1000 return (np->devicesname); 1001 1002 /* follow symlink */ 1003 if ((len = readlink(np->bname, path, (sizeof (path) - 1))) < 0) { 1004 (void) mdsyserror(ep, errno, np->bname); 1005 return (NULL); 1006 } else if (len >= sizeof (path)) { 1007 (void) mdsyserror(ep, ENAMETOOLONG, np->bname); 1008 return (NULL); 1009 } 1010 path[len] = '\0'; 1011 if ((len = strfind(path, "/devices/")) < 0) { 1012 (void) mddeverror(ep, MDE_DEVICES_NAME, np->dev, np->bname); 1013 return (NULL); 1014 } 1015 1016 /* return name */ 1017 np->devicesname = Strdup(path + len + strlen("/devices")); 1018 return (np->devicesname); 1019} 1020 1021/* 1022 * get metadevice misc name 1023 */ 1024char * 1025metagetmiscname( 1026 mdname_t *np, 1027 md_error_t *ep 1028) 1029{ 1030 mddrivename_t *dnp = np->drivenamep; 1031 md_i_driverinfo_t mid; 1032 1033 /* short circuit */ 1034 if (dnp->miscname != NULL) 1035 return (dnp->miscname); 1036 if (metachkmeta(np, ep) != 0) 1037 return (NULL); 1038 1039 /* get misc module from driver */ 1040 (void) memset(&mid, 0, sizeof (mid)); 1041 mid.mnum = meta_getminor(np->dev); 1042 if (metaioctl(MD_IOCGET_DRVNM, &mid, &mid.mde, np->cname) != 0) { 1043 (void) mdstealerror(ep, &mid.mde); 1044 return (NULL); 1045 } 1046 1047 /* return miscname */ 1048 dnp->miscname = Strdup(MD_PNTDRIVERNAME(&mid)); 1049 return (dnp->miscname); 1050} 1051 1052/* 1053 * get unit structure from driver 1054 */ 1055md_unit_t * 1056meta_get_mdunit( 1057 mdsetname_t *sp, 1058 mdname_t *np, 1059 md_error_t *ep 1060) 1061{ 1062 md_i_get_t mig; 1063 char *miscname = NULL; 1064 1065 /* should have a set */ 1066 assert(sp != NULL); 1067 assert(sp->setno == MD_MIN2SET(meta_getminor(np->dev))); 1068 1069 /* get size of unit structure */ 1070 if (metachkmeta(np, ep) != 0) 1071 return (NULL); 1072 if ((miscname = metagetmiscname(np, ep)) == NULL) 1073 return (NULL); 1074 (void) memset(&mig, '\0', sizeof (mig)); 1075 MD_SETDRIVERNAME(&mig, miscname, sp->setno); 1076 mig.id = meta_getminor(np->dev); 1077 if (metaioctl(MD_IOCGET, &mig, &mig.mde, np->cname) != 0) { 1078 (void) mdstealerror(ep, &mig.mde); 1079 return (NULL); 1080 } 1081 1082 /* get actual unit structure */ 1083 assert(mig.size > 0); 1084 mig.mdp = (uintptr_t)Zalloc(mig.size); 1085 if (metaioctl(MD_IOCGET, &mig, &mig.mde, np->cname) != 0) { 1086 (void) mdstealerror(ep, &mig.mde); 1087 Free((void *)(uintptr_t)mig.mdp); 1088 return (NULL); 1089 } 1090 1091 return ((md_unit_t *)(uintptr_t)mig.mdp); 1092} 1093 1094/* 1095 * free metadevice unit 1096 */ 1097void 1098meta_free_unit( 1099 mddrivename_t *dnp 1100) 1101{ 1102 if (dnp->unitp != NULL) { 1103 switch (dnp->unitp->type) { 1104 case MD_DEVICE: 1105 meta_free_stripe((md_stripe_t *)dnp->unitp); 1106 break; 1107 case MD_METAMIRROR: 1108 meta_free_mirror((md_mirror_t *)dnp->unitp); 1109 break; 1110 case MD_METATRANS: 1111 meta_free_trans((md_trans_t *)dnp->unitp); 1112 break; 1113 case MD_METARAID: 1114 meta_free_raid((md_raid_t *)dnp->unitp); 1115 break; 1116 case MD_METASP: 1117 meta_free_sp((md_sp_t *)dnp->unitp); 1118 break; 1119 default: 1120 assert(0); 1121 break; 1122 } 1123 dnp->unitp = NULL; 1124 } 1125} 1126 1127/* 1128 * free metadevice name info 1129 */ 1130void 1131meta_invalidate_name( 1132 mdname_t *namep 1133) 1134{ 1135 mddrivename_t *dnp = namep->drivenamep; 1136 1137 /* get rid of cached name info */ 1138 if (namep->devicesname != NULL) { 1139 Free(namep->devicesname); 1140 namep->devicesname = NULL; 1141 } 1142 namep->key = MD_KEYBAD; 1143 namep->start_blk = -1; 1144 namep->end_blk = -1; 1145 1146 /* get rid of cached drivename info */ 1147 (void) memset(&dnp->geom, 0, sizeof (dnp->geom)); 1148 (void) memset(&dnp->cinfo, 0, sizeof (dnp->cinfo)); 1149 metafreevtoc(&dnp->vtoc); 1150 metaflushsidenames(dnp); 1151 dnp->side_names_key = MD_KEYBAD; 1152 if (dnp->miscname != NULL) { 1153 Free(dnp->miscname); 1154 dnp->miscname = NULL; 1155 } 1156 meta_free_unit(dnp); 1157} 1158 1159/* 1160 * get metadevice unit 1161 */ 1162md_common_t * 1163meta_get_unit( 1164 mdsetname_t *sp, 1165 mdname_t *np, 1166 md_error_t *ep 1167) 1168{ 1169 char *miscname; 1170 1171 /* short circuit */ 1172 if (np->drivenamep->unitp != NULL) 1173 return (np->drivenamep->unitp); 1174 if (metachkmeta(np, ep) != 0) 1175 return (NULL); 1176 1177 /* dispatch */ 1178 if ((miscname = metagetmiscname(np, ep)) == NULL) 1179 return (NULL); 1180 else if (strcmp(miscname, MD_STRIPE) == 0) 1181 return ((md_common_t *)meta_get_stripe(sp, np, ep)); 1182 else if (strcmp(miscname, MD_MIRROR) == 0) 1183 return ((md_common_t *)meta_get_mirror(sp, np, ep)); 1184 else if (strcmp(miscname, MD_TRANS) == 0) 1185 return ((md_common_t *)meta_get_trans(sp, np, ep)); 1186 else if (strcmp(miscname, MD_RAID) == 0) 1187 return ((md_common_t *)meta_get_raid(sp, np, ep)); 1188 else if (strcmp(miscname, MD_SP) == 0) 1189 return ((md_common_t *)meta_get_sp(sp, np, ep)); 1190 else { 1191 (void) mdmderror(ep, MDE_UNKNOWN_TYPE, meta_getminor(np->dev), 1192 np->cname); 1193 return (NULL); 1194 } 1195} 1196 1197 1198int 1199meta_isopen( 1200 mdsetname_t *sp, 1201 mdname_t *np, 1202 md_error_t *ep, 1203 mdcmdopts_t options 1204) 1205{ 1206 md_isopen_t d; 1207 1208 if (metachkmeta(np, ep) != 0) 1209 return (-1); 1210 1211 (void) memset(&d, '\0', sizeof (d)); 1212 d.dev = np->dev; 1213 if (metaioctl(MD_IOCISOPEN, &d, &d.mde, np->cname) != 0) 1214 return (mdstealerror(ep, &d.mde)); 1215 1216 /* 1217 * shortcut: if the device is open, no need to check on other nodes, 1218 * even in case of a mn metadevice 1219 * Also return in case we're told not to check on other nodes. 1220 */ 1221 if ((d.isopen != 0) || ((options & MDCMD_MN_OPEN_CHECK) == 0)) { 1222 return (d.isopen); 1223 } 1224 1225 /* 1226 * If the device is closed locally, but it's a mn device, 1227 * check on all other nodes, too 1228 */ 1229 if (sp->setno != MD_LOCAL_SET) { 1230 (void) metaget_setdesc(sp, ep); /* not supposed to fail */ 1231 if (sp->setdesc->sd_flags & MD_SR_MN) { 1232 int err = 0; 1233 md_mn_result_t *resp; 1234 /* 1235 * This message is never directly issued. 1236 * So we launch it with a suspend override flag. 1237 * If the commd is suspended, and this message comes 1238 * along it must be sent due to replaying a metainit or 1239 * similar. In that case we don't want this message to 1240 * be blocked. 1241 * If the commd is not suspended, the flag does no harm. 1242 * Additionally we don't want the result of the message 1243 * cached in the MCT, because we want uptodate results, 1244 * and the message doesn't need being logged either. 1245 * Hence NO_LOG and NO_MCT 1246 */ 1247 err = mdmn_send_message(sp->setno, 1248 MD_MN_MSG_CLU_CHECK, MD_MSGF_NO_MCT | 1249 MD_MSGF_STOP_ON_ERROR | MD_MSGF_NO_LOG | 1250 MD_MSGF_OVERRIDE_SUSPEND, 0, (char *)&d, 1251 sizeof (md_isopen_t), &resp, ep); 1252 if (err == 0) { 1253 d.isopen = resp->mmr_exitval; 1254 } else { 1255 /* 1256 * in case some error occurred, 1257 * we better say the device is open 1258 */ 1259 d.isopen = 1; 1260 } 1261 if (resp != (md_mn_result_t *)NULL) { 1262 free_result(resp); 1263 } 1264 1265 } 1266 } 1267 1268 return (d.isopen); 1269} 1270