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