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