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