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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <sun_sas.h> 27 #include <sys/modctl.h> 28 #include <sys/types.h> 29 #include <netinet/in.h> 30 #include <inttypes.h> 31 #include <ctype.h> 32 33 /* free hba port info for the given hba */ 34 static void 35 free_hba_port(struct sun_sas_hba *hba_ptr) 36 { 37 struct sun_sas_port *hba_port = NULL; 38 struct sun_sas_port *last_hba_port = NULL; 39 struct sun_sas_port *tgt_port = NULL; 40 struct sun_sas_port *last_tgt_port = NULL; 41 struct ScsiEntryList *scsi_info = NULL; 42 struct ScsiEntryList *last_scsi_info = NULL; 43 struct phy_info *phy_ptr = NULL; 44 struct phy_info *last_phy = NULL; 45 46 /* Free the nested structures (port and attached port) */ 47 hba_port = hba_ptr->first_port; 48 while (hba_port != NULL) { 49 /* Free discovered port structure list. */ 50 tgt_port = hba_port->first_attached_port; 51 while (tgt_port != NULL) { 52 /* Free target mapping data list first. */ 53 scsi_info = tgt_port->scsiInfo; 54 while (scsi_info != NULL) { 55 last_scsi_info = scsi_info; 56 scsi_info = scsi_info->next; 57 free(last_scsi_info); 58 } 59 last_tgt_port = tgt_port; 60 tgt_port = tgt_port->next; 61 free(last_tgt_port->port_attributes.\ 62 PortSpecificAttribute.SASPort); 63 free(last_tgt_port); 64 } 65 hba_port->first_attached_port = NULL; 66 67 phy_ptr = hba_port->first_phy; 68 while (phy_ptr != NULL) { 69 last_phy = phy_ptr; 70 phy_ptr = phy_ptr->next; 71 free(last_phy); 72 } 73 hba_port->first_phy = NULL; 74 75 last_hba_port = hba_port; 76 hba_port = hba_port->next; 77 free(last_hba_port->port_attributes.\ 78 PortSpecificAttribute.SASPort); 79 free(last_hba_port); 80 } 81 82 hba_ptr->first_port = NULL; 83 } 84 85 /* 86 * Internal routine for adding an HBA port 87 */ 88 static HBA_STATUS 89 add_hba_port_info(di_node_t portNode, struct sun_sas_hba *hba_ptr, int protocol) 90 { 91 const char ROUTINE[] = "add_hba_port_info"; 92 struct sun_sas_port *port_ptr; 93 char *portDevpath; 94 int *propIntData; 95 char *propStringData; 96 uint64_t tmpAddr; 97 char *charptr, cntlLink[MAXPATHLEN] = {'\0'}; 98 int rval; 99 di_node_t branchNode; 100 uint_t state = HBA_PORTSTATE_UNKNOWN; 101 102 if (hba_ptr == NULL) { 103 log(LOG_DEBUG, ROUTINE, 104 "Sun_sas handle ptr set to NULL."); 105 return (HBA_STATUS_ERROR_ARG); 106 } 107 108 if ((port_ptr = (struct sun_sas_port *)calloc(1, 109 sizeof (struct sun_sas_port))) == NULL) { 110 OUT_OF_MEMORY(ROUTINE); 111 return (HBA_STATUS_ERROR); 112 } 113 114 if ((port_ptr->port_attributes.PortSpecificAttribute.SASPort = 115 (struct SMHBA_SAS_Port *)calloc(1, sizeof (struct SMHBA_SAS_Port))) 116 == NULL) { 117 OUT_OF_MEMORY(ROUTINE); 118 return (HBA_STATUS_ERROR); 119 } 120 121 if ((portDevpath = di_devfs_path(portNode)) == NULL) { 122 log(LOG_DEBUG, ROUTINE, 123 "Unable to get device path from HBA Port Node."); 124 S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort); 125 S_FREE(port_ptr); 126 return (HBA_STATUS_ERROR); 127 } 128 129 /* 130 * Let's take a branch snap shot for pulling attributes. 131 * The attribute change doesn't invalidate devinfo cache snapshot. 132 * Phy info prop and num-phys can be obsolate when the same hba 133 * connected to the same expander(SIM) thus phy numbers are increased. 134 * Also the phy number may get decreased when a connection is removed 135 * while the iport still exist through another connection. 136 */ 137 branchNode = di_init(portDevpath, DINFOPROP); 138 if (branchNode == DI_NODE_NIL) { 139 /* something is wrong here. */ 140 di_fini(branchNode); 141 log(LOG_DEBUG, ROUTINE, 142 "Unable to take devinfoi branch snapshot on HBA port \"%s\"" 143 " due to %s", portDevpath, strerror(errno)); 144 S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort); 145 S_FREE(port_ptr); 146 return (HBA_STATUS_ERROR); 147 } 148 149 state = di_state(portNode); 150 if (((state & DI_DRIVER_DETACHED) == DI_DRIVER_DETACHED) || 151 ((state & DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE)) { 152 log(LOG_DEBUG, ROUTINE, 153 "HBA port node %s is either OFFLINE or DETACHED", 154 portDevpath); 155 port_ptr->port_attributes.PortState = HBA_PORTSTATE_OFFLINE; 156 } else { 157 port_ptr->port_attributes.PortState = HBA_PORTSTATE_ONLINE; 158 } 159 160 port_ptr->port_attributes.PortType = HBA_PORTTYPE_SASDEVICE; 161 162 (void) strlcpy(port_ptr->device_path, portDevpath, MAXPATHLEN + 1); 163 164 if (lookupControllerLink(portDevpath, (char *)cntlLink) == 165 HBA_STATUS_OK) { 166 (void) strlcpy(port_ptr->port_attributes.OSDeviceName, cntlLink, 167 sizeof (port_ptr->port_attributes.OSDeviceName)); 168 if ((charptr = strrchr(cntlLink, '/')) != NULL) { 169 charptr++; 170 } 171 if (charptr[0] == 'c') { 172 port_ptr->cntlNumber = atoi(++charptr); 173 } else { 174 port_ptr->cntlNumber = -1; 175 } 176 } else { 177 (void) snprintf(port_ptr->port_attributes.OSDeviceName, 178 sizeof (port_ptr->port_attributes.OSDeviceName), 179 "%s%s%s", DEVICES_DIR, portDevpath, SCSI_SUFFIX); 180 } 181 182 di_devfs_path_free(portDevpath); 183 184 port_ptr->port_attributes.PortSpecificAttribute. 185 SASPort->PortProtocol = protocol; 186 187 rval = di_prop_lookup_strings(DDI_DEV_T_ANY, branchNode, 188 "initiator-port", &propStringData); 189 if (rval < 0) { 190 log(LOG_DEBUG, ROUTINE, 191 "Unable to get initiator-port from HBA port node %s.", 192 port_ptr->port_attributes.OSDeviceName); 193 di_fini(branchNode); 194 S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort); 195 S_FREE(port_ptr); 196 return (HBA_STATUS_ERROR); 197 } else { 198 for (charptr = propStringData; *charptr != '\0'; charptr++) { 199 if (isxdigit(*charptr)) { 200 break; 201 } 202 } 203 if (*charptr != '\0') { 204 tmpAddr = htonll(strtoll(charptr, NULL, 16)); 205 (void) memcpy(port_ptr->port_attributes. 206 PortSpecificAttribute.SASPort->LocalSASAddress.wwn, 207 &tmpAddr, 8); 208 } else { 209 log(LOG_DEBUG, ROUTINE, 210 "No proper intiator-port prop value on HBA port %s", 211 port_ptr->port_attributes.OSDeviceName); 212 } 213 } 214 215 rval = di_prop_lookup_strings(DDI_DEV_T_ANY, branchNode, 216 "attached-port", &propStringData); 217 if (rval < 0) { 218 log(LOG_DEBUG, ROUTINE, 219 "Unable to get attached-port from HBA port node %s.", 220 port_ptr->port_attributes.OSDeviceName); 221 di_fini(branchNode); 222 S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort); 223 S_FREE(port_ptr); 224 return (HBA_STATUS_ERROR); 225 } else { 226 for (charptr = propStringData; *charptr != '\0'; charptr++) { 227 if (isxdigit(*charptr)) { 228 break; 229 } 230 } 231 if (*charptr != '\0') { 232 tmpAddr = htonll(strtoll(charptr, NULL, 16)); 233 (void) memcpy(port_ptr->port_attributes. 234 PortSpecificAttribute.SASPort-> 235 AttachedSASAddress.wwn, &tmpAddr, 8); 236 } else { 237 /* continue even if the attached port is NULL. */ 238 log(LOG_DEBUG, ROUTINE, 239 "No proper attached-port prop value: " 240 "HBA port Local SAS Address(%016llx)", 241 wwnConversion(port_ptr->port_attributes. 242 PortSpecificAttribute. 243 SASPort->LocalSASAddress.wwn)); 244 } 245 } 246 247 rval = di_prop_lookup_ints(DDI_DEV_T_ANY, branchNode, 248 "num-phys", &propIntData); 249 if (rval < 0) { 250 log(LOG_DEBUG, ROUTINE, 251 "Unable to get NumberofPhys from HBA port %s.", 252 port_ptr->port_attributes.OSDeviceName); 253 di_fini(branchNode); 254 S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort); 255 S_FREE(port_ptr); 256 return (HBA_STATUS_ERROR); 257 } else { 258 port_ptr->port_attributes.PortSpecificAttribute.\ 259 SASPort->NumberofPhys = *propIntData; 260 } 261 262 if (port_ptr->port_attributes.PortSpecificAttribute.\ 263 SASPort->NumberofPhys > 0) { 264 if (get_phy_info(branchNode, port_ptr) != HBA_STATUS_OK) { 265 log(LOG_DEBUG, ROUTINE, 266 "Failed to get phy info on HBA port %s.", 267 port_ptr->port_attributes.OSDeviceName); 268 di_fini(branchNode); 269 S_FREE(port_ptr->port_attributes. 270 PortSpecificAttribute.SASPort); 271 S_FREE(port_ptr); 272 return (HBA_STATUS_ERROR); 273 } 274 } 275 276 /* now done with prop checking. remove branchNode. */ 277 di_fini(branchNode); 278 279 /* Construct discovered target port. */ 280 if (devtree_attached_devices(portNode, port_ptr) != HBA_STATUS_OK) { 281 log(LOG_DEBUG, ROUTINE, 282 "Failed to get attached device info HBA port %s.", 283 port_ptr->port_attributes.OSDeviceName); 284 S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort); 285 S_FREE(port_ptr); 286 return (HBA_STATUS_ERROR); 287 } 288 289 fillDomainPortWWN(port_ptr); 290 291 /* add new port onto hba handle list */ 292 if (hba_ptr->first_port == NULL) { 293 port_ptr->index = 0; 294 hba_ptr->first_port = port_ptr; 295 } else { 296 port_ptr->index = hba_ptr->first_port->index + 1; 297 port_ptr->next = hba_ptr->first_port; 298 hba_ptr->first_port = port_ptr; 299 } 300 301 return (HBA_STATUS_OK); 302 } 303 304 HBA_STATUS 305 refresh_hba(di_node_t hbaNode, struct sun_sas_hba *hba_ptr) 306 { 307 const char ROUTINE[] = "refresh_hba"; 308 di_node_t portNode; 309 int protocol = 0; 310 int *propIntData; 311 312 /* 313 * clean up existing hba port, discovered target, phy info. 314 * leave open handles intact. 315 */ 316 free_hba_port(hba_ptr); 317 318 if ((portNode = di_child_node(hbaNode)) == NULL) { 319 log(LOG_DEBUG, ROUTINE, 320 "HBA node doesn't have iport child."); 321 return (HBA_STATUS_ERROR); 322 } 323 324 if ((di_prop_lookup_ints(DDI_DEV_T_ANY, hbaNode, 325 "supported-protocol", &propIntData)) == -1) { 326 log(LOG_DEBUG, ROUTINE, 327 "Unable to get supported-protocol from HBA node."); 328 } else { 329 protocol = *propIntData; 330 } 331 332 while (portNode != DI_NODE_NIL) { 333 if (di_prop_lookup_ints(DDI_DEV_T_ANY, portNode, 334 "virtual-port", &propIntData) >= 0) { 335 if (*propIntData) { 336 /* ignore a virtual port. */ 337 portNode = di_sibling_node(portNode); 338 continue; 339 } 340 } 341 if (add_hba_port_info(portNode, hba_ptr, protocol) 342 == HBA_STATUS_ERROR) { 343 S_FREE(hba_ptr->first_port); 344 S_FREE(hba_ptr); 345 return (HBA_STATUS_ERROR); 346 } 347 portNode = di_sibling_node(portNode); 348 } 349 350 return (HBA_STATUS_OK); 351 } 352 353 /* 354 * Discover information for one HBA in the device tree. 355 * The di_node_t argument should be a node with smhba-supported prop set 356 * to true. 357 * Without iport support, the devinfo node will represent one port hba. 358 * This routine assumes the locks have been taken. 359 */ 360 HBA_STATUS 361 devtree_get_one_hba(di_node_t hbaNode) 362 { 363 const char ROUTINE[] = "devtree_get_one_hba"; 364 char *propdata = NULL; 365 int *propIntData = NULL; 366 struct sun_sas_hba *new_hba, *hba_ptr; 367 char *hbaDevpath, *hba_driver; 368 int protocol = 0; 369 di_node_t portNode; 370 int hba_instance = -1; 371 372 hba_instance = di_instance(hbaNode); 373 if (hba_instance == -1) { 374 log(LOG_DEBUG, ROUTINE, 375 "portNode has instance of -1"); 376 return (DI_WALK_CONTINUE); 377 } 378 379 if ((hbaDevpath = di_devfs_path(hbaNode)) == NULL) { 380 log(LOG_DEBUG, ROUTINE, "Unable to get " 381 "device path from hbaNode"); 382 return (HBA_STATUS_ERROR); 383 } 384 385 /* check to see if this is a repeat HBA */ 386 if (global_hba_head) { 387 for (hba_ptr = global_hba_head; 388 hba_ptr != NULL; 389 hba_ptr = hba_ptr->next) { 390 if ((strncmp(hba_ptr->device_path, hbaDevpath, 391 strlen(hbaDevpath))) == 0) { 392 if (refresh_hba(hbaNode, hba_ptr) != 393 HBA_STATUS_OK) { 394 log(LOG_DEBUG, ROUTINE, "Refresh failed" 395 " on hbaNode %s", hbaDevpath); 396 } 397 di_devfs_path_free(hbaDevpath); 398 return (HBA_STATUS_OK); 399 } 400 } 401 } 402 403 /* this is a new hba */ 404 if ((new_hba = (struct sun_sas_hba *)calloc(1, 405 sizeof (struct sun_sas_hba))) == NULL) { 406 OUT_OF_MEMORY(ROUTINE); 407 di_devfs_path_free(hbaDevpath); 408 return (HBA_STATUS_ERROR); 409 } 410 411 (void) strlcpy(new_hba->device_path, hbaDevpath, 412 sizeof (new_hba->device_path)); 413 di_devfs_path_free(hbaDevpath); 414 415 (void) snprintf(new_hba->adapter_attributes.HBASymbolicName, 416 sizeof (new_hba->adapter_attributes.HBASymbolicName), 417 "%s%s", DEVICES_DIR, new_hba->device_path); 418 419 /* Manufacturer */ 420 if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode, 421 "Manufacturer", (char **)&propdata)) == -1) { 422 (void) strlcpy(new_hba->adapter_attributes.Manufacturer, 423 SUN_MICROSYSTEMS, 424 sizeof (new_hba->adapter_attributes.Manufacturer)); 425 } else { 426 (void) strlcpy(new_hba->adapter_attributes.Manufacturer, 427 propdata, 428 sizeof (new_hba->adapter_attributes.Manufacturer)); 429 } 430 431 /* SerialNumber */ 432 if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode, 433 "SerialNumber", (char **)&propdata)) == -1) { 434 new_hba->adapter_attributes.SerialNumber[0] = '\0'; 435 } else { 436 (void) strlcpy(new_hba->adapter_attributes.SerialNumber, 437 propdata, 438 sizeof (new_hba->adapter_attributes.SerialNumber)); 439 } 440 441 /* Model */ 442 if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode, 443 "ModelName", (char **)&propdata)) == -1) { 444 new_hba->adapter_attributes.Model[0] = '\0'; 445 } else { 446 (void) strlcpy(new_hba->adapter_attributes.Model, 447 propdata, 448 sizeof (new_hba->adapter_attributes.Model)); 449 } 450 451 /* FirmwareVersion */ 452 if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode, 453 "firmware-version", (char **)&propdata)) == -1) { 454 log(LOG_DEBUG, ROUTINE, 455 "Property \"%s\" not found for device \"%s\"", 456 "firmware-version", new_hba->device_path); 457 } else { 458 (void) strlcpy(new_hba->adapter_attributes.FirmwareVersion, 459 propdata, 460 sizeof (new_hba->adapter_attributes.FirmwareVersion)); 461 } 462 463 /* HardwareVersion */ 464 if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode, 465 "hardware-version", (char **)&propdata)) == -1) { 466 log(LOG_DEBUG, ROUTINE, 467 "Property \"%s\" not found for device \"%s\"", 468 "hardware-version", new_hba->device_path); 469 } else { 470 (void) strlcpy(new_hba->adapter_attributes.HardwareVersion, 471 propdata, 472 sizeof (new_hba->adapter_attributes.HardwareVersion)); 473 } 474 475 /* DriverVersion */ 476 if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode, 477 "driver-version", (char **)&propdata)) == -1) { 478 log(LOG_DEBUG, ROUTINE, 479 "Property \"%s\" not found for device \"%s\"", 480 "driver-version", new_hba->device_path); 481 } else { 482 (void) strlcpy(new_hba->adapter_attributes.DriverVersion, 483 propdata, 484 sizeof (new_hba->adapter_attributes.DriverVersion)); 485 } 486 487 if ((di_prop_lookup_ints(DDI_DEV_T_ANY, hbaNode, 488 "supported-protocol", &propIntData)) == -1) { 489 log(LOG_DEBUG, ROUTINE, 490 "Unable to get supported-protocol from HBA node."); 491 } else { 492 protocol = *propIntData; 493 } 494 495 /* We don't use these */ 496 new_hba->adapter_attributes.OptionROMVersion[0] = '\0'; 497 new_hba->adapter_attributes.RedundantOptionROMVersion[0] = '\0'; 498 new_hba->adapter_attributes.RedundantFirmwareVersion[0] = '\0'; 499 new_hba->adapter_attributes.VendorSpecificID = 0; 500 501 if ((hba_driver = di_driver_name(hbaNode)) != NULL) { 502 (void) strlcpy(new_hba->adapter_attributes.DriverName, 503 hba_driver, 504 sizeof (new_hba->adapter_attributes.DriverName)); 505 } else { 506 log(LOG_DEBUG, ROUTINE, 507 "HBA driver name not found for device \"%s\"", 508 new_hba->device_path); 509 } 510 511 /* 512 * Name the adapter: like SUNW-pmcs-1 513 * Using di_instance number as the suffix for the name for persistent 514 * among rebooting. 515 */ 516 (void) snprintf(new_hba->handle_name, HANDLE_NAME_LENGTH, "%s-%s-%d", 517 "SUNW", new_hba->adapter_attributes.DriverName, hba_instance); 518 519 if ((portNode = di_child_node(hbaNode)) == NULL) { 520 log(LOG_DEBUG, ROUTINE, 521 "HBA driver doesn't have iport child. \"%s\"", 522 new_hba->device_path); 523 /* continue on with an hba without any port. */ 524 new_hba->index = hba_count++; 525 526 /* 527 * add newly created handle into global_hba_head list 528 */ 529 if (global_hba_head != NULL) { 530 /* 531 * Make sure to move the open_handles list to back to 532 * the head if it's there (for refresh scenario) 533 */ 534 if (global_hba_head->open_handles) { 535 new_hba->open_handles = 536 global_hba_head->open_handles; 537 global_hba_head->open_handles = NULL; 538 } 539 /* Now bump the new one to the head of the list */ 540 new_hba->next = global_hba_head; 541 global_hba_head = new_hba; 542 } else { 543 global_hba_head = new_hba; 544 } 545 return (HBA_STATUS_OK); 546 } 547 548 while (portNode != DI_NODE_NIL) { 549 if (di_prop_lookup_ints(DDI_DEV_T_ANY, portNode, 550 "virtual-port", &propIntData) >= 0) { 551 if (*propIntData) { 552 /* ignore a virtual port. */ 553 portNode = di_sibling_node(portNode); 554 continue; 555 } 556 } 557 if (add_hba_port_info(portNode, new_hba, protocol) 558 == HBA_STATUS_ERROR) { 559 S_FREE(new_hba->first_port); 560 S_FREE(new_hba); 561 return (HBA_STATUS_ERROR); 562 } 563 portNode = di_sibling_node(portNode); 564 } 565 566 new_hba->index = hba_count++; 567 568 /* 569 * add newly created handle into global_hba_head list 570 */ 571 if (global_hba_head != NULL) { 572 /* 573 * Make sure to move the open_handles list to back to the 574 * head if it's there (for refresh scenario) 575 */ 576 if (global_hba_head->open_handles) { 577 new_hba->open_handles = global_hba_head->open_handles; 578 global_hba_head->open_handles = NULL; 579 } 580 /* Now bump the new one to the head of the list */ 581 new_hba->next = global_hba_head; 582 global_hba_head = new_hba; 583 } else { 584 global_hba_head = new_hba; 585 } 586 587 return (HBA_STATUS_OK); 588 } 589 590 /* 591 * Discover information for all HBAs found on the system. 592 * The di_node_t argument should be the root of the device tree. 593 * This routine assumes the locks have been taken 594 */ 595 static int 596 lookup_smhba_sas_hba(di_node_t node, void *arg) 597 { 598 const char ROUTINE[] = "lookup_smhba_sas_hba"; 599 int *propData, rval; 600 walkarg_t *wa = (walkarg_t *)arg; 601 602 /* Skip stub(instance -1) nodes */ 603 if (IS_STUB_NODE(node)) { 604 log(LOG_DEBUG, ROUTINE, "Walk continue"); 605 return (DI_WALK_CONTINUE); 606 } 607 608 rval = di_prop_lookup_ints(DDI_DEV_T_ANY, node, 609 "sm-hba-supported", &propData); 610 if (rval >= 0) { 611 if (*propData) { 612 /* add the hba to the hba list */ 613 if (devtree_get_one_hba(node) != HBA_STATUS_OK) { 614 *(wa->flag) = B_TRUE; 615 } 616 /* Found a node. No need to walk the child. */ 617 log(LOG_DEBUG, ROUTINE, "Walk prunechild"); 618 return (DI_WALK_PRUNECHILD); 619 } 620 } 621 622 return (DI_WALK_CONTINUE); 623 } 624 625 /* 626 * Discover information for all HBAs found on the system. 627 * The di_node_t argument should be the root of the device tree. 628 * This routine assumes the locks have been taken 629 */ 630 HBA_STATUS 631 devtree_get_all_hbas(di_node_t root) 632 { 633 const char ROUTINE[] = "devtree_get_all_hbas"; 634 int rv, ret = HBA_STATUS_ERROR; 635 walkarg_t wa; 636 637 wa.devpath = NULL; 638 if ((wa.flag = (boolean_t *)calloc(1, 639 sizeof (boolean_t))) == NULL) { 640 OUT_OF_MEMORY(ROUTINE); 641 return (HBA_STATUS_ERROR); 642 } 643 *wa.flag = B_FALSE; 644 rv = di_walk_node(root, DI_WALK_SIBFIRST, &wa, lookup_smhba_sas_hba); 645 646 if (rv == 0) { 647 /* 648 * Now determine what status code to return, taking 649 * partial failure scenarios into consideration. 650 * 651 * If we have at least one working HBA, then we return an 652 * OK status. If we have no good HBAs, but at least one 653 * failed HBA, we return an ERROR status. If we have 654 * no HBAs and no failures, we return OK. 655 */ 656 if (global_hba_head) { 657 /* 658 * We've got at least one HBA and possibly some 659 * failures. 660 */ 661 ret = HBA_STATUS_OK; 662 } else if (*(wa.flag)) { 663 /* We have no HBAs but have failures */ 664 ret = HBA_STATUS_ERROR; 665 } else { 666 /* We have no HBAs and no failures */ 667 ret = HBA_STATUS_OK; 668 } 669 } 670 671 672 S_FREE(wa.flag); 673 674 if (ret == HBA_STATUS_OK) 675 (void) registerSysevent(); 676 677 return (ret); 678 } 679