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 2003 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 #include "mhd_local.h" 30 31 #include <ftw.h> 32 #include <libgen.h> 33 #include <sys/mhd.h> 34 #include <sys/scsi/impl/uscsi.h> 35 #include <sys/scsi/generic/commands.h> 36 #include <sys/scsi/generic/inquiry.h> 37 38 /* 39 * manipulate drives 40 */ 41 42 /* 43 * null list constant 44 */ 45 const mhd_drive_list_t mhd_null_list = MHD_NULL_LIST; 46 47 /* 48 * add drive to list 49 */ 50 void 51 mhd_add_drive( 52 mhd_drive_list_t *dlp, 53 mhd_drive_t *dp 54 ) 55 { 56 /* add drive to list */ 57 if (dlp->dl_ndrive >= dlp->dl_alloc) { 58 dlp->dl_alloc += 10; 59 dlp->dl_drives = Realloc(dlp->dl_drives, 60 (dlp->dl_alloc * sizeof (*dlp->dl_drives))); 61 } 62 dlp->dl_drives[dlp->dl_ndrive++] = dp; 63 } 64 65 /* 66 * delete drive from list 67 */ 68 void 69 mhd_del_drive( 70 mhd_drive_list_t *dlp, 71 mhd_drive_t *dp 72 ) 73 { 74 uint_t i; 75 76 /* delete drive from list */ 77 for (i = 0; (i < dlp->dl_ndrive); ++i) { 78 if (dlp->dl_drives[i] == dp) 79 break; 80 } 81 assert(dlp->dl_drives[i] == dp); 82 for (/* void */; (i < dlp->dl_ndrive); ++i) 83 dlp->dl_drives[i] = dlp->dl_drives[i + 1]; 84 dlp->dl_ndrive--; 85 } 86 87 /* 88 * free drive list 89 */ 90 void 91 mhd_free_list( 92 mhd_drive_list_t *dlp 93 ) 94 { 95 if (dlp->dl_drives != NULL) 96 Free(dlp->dl_drives); 97 (void) memset(dlp, 0, sizeof (*dlp)); 98 } 99 100 /* 101 * manipulate drive state 102 */ 103 int 104 mhd_state( 105 mhd_drive_t *dp, 106 mhd_state_t new_state, 107 mhd_error_t *mhep 108 ) 109 { 110 mhd_drive_set_t *sp = dp->dr_sp; 111 mhd_state_t old_state = dp->dr_state; 112 113 /* check lock */ 114 assert(MUTEX_HELD(&sp->sr_mx)); 115 116 /* set state and kick thread */ 117 MHDPRINTF2(("%s: state 0x%x now 0x%x\n", 118 dp->dr_rname, dp->dr_state, new_state)); 119 dp->dr_state = new_state; 120 mhd_cv_broadcast(&dp->dr_cv); 121 122 /* if this is the last PROBING drive, disable any failfast */ 123 if ((old_state & DRIVE_PROBING) && (! (new_state & DRIVE_PROBING))) { 124 mhd_drive_list_t *dlp = &sp->sr_drives; 125 uint_t cnt, i; 126 127 for (cnt = 0, i = 0; (i < dlp->dl_ndrive); ++i) { 128 if (dlp->dl_drives[i]->dr_state & DRIVE_PROBING) 129 ++cnt; 130 } 131 if (cnt == 0) { 132 mhd_error_t status = mhd_null_error; 133 134 if (mhep == NULL) 135 mhep = &status; 136 if (mhd_ff_disarm(sp, mhep) != 0) { 137 if (mhep == &status) { 138 mhde_perror(mhep, dp->dr_rname); 139 mhd_clrerror(mhep); 140 } 141 return (-1); 142 } 143 } 144 } 145 146 /* return success */ 147 return (0); 148 } 149 150 int 151 mhd_state_set( 152 mhd_drive_t *dp, 153 mhd_state_t new_state, 154 mhd_error_t *mhep 155 ) 156 { 157 return (mhd_state(dp, (dp->dr_state | new_state), mhep)); 158 } 159 160 static int 161 mhd_state_clr( 162 mhd_drive_t *dp, 163 mhd_state_t new_state, 164 mhd_error_t *mhep 165 ) 166 { 167 return (mhd_state(dp, (dp->dr_state & ~new_state), mhep)); 168 } 169 170 /* 171 * idle a drive 172 */ 173 int 174 mhd_idle( 175 mhd_drive_t *dp, 176 mhd_error_t *mhep 177 ) 178 { 179 mhd_drive_set_t *sp = dp->dr_sp; 180 181 /* check lock */ 182 assert(MUTEX_HELD(&sp->sr_mx)); 183 184 /* wait for thread to idle */ 185 for (;;) { 186 if (DRIVE_IS_IDLE(dp)) 187 return (0); 188 if (mhd_state(dp, DRIVE_IDLING, mhep) != 0) 189 return (-1); 190 (void) mhd_cv_wait(&sp->sr_cv, &sp->sr_mx); 191 } 192 } 193 194 /* 195 * reserve the drive 196 */ 197 static int 198 mhd_reserve( 199 mhd_drive_t *dp 200 ) 201 { 202 mhd_drive_set_t *sp = dp->dr_sp; 203 int serial = (sp->sr_options & MHD_SERIAL); 204 mhd_mhioctkown_t *tkp = &sp->sr_timeouts.mh_tk; 205 struct mhioctkown tkown; 206 int err; 207 208 /* check locks */ 209 assert(MUTEX_HELD(&sp->sr_mx)); 210 assert(dp->dr_fd >= 0); 211 assert(dp->dr_state == DRIVE_RESERVING); 212 213 /* setup timeouts */ 214 (void) memset(&tkown, 0, sizeof (tkown)); 215 tkown.reinstate_resv_delay = tkp->reinstate_resv_delay; 216 tkown.min_ownership_delay = tkp->min_ownership_delay; 217 tkown.max_ownership_delay = tkp->max_ownership_delay; 218 219 /* reserve drive */ 220 if (! serial) 221 mhd_mx_unlock(&sp->sr_mx); 222 err = ioctl(dp->dr_fd, MHIOCTKOWN, &tkown); 223 if (! serial) 224 mhd_mx_lock(&sp->sr_mx); 225 if (err != 0) { 226 mhd_perror("%s: MHIOCTKOWN", dp->dr_rname); 227 (void) mhd_state(dp, DRIVE_ERRORED, NULL); 228 dp->dr_errnum = errno; 229 return (-1); 230 } 231 232 /* return success */ 233 MHDPRINTF(("%s: MHIOCTKOWN: succeeded\n", dp->dr_rname)); 234 (void) mhd_state(dp, DRIVE_IDLE, NULL); 235 return (0); 236 } 237 238 /* 239 * failfast the drive 240 */ 241 static int 242 mhd_failfast( 243 mhd_drive_t *dp 244 ) 245 { 246 mhd_drive_set_t *sp = dp->dr_sp; 247 int serial = (sp->sr_options & MHD_SERIAL); 248 int ff = sp->sr_timeouts.mh_ff; 249 char *release = ((ff == 0) ? " (release)" : ""); 250 int err; 251 252 /* check locks */ 253 assert(MUTEX_HELD(&sp->sr_mx)); 254 assert(dp->dr_fd >= 0); 255 assert(dp->dr_state == DRIVE_FAILFASTING); 256 257 /* failfast drive */ 258 if (! serial) 259 mhd_mx_unlock(&sp->sr_mx); 260 err = ioctl(dp->dr_fd, MHIOCENFAILFAST, &ff); 261 if (! serial) 262 mhd_mx_lock(&sp->sr_mx); 263 if (err != 0) { 264 mhd_perror("%s: MHIOCENFAILFAST%s", dp->dr_rname, release); 265 (void) mhd_state(dp, DRIVE_ERRORED, NULL); 266 dp->dr_errnum = errno; 267 return (-1); 268 } 269 270 /* return success */ 271 MHDPRINTF(("%s: MHIOCENFAILFAST%s: succeeded\n", 272 dp->dr_rname, release)); 273 (void) mhd_state(dp, DRIVE_IDLE, NULL); 274 return (0); 275 } 276 277 /* 278 * release the drive 279 */ 280 static int 281 mhd_release( 282 mhd_drive_t *dp 283 ) 284 { 285 mhd_drive_set_t *sp = dp->dr_sp; 286 int serial = (sp->sr_options & MHD_SERIAL); 287 int ff = 0; /* disable failfast */ 288 int err; 289 290 /* check locks */ 291 assert(MUTEX_HELD(&sp->sr_mx)); 292 assert(dp->dr_fd >= 0); 293 assert(dp->dr_state == DRIVE_RELEASING); 294 295 /* disable failfast */ 296 if (! serial) 297 mhd_mx_unlock(&sp->sr_mx); 298 err = ioctl(dp->dr_fd, MHIOCENFAILFAST, &ff); 299 if (! serial) 300 mhd_mx_lock(&sp->sr_mx); 301 if (err != 0) { 302 mhd_perror("%s: MHIOCENFAILFAST (release)", dp->dr_rname); 303 (void) mhd_state(dp, DRIVE_ERRORED, NULL); 304 dp->dr_errnum = errno; 305 return (-1); 306 } 307 MHDPRINTF(("%s: MHIOCENFAILFAST (release): succeeded\n", 308 dp->dr_rname)); 309 310 /* release drive */ 311 if (! serial) 312 mhd_mx_unlock(&sp->sr_mx); 313 err = ioctl(dp->dr_fd, MHIOCRELEASE, NULL); 314 if (! serial) 315 mhd_mx_lock(&sp->sr_mx); 316 if (err != 0) { 317 mhd_perror("%s: MHIOCRELEASE", dp->dr_rname); 318 (void) mhd_state(dp, DRIVE_ERRORED, NULL); 319 dp->dr_errnum = errno; 320 return (-1); 321 } 322 323 /* return success */ 324 MHDPRINTF(("%s: MHIOCRELEASE: succeeded\n", dp->dr_rname)); 325 (void) mhd_state(dp, DRIVE_IDLE, NULL); 326 return (0); 327 } 328 329 /* 330 * probe the drive 331 */ 332 static int 333 mhd_probe( 334 mhd_drive_t *dp 335 ) 336 { 337 mhd_drive_set_t *sp = dp->dr_sp; 338 int serial = (sp->sr_options & MHD_SERIAL); 339 int err; 340 mhd_msec_t now; 341 342 /* check locks */ 343 assert(MUTEX_HELD(&sp->sr_mx)); 344 assert(dp->dr_fd >= 0); 345 assert(dp->dr_state & (DRIVE_PROBING | DRIVE_STATUSING)); 346 347 /* get status (we may get dumped from PROBING here) */ 348 if (! serial) 349 mhd_mx_unlock(&sp->sr_mx); 350 err = ioctl(dp->dr_fd, MHIOCSTATUS, NULL); 351 now = mhd_time(); 352 if (! serial) 353 mhd_mx_lock(&sp->sr_mx); 354 if (! (dp->dr_state & (DRIVE_PROBING | DRIVE_STATUSING))) 355 return (0); 356 357 /* update status */ 358 if (dp->dr_state & DRIVE_STATUSING) { 359 if (err == 1) { 360 MHDPRINTF(("%s: MHIOCSTATUS: reserved\n", 361 dp->dr_rname)); 362 dp->dr_errnum = MHD_E_RESERVED; 363 } else if (err != 0) { 364 mhd_perror("%s: MHIOCSTATUS", dp->dr_rname); 365 dp->dr_errnum = errno; 366 } else { 367 MHDPRINTF(("%s: MHIOCSTATUS: available\n", 368 dp->dr_rname)); 369 dp->dr_errnum = 0; 370 } 371 (void) mhd_state_clr(dp, DRIVE_STATUSING, NULL); 372 } 373 374 /* update time or die */ 375 if (dp->dr_state & DRIVE_PROBING) { 376 /* check our drive */ 377 if (err == 0) { 378 dp->dr_time = now; 379 } else if (err == 1) { 380 mhd_eprintf("%s: %s: reservation conflict\n", 381 sp->sr_name, dp->dr_rname); 382 mhd_ff_die(sp); 383 } 384 385 /* check other drives */ 386 mhd_ff_check(sp); 387 } 388 389 /* return success */ 390 return (0); 391 } 392 393 /* 394 * cached controller map 395 */ 396 typedef struct { 397 char *regexpr1; 398 uint_t tray; 399 uint_t bus; 400 char *regexpr2; 401 char *scan; 402 } mhd_ctlrmap_t; 403 404 static rwlock_t ctlr_rw = DEFAULTRWLOCK; 405 static time_t ctlr_mtime = 0; 406 static size_t ctlr_num = 0; 407 static mhd_ctlrmap_t *ctlr_map = NULL; 408 409 /* 410 * free up controller map 411 */ 412 static void 413 free_map() 414 { 415 size_t i; 416 417 assert(RW_WRITE_HELD(&ctlr_rw)); 418 419 for (i = 0; (i < ctlr_num); ++i) { 420 mhd_ctlrmap_t *cmp = &ctlr_map[i]; 421 422 if (cmp->regexpr1 != NULL) 423 Free(cmp->regexpr1); 424 if (cmp->regexpr2 != NULL) 425 Free(cmp->regexpr2); 426 if (cmp->scan != NULL) 427 Free(cmp->scan); 428 } 429 if (ctlr_map != NULL) 430 Free(ctlr_map); 431 ctlr_num = 0; 432 ctlr_map = NULL; 433 } 434 435 /* 436 * unlock controller map 437 */ 438 static void 439 unlock_map() 440 { 441 assert(RW_WRITE_HELD(&ctlr_rw) | RW_READ_HELD(&ctlr_rw)); 442 443 mhd_rw_unlock(&ctlr_rw); 444 } 445 446 /* 447 * update controller map and lock it 448 */ 449 static int 450 update_map() 451 { 452 struct stat statbuf; 453 FILE *fp; 454 char line[256], expr1[256], expr2[256], scan[256]; 455 unsigned tray, bus; 456 int rval = -1; 457 458 /* see if map file has changed */ 459 mhd_rw_rdlock(&ctlr_rw); 460 if (stat(METACTLRMAP, &statbuf) != 0) { 461 mhd_perror(METACTLRMAP); 462 goto out; 463 } 464 if (statbuf.st_mtime == ctlr_mtime) { 465 rval = 0; 466 goto out; 467 } 468 469 /* trade up to writer lock, check again */ 470 mhd_rw_unlock(&ctlr_rw); 471 mhd_rw_wrlock(&ctlr_rw); 472 if (statbuf.st_mtime == ctlr_mtime) { 473 rval = 0; 474 goto out; 475 } 476 if (ctlr_mtime != 0) 477 mhd_eprintf("updating controller map\n"); 478 ctlr_mtime = statbuf.st_mtime; 479 480 /* toss existing cache */ 481 free_map(); 482 483 /* parse md.ctlrmap */ 484 if ((fp = fopen(METACTLRMAP, "r")) == NULL) { 485 mhd_perror(METACTLRMAP); 486 goto out; 487 } 488 clearerr(fp); 489 while (fgets(line, sizeof (line), fp) != NULL) { 490 char *regexpr1 = NULL; 491 char *regexpr2 = NULL; 492 mhd_ctlrmap_t *cmp; 493 494 /* skip blank lines and comments */ 495 if ((line[0] == '\0') || (line[0] == '\n') || (line[0] == '#')) 496 continue; 497 498 /* parse line */ 499 if (((sscanf(line, "\"%[^\"]\" %u %u \"%[^\"]\" \"%[^\"]\"", 500 expr1, &tray, &bus, expr2, scan)) != 5) || 501 ((regexpr1 = regcmp(expr1, 0)) == NULL) || 502 ((regexpr2 = regcmp(expr2, 0)) == NULL)) { 503 mhd_eprintf("%s: bad regex(es) '%s'\n", 504 METACTLRMAP, line); 505 if (regexpr1 != NULL) 506 Free(regexpr1); 507 if (regexpr2 != NULL) 508 Free(regexpr2); 509 continue; 510 } 511 512 /* add to cache */ 513 ctlr_map = Realloc(ctlr_map, 514 ((ctlr_num + 1) * sizeof (*ctlr_map))); 515 cmp = &ctlr_map[ctlr_num++]; 516 cmp->regexpr1 = regexpr1; 517 cmp->tray = tray; 518 cmp->bus = bus; 519 cmp->regexpr2 = regexpr2; 520 cmp->scan = Strdup(scan); 521 } 522 if (ferror(fp)) { 523 mhd_perror(METACTLRMAP); 524 (void) fclose(fp); 525 goto out; 526 } 527 if (fclose(fp) != 0) { 528 mhd_perror(METACTLRMAP); 529 goto out; 530 } 531 532 /* success */ 533 rval = 0; 534 535 /* return success */ 536 out: 537 if (rval != 0) { 538 mhd_rw_unlock(&ctlr_rw); 539 return (-1); 540 } 541 return (0); 542 } 543 544 static char * 545 get_pln_ctlr_name( 546 char *path 547 ) 548 { 549 char *devicesname, *p; 550 char retval[MAXPATHLEN]; 551 552 devicesname = Strdup(path); 553 if ((p = strrchr(devicesname, '/')) == NULL) { 554 Free(devicesname); 555 return (NULL); 556 } 557 558 /* strip off the "ssd@..." portion of the devices name */ 559 *p = '\0'; 560 561 /* strip off the "../../" in front of "devices" */ 562 if ((p = strstr(devicesname, "/devices/")) == NULL) { 563 Free(devicesname); 564 return (NULL); 565 } 566 567 (void) snprintf(retval, sizeof (retval), "%s:ctlr", p); 568 Free(devicesname); 569 return (Strdup(retval)); 570 } 571 572 struct pln_cache { 573 char *pln_name; 574 enum mhd_ctlrtype_t ctype; 575 struct pln_cache *next; 576 }; 577 578 static struct pln_cache *pln_cache_anchor = NULL; 579 static mutex_t mhd_pln_mx = DEFAULTMUTEX; 580 581 /* singled threaded by caller */ 582 static void 583 add_pln_cache( 584 char *pln_name, 585 enum mhd_ctlrtype_t ctype 586 587 ) 588 { 589 struct pln_cache *p; 590 591 p = Malloc(sizeof (*p)); 592 593 p->pln_name = pln_name; 594 p->ctype = ctype; 595 p->next = pln_cache_anchor; 596 pln_cache_anchor = p; 597 } 598 599 /* singled threaded by caller */ 600 static int 601 find_pln_cache( 602 char *pln_name, 603 enum mhd_ctlrtype_t *ctype_ret 604 ) 605 { 606 struct pln_cache *p; 607 608 for (p = pln_cache_anchor; p != NULL; p = p->next) { 609 if (strcmp(pln_name, p->pln_name) == 0) { 610 *ctype_ret = p->ctype; 611 return (1); 612 } 613 } 614 return (0); 615 } 616 617 static void 618 free_pln_cache(void) 619 { 620 struct pln_cache *p, *n = NULL; 621 622 mutex_lock(&mhd_pln_mx); 623 for (p = pln_cache_anchor; p != NULL; p = n) { 624 n = p->next; 625 Free(p->pln_name); 626 Free(p); 627 } 628 629 pln_cache_anchor = NULL; 630 mutex_unlock(&mhd_pln_mx); 631 } 632 633 /* 634 * match on SSA Model 200. 635 */ 636 static void 637 match_SSA200( 638 mhd_drive_t *dp, 639 char *path 640 ) 641 { 642 mhd_cinfo_t *cinfop = &dp->dr_drive_id.did_cinfo; 643 struct uscsi_cmd ucmd; 644 union scsi_cdb cdb; 645 struct scsi_inquiry inq; 646 int fd; 647 char *pln_ctlr_name; 648 enum mhd_ctlrtype_t ctype; 649 char *p; 650 651 if ((pln_ctlr_name = get_pln_ctlr_name(path)) == NULL) 652 return; 653 654 mutex_lock(&mhd_pln_mx); 655 if (find_pln_cache(pln_ctlr_name, &ctype) == 1) { 656 mutex_unlock(&mhd_pln_mx); 657 if (ctype != MHD_CTLR_SSA200) 658 return; 659 660 /* over-ride for SSA200 */ 661 cinfop->mhc_ctype = ctype; 662 cinfop->mhc_tray = cinfop->mhc_bus; 663 return; 664 } 665 666 if ((fd = open(pln_ctlr_name, (O_RDONLY|O_NDELAY), 0)) < 0) { 667 mutex_unlock(&mhd_pln_mx); 668 Free(pln_ctlr_name); 669 return; 670 } 671 672 (void) memset(&ucmd, 0, sizeof (ucmd)); 673 (void) memset(&cdb, 0, sizeof (cdb)); 674 (void) memset(&inq, 0, sizeof (inq)); 675 cdb.scc_cmd = SCMD_INQUIRY; 676 cdb.g0_count0 = sizeof (inq); 677 ucmd.uscsi_cdb = (caddr_t)&cdb; 678 ucmd.uscsi_cdblen = CDB_GROUP0; 679 ucmd.uscsi_bufaddr = (caddr_t)&inq; 680 ucmd.uscsi_buflen = sizeof (inq); 681 ucmd.uscsi_flags = USCSI_READ | USCSI_ISOLATE | USCSI_DIAGNOSE; 682 ucmd.uscsi_timeout = 30; 683 if (ioctl(fd, USCSICMD, &ucmd)) { 684 mutex_unlock(&mhd_pln_mx); 685 (void) close(fd); 686 MHDPRINTF(("%s: USCSICMD(SCMD_INQUIRY): failed errno %d\n", 687 pln_ctlr_name, errno)); 688 Free(pln_ctlr_name); 689 return; 690 } 691 692 (void) close(fd); 693 MHDPRINTF(("%s: USCSICMD(SCMD_INQUIRY): success\n", pln_ctlr_name)); 694 695 /* Make all trailing spaces be null char */ 696 for (p = inq.inq_pid + sizeof (inq.inq_pid) - 1; p != inq.inq_pid; 697 p--) { 698 if (*p == '\0') 699 continue; 700 if (!isspace(*p)) 701 break; 702 *p = '\0'; 703 } 704 705 if (strncmp(inq.inq_pid, META_SSA200_PID, sizeof (inq.inq_pid)) != 0) 706 goto out; 707 708 /* over-ride the ctype, and tray */ 709 cinfop->mhc_ctype = MHD_CTLR_SSA200; 710 cinfop->mhc_tray = cinfop->mhc_bus; 711 712 out: 713 add_pln_cache(pln_ctlr_name, cinfop->mhc_ctype); 714 mutex_unlock(&mhd_pln_mx); 715 } 716 717 /* 718 * get controller info 719 */ 720 static void 721 match_SSA100( 722 mhd_drive_t *dp, 723 char *path 724 ) 725 { 726 mhd_cinfo_t *cinfop = &dp->dr_drive_id.did_cinfo; 727 uint_t i; 728 char *p; 729 lloff_t wwn; 730 const char *fmt; 731 732 /* update and lock controller map */ 733 if (update_map() != 0) 734 return; /* give up */ 735 assert(RW_WRITE_HELD(&ctlr_rw) || RW_READ_HELD(&ctlr_rw)); 736 737 /* look for match in cache */ 738 for (i = 0; (i < ctlr_num); ++i) { 739 mhd_ctlrmap_t *cmp = &ctlr_map[i]; 740 741 fmt = cmp->scan; 742 if ((regex(cmp->regexpr1, path) != NULL) && 743 ((p = regex(cmp->regexpr2, path)) != NULL) && 744 (sscanf(p, fmt, 745 (ulong_t *)&wwn._p._u, (ulong_t *)&wwn._p._l) == 2)) { 746 cinfop->mhc_ctype = MHD_CTLR_SSA100; 747 cinfop->mhc_tray = cmp->tray; 748 cinfop->mhc_bus = cmp->bus; 749 cinfop->mhc_wwn = wwn._f; 750 match_SSA200(dp, path); 751 break; 752 } 753 } 754 755 /* unlock controller map */ 756 unlock_map(); 757 } 758 759 /* 760 * get unique drive ID 761 */ 762 static int 763 mhd_ident( 764 mhd_drive_t *dp 765 ) 766 { 767 mhd_drive_set_t *sp = dp->dr_sp; 768 int serial = (sp->sr_options & MHD_SERIAL); 769 struct uscsi_cmd ucmd; 770 union scsi_cdb cdb; 771 struct scsi_inquiry inq; 772 struct vtoc vtoc_buf; 773 char path[MAXPATHLEN + 1]; 774 int len; 775 int err; 776 777 /* check locks */ 778 assert(MUTEX_HELD(&sp->sr_mx)); 779 assert(dp->dr_fd >= 0); 780 assert(dp->dr_state & DRIVE_IDENTING); 781 782 /* reset ID */ 783 (void) memset(&dp->dr_drive_id, 0, sizeof (dp->dr_drive_id)); 784 785 /* get serial number */ 786 if (dp->dr_state & DRIVE_SERIALING) { 787 if (! serial) 788 mhd_mx_unlock(&sp->sr_mx); 789 (void) memset(&ucmd, 0, sizeof (ucmd)); 790 (void) memset(&cdb, 0, sizeof (cdb)); 791 (void) memset(&inq, 0, sizeof (inq)); 792 cdb.scc_cmd = SCMD_INQUIRY; 793 cdb.g0_count0 = sizeof (inq); 794 ucmd.uscsi_cdb = (caddr_t)&cdb; 795 ucmd.uscsi_cdblen = CDB_GROUP0; 796 ucmd.uscsi_bufaddr = (caddr_t)&inq; 797 ucmd.uscsi_buflen = sizeof (inq); 798 ucmd.uscsi_flags = USCSI_READ | USCSI_ISOLATE | USCSI_DIAGNOSE; 799 ucmd.uscsi_timeout = 30; 800 err = ioctl(dp->dr_fd, USCSICMD, &ucmd); 801 if (! serial) 802 mhd_mx_lock(&sp->sr_mx); 803 if (err != 0) { 804 MHDPRINTF(( 805 "%s: USCSICMD(SCMD_INQUIRY): failed errno %d\n", 806 dp->dr_rname, errno)); 807 dp->dr_drive_id.did_flags &= ~MHD_DID_SERIAL; 808 } else { 809 char *p, *e; 810 uint_t i; 811 812 MHDPRINTF(("%s: USCSICMD(SCMD_INQUIRY): success\n", 813 dp->dr_rname)); 814 dp->dr_drive_id.did_flags |= MHD_DID_SERIAL; 815 p = dp->dr_drive_id.did_serial; 816 e = p + sizeof (dp->dr_drive_id.did_serial); 817 for (i = 0; 818 ((i < sizeof (inq.inq_vid)) && (p < e)); ++i) 819 *p++ = inq.inq_vid[i]; 820 for (i = 0; 821 ((i < sizeof (inq.inq_pid)) && (p < e)); ++i) 822 *p++ = inq.inq_pid[i]; 823 for (i = 0; 824 ((i < sizeof (inq.inq_revision)) && (p < e)); ++i) 825 *p++ = inq.inq_revision[i]; 826 for (i = 0; 827 ((i < sizeof (inq.inq_serial)) && (p < e)); ++i) 828 *p++ = inq.inq_serial[i]; 829 assert(p == e); 830 for (p = dp->dr_drive_id.did_serial; (p < e); ++p) { 831 if (*p == '\0') 832 *p = ' '; 833 } 834 } 835 } else { 836 dp->dr_drive_id.did_flags &= ~MHD_DID_SERIAL; 837 } 838 839 /* get VTOC */ 840 if (dp->dr_state & DRIVE_VTOCING) { 841 if (! serial) 842 mhd_mx_unlock(&sp->sr_mx); 843 (void) memset(&vtoc_buf, 0, sizeof (vtoc_buf)); 844 err = read_vtoc(dp->dr_fd, &vtoc_buf); 845 if (! serial) 846 mhd_mx_lock(&sp->sr_mx); 847 if (err < 0) { 848 MHDPRINTF(("%s: read_vtoc: failed errno %d\n", 849 dp->dr_rname, errno)); 850 dp->dr_drive_id.did_flags &= ~MHD_DID_TIME; 851 } else { 852 MHDPRINTF(("%s: read_vtoc: success\n", 853 dp->dr_rname)); 854 dp->dr_drive_id.did_flags |= MHD_DID_TIME; 855 dp->dr_drive_id.did_time = vtoc_buf.timestamp[0]; 856 } 857 } else { 858 dp->dr_drive_id.did_flags &= ~MHD_DID_TIME; 859 } 860 861 /* get controller info */ 862 if (dp->dr_state & DRIVE_CINFOING) { 863 if (! serial) 864 mhd_mx_unlock(&sp->sr_mx); 865 len = readlink(dp->dr_rname0, path, (sizeof (path) - 1)); 866 if (! serial) 867 mhd_mx_lock(&sp->sr_mx); 868 if (len >= sizeof (path)) { 869 len = -1; 870 errno = ENAMETOOLONG; 871 } 872 if (len < 0) { 873 MHDPRINTF(("%s: readlink: failed errno %d\n", 874 dp->dr_rname0, errno)); 875 dp->dr_drive_id.did_flags &= ~MHD_DID_CINFO; 876 } else { 877 MHDPRINTF(("%s: readlink: success\n", 878 dp->dr_rname0)); 879 dp->dr_drive_id.did_flags |= MHD_DID_CINFO; 880 (void) memset(&dp->dr_drive_id.did_cinfo, 0, 881 sizeof (dp->dr_drive_id.did_cinfo)); 882 match_SSA100(dp, path); 883 } 884 } else { 885 dp->dr_drive_id.did_flags &= ~MHD_DID_CINFO; 886 } 887 888 /* return success */ 889 (void) mhd_state_clr(dp, DRIVE_IDENTING, NULL); 890 return (0); 891 } 892 893 /* 894 * disk thread 895 */ 896 static void 897 mhd_drive_thread( 898 mhd_drive_t *dp 899 ) 900 { 901 mhd_drive_set_t *sp = dp->dr_sp; 902 903 /* wait for dp->dr_thread to be filled in */ 904 assert(sp != NULL); 905 mhd_mx_lock(&sp->sr_mx); 906 907 /* forever */ 908 for (;;) { 909 /* check locks */ 910 assert(MUTEX_HELD(&sp->sr_mx)); 911 assert(dp->dr_thread == thr_self()); 912 913 /* check for changed set */ 914 if (sp != dp->dr_sp) { 915 MHDPRINTF2(("%s: changed from set '%s' to '%s'\n", 916 dp->dr_rname, sp->sr_name, dp->dr_sp->sr_name)); 917 918 mhd_mx_unlock(&sp->sr_mx); 919 sp = dp->dr_sp; 920 mhd_mx_lock(&sp->sr_mx); 921 } 922 923 /* open drive, if necessary */ 924 if ((dp->dr_fd < 0) && (! (DRIVE_IS_IDLE(dp) || 925 (dp->dr_state == DRIVE_IDLING)))) { 926 int serial = (sp->sr_options & MHD_SERIAL); 927 928 if (! serial) 929 mhd_mx_unlock(&sp->sr_mx); 930 dp->dr_fd = open(dp->dr_rname0, (O_RDWR|O_NDELAY), 0); 931 if (! serial) 932 mhd_mx_lock(&sp->sr_mx); 933 if (dp->dr_fd < 0) { 934 mhd_perror("%s: open", dp->dr_rname); 935 (void) mhd_state(dp, DRIVE_ERRORED, NULL); 936 dp->dr_errnum = errno; 937 } 938 continue; 939 } 940 941 /* dispatch */ 942 switch (dp->dr_state) { 943 case DRIVE_IDLE: 944 MHDPRINTF1(("%s: IDLE\n", dp->dr_rname)); 945 break; 946 947 case DRIVE_ERRORED: 948 MHDPRINTF1(("%s: ERRORED %d\n", 949 dp->dr_rname, dp->dr_errnum)); 950 break; 951 952 case DRIVE_IDLING: 953 (void) mhd_state(dp, DRIVE_IDLE, NULL); 954 continue; 955 956 case DRIVE_RESERVING: 957 MHDPRINTF1(("%s: RESERVING\n", dp->dr_rname)); 958 (void) mhd_reserve(dp); 959 assert(DRIVE_IS_IDLE(dp)); 960 continue; 961 962 case DRIVE_FAILFASTING: 963 MHDPRINTF1(("%s: FAILFASTING\n", dp->dr_rname)); 964 (void) mhd_failfast(dp); 965 assert(DRIVE_IS_IDLE(dp)); 966 continue; 967 968 case DRIVE_RELEASING: 969 MHDPRINTF1(("%s: RELEASING\n", dp->dr_rname)); 970 (void) mhd_release(dp); 971 assert(DRIVE_IS_IDLE(dp)); 972 continue; 973 974 /* non-exclusive states */ 975 default: 976 assert(! (dp->dr_state & 977 (DRIVE_EXCLUSIVE_STATES & ~DRIVE_ERRORED))); 978 if (dp->dr_state & (DRIVE_PROBING | DRIVE_STATUSING)) { 979 MHDPRINTF1(("%s: PROBING\n", dp->dr_rname)); 980 (void) mhd_probe(dp); 981 assert(! (dp->dr_state & DRIVE_STATUSING)); 982 } 983 if (dp->dr_state & DRIVE_IDENTING) { 984 MHDPRINTF1(("%s: IDENTING\n", dp->dr_rname)); 985 (void) mhd_ident(dp); 986 assert(! (dp->dr_state & DRIVE_IDENTING)); 987 continue; /* in case we're probing */ 988 } 989 break; 990 } 991 992 /* close drive, if possible */ 993 if ((dp->dr_fd >= 0) && (DRIVE_IS_IDLE(dp))) { 994 int serial = (sp->sr_options & MHD_SERIAL); 995 996 if (! serial) 997 mhd_mx_unlock(&sp->sr_mx); 998 (void) close(dp->dr_fd); /* sd/ssd bug */ 999 if (! serial) 1000 mhd_mx_lock(&sp->sr_mx); 1001 dp->dr_fd = -1; 1002 } 1003 1004 /* wake up anybody waiting */ 1005 mhd_cv_broadcast(&sp->sr_cv); 1006 1007 /* see if anything happened */ 1008 if (! DRIVE_IS_IDLE(dp)) 1009 continue; 1010 1011 /* wait for something to happen */ 1012 if (! (dp->dr_state & DRIVE_PROBING)) { 1013 mhd_cv_wait(&dp->dr_cv, &sp->sr_mx); 1014 } else { 1015 mhd_cv_timedwait(&dp->dr_cv, &sp->sr_mx, 1016 (sp->sr_timeouts.mh_ff / 2)); 1017 } 1018 } 1019 } 1020 1021 /* 1022 * kick off drive thread 1023 */ 1024 static int 1025 mhd_thread_create( 1026 mhd_drive_t *dp, 1027 mhd_error_t *mhep 1028 ) 1029 { 1030 mhd_drive_set_t *sp = dp->dr_sp; 1031 thread_t thread = NULL; 1032 int rval = 0; 1033 1034 /* check lock and thread */ 1035 assert(MUTEX_HELD(&sp->sr_mx)); 1036 assert(dp->dr_thread == NULL); 1037 1038 /* create thread */ 1039 if (thr_create(NULL, 0, (void *(*)(void *))mhd_drive_thread, 1040 (void *)dp, (THR_DETACHED | THR_BOUND), &thread) != 0) { 1041 rval = mhd_error(mhep, errno, "thr_create"); 1042 } else { 1043 assert(thread != NULL); 1044 dp->dr_thread = thread; 1045 } 1046 1047 /* return success */ 1048 return (rval); 1049 } 1050 1051 /* 1052 * peel off s%u from name 1053 */ 1054 static char * 1055 diskname( 1056 const char *sname 1057 ) 1058 { 1059 char *dname; 1060 char *p, *e; 1061 1062 /* duplicate name */ 1063 if ((dname = Strdup(sname)) == NULL) 1064 return (NULL); 1065 1066 /* gobble number and 's' */ 1067 p = e = dname + strlen(dname) - 1; 1068 for (; (p > dname); --p) { 1069 if (!isdigit(*p)) 1070 break; 1071 } 1072 if ((p == e) || (p <= dname)) { 1073 Free(dname); 1074 return (NULL); 1075 } 1076 if (*p-- != 's') { 1077 Free(dname); 1078 return (NULL); 1079 } 1080 if ((p <= dname) || (!isdigit(*p))) { 1081 Free(dname); 1082 return (NULL); 1083 } 1084 *(++p) = '\0'; 1085 return (dname); 1086 } 1087 1088 /* 1089 * create new drive 1090 */ 1091 mhd_drive_t * 1092 mhd_create_drive( 1093 mhd_drive_set_t *sp, /* new set */ 1094 char *rname, /* raw drive name */ 1095 int *fdp, /* open device or -1 */ 1096 mhd_error_t *mhep /* returned error */ 1097 ) 1098 { 1099 mhd_drive_t *dp = NULL; 1100 char *rname0 = NULL; 1101 1102 /* check locks */ 1103 assert(MUTEX_HELD(&sp->sr_mx)); 1104 1105 /* if drive already exists */ 1106 if ((dp = mhd_find_drive(rname)) != NULL) { 1107 mhd_drive_set_t *oldsp = dp->dr_sp; 1108 1109 /* if set has changed, move drive */ 1110 if (oldsp != sp) { 1111 mhd_mx_unlock(&sp->sr_mx); 1112 mhd_mx_lock(&oldsp->sr_mx); 1113 if (mhd_idle(dp, mhep) != 0) { 1114 mhd_mx_unlock(&oldsp->sr_mx); 1115 mhd_mx_lock(&sp->sr_mx); 1116 return (NULL); 1117 } 1118 mhd_del_drive_from_set(dp); 1119 mhd_mx_unlock(&oldsp->sr_mx); 1120 mhd_mx_lock(&sp->sr_mx); 1121 mhd_add_drive_to_set(sp, dp); 1122 } 1123 1124 /* return drive */ 1125 return (dp); 1126 } 1127 1128 /* build slice0 */ 1129 rname0 = Malloc(strlen(rname) + strlen("s0") + 1); 1130 (void) strcpy(rname0, rname); 1131 (void) strcat(rname0, "s0"); 1132 1133 /* allocate and initialize drive */ 1134 dp = Zalloc(sizeof (*dp)); 1135 dp->dr_sp = sp; 1136 dp->dr_rname = Strdup(rname); 1137 dp->dr_rname0 = rname0; 1138 mhd_cv_init(&dp->dr_cv); 1139 dp->dr_thread = NULL; 1140 dp->dr_fd = -1; 1141 dp->dr_state = DRIVE_IDLE; 1142 1143 /* steal open drive */ 1144 if ((fdp != NULL) && (*fdp >= 0)) { 1145 dp->dr_fd = *fdp; 1146 *fdp = -1; 1147 } 1148 1149 /* add to set */ 1150 mhd_add_drive_to_set(sp, dp); 1151 1152 /* kick off drive thread */ 1153 if (mhd_thread_create(dp, mhep) != 0) { 1154 Free(dp->dr_rname0); 1155 Free(dp->dr_rname); 1156 Free(dp); 1157 return (NULL); 1158 } 1159 1160 /* return drive */ 1161 return (dp); 1162 } 1163 1164 /* 1165 * find or create drive in any set 1166 */ 1167 static mhd_drive_t * 1168 mhd_create_drive_anyset( 1169 char *rname, 1170 int *fdp, 1171 mhd_error_t *mhep 1172 ) 1173 { 1174 mhd_drive_set_t *null_sp = mhd_create_set(NULL, 0, NULL, NULL); 1175 mhd_drive_t *dp; 1176 1177 /* check locks */ 1178 assert(null_sp != NULL); 1179 1180 /* drive already exists */ 1181 if ((dp = mhd_find_drive(rname)) != NULL) 1182 return (dp); 1183 1184 /* add to null set */ 1185 mhd_mx_lock(&null_sp->sr_mx); 1186 dp = mhd_create_drive(null_sp, rname, fdp, mhep); 1187 mhd_mx_unlock(&null_sp->sr_mx); 1188 1189 /* return drive */ 1190 return (dp); 1191 } 1192 1193 /* 1194 * process a file in the tree walk 1195 */ 1196 static int 1197 do_disk( 1198 const char *path, 1199 const struct stat *statp, 1200 int type 1201 ) 1202 { 1203 char *dname = NULL; 1204 int fd = -1; 1205 struct dk_cinfo cinfo; 1206 mhd_error_t status = mhd_null_error; 1207 1208 /* skip all but character devices */ 1209 if ((type != FTW_F) || (! S_ISCHR(statp->st_mode)) || 1210 ((dname = diskname(path)) == NULL)) { 1211 return (0); 1212 } 1213 1214 /* see if drive already exists */ 1215 if (mhd_find_drive(dname) != NULL) 1216 return (0); 1217 1218 /* see if device is a disk */ 1219 if ((fd = open(path, (O_RDONLY|O_NDELAY), 0)) < 0) 1220 goto out; 1221 if (ioctl(fd, DKIOCINFO, &cinfo) != 0) { 1222 switch (errno) { 1223 case EINVAL: 1224 case ENOTTY: 1225 break; 1226 default: 1227 mhd_perror("DKIOCINFO: %s", path); 1228 break; 1229 } 1230 goto out; 1231 } 1232 1233 /* skip CDROMs */ 1234 if (cinfo.dki_ctype == DKC_CDROM) { 1235 (void) close(fd); 1236 Free(dname); 1237 return (0); 1238 } 1239 1240 /* put disk on list */ 1241 if (mhd_create_drive_anyset(dname, &fd, &status) == NULL) { 1242 mhde_perror(&status, ""); 1243 goto out; 1244 } 1245 1246 /* cleanup, return success (no matter what) */ 1247 out: 1248 if (dname != NULL) 1249 Free(dname); 1250 if (fd >= 0) 1251 (void) close(fd); 1252 mhd_clrerror(&status); 1253 return (0); 1254 } 1255 1256 /* 1257 * find or create all the drives under a given directory 1258 */ 1259 int 1260 mhd_create_drives( 1261 char *path, 1262 mhd_error_t *mhep 1263 ) 1264 { 1265 /* default */ 1266 if ((path == NULL) || (*path == '\0')) 1267 path = "/dev/rdsk"; 1268 1269 free_pln_cache(); 1270 1271 /* walk the directory, adding disks */ 1272 if (ftw(path, do_disk, 5) != 0) 1273 return (mhd_error(mhep, errno, path)); 1274 1275 /* return success */ 1276 return (0); 1277 } 1278