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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include "cfga_scsi.h" 28 29 struct larg { 30 int ndevs; 31 int nelem; 32 char *dev; 33 char **dev_list; 34 }; 35 36 #define ETC_VFSTAB "/etc/vfstab" 37 #define SCFGA_LOCK "/var/run/cfgadm_scsi" 38 39 /* Function prototypes */ 40 41 static scfga_ret_t quiesce_confirm(apid_t *apidp, 42 msgid_t cmd_msg, prompt_t *pt, int *okp, int *quiesce, int *l_errnop); 43 static scfga_ret_t dev_hotplug(apid_t *apidp, 44 prompt_t *pt, cfga_flags_t flags, int quiesce, char **errstring); 45 static int disconnect(struct cfga_confirm *confp); 46 static int critical_ctrlr(const char *hba_phys); 47 static cfga_stat_t bus_devctl_to_recep_state(uint_t bus_dc_state); 48 static int get_hba_children(char *bus_path, char *dev_excl, char ***dev_list); 49 static char *get_node_path(char *minor_path); 50 static void free_dev_list_elements(char **dev_list); 51 static void free_dev_list(char **dev_list); 52 static int alloc_dev_list(struct larg *largp); 53 54 /* 55 * Single thread all implicit quiesce operations 56 */ 57 static mutex_t quiesce_mutex = DEFAULTMUTEX; 58 59 /*ARGSUSED*/ 60 scfga_ret_t 61 bus_change_state( 62 cfga_cmd_t state_change_cmd, 63 apid_t *apidp, 64 struct cfga_confirm *confp, 65 cfga_flags_t flags, 66 char **errstring) 67 { 68 int l_errno = 0, force; 69 uint_t state = 0; 70 cfga_stat_t bus_state; 71 scfga_cmd_t cmd; 72 msgid_t errid; 73 cfga_stat_t prereq; 74 scfga_ret_t ret; 75 char **dev_list = NULL; 76 77 assert(apidp->path != NULL); 78 assert(apidp->hba_phys != NULL); 79 80 /* 81 * No dynamic components allowed 82 */ 83 if (apidp->dyncomp != NULL) { 84 cfga_err(errstring, 0, ERR_NOT_BUSAPID, 0); 85 return (SCFGA_ERR); 86 } 87 88 /* Get bus state */ 89 if (devctl_cmd(apidp->path, SCFGA_BUS_GETSTATE, &state, 90 &l_errno) != SCFGA_OK) { 91 cfga_err(errstring, l_errno, ERR_BUS_GETSTATE, 0); 92 return (SCFGA_ERR); 93 } 94 95 bus_state = bus_devctl_to_recep_state(state); 96 force = ((flags & CFGA_FLAG_FORCE) == CFGA_FLAG_FORCE) ? 1 : 0; 97 assert(confp->confirm != NULL); 98 99 switch (state_change_cmd) { 100 case CFGA_CMD_DISCONNECT: /* quiesce bus */ 101 /* 102 * If force flag not specified, check if controller is 103 * critical. 104 */ 105 if (!force) { 106 /* 107 * This check is not foolproof, get user confirmation 108 * if test passes. 109 */ 110 if (critical_ctrlr(apidp->path)) { 111 cfga_err(errstring, 0, ERR_CTRLR_CRIT, 0); 112 ret = SCFGA_ERR; 113 break; 114 } else if (!disconnect(confp)) { 115 ret = SCFGA_NACK; 116 break; 117 } 118 } 119 120 cmd = SCFGA_BUS_QUIESCE; 121 errid = ERR_BUS_QUIESCE; 122 prereq = CFGA_STAT_CONNECTED; 123 124 goto common; 125 126 case CFGA_CMD_CONNECT: /* unquiesce bus */ 127 cmd = SCFGA_BUS_UNQUIESCE; 128 errid = ERR_BUS_UNQUIESCE; 129 prereq = CFGA_STAT_DISCONNECTED; 130 131 goto common; 132 133 case CFGA_CMD_CONFIGURE: 134 cmd = SCFGA_BUS_CONFIGURE; 135 errid = ERR_BUS_CONFIGURE; 136 prereq = CFGA_STAT_CONNECTED; 137 138 goto common; 139 140 case CFGA_CMD_UNCONFIGURE: 141 cmd = SCFGA_BUS_UNCONFIGURE; 142 errid = ERR_BUS_UNCONFIGURE; 143 prereq = CFGA_STAT_CONNECTED; 144 145 /* FALLTHROUGH */ 146 common: 147 if (bus_state != prereq) { 148 cfga_err(errstring, 0, 149 (prereq == CFGA_STAT_CONNECTED) 150 ? ERR_BUS_NOTCONNECTED 151 : ERR_BUS_CONNECTED, 0); 152 ret = SCFGA_ERR; 153 break; 154 } 155 156 /* 157 * When quiescing or unconfiguring a bus, first suspend or 158 * offline it through RCM. 159 * For unquiescing, we simple build the dev_list for 160 * resume notification. 161 */ 162 if (((apidp->flags & FLAG_DISABLE_RCM) == 0) && 163 ((cmd == SCFGA_BUS_QUIESCE) || 164 (cmd == SCFGA_BUS_UNQUIESCE) || 165 (cmd == SCFGA_BUS_UNCONFIGURE))) { 166 ret = get_hba_children(apidp->path, NULL, &dev_list); 167 if (ret != SCFGA_OK) { 168 break; 169 } 170 if (cmd == SCFGA_BUS_QUIESCE) { 171 if ((ret = scsi_rcm_suspend(dev_list, 172 errstring, flags, 1)) != SCFGA_OK) { 173 break; 174 } 175 } else if (cmd == SCFGA_BUS_UNCONFIGURE) { 176 if ((ret = scsi_rcm_offline(dev_list, 177 errstring, flags)) != SCFGA_OK) { 178 break; 179 } 180 } 181 } 182 183 ret = devctl_cmd(apidp->path, cmd, NULL, &l_errno); 184 if (ret != SCFGA_OK) { 185 /* 186 * EIO when child devices are busy may confuse user. 187 * So explain it. 188 */ 189 if (cmd == SCFGA_BUS_UNCONFIGURE && l_errno == EIO) 190 errid = ERR_MAYBE_BUSY; 191 192 cfga_err(errstring, l_errno, errid, 0); 193 194 /* 195 * If the bus was suspended in RCM, then cancel the RCM 196 * operation. Discard RCM failures here because the 197 * devctl's failure is what is most relevant. 198 */ 199 if ((apidp->flags & FLAG_DISABLE_RCM) == 0) { 200 if (cmd == SCFGA_BUS_QUIESCE) 201 (void) scsi_rcm_resume(dev_list, 202 errstring, 203 (flags & (~CFGA_FLAG_FORCE)), 1); 204 else if (cmd == SCFGA_BUS_UNCONFIGURE) { 205 (void) devctl_cmd(apidp->path, 206 SCFGA_BUS_CONFIGURE, NULL, 207 &l_errno); 208 (void) scsi_rcm_online(dev_list, 209 errstring, 210 (flags & (~CFGA_FLAG_FORCE))); 211 } 212 } 213 214 break; 215 } 216 217 /* 218 * When unquiescing or configuring a bus, resume or online it 219 * in RCM when the devctl command is complete. 220 * When unconfiguring a bus, notify removal of devices. 221 */ 222 if ((apidp->flags & FLAG_DISABLE_RCM) == 0) { 223 if (cmd == SCFGA_BUS_UNQUIESCE) { 224 ret = scsi_rcm_resume(dev_list, errstring, 225 (flags & (~CFGA_FLAG_FORCE)), 1); 226 } else if (cmd == SCFGA_BUS_UNCONFIGURE) { 227 ret = scsi_rcm_remove(dev_list, errstring, 228 (flags & (~CFGA_FLAG_FORCE))); 229 } 230 } 231 break; 232 233 case CFGA_CMD_LOAD: 234 case CFGA_CMD_UNLOAD: 235 ret = SCFGA_OPNOTSUPP; 236 break; 237 238 default: 239 cfga_err(errstring, 0, ERR_CMD_INVAL, 0); 240 ret = SCFGA_ERR; 241 break; 242 } 243 244 free_dev_list(dev_list); 245 return (ret); 246 } 247 248 scfga_ret_t 249 dev_change_state( 250 cfga_cmd_t state_change_cmd, 251 apid_t *apidp, 252 cfga_flags_t flags, 253 char **errstring) 254 { 255 uint_t state = 0; 256 int l_errno = 0; 257 cfga_stat_t bus_state; 258 scfga_cmd_t cmd; 259 msgid_t errid; 260 scfga_ret_t ret; 261 char *dev_list[2] = {NULL}; 262 263 assert(apidp->path != NULL); 264 assert(apidp->hba_phys != NULL); 265 266 /* 267 * For a device, dynamic component must be present 268 */ 269 if (apidp->dyncomp == NULL) { 270 cfga_err(errstring, 0, ERR_APID_INVAL, 0); 271 return (SCFGA_ERR); 272 } 273 274 /* Get bus state */ 275 if (devctl_cmd(apidp->hba_phys, SCFGA_BUS_GETSTATE, &state, 276 &l_errno) != SCFGA_OK) { 277 cfga_err(errstring, l_errno, ERR_BUS_GETSTATE, 0); 278 return (SCFGA_ERR); 279 } 280 281 bus_state = bus_devctl_to_recep_state(state); 282 283 switch (state_change_cmd) { 284 case CFGA_CMD_CONFIGURE: /* online device */ 285 cmd = SCFGA_DEV_CONFIGURE; 286 errid = ERR_DEV_CONFIGURE; 287 goto common; 288 289 case CFGA_CMD_UNCONFIGURE: /* offline device */ 290 cmd = SCFGA_DEV_UNCONFIGURE; 291 errid = ERR_DEV_UNCONFIGURE; 292 /* FALLTHROUGH */ 293 common: 294 if (bus_state != CFGA_STAT_CONNECTED) { 295 cfga_err(errstring, 0, ERR_BUS_NOTCONNECTED, 0); 296 ret = SCFGA_ERR; 297 break; 298 } 299 300 if (apidp->dyntype == PATH_APID) { 301 /* call a scsi_vhci ioctl to do online/offline path. */ 302 ret = path_apid_state_change(apidp, cmd, 303 flags, errstring, &l_errno, errid); 304 } else { 305 /* 306 * When unconfiguring a device, first offline it 307 * through RCM. 308 */ 309 if ((apidp->flags & FLAG_DISABLE_RCM) == 0) { 310 if (cmd == SCFGA_DEV_UNCONFIGURE) { 311 dev_list[0] = 312 get_node_path(apidp->path); 313 if (dev_list[0] == NULL) { 314 ret = SCFGA_ERR; 315 break; 316 } 317 if ((ret = scsi_rcm_offline(dev_list, 318 errstring, flags)) != SCFGA_OK) { 319 break; 320 } 321 } 322 } 323 324 ret = devctl_cmd(apidp->path, cmd, NULL, &l_errno); 325 if (ret != SCFGA_OK) { 326 cfga_err(errstring, l_errno, errid, 0); 327 328 /* 329 * If an unconfigure fails, cancel the RCM offline. 330 * Discard any RCM failures so that the devctl 331 * failure will still be reported. 332 */ 333 if ((apidp->flags & FLAG_DISABLE_RCM) == 0) { 334 if (cmd == SCFGA_DEV_UNCONFIGURE) 335 (void) scsi_rcm_online(dev_list, 336 errstring, flags); 337 } 338 break; 339 } 340 if ((apidp->flags & FLAG_DISABLE_RCM) == 0) { 341 /* 342 * Unconfigure succeeded, call the RCM notify_remove. 343 */ 344 if (cmd == SCFGA_DEV_UNCONFIGURE) 345 (void) scsi_rcm_remove(dev_list, 346 errstring, flags); 347 } 348 } 349 break; 350 351 /* 352 * Cannot disconnect/connect individual devices without affecting 353 * other devices on the bus. So we don't support these ops. 354 */ 355 case CFGA_CMD_DISCONNECT: 356 case CFGA_CMD_CONNECT: 357 cfga_err(errstring, 0, ERR_NOT_DEVOP, 0); 358 ret = SCFGA_ERR; 359 break; 360 case CFGA_CMD_LOAD: 361 case CFGA_CMD_UNLOAD: 362 ret = SCFGA_OPNOTSUPP; 363 break; 364 default: 365 cfga_err(errstring, 0, ERR_CMD_INVAL, 0); 366 ret = SCFGA_ERR; 367 break; 368 } 369 370 free_dev_list_elements(dev_list); 371 return (ret); 372 } 373 374 /*ARGSUSED*/ 375 scfga_ret_t 376 dev_remove( 377 const char *func, 378 scfga_cmd_t cmd, 379 apid_t *apidp, 380 prompt_t *prp, 381 cfga_flags_t flags, 382 char **errstring) 383 { 384 int proceed, l_errno = 0; 385 scfga_ret_t ret; 386 int do_quiesce; 387 char *dev_list[2] = {NULL}; 388 389 assert(apidp->hba_phys != NULL); 390 assert(apidp->path != NULL); 391 392 /* device operation only */ 393 if (apidp->dyncomp == NULL) { 394 cfga_err(errstring, 0, ERR_NOT_BUSOP, 0); 395 return (SCFGA_ERR); 396 } 397 398 proceed = 1; 399 ret = quiesce_confirm(apidp, MSG_RMDEV, prp, &proceed, &do_quiesce, 400 &l_errno); 401 if (ret != SCFGA_OK) { 402 cfga_err(errstring, l_errno, ERR_DEV_REMOVE, 0); 403 return (ret); 404 } 405 406 if (!proceed) { 407 return (SCFGA_NACK); 408 } 409 410 /* 411 * Offline the device in RCM 412 */ 413 if ((apidp->flags & FLAG_DISABLE_RCM) == 0) { 414 dev_list[0] = get_node_path(apidp->path); 415 if (dev_list[0] == NULL) 416 return (SCFGA_ERR); 417 if ((ret = scsi_rcm_offline(dev_list, errstring, flags)) 418 != SCFGA_OK) { 419 free_dev_list_elements(dev_list); 420 return (ret); 421 } 422 } 423 424 /* 425 * Offline the device 426 */ 427 ret = devctl_cmd(apidp->path, SCFGA_DEV_UNCONFIGURE, NULL, &l_errno); 428 if (ret != SCFGA_OK) { 429 430 cfga_err(errstring, l_errno, ERR_DEV_REMOVE, 0); 431 432 /* 433 * Cancel the RCM offline. Discard the RCM failures so that 434 * the above devctl failure is still reported. 435 */ 436 if ((apidp->flags & FLAG_DISABLE_RCM) == 0) 437 (void) scsi_rcm_online(dev_list, errstring, flags); 438 free_dev_list_elements(dev_list); 439 return (ret); 440 } 441 442 /* Do the physical removal */ 443 ret = dev_hotplug(apidp, prp, flags, do_quiesce, errstring); 444 445 if (ret == SCFGA_OK) { 446 /* 447 * Complete the remove. 448 * Since the device is already offlined, remove shouldn't 449 * fail. Even if remove fails, there is no side effect. 450 */ 451 (void) devctl_cmd(apidp->path, SCFGA_DEV_REMOVE, 452 NULL, &l_errno); 453 if ((apidp->flags & FLAG_DISABLE_RCM) == 0) 454 ret = scsi_rcm_remove(dev_list, errstring, flags); 455 } else { 456 /* 457 * Reconfigure the device and restore the device's RCM state. 458 * If reconfigure succeeds, restore the state to online. 459 * If reconfigure fails (e.g. a typo from user), we treat 460 * the device as removed. 461 */ 462 if (devctl_cmd(apidp->path, SCFGA_DEV_CONFIGURE, NULL, &l_errno) 463 == SCFGA_OK) { 464 if ((apidp->flags & FLAG_DISABLE_RCM) == 0) 465 (void) scsi_rcm_online(dev_list, errstring, 466 flags); 467 } else { 468 char *cp = strrchr(apidp->path, ':'); 469 if (cp) 470 *cp = '\0'; 471 cfga_err(errstring, l_errno, ERR_DEV_RECONFIGURE, 472 apidp->path, 0); 473 if (cp) 474 *cp = ':'; 475 if ((apidp->flags & FLAG_DISABLE_RCM) == 0) 476 (void) scsi_rcm_remove(dev_list, errstring, 477 flags); 478 } 479 } 480 481 free_dev_list_elements(dev_list); 482 return (ret); 483 } 484 485 /*ARGSUSED*/ 486 scfga_ret_t 487 dev_insert( 488 const char *func, 489 scfga_cmd_t cmd, 490 apid_t *apidp, 491 prompt_t *prp, 492 cfga_flags_t flags, 493 char **errstring) 494 { 495 int proceed, l_errno = 0; 496 scfga_ret_t ret; 497 int do_quiesce; 498 499 assert(apidp->hba_phys != NULL); 500 assert(apidp->path != NULL); 501 502 /* Currently, insert operation only allowed for bus */ 503 if (apidp->dyncomp != NULL) { 504 cfga_err(errstring, 0, ERR_NOT_DEVOP, 0); 505 return (SCFGA_ERR); 506 } 507 508 proceed = 1; 509 ret = quiesce_confirm(apidp, MSG_INSDEV, prp, &proceed, &do_quiesce, 510 &l_errno); 511 if (ret != SCFGA_OK) { 512 cfga_err(errstring, l_errno, ERR_DEV_INSERT, 0); 513 return (ret); 514 } 515 516 if (!proceed) { 517 return (SCFGA_NACK); 518 } 519 520 /* Do the physical addition */ 521 ret = dev_hotplug(apidp, prp, flags, do_quiesce, errstring); 522 if (ret != SCFGA_OK) { 523 return (ret); 524 } 525 526 /* 527 * Configure bus to online new device(s). 528 * Previously offlined devices will not be onlined. 529 */ 530 ret = devctl_cmd(apidp->hba_phys, SCFGA_BUS_CONFIGURE, NULL, &l_errno); 531 if (ret != SCFGA_OK) { 532 cfga_err(errstring, l_errno, ERR_DEV_INSERT, 0); 533 return (SCFGA_ERR); 534 } 535 536 return (SCFGA_OK); 537 } 538 539 /*ARGSUSED*/ 540 scfga_ret_t 541 dev_replace( 542 const char *func, 543 scfga_cmd_t cmd, 544 apid_t *apidp, 545 prompt_t *prp, 546 cfga_flags_t flags, 547 char **errstring) 548 { 549 int proceed, l_errno = 0; 550 scfga_ret_t ret, ret2; 551 int do_quiesce; 552 char *dev_list[2] = {NULL}; 553 554 assert(apidp->hba_phys != NULL); 555 assert(apidp->path != NULL); 556 557 /* device operation only */ 558 if (apidp->dyncomp == NULL) { 559 cfga_err(errstring, 0, ERR_NOT_BUSOP, 0); 560 return (SCFGA_ERR); 561 } 562 563 proceed = 1; 564 ret = quiesce_confirm(apidp, MSG_REPLDEV, prp, &proceed, &do_quiesce, 565 &l_errno); 566 if (ret != SCFGA_OK) { 567 cfga_err(errstring, l_errno, ERR_DEV_REPLACE, 0); 568 return (ret); 569 } 570 571 if (!proceed) { 572 return (SCFGA_NACK); 573 } 574 575 /* Offline the device in RCM */ 576 if ((apidp->flags & FLAG_DISABLE_RCM) == 0) { 577 dev_list[0] = get_node_path(apidp->path); 578 if (dev_list[0] == NULL) 579 return (SCFGA_ERR); 580 if ((ret = scsi_rcm_offline(dev_list, errstring, flags)) 581 != SCFGA_OK) { 582 free_dev_list_elements(dev_list); 583 return (ret); 584 } 585 } 586 587 ret = devctl_cmd(apidp->path, SCFGA_DEV_REMOVE, NULL, &l_errno); 588 if (ret != SCFGA_OK) { 589 590 /* 591 * Cancel the RCM offline. Discard any RCM failures so that 592 * the devctl failure can still be reported. 593 */ 594 if ((apidp->flags & FLAG_DISABLE_RCM) == 0) 595 (void) scsi_rcm_online(dev_list, errstring, flags); 596 597 cfga_err(errstring, l_errno, ERR_DEV_REPLACE, 0); 598 free_dev_list_elements(dev_list); 599 return (ret); 600 } 601 602 /* do the physical replace */ 603 ret = dev_hotplug(apidp, prp, flags, do_quiesce, errstring); 604 605 /* Online the replacement, or restore state on error */ 606 ret2 = devctl_cmd(apidp->path, SCFGA_DEV_CONFIGURE, NULL, &l_errno); 607 608 if (ret2 != SCFGA_OK) { 609 cfga_err(errstring, l_errno, ERR_DEV_REPLACE, 0); 610 } 611 612 /* 613 * Remove the replaced device in RCM, or online the device in RCM 614 * to recover. 615 */ 616 if ((apidp->flags & FLAG_DISABLE_RCM) == 0) { 617 if (ret == SCFGA_OK) 618 ret = scsi_rcm_remove(dev_list, errstring, flags); 619 else if (ret2 == SCFGA_OK) 620 ret2 = scsi_rcm_online(dev_list, errstring, flags); 621 } 622 free_dev_list_elements(dev_list); 623 624 return (ret == SCFGA_OK ? ret2 : ret); 625 } 626 627 #pragma weak plat_dev_led 628 /*ARGSUSED*/ 629 scfga_ret_t 630 dev_led( 631 const char *func, 632 scfga_cmd_t cmd, 633 apid_t *apidp, 634 prompt_t *prp, 635 cfga_flags_t flags, 636 char **errstring) 637 { 638 639 /* 640 * The implementation of the led command is platform-specific, so 641 * the default behavior is to say that the functionality is not 642 * available for this device. 643 */ 644 if (plat_dev_led) { 645 return (plat_dev_led(func, cmd, apidp, prp, flags, errstring)); 646 } 647 cfga_err(errstring, 0, ERR_UNAVAILABLE, 0); 648 return (SCFGA_ERR); 649 } 650 651 /*ARGSUSED*/ 652 scfga_ret_t 653 reset_common( 654 const char *func, 655 scfga_cmd_t cmd, 656 apid_t *apidp, 657 prompt_t *prp, 658 cfga_flags_t flags, 659 char **errstring) 660 { 661 int l_errno = 0; 662 scfga_ret_t ret; 663 664 665 assert(apidp->path != NULL); 666 assert(apidp->hba_phys != NULL); 667 668 switch (cmd) { 669 case SCFGA_RESET_DEV: 670 if (apidp->dyncomp == NULL) { 671 cfga_err(errstring, 0, ERR_NOT_BUSOP, 0); 672 return (SCFGA_ERR); 673 } 674 break; 675 676 case SCFGA_RESET_BUS: 677 case SCFGA_RESET_ALL: 678 if (apidp->dyncomp != NULL) { 679 cfga_err(errstring, 0, ERR_NOT_DEVOP, 0); 680 return (SCFGA_ERR); 681 } 682 break; 683 default: 684 cfga_err(errstring, 0, ERR_CMD_INVAL, 0); 685 return (SCFGA_ERR); 686 } 687 688 ret = devctl_cmd(apidp->path, cmd, NULL, &l_errno); 689 if (ret != SCFGA_OK) { 690 cfga_err(errstring, l_errno, ERR_RESET, 0); 691 } 692 693 return (ret); 694 } 695 696 static int 697 disconnect(struct cfga_confirm *confp) 698 { 699 int ans, append_newline; 700 char *cq; 701 702 append_newline = 0; 703 cq = cfga_str(append_newline, WARN_DISCONNECT, 0); 704 705 ans = confp->confirm(confp->appdata_ptr, cq); 706 707 S_FREE(cq); 708 709 return (ans == 1); 710 } 711 712 /* 713 * Check for "scsi-no-quiesce" property 714 * Return code: -1 error, 0 quiesce not required, 1 quiesce required 715 */ 716 static int 717 quiesce_required(apid_t *apidp, int *l_errnop) 718 { 719 di_node_t bus_node, dev_node; 720 char *bus_path, *bus_end; 721 char *dev_path, *dev_end; 722 int *propval; 723 724 /* take libdevinfo snapshot of subtree at hba */ 725 bus_path = apidp->hba_phys + strlen(DEVICES_DIR); 726 bus_end = strrchr(bus_path, ':'); 727 if (bus_end) 728 *bus_end = '\0'; 729 730 bus_node = di_init(bus_path, DINFOSUBTREE|DINFOPROP); 731 if (bus_end) 732 *bus_end = ':'; 733 if (bus_node == DI_NODE_NIL) { 734 *l_errnop = errno; 735 return (-1); /* error */ 736 } 737 738 /* check bus node for property */ 739 if (di_prop_lookup_ints(DDI_DEV_T_ANY, bus_node, SCSI_NO_QUIESCE, 740 &propval) == 1) { 741 di_fini(bus_node); 742 return (0); /* quiesce not required */ 743 } 744 745 /* if this ap is HBA, return with quiesce required */ 746 if (apidp->dyncomp == NULL) { 747 di_fini(bus_node); 748 return (1); 749 } 750 751 /* check device node for property */ 752 dev_path = apidp->path + strlen(DEVICES_DIR); 753 dev_end = strrchr(dev_path, ':'); 754 if (dev_end) 755 *dev_end = '\0'; 756 757 dev_node = di_child_node(bus_node); 758 while (dev_node != DI_NODE_NIL) { 759 char *child_path; 760 child_path = di_devfs_path(dev_node); 761 if (strcmp(child_path, dev_path) == 0) { 762 di_devfs_path_free(child_path); 763 break; 764 } 765 di_devfs_path_free(child_path); 766 dev_node = di_sibling_node(dev_node); 767 } 768 769 if (dev_end) 770 *dev_end = ':'; 771 if (dev_node == DI_NODE_NIL) { 772 di_fini(bus_node); 773 return (1); /* dev not found (insert case) */ 774 } 775 776 /* check child node for property */ 777 if (di_prop_lookup_ints(DDI_DEV_T_ANY, dev_node, "scsi-no-quiesce", 778 &propval) == 1) { 779 di_fini(bus_node); 780 return (0); /* quiesce not required */ 781 } 782 return (1); /* quiesce required */ 783 } 784 785 static scfga_ret_t 786 quiesce_confirm( 787 apid_t *apidp, 788 msgid_t cmd_msg, 789 prompt_t *prp, 790 int *okp, 791 int *quiesce, 792 int *l_errnop) 793 { 794 char *buf = NULL, *hbap = NULL, *cq1 = NULL, *cq2 = NULL; 795 char *cp; 796 size_t len = 0; 797 int i = 0, append_newline; 798 scfga_ret_t ret; 799 800 assert(apidp->path != NULL); 801 assert(apidp->hba_phys != NULL); 802 803 *quiesce = quiesce_required(apidp, l_errnop); 804 if (*quiesce == -1) 805 return (SCFGA_ERR); 806 else if (*quiesce == 0) 807 return (SCFGA_OK); 808 809 /* 810 * Try to create HBA logical ap_id. 811 * If that fails use physical path 812 */ 813 ret = make_hba_logid(apidp->hba_phys, &hbap, &i); 814 if (ret != SCFGA_OK) { 815 if ((hbap = get_node_path(apidp->hba_phys)) == NULL) { 816 *l_errnop = errno; 817 return (SCFGA_LIB_ERR); 818 } 819 } 820 821 assert(hbap != NULL); 822 823 append_newline = 0; 824 cq1 = cfga_str(append_newline, CONF_QUIESCE_1, hbap, 0); 825 cq2 = cfga_str(append_newline, CONF_QUIESCE_2, 0); 826 len = strlen(cq1) + strlen(cq2) + 1; /* Includes term. NULL */ 827 828 if ((buf = calloc(1, len)) == NULL) { 829 *l_errnop = errno; 830 ret = SCFGA_LIB_ERR; 831 S_FREE(cq1); 832 S_FREE(cq2); 833 goto out; 834 } 835 (void) strcpy(buf, cq1); 836 (void) strcat(buf, cq2); 837 838 S_FREE(cq1); 839 S_FREE(cq2); 840 841 842 /* Remove minor name (if any) from phys path */ 843 if ((cp = strrchr(apidp->path, ':')) != NULL) { 844 *cp = '\0'; 845 } 846 847 /* describe operation being attempted */ 848 cfga_msg(prp->msgp, cmd_msg, apidp->path, 0); 849 850 /* Restore minor name */ 851 if (cp != NULL) { 852 *cp = ':'; 853 } 854 855 /* request permission to quiesce */ 856 assert(prp->confp != NULL && prp->confp->confirm != NULL); 857 *okp = prp->confp->confirm(prp->confp->appdata_ptr, buf); 858 859 ret = SCFGA_OK; 860 /*FALLTHRU*/ 861 out: 862 S_FREE(buf); 863 S_FREE(hbap); 864 return (ret); 865 } 866 867 static scfga_ret_t 868 suspend_in_rcm( 869 apid_t *apidp, 870 char ***suspend_list_ptr, 871 char **errstring, 872 cfga_flags_t flags) 873 { 874 scfga_ret_t ret; 875 char *bus_path = NULL; 876 char *dev_path = NULL; 877 char **suspend_list = NULL; 878 879 *suspend_list_ptr = NULL; 880 881 /* Suspend the bus through RCM */ 882 if (apidp->flags & FLAG_DISABLE_RCM) 883 return (SCFGA_OK); 884 885 /* The bus_path is the HBA path without its minor */ 886 if ((bus_path = get_node_path(apidp->hba_phys)) == NULL) 887 return (SCFGA_ERR); 888 889 /* 890 * The dev_path is already initialized to NULL. If the AP Id 891 * path differs from the HBA path, then the dev_path should 892 * instead be set to the AP Id path without its minor. 893 */ 894 if (strcmp(apidp->hba_phys, apidp->path) != 0) { 895 if ((dev_path = get_node_path(apidp->path)) == NULL) { 896 ret = SCFGA_ERR; 897 goto out; 898 } 899 } 900 901 if ((ret = get_hba_children(bus_path, dev_path, &suspend_list)) 902 != SCFGA_OK) { 903 free_dev_list(suspend_list); 904 goto out; 905 } 906 907 if (scsi_rcm_suspend(suspend_list, errstring, flags, 0) != SCFGA_OK) { 908 ret = SCFGA_ERR; 909 free_dev_list(suspend_list); 910 } else { 911 ret = SCFGA_OK; 912 *suspend_list_ptr = suspend_list; 913 } 914 /*FALLTHROUGH*/ 915 out: 916 S_FREE(bus_path); 917 S_FREE(dev_path); 918 return (ret); 919 } 920 921 /* 922 * Resume the bus through RCM if it successfully 923 * unquiesced. 924 */ 925 static void 926 resume_in_rcm( 927 apid_t *apidp, 928 char **suspend_list, 929 char **errstring, 930 cfga_flags_t flags) 931 { 932 if (apidp->flags & FLAG_DISABLE_RCM) 933 return; 934 935 (void) scsi_rcm_resume(suspend_list, errstring, flags, 0); 936 937 free_dev_list(suspend_list); 938 } 939 940 static scfga_ret_t 941 wait_for_hotplug(prompt_t *pt, int msg) 942 { 943 char *cu = NULL; 944 int append_newline = 0; 945 scfga_ret_t ret; 946 947 cu = cfga_str(append_newline, msg, 0); 948 if (pt->confp->confirm(pt->confp->appdata_ptr, cu) != 1) { 949 ret = SCFGA_NACK; 950 } else { 951 ret = SCFGA_OK; 952 } 953 S_FREE(cu); 954 return (ret); 955 } 956 957 static scfga_ret_t 958 bus_quiesce(apid_t *apidp, prompt_t *pt, char **errstring, cfga_flags_t flags) 959 { 960 int l_errno; 961 scfga_ret_t ret; 962 scfga_ret_t hpret; 963 char **suspend_list = NULL; 964 965 ret = suspend_in_rcm(apidp, &suspend_list, errstring, flags); 966 if (ret != SCFGA_OK) { 967 return (ret); 968 } 969 970 /* 971 * If the quiesce fails, then cancel the RCM suspend. 972 * Discard any RCM failures so that the devctl failure 973 * can still be reported. 974 */ 975 l_errno = 0; 976 ret = devctl_cmd(apidp->hba_phys, SCFGA_BUS_QUIESCE, NULL, &l_errno); 977 if (ret != SCFGA_OK) { 978 resume_in_rcm(apidp, suspend_list, errstring, flags); 979 cfga_err(errstring, l_errno, ERR_BUS_QUIESCE, 0); 980 return (ret); 981 } 982 983 /* 984 * Prompt user to proceed with physical hotplug 985 * and wait until they are done. 986 */ 987 hpret = wait_for_hotplug(pt, CONF_UNQUIESCE); 988 989 /* 990 * The unquiesce may fail with EALREADY (which is ok) 991 * or some other error (which is not ok). 992 */ 993 l_errno = 0; 994 ret = devctl_cmd(apidp->hba_phys, SCFGA_BUS_UNQUIESCE, NULL, &l_errno); 995 if (ret != SCFGA_OK && l_errno != EALREADY) { 996 free_dev_list(suspend_list); 997 cfga_err(errstring, l_errno, ERR_BUS_UNQUIESCE, 0); 998 return (SCFGA_ERR); 999 } 1000 1001 resume_in_rcm(apidp, suspend_list, errstring, flags); 1002 1003 return (hpret); 1004 } 1005 1006 #define MAX_LOCK_TRIES 20 1007 #define MAX_UNLINK_TRIES 60 1008 #define s_getpid (int)getpid /* else lint causes problems */ 1009 1010 static void 1011 s_unlink(char *file) 1012 { 1013 int count = 0; 1014 1015 retry: 1016 if (unlink(file) == -1) { 1017 if (errno != EINTR && errno != EAGAIN) { 1018 CFGA_TRACE1((stdout, "s_unlink[%d]: unlink failed: " 1019 "%s: %s\n", s_getpid(), file, strerror(errno))); 1020 return; 1021 } 1022 1023 if (++count < MAX_UNLINK_TRIES) { 1024 (void) sleep(1); 1025 goto retry; 1026 } 1027 CFGA_TRACE1((stdout, "s_unlink[%d]: retry limit: %s\n", 1028 s_getpid(), file)); 1029 } else { 1030 CFGA_TRACE3((stdout, "s_unlink[%d]: unlinked: %s\n", 1031 s_getpid(), file)); 1032 } 1033 } 1034 1035 static scfga_ret_t 1036 create_lock(int *fdp, struct cfga_msg *msgp, char **errstring) 1037 { 1038 FILE *fp; 1039 int count; 1040 struct extmnttab ent; 1041 int mnted; 1042 1043 1044 *fdp = -1; 1045 1046 /* 1047 * Check that /var/run is mounted. In the unlikely event 1048 * that the lock file is left behind, we want it 1049 * cleared on the next reboot. 1050 */ 1051 errno = 0; 1052 if ((fp = fopen(MNTTAB, "r")) == NULL) { 1053 cfga_err(errstring, errno, ERRARG_OPEN, MNTTAB, 0); 1054 return (SCFGA_LIB_ERR); 1055 } 1056 1057 resetmnttab(fp); 1058 1059 mnted = 0; 1060 while (getextmntent(fp, &ent, sizeof (ent)) == 0) { 1061 if (strcmp(ent.mnt_mountp, "/var/run") == 0) { 1062 mnted = 1; 1063 break; 1064 } 1065 } 1066 1067 (void) fclose(fp); 1068 1069 if (!mnted) { 1070 cfga_err(errstring, 0, ERR_VAR_RUN, 0); 1071 return (SCFGA_LIB_ERR); 1072 } 1073 1074 /* 1075 * Wait for a short period of time if we cannot O_EXCL create 1076 * lock file. If some other cfgadm process is finishing up, we 1077 * can get in. If the wait required is long however, just 1078 * return SYSTEM_BUSY to the user - a hotplug operation is 1079 * probably in progress. 1080 */ 1081 count = 0; 1082 retry: 1083 *fdp = open(SCFGA_LOCK, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR); 1084 if (*fdp == -1 && errno == EEXIST) { 1085 if (++count < MAX_LOCK_TRIES) { 1086 if (count == 1) 1087 cfga_msg(msgp, MSG_WAIT_LOCK, 0); 1088 (void) sleep(1); 1089 goto retry; 1090 } 1091 } 1092 1093 if (*fdp == -1 && errno == EEXIST) { 1094 cfga_err(errstring, 0, ERRARG_QUIESCE_LOCK, SCFGA_LOCK, 0); 1095 return (SCFGA_SYSTEM_BUSY); 1096 } else if (*fdp == -1) { 1097 cfga_err(errstring, errno, ERRARG_QUIESCE_LOCK, SCFGA_LOCK, 0); 1098 return (SCFGA_LIB_ERR); 1099 } 1100 1101 CFGA_TRACE3((stdout, "create_lock[%d]: created lockfile: %s\n", 1102 s_getpid(), SCFGA_LOCK)); 1103 1104 return (SCFGA_OK); 1105 } 1106 1107 static scfga_ret_t 1108 syslock(int fd, char **errstring) 1109 { 1110 struct flock lock; 1111 int count; 1112 int rval; 1113 1114 assert(fd != -1); 1115 1116 CFGA_TRACE3((stdout, "syslock[%d]: trying lock: %s\n", 1117 s_getpid(), SCFGA_LOCK)); 1118 1119 lock.l_type = F_WRLCK; 1120 lock.l_whence = SEEK_SET; 1121 lock.l_start = 0; 1122 lock.l_len = 0; 1123 1124 count = 0; 1125 while ((rval = fcntl(fd, F_SETLKW, &lock)) == -1 && errno == EINTR) { 1126 if (++count >= MAX_LOCK_TRIES) { 1127 CFGA_TRACE1((stdout, "syslock[%d]: retry limit: %s\n", 1128 s_getpid(), SCFGA_LOCK)); 1129 goto badlock; 1130 } 1131 (void) sleep(1); 1132 } 1133 1134 if (rval != -1) { 1135 CFGA_TRACE3((stdout, "syslock[%d]: locked file: %s\n", 1136 s_getpid(), SCFGA_LOCK)); 1137 return (SCFGA_OK); 1138 } 1139 1140 /*FALLTHROUGH*/ 1141 badlock: 1142 cfga_err(errstring, errno, ERRARG_LOCK, SCFGA_LOCK, 0); 1143 /* trace message to display pid */ 1144 CFGA_TRACE1((stdout, "syslock[%d]: cannot lock %s\n", 1145 s_getpid(), SCFGA_LOCK)); 1146 return (SCFGA_LIB_ERR); 1147 } 1148 1149 static void 1150 wait_for_child(pid_t cpid) 1151 { 1152 int status; 1153 pid_t rval; 1154 1155 CFGA_TRACE2((stdout, "wait_for_child[%d]: child[%d]\n", 1156 s_getpid(), (int)cpid)); 1157 1158 for (;;) { 1159 while ((rval = waitpid(cpid, &status, 0)) != cpid) { 1160 if (errno == ECHILD) { 1161 CFGA_TRACE1((stdout, "waitpid[%d]: child[%d] " 1162 "doesn't exist\n", s_getpid(), (int)cpid)); 1163 return; 1164 } 1165 1166 CFGA_TRACE3((stdout, "waitpid[%d]: returned: %d" 1167 ": errno: %s\n", s_getpid(), (int)rval, 1168 strerror(errno))); 1169 } 1170 1171 if (WIFEXITED(status)) { 1172 CFGA_TRACE2((stdout, "waitpid[%d]: child[%d]: " 1173 "normal exit\n", s_getpid(), (int)cpid)); 1174 return; 1175 } 1176 1177 if (WIFSIGNALED(status)) { 1178 CFGA_TRACE2((stdout, "waitpid[%d]: child[%d]: " 1179 "signal exit\n", s_getpid(), (int)cpid)); 1180 return; 1181 } 1182 1183 /* 1184 * The child has not terminated. We received status 1185 * because the child was either stopped or continued. 1186 * Wait for child termination by calling waitpid() again. 1187 */ 1188 } 1189 } 1190 1191 static void 1192 wait_and_cleanup(int fd, apid_t *apidp) 1193 { 1194 int l_errno; 1195 scfga_ret_t ret; 1196 1197 /* This is the child */ 1198 CFGA_TRACE2((stdout, "child[%d]: Entering wait_cleanup\n", s_getpid())); 1199 1200 if (syslock(fd, NULL) != SCFGA_OK) { 1201 CFGA_TRACE1((stdout, "child[%d]: lock failure " 1202 " - _exit(1)\n", s_getpid())); 1203 /* 1204 * As a last resort, unlink the lock file. This is relatively 1205 * safe as the child doesn't unquiesce the bus in this case. 1206 */ 1207 s_unlink(SCFGA_LOCK); 1208 _exit(1); 1209 } 1210 1211 l_errno = 0; 1212 ret = devctl_cmd(apidp->hba_phys, SCFGA_BUS_UNQUIESCE, NULL, &l_errno); 1213 if (ret != SCFGA_OK) { 1214 if (l_errno == EALREADY) 1215 CFGA_TRACE3((stdout, "child[%d]: bus already " 1216 "unquiesced: %s\n", s_getpid(), apidp->hba_phys)); 1217 else 1218 CFGA_TRACE1((stdout, "child[%d]: unquiesce failed: " 1219 "%s\n", s_getpid(), strerror(l_errno))); 1220 } else { 1221 CFGA_TRACE1((stdout, "child[%d]: unquiesced bus: %s\n", 1222 s_getpid(), apidp->hba_phys)); 1223 } 1224 1225 s_unlink(SCFGA_LOCK); 1226 1227 CFGA_TRACE2((stdout, "child[%d]: _exit(0)\n", s_getpid())); 1228 1229 _exit(0); 1230 } 1231 1232 static void 1233 sigblk(sigset_t *osp) 1234 { 1235 sigset_t set; 1236 1237 (void) sigemptyset(&set); 1238 (void) sigemptyset(osp); 1239 (void) sigaddset(&set, SIGHUP); 1240 (void) sigaddset(&set, SIGINT); 1241 (void) sigaddset(&set, SIGQUIT); 1242 (void) sigaddset(&set, SIGTERM); 1243 (void) sigaddset(&set, SIGUSR1); 1244 (void) sigaddset(&set, SIGUSR2); 1245 (void) sigprocmask(SIG_BLOCK, &set, osp); 1246 } 1247 1248 static void 1249 sigunblk(sigset_t *osp) 1250 { 1251 (void) sigprocmask(SIG_SETMASK, osp, NULL); 1252 } 1253 1254 /* 1255 * Here is the algorithm used to ensure that a SCSI bus is not 1256 * left in the quiesced state: 1257 * 1258 * lock quiesce mutex // single threads this code 1259 * open(O_CREAT|O_EXCL) lock file // only 1 process at a time 1260 * exclusive record lock on lock file 1261 * fork1() 1262 * quiesce bus 1263 * do the physical hotplug operation 1264 * unquiesce bus 1265 * unlock record lock 1266 * -> *child* 1267 * -> wait for record lock 1268 * -> unconditionally unquiesce bus 1269 * -> unlink lock file 1270 * -> exit 1271 * wait for child to exit 1272 * unlock quiesce mutex 1273 * 1274 * NOTE1: since record locks are per-process and a close() can 1275 * release a lock, to keep things MT-safe we need a quiesce mutex. 1276 * 1277 * NOTE2: To ensure that the child does not unquiesce a bus quiesced 1278 * by an unrelated cfgadm_scsi operation, exactly 1 process in the 1279 * system can be doing an implicit quiesce operation The exclusive 1280 * creation of the lock file guarantees this. 1281 * 1282 * NOTE3: This works even if the parent process dumps core and/or is 1283 * abnormally terminated. If the parent dies before the child is 1284 * forked, the bus is not quiesced. If the parent dies after the 1285 * bus is quiesced, the child process will ensure that the bus is 1286 * unquiesced. 1287 */ 1288 static scfga_ret_t 1289 dev_hotplug( 1290 apid_t *apidp, 1291 prompt_t *pt, 1292 cfga_flags_t flags, 1293 int do_quiesce, 1294 char **errstring) 1295 { 1296 scfga_ret_t ret; 1297 pid_t cpid; 1298 int fd; 1299 sigset_t oset; 1300 1301 assert(apidp->hba_phys != NULL); 1302 assert(apidp->path != NULL); 1303 1304 /* If no quiesce required, prompt the user to do the operation */ 1305 if (!do_quiesce) 1306 return (wait_for_hotplug(pt, CONF_NO_QUIESCE)); 1307 1308 (void) mutex_lock(&quiesce_mutex); 1309 1310 ret = create_lock(&fd, pt->msgp, errstring); 1311 if (ret != SCFGA_OK) { 1312 (void) mutex_unlock(&quiesce_mutex); 1313 return (ret); 1314 } 1315 1316 ret = syslock(fd, errstring); 1317 if (ret != SCFGA_OK) { 1318 goto bad; 1319 } 1320 1321 /* 1322 * block signals in the child. Parent may 1323 * exit, causing signal to be sent to child. 1324 */ 1325 sigblk(&oset); 1326 1327 switch (cpid = fork1()) { 1328 case 0: 1329 /* child */ 1330 wait_and_cleanup(fd, apidp); 1331 _exit(0); /* paranoia */ 1332 /*NOTREACHED*/ 1333 case -1: 1334 cfga_err(errstring, errno, ERR_FORK, 0); 1335 sigunblk(&oset); 1336 ret = SCFGA_LIB_ERR; 1337 goto bad; 1338 default: 1339 /* parent */ 1340 break; 1341 } 1342 1343 sigunblk(&oset); 1344 1345 /* We have forked successfully - this is the parent */ 1346 ret = bus_quiesce(apidp, pt, errstring, flags); 1347 1348 (void) close(fd); /* also unlocks */ 1349 1350 wait_for_child(cpid); 1351 1352 (void) mutex_unlock(&quiesce_mutex); 1353 1354 return (ret); 1355 bad: 1356 (void) close(fd); 1357 s_unlink(SCFGA_LOCK); 1358 (void) mutex_unlock(&quiesce_mutex); 1359 return (ret); 1360 } 1361 1362 /* 1363 * Checks if HBA controls a critical file-system (/, /usr or swap) 1364 * This routine reads /etc/vfstab and is NOT foolproof. 1365 * If an error occurs, assumes that controller is NOT critical. 1366 */ 1367 static int 1368 critical_ctrlr(const char *hba_phys) 1369 { 1370 FILE *fp; 1371 struct vfstab vfst; 1372 int vfsret = 1, rv = -1; 1373 char *bufp; 1374 const size_t buflen = PATH_MAX; 1375 char mount[MAXPATHLEN], fstype[MAXPATHLEN], spec[MAXPATHLEN]; 1376 1377 1378 if ((bufp = calloc(1, buflen)) == NULL) { 1379 return (0); 1380 } 1381 1382 fp = NULL; 1383 if ((fp = fopen(ETC_VFSTAB, "r")) == NULL) { 1384 rv = 0; 1385 goto out; 1386 } 1387 1388 while ((vfsret = getvfsent(fp, &vfst)) == 0) { 1389 1390 (void) strcpy(mount, S_STR(vfst.vfs_mountp)); 1391 (void) strcpy(fstype, S_STR(vfst.vfs_fstype)); 1392 (void) strcpy(spec, S_STR(vfst.vfs_special)); 1393 1394 /* Ignore non-critical entries */ 1395 if (strcmp(mount, "/") && strcmp(mount, "/usr") && 1396 strcmp(fstype, "swap")) { 1397 continue; 1398 } 1399 1400 /* get physical path */ 1401 if (realpath(spec, bufp) == NULL) { 1402 continue; 1403 } 1404 1405 /* Check if critical partition is on the HBA */ 1406 if (!(rv = hba_dev_cmp(hba_phys, bufp))) { 1407 break; 1408 } 1409 } 1410 1411 rv = !vfsret; 1412 1413 /*FALLTHRU*/ 1414 out: 1415 S_FREE(bufp); 1416 if (fp != NULL) { 1417 (void) fclose(fp); 1418 } 1419 return (rv); 1420 } 1421 1422 /* 1423 * Convert bus state to receptacle state 1424 */ 1425 static cfga_stat_t 1426 bus_devctl_to_recep_state(uint_t bus_dc_state) 1427 { 1428 cfga_stat_t rs; 1429 1430 switch (bus_dc_state) { 1431 case BUS_ACTIVE: 1432 rs = CFGA_STAT_CONNECTED; 1433 break; 1434 case BUS_QUIESCED: 1435 case BUS_SHUTDOWN: 1436 rs = CFGA_STAT_DISCONNECTED; 1437 break; 1438 default: 1439 rs = CFGA_STAT_NONE; 1440 break; 1441 } 1442 1443 return (rs); 1444 } 1445 1446 static int 1447 add_dev(di_node_t node, void *arg) 1448 { 1449 int ndevs, len; 1450 char *path, *p; 1451 struct larg *largp = (struct larg *)arg; 1452 1453 /* ignore hba itself and all detached nodes */ 1454 if (di_parent_node(node) == DI_NODE_NIL || 1455 di_node_state(node) < DS_ATTACHED) 1456 return (DI_WALK_CONTINUE); 1457 1458 if ((path = di_devfs_path(node)) == NULL) { 1459 largp->ndevs = -1; 1460 return (DI_WALK_TERMINATE); 1461 } 1462 1463 /* sizeof (DEVICES_DIR) includes the null terminator */ 1464 len = strlen(path) + sizeof (DEVICES_DIR); 1465 if ((p = malloc(len)) == NULL) { 1466 di_devfs_path_free(path); 1467 largp->ndevs = -1; 1468 return (DI_WALK_TERMINATE); 1469 } 1470 (void) snprintf(p, len, "%s%s", DEVICES_DIR, path); 1471 di_devfs_path_free(path); 1472 1473 /* ignore device to be excluded */ 1474 if (largp->dev && strcmp(largp->dev, p) == 0) { 1475 free(p); 1476 return (DI_WALK_CONTINUE); 1477 } 1478 1479 /* grow dev_list to allow room for one more device */ 1480 if (alloc_dev_list(largp) != 0) { 1481 free(p); 1482 return (DI_WALK_TERMINATE); 1483 } 1484 ndevs = largp->ndevs; 1485 largp->ndevs++; 1486 largp->dev_list[ndevs] = p; 1487 largp->dev_list[ndevs + 1] = NULL; 1488 return (DI_WALK_CONTINUE); 1489 } 1490 1491 /* 1492 * Get list of children excluding dev_excl (if not null). 1493 */ 1494 static int 1495 get_hba_children(char *bus_path, char *dev_excl, char ***dev_listp) 1496 { 1497 int err, ret; 1498 walkarg_t u; 1499 struct larg larg; 1500 1501 *dev_listp = NULL; 1502 1503 u.node_args.flags = DI_WALK_CLDFIRST; 1504 u.node_args.fcn = add_dev; 1505 1506 larg.ndevs = 0; 1507 larg.nelem = 0; 1508 larg.dev = dev_excl; 1509 larg.dev_list = NULL; 1510 1511 ret = walk_tree(bus_path, &larg, DINFOSUBTREE, &u, SCFGA_WALK_NODE, 1512 &err); 1513 if (larg.ndevs == -1) { 1514 free_dev_list(larg.dev_list); 1515 return (SCFGA_ERR); 1516 } 1517 *dev_listp = larg.dev_list; 1518 return (ret); 1519 } 1520 1521 static char * 1522 get_node_path(char *minor_path) 1523 { 1524 char *path, *cp; 1525 1526 if ((path = strdup(minor_path)) == NULL) 1527 return (NULL); 1528 if ((cp = strrchr(path, ':')) != NULL) 1529 *cp = '\0'; 1530 return (path); 1531 } 1532 1533 /* 1534 * Ensure largp->dev_list has room for one more device. 1535 * Returns 0 on success, -1 on failure. 1536 */ 1537 static int 1538 alloc_dev_list(struct larg *largp) 1539 { 1540 int nelem; 1541 char **p; 1542 1543 if (largp->nelem > largp->ndevs + 2) /* +1 for NULL termination */ 1544 return (0); 1545 1546 nelem = largp->nelem + 16; 1547 p = realloc(largp->dev_list, nelem * sizeof (char *)); 1548 if (p == NULL) 1549 return (-1); 1550 1551 largp->dev_list = p; 1552 largp->nelem = nelem; 1553 return (0); 1554 } 1555 1556 static void 1557 free_dev_list_elements(char **dev_list) 1558 { 1559 while (*dev_list) { 1560 free(*dev_list); 1561 dev_list++; 1562 } 1563 } 1564 1565 static void 1566 free_dev_list(char **dev_list) 1567 { 1568 if (dev_list == NULL) 1569 return; 1570 1571 free_dev_list_elements(dev_list); 1572 free(dev_list); 1573 } 1574