2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <sun_sas.h>
2N/A#include <sys/modctl.h>
2N/A#include <sys/types.h>
2N/A#include <netinet/in.h>
2N/A#include <inttypes.h>
2N/A#include <ctype.h>
2N/A
2N/A/* free hba port info for the given hba */
2N/Astatic void
2N/Afree_hba_port(struct sun_sas_hba *hba_ptr)
2N/A{
2N/A struct sun_sas_port *hba_port = NULL;
2N/A struct sun_sas_port *last_hba_port = NULL;
2N/A struct sun_sas_port *tgt_port = NULL;
2N/A struct sun_sas_port *last_tgt_port = NULL;
2N/A struct ScsiEntryList *scsi_info = NULL;
2N/A struct ScsiEntryList *last_scsi_info = NULL;
2N/A struct phy_info *phy_ptr = NULL;
2N/A struct phy_info *last_phy = NULL;
2N/A
2N/A /* Free the nested structures (port and attached port) */
2N/A hba_port = hba_ptr->first_port;
2N/A while (hba_port != NULL) {
2N/A /* Free discovered port structure list. */
2N/A tgt_port = hba_port->first_attached_port;
2N/A while (tgt_port != NULL) {
2N/A /* Free target mapping data list first. */
2N/A scsi_info = tgt_port->scsiInfo;
2N/A while (scsi_info != NULL) {
2N/A last_scsi_info = scsi_info;
2N/A scsi_info = scsi_info->next;
2N/A free(last_scsi_info);
2N/A }
2N/A last_tgt_port = tgt_port;
2N/A tgt_port = tgt_port->next;
2N/A free(last_tgt_port->port_attributes.\
2N/A PortSpecificAttribute.SASPort);
2N/A free(last_tgt_port);
2N/A }
2N/A hba_port->first_attached_port = NULL;
2N/A
2N/A phy_ptr = hba_port->first_phy;
2N/A while (phy_ptr != NULL) {
2N/A last_phy = phy_ptr;
2N/A phy_ptr = phy_ptr->next;
2N/A free(last_phy);
2N/A }
2N/A hba_port->first_phy = NULL;
2N/A
2N/A last_hba_port = hba_port;
2N/A hba_port = hba_port->next;
2N/A free(last_hba_port->port_attributes.\
2N/A PortSpecificAttribute.SASPort);
2N/A free(last_hba_port);
2N/A }
2N/A
2N/A hba_ptr->first_port = NULL;
2N/A}
2N/A
2N/A/*
2N/A * Internal routine for adding an HBA port
2N/A */
2N/Astatic HBA_STATUS
2N/Aadd_hba_port_info(di_node_t portNode, struct sun_sas_hba *hba_ptr, int protocol)
2N/A{
2N/A const char ROUTINE[] = "add_hba_port_info";
2N/A struct sun_sas_port *port_ptr;
2N/A char *portDevpath;
2N/A int *propIntData;
2N/A char *propStringData;
2N/A uint64_t tmpAddr;
2N/A char *charptr, cntlLink[MAXPATHLEN] = {'\0'};
2N/A int rval;
2N/A di_node_t branchNode;
2N/A uint_t state = HBA_PORTSTATE_UNKNOWN;
2N/A
2N/A if (hba_ptr == NULL) {
2N/A log(LOG_DEBUG, ROUTINE,
2N/A "Sun_sas handle ptr set to NULL.");
2N/A return (HBA_STATUS_ERROR_ARG);
2N/A }
2N/A
2N/A if ((port_ptr = (struct sun_sas_port *)calloc(1,
2N/A sizeof (struct sun_sas_port))) == NULL) {
2N/A OUT_OF_MEMORY(ROUTINE);
2N/A return (HBA_STATUS_ERROR);
2N/A }
2N/A
2N/A if ((port_ptr->port_attributes.PortSpecificAttribute.SASPort =
2N/A (struct SMHBA_SAS_Port *)calloc(1, sizeof (struct SMHBA_SAS_Port)))
2N/A == NULL) {
2N/A OUT_OF_MEMORY(ROUTINE);
2N/A return (HBA_STATUS_ERROR);
2N/A }
2N/A
2N/A if ((portDevpath = di_devfs_path(portNode)) == NULL) {
2N/A log(LOG_DEBUG, ROUTINE,
2N/A "Unable to get device path from HBA Port Node.");
2N/A S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
2N/A S_FREE(port_ptr);
2N/A return (HBA_STATUS_ERROR);
2N/A }
2N/A
2N/A /*
2N/A * Let's take a branch snap shot for pulling attributes.
2N/A * The attribute change doesn't invalidate devinfo cache snapshot.
2N/A * Phy info prop and num-phys can be obsolate when the same hba
2N/A * connected to the same expander(SIM) thus phy numbers are increased.
2N/A * Also the phy number may get decreased when a connection is removed
2N/A * while the iport still exist through another connection.
2N/A */
2N/A branchNode = di_init(portDevpath, DINFOPROP);
2N/A if (branchNode == DI_NODE_NIL) {
2N/A /* something is wrong here. */
2N/A di_fini(branchNode);
2N/A log(LOG_DEBUG, ROUTINE,
2N/A "Unable to take devinfoi branch snapshot on HBA port \"%s\""
2N/A " due to %s", portDevpath, strerror(errno));
2N/A S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
2N/A S_FREE(port_ptr);
2N/A return (HBA_STATUS_ERROR);
2N/A }
2N/A
2N/A state = di_state(portNode);
2N/A if (((state & DI_DRIVER_DETACHED) == DI_DRIVER_DETACHED) ||
2N/A ((state & DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE)) {
2N/A log(LOG_DEBUG, ROUTINE,
2N/A "HBA port node %s is either OFFLINE or DETACHED",
2N/A portDevpath);
2N/A port_ptr->port_attributes.PortState = HBA_PORTSTATE_OFFLINE;
2N/A } else {
2N/A port_ptr->port_attributes.PortState = HBA_PORTSTATE_ONLINE;
2N/A }
2N/A
2N/A port_ptr->port_attributes.PortType = HBA_PORTTYPE_SASDEVICE;
2N/A
2N/A (void) strlcpy(port_ptr->device_path, portDevpath, MAXPATHLEN + 1);
2N/A
2N/A if (lookupControllerLink(portDevpath, (char *)cntlLink) ==
2N/A HBA_STATUS_OK) {
2N/A (void) strlcpy(port_ptr->port_attributes.OSDeviceName, cntlLink,
2N/A sizeof (port_ptr->port_attributes.OSDeviceName));
2N/A if ((charptr = strrchr(cntlLink, '/')) != NULL) {
2N/A charptr++;
2N/A }
2N/A if (charptr[0] == 'c') {
2N/A port_ptr->cntlNumber = atoi(++charptr);
2N/A } else {
2N/A port_ptr->cntlNumber = -1;
2N/A }
2N/A } else {
2N/A (void) snprintf(port_ptr->port_attributes.OSDeviceName,
2N/A sizeof (port_ptr->port_attributes.OSDeviceName),
2N/A "%s%s%s", DEVICES_DIR, portDevpath, SCSI_SUFFIX);
2N/A }
2N/A
2N/A di_devfs_path_free(portDevpath);
2N/A
2N/A port_ptr->port_attributes.PortSpecificAttribute.
2N/A SASPort->PortProtocol = protocol;
2N/A
2N/A rval = di_prop_lookup_strings(DDI_DEV_T_ANY, branchNode,
2N/A "initiator-port", &propStringData);
2N/A if (rval < 0) {
2N/A log(LOG_DEBUG, ROUTINE,
2N/A "Unable to get initiator-port from HBA port node %s.",
2N/A port_ptr->port_attributes.OSDeviceName);
2N/A di_fini(branchNode);
2N/A S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
2N/A S_FREE(port_ptr);
2N/A return (HBA_STATUS_ERROR);
2N/A } else {
2N/A for (charptr = propStringData; *charptr != '\0'; charptr++) {
2N/A if (isxdigit(*charptr)) {
2N/A break;
2N/A }
2N/A }
2N/A if (*charptr != '\0') {
2N/A tmpAddr = htonll(strtoll(charptr, NULL, 16));
2N/A (void) memcpy(port_ptr->port_attributes.
2N/A PortSpecificAttribute.SASPort->LocalSASAddress.wwn,
2N/A &tmpAddr, 8);
2N/A } else {
2N/A log(LOG_DEBUG, ROUTINE,
2N/A "No proper intiator-port prop value on HBA port %s",
2N/A port_ptr->port_attributes.OSDeviceName);
2N/A }
2N/A }
2N/A
2N/A rval = di_prop_lookup_strings(DDI_DEV_T_ANY, branchNode,
2N/A "attached-port", &propStringData);
2N/A if (rval < 0) {
2N/A log(LOG_DEBUG, ROUTINE,
2N/A "Unable to get attached-port from HBA port node %s.",
2N/A port_ptr->port_attributes.OSDeviceName);
2N/A di_fini(branchNode);
2N/A S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
2N/A S_FREE(port_ptr);
2N/A return (HBA_STATUS_ERROR);
2N/A } else {
2N/A for (charptr = propStringData; *charptr != '\0'; charptr++) {
2N/A if (isxdigit(*charptr)) {
2N/A break;
2N/A }
2N/A }
2N/A if (*charptr != '\0') {
2N/A tmpAddr = htonll(strtoll(charptr, NULL, 16));
2N/A (void) memcpy(port_ptr->port_attributes.
2N/A PortSpecificAttribute.SASPort->
2N/A AttachedSASAddress.wwn, &tmpAddr, 8);
2N/A } else {
2N/A /* continue even if the attached port is NULL. */
2N/A log(LOG_DEBUG, ROUTINE,
2N/A "No proper attached-port prop value: "
2N/A "HBA port Local SAS Address(%016llx)",
2N/A wwnConversion(port_ptr->port_attributes.
2N/A PortSpecificAttribute.
2N/A SASPort->LocalSASAddress.wwn));
2N/A }
2N/A }
2N/A
2N/A rval = di_prop_lookup_ints(DDI_DEV_T_ANY, branchNode,
2N/A "num-phys", &propIntData);
2N/A if (rval < 0) {
2N/A log(LOG_DEBUG, ROUTINE,
2N/A "Unable to get NumberofPhys from HBA port %s.",
2N/A port_ptr->port_attributes.OSDeviceName);
2N/A di_fini(branchNode);
2N/A S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
2N/A S_FREE(port_ptr);
2N/A return (HBA_STATUS_ERROR);
2N/A } else {
2N/A port_ptr->port_attributes.PortSpecificAttribute.\
2N/A SASPort->NumberofPhys = *propIntData;
2N/A }
2N/A
2N/A if (port_ptr->port_attributes.PortSpecificAttribute.\
2N/A SASPort->NumberofPhys > 0) {
2N/A if (get_phy_info(branchNode, port_ptr) != HBA_STATUS_OK) {
2N/A log(LOG_DEBUG, ROUTINE,
2N/A "Failed to get phy info on HBA port %s.",
2N/A port_ptr->port_attributes.OSDeviceName);
2N/A di_fini(branchNode);
2N/A S_FREE(port_ptr->port_attributes.
2N/A PortSpecificAttribute.SASPort);
2N/A S_FREE(port_ptr);
2N/A return (HBA_STATUS_ERROR);
2N/A }
2N/A }
2N/A
2N/A /* now done with prop checking. remove branchNode. */
2N/A di_fini(branchNode);
2N/A
2N/A /* Construct discovered target port. */
2N/A if (devtree_attached_devices(portNode, port_ptr) != HBA_STATUS_OK) {
2N/A log(LOG_DEBUG, ROUTINE,
2N/A "Failed to get attached device info HBA port %s.",
2N/A port_ptr->port_attributes.OSDeviceName);
2N/A S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
2N/A S_FREE(port_ptr);
2N/A return (HBA_STATUS_ERROR);
2N/A }
2N/A
2N/A fillDomainPortWWN(port_ptr);
2N/A
2N/A /* add new port onto hba handle list */
2N/A if (hba_ptr->first_port == NULL) {
2N/A port_ptr->index = 0;
2N/A hba_ptr->first_port = port_ptr;
2N/A } else {
2N/A port_ptr->index = hba_ptr->first_port->index + 1;
2N/A port_ptr->next = hba_ptr->first_port;
2N/A hba_ptr->first_port = port_ptr;
2N/A }
2N/A
2N/A return (HBA_STATUS_OK);
2N/A}
2N/A
2N/AHBA_STATUS
2N/Arefresh_hba(di_node_t hbaNode, struct sun_sas_hba *hba_ptr)
2N/A{
2N/A const char ROUTINE[] = "refresh_hba";
2N/A di_node_t portNode;
2N/A int protocol = 0;
2N/A int *propIntData;
2N/A
2N/A /*
2N/A * clean up existing hba port, discovered target, phy info.
2N/A * leave open handles intact.
2N/A */
2N/A free_hba_port(hba_ptr);
2N/A
2N/A if ((portNode = di_child_node(hbaNode)) == NULL) {
2N/A log(LOG_DEBUG, ROUTINE,
2N/A "HBA node doesn't have iport child.");
2N/A return (HBA_STATUS_ERROR);
2N/A }
2N/A
2N/A if ((di_prop_lookup_ints(DDI_DEV_T_ANY, hbaNode,
2N/A "supported-protocol", &propIntData)) == -1) {
2N/A log(LOG_DEBUG, ROUTINE,
2N/A "Unable to get supported-protocol from HBA node.");
2N/A } else {
2N/A protocol = *propIntData;
2N/A }
2N/A
2N/A while (portNode != DI_NODE_NIL) {
2N/A if (di_prop_lookup_ints(DDI_DEV_T_ANY, portNode,
2N/A "virtual-port", &propIntData) >= 0) {
2N/A if (*propIntData) {
2N/A /* ignore a virtual port. */
2N/A portNode = di_sibling_node(portNode);
2N/A continue;
2N/A }
2N/A }
2N/A if (add_hba_port_info(portNode, hba_ptr, protocol)
2N/A == HBA_STATUS_ERROR) {
2N/A S_FREE(hba_ptr->first_port);
2N/A S_FREE(hba_ptr);
2N/A return (HBA_STATUS_ERROR);
2N/A }
2N/A portNode = di_sibling_node(portNode);
2N/A }
2N/A
2N/A return (HBA_STATUS_OK);
2N/A}
2N/A
2N/A/*
2N/A * Discover information for one HBA in the device tree.
2N/A * The di_node_t argument should be a node with smhba-supported prop set
2N/A * to true.
2N/A * Without iport support, the devinfo node will represent one port hba.
2N/A * This routine assumes the locks have been taken.
2N/A */
2N/AHBA_STATUS
2N/Adevtree_get_one_hba(di_node_t hbaNode)
2N/A{
2N/A const char ROUTINE[] = "devtree_get_one_hba";
2N/A char *propdata = NULL;
2N/A int *propIntData = NULL;
2N/A struct sun_sas_hba *new_hba, *hba_ptr;
2N/A char *hbaDevpath, *hba_driver;
2N/A int protocol = 0;
2N/A di_node_t portNode;
2N/A int hba_instance = -1;
2N/A
2N/A hba_instance = di_instance(hbaNode);
2N/A if (hba_instance == -1) {
2N/A log(LOG_DEBUG, ROUTINE,
2N/A "portNode has instance of -1");
2N/A return (DI_WALK_CONTINUE);
2N/A }
2N/A
2N/A if ((hbaDevpath = di_devfs_path(hbaNode)) == NULL) {
2N/A log(LOG_DEBUG, ROUTINE, "Unable to get "
2N/A "device path from hbaNode");
2N/A return (HBA_STATUS_ERROR);
2N/A }
2N/A
2N/A /* check to see if this is a repeat HBA */
2N/A if (global_hba_head) {
2N/A for (hba_ptr = global_hba_head;
2N/A hba_ptr != NULL;
2N/A hba_ptr = hba_ptr->next) {
2N/A if ((strncmp(hba_ptr->device_path, hbaDevpath,
2N/A strlen(hbaDevpath))) == 0) {
2N/A if (refresh_hba(hbaNode, hba_ptr) !=
2N/A HBA_STATUS_OK) {
2N/A log(LOG_DEBUG, ROUTINE, "Refresh failed"
2N/A " on hbaNode %s", hbaDevpath);
2N/A }
2N/A di_devfs_path_free(hbaDevpath);
2N/A return (HBA_STATUS_OK);
2N/A }
2N/A }
2N/A }
2N/A
2N/A /* this is a new hba */
2N/A if ((new_hba = (struct sun_sas_hba *)calloc(1,
2N/A sizeof (struct sun_sas_hba))) == NULL) {
2N/A OUT_OF_MEMORY(ROUTINE);
2N/A di_devfs_path_free(hbaDevpath);
2N/A return (HBA_STATUS_ERROR);
2N/A }
2N/A
2N/A (void) strlcpy(new_hba->device_path, hbaDevpath,
2N/A sizeof (new_hba->device_path));
2N/A di_devfs_path_free(hbaDevpath);
2N/A
2N/A (void) snprintf(new_hba->adapter_attributes.HBASymbolicName,
2N/A sizeof (new_hba->adapter_attributes.HBASymbolicName),
2N/A "%s%s", DEVICES_DIR, new_hba->device_path);
2N/A
2N/A /* Manufacturer */
2N/A if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
2N/A "Manufacturer", (char **)&propdata)) == -1) {
2N/A (void) strlcpy(new_hba->adapter_attributes.Manufacturer,
2N/A SUN_MICROSYSTEMS,
2N/A sizeof (new_hba->adapter_attributes.Manufacturer));
2N/A } else {
2N/A (void) strlcpy(new_hba->adapter_attributes.Manufacturer,
2N/A propdata,
2N/A sizeof (new_hba->adapter_attributes.Manufacturer));
2N/A }
2N/A
2N/A /* SerialNumber */
2N/A if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
2N/A "SerialNumber", (char **)&propdata)) == -1) {
2N/A new_hba->adapter_attributes.SerialNumber[0] = '\0';
2N/A } else {
2N/A (void) strlcpy(new_hba->adapter_attributes.SerialNumber,
2N/A propdata,
2N/A sizeof (new_hba->adapter_attributes.SerialNumber));
2N/A }
2N/A
2N/A /* Model */
2N/A if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
2N/A "ModelName", (char **)&propdata)) == -1) {
2N/A new_hba->adapter_attributes.Model[0] = '\0';
2N/A } else {
2N/A (void) strlcpy(new_hba->adapter_attributes.Model,
2N/A propdata,
2N/A sizeof (new_hba->adapter_attributes.Model));
2N/A }
2N/A
2N/A /* FirmwareVersion */
2N/A if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
2N/A "firmware-version", (char **)&propdata)) == -1) {
2N/A log(LOG_DEBUG, ROUTINE,
2N/A "Property \"%s\" not found for device \"%s\"",
2N/A "firmware-version", new_hba->device_path);
2N/A } else {
2N/A (void) strlcpy(new_hba->adapter_attributes.FirmwareVersion,
2N/A propdata,
2N/A sizeof (new_hba->adapter_attributes.FirmwareVersion));
2N/A }
2N/A
2N/A /* HardwareVersion */
2N/A if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
2N/A "hardware-version", (char **)&propdata)) == -1) {
2N/A log(LOG_DEBUG, ROUTINE,
2N/A "Property \"%s\" not found for device \"%s\"",
2N/A "hardware-version", new_hba->device_path);
2N/A } else {
2N/A (void) strlcpy(new_hba->adapter_attributes.HardwareVersion,
2N/A propdata,
2N/A sizeof (new_hba->adapter_attributes.HardwareVersion));
2N/A }
2N/A
2N/A /* DriverVersion */
2N/A if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
2N/A "driver-version", (char **)&propdata)) == -1) {
2N/A log(LOG_DEBUG, ROUTINE,
2N/A "Property \"%s\" not found for device \"%s\"",
2N/A "driver-version", new_hba->device_path);
2N/A } else {
2N/A (void) strlcpy(new_hba->adapter_attributes.DriverVersion,
2N/A propdata,
2N/A sizeof (new_hba->adapter_attributes.DriverVersion));
2N/A }
2N/A
2N/A if ((di_prop_lookup_ints(DDI_DEV_T_ANY, hbaNode,
2N/A "supported-protocol", &propIntData)) == -1) {
2N/A log(LOG_DEBUG, ROUTINE,
2N/A "Unable to get supported-protocol from HBA node.");
2N/A } else {
2N/A protocol = *propIntData;
2N/A }
2N/A
2N/A /* We don't use these */
2N/A new_hba->adapter_attributes.OptionROMVersion[0] = '\0';
2N/A new_hba->adapter_attributes.RedundantOptionROMVersion[0] = '\0';
2N/A new_hba->adapter_attributes.RedundantFirmwareVersion[0] = '\0';
2N/A new_hba->adapter_attributes.VendorSpecificID = 0;
2N/A
2N/A if ((hba_driver = di_driver_name(hbaNode)) != NULL) {
2N/A (void) strlcpy(new_hba->adapter_attributes.DriverName,
2N/A hba_driver,
2N/A sizeof (new_hba->adapter_attributes.DriverName));
2N/A } else {
2N/A log(LOG_DEBUG, ROUTINE,
2N/A "HBA driver name not found for device \"%s\"",
2N/A new_hba->device_path);
2N/A }
2N/A
2N/A /*
2N/A * Name the adapter: like SUNW-pmcs-1
2N/A * Using di_instance number as the suffix for the name for persistent
2N/A * among rebooting.
2N/A */
2N/A (void) snprintf(new_hba->handle_name, HANDLE_NAME_LENGTH, "%s-%s-%d",
2N/A "SUNW", new_hba->adapter_attributes.DriverName, hba_instance);
2N/A
2N/A if ((portNode = di_child_node(hbaNode)) == NULL) {
2N/A log(LOG_DEBUG, ROUTINE,
2N/A "HBA driver doesn't have iport child. \"%s\"",
2N/A new_hba->device_path);
2N/A /* continue on with an hba without any port. */
2N/A new_hba->index = hba_count++;
2N/A
2N/A /*
2N/A * add newly created handle into global_hba_head list
2N/A */
2N/A if (global_hba_head != NULL) {
2N/A /*
2N/A * Make sure to move the open_handles list to back to
2N/A * the head if it's there (for refresh scenario)
2N/A */
2N/A if (global_hba_head->open_handles) {
2N/A new_hba->open_handles =
2N/A global_hba_head->open_handles;
2N/A global_hba_head->open_handles = NULL;
2N/A }
2N/A /* Now bump the new one to the head of the list */
2N/A new_hba->next = global_hba_head;
2N/A global_hba_head = new_hba;
2N/A } else {
2N/A global_hba_head = new_hba;
2N/A }
2N/A return (HBA_STATUS_OK);
2N/A }
2N/A
2N/A while (portNode != DI_NODE_NIL) {
2N/A if (di_prop_lookup_ints(DDI_DEV_T_ANY, portNode,
2N/A "virtual-port", &propIntData) >= 0) {
2N/A if (*propIntData) {
2N/A /* ignore a virtual port. */
2N/A portNode = di_sibling_node(portNode);
2N/A continue;
2N/A }
2N/A }
2N/A if (add_hba_port_info(portNode, new_hba, protocol)
2N/A == HBA_STATUS_ERROR) {
2N/A S_FREE(new_hba->first_port);
2N/A S_FREE(new_hba);
2N/A return (HBA_STATUS_ERROR);
2N/A }
2N/A portNode = di_sibling_node(portNode);
2N/A }
2N/A
2N/A new_hba->index = hba_count++;
2N/A
2N/A /*
2N/A * add newly created handle into global_hba_head list
2N/A */
2N/A if (global_hba_head != NULL) {
2N/A /*
2N/A * Make sure to move the open_handles list to back to the
2N/A * head if it's there (for refresh scenario)
2N/A */
2N/A if (global_hba_head->open_handles) {
2N/A new_hba->open_handles = global_hba_head->open_handles;
2N/A global_hba_head->open_handles = NULL;
2N/A }
2N/A /* Now bump the new one to the head of the list */
2N/A new_hba->next = global_hba_head;
2N/A global_hba_head = new_hba;
2N/A } else {
2N/A global_hba_head = new_hba;
2N/A }
2N/A
2N/A return (HBA_STATUS_OK);
2N/A}
2N/A
2N/A/*
2N/A * Discover information for all HBAs found on the system.
2N/A * The di_node_t argument should be the root of the device tree.
2N/A * This routine assumes the locks have been taken
2N/A */
2N/Astatic int
2N/Alookup_smhba_sas_hba(di_node_t node, void *arg)
2N/A{
2N/A const char ROUTINE[] = "lookup_smhba_sas_hba";
2N/A int *propData, rval;
2N/A walkarg_t *wa = (walkarg_t *)arg;
2N/A
2N/A /* Skip stub(instance -1) nodes */
2N/A if (IS_STUB_NODE(node)) {
2N/A log(LOG_DEBUG, ROUTINE, "Walk continue");
2N/A return (DI_WALK_CONTINUE);
2N/A }
2N/A
2N/A rval = di_prop_lookup_ints(DDI_DEV_T_ANY, node,
2N/A "sm-hba-supported", &propData);
2N/A if (rval >= 0) {
2N/A if (*propData) {
2N/A /* add the hba to the hba list */
2N/A if (devtree_get_one_hba(node) != HBA_STATUS_OK) {
2N/A *(wa->flag) = B_TRUE;
2N/A }
2N/A /* Found a node. No need to walk the child. */
2N/A log(LOG_DEBUG, ROUTINE, "Walk prunechild");
2N/A return (DI_WALK_PRUNECHILD);
2N/A }
2N/A }
2N/A
2N/A return (DI_WALK_CONTINUE);
2N/A}
2N/A
2N/A/*
2N/A * Discover information for all HBAs found on the system.
2N/A * The di_node_t argument should be the root of the device tree.
2N/A * This routine assumes the locks have been taken
2N/A */
2N/AHBA_STATUS
2N/Adevtree_get_all_hbas(di_node_t root)
2N/A{
2N/A const char ROUTINE[] = "devtree_get_all_hbas";
2N/A int rv, ret = HBA_STATUS_ERROR;
2N/A walkarg_t wa;
2N/A
2N/A wa.devpath = NULL;
2N/A if ((wa.flag = (boolean_t *)calloc(1,
2N/A sizeof (boolean_t))) == NULL) {
2N/A OUT_OF_MEMORY(ROUTINE);
2N/A return (HBA_STATUS_ERROR);
2N/A }
2N/A *wa.flag = B_FALSE;
2N/A rv = di_walk_node(root, DI_WALK_SIBFIRST, &wa, lookup_smhba_sas_hba);
2N/A
2N/A if (rv == 0) {
2N/A /*
2N/A * Now determine what status code to return, taking
2N/A * partial failure scenarios into consideration.
2N/A *
2N/A * If we have at least one working HBA, then we return an
2N/A * OK status. If we have no good HBAs, but at least one
2N/A * failed HBA, we return an ERROR status. If we have
2N/A * no HBAs and no failures, we return OK.
2N/A */
2N/A if (global_hba_head) {
2N/A /*
2N/A * We've got at least one HBA and possibly some
2N/A * failures.
2N/A */
2N/A ret = HBA_STATUS_OK;
2N/A } else if (*(wa.flag)) {
2N/A /* We have no HBAs but have failures */
2N/A ret = HBA_STATUS_ERROR;
2N/A } else {
2N/A /* We have no HBAs and no failures */
2N/A ret = HBA_STATUS_OK;
2N/A }
2N/A }
2N/A
2N/A
2N/A S_FREE(wa.flag);
2N/A
2N/A if (ret == HBA_STATUS_OK)
2N/A (void) registerSysevent();
2N/A
2N/A return (ret);
2N/A}