19e86db79SHyon Kim /*
29e86db79SHyon Kim * CDDL HEADER START
39e86db79SHyon Kim *
49e86db79SHyon Kim * The contents of this file are subject to the terms of the
59e86db79SHyon Kim * Common Development and Distribution License (the "License").
69e86db79SHyon Kim * You may not use this file except in compliance with the License.
79e86db79SHyon Kim *
89e86db79SHyon Kim * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99e86db79SHyon Kim * or http://www.opensolaris.org/os/licensing.
109e86db79SHyon Kim * See the License for the specific language governing permissions
119e86db79SHyon Kim * and limitations under the License.
129e86db79SHyon Kim *
139e86db79SHyon Kim * When distributing Covered Code, include this CDDL HEADER in each
149e86db79SHyon Kim * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159e86db79SHyon Kim * If applicable, add the following below this CDDL HEADER, with the
169e86db79SHyon Kim * fields enclosed by brackets "[]" replaced with your own identifying
179e86db79SHyon Kim * information: Portions Copyright [yyyy] [name of copyright owner]
189e86db79SHyon Kim *
199e86db79SHyon Kim * CDDL HEADER END
209e86db79SHyon Kim */
219e86db79SHyon Kim
229e86db79SHyon Kim /*
23f2e8686eSxun ni - Sun Microsystems - Beijing China * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
249e86db79SHyon Kim */
2500f453f4SRob Johnston /*
2600f453f4SRob Johnston * Copyright 2019 Joyent, Inc.
2700f453f4SRob Johnston */
289e86db79SHyon Kim
299e86db79SHyon Kim #include <sun_sas.h>
309e86db79SHyon Kim #include <sys/modctl.h>
319e86db79SHyon Kim #include <sys/types.h>
329e86db79SHyon Kim #include <netinet/in.h>
339e86db79SHyon Kim #include <inttypes.h>
349e86db79SHyon Kim #include <ctype.h>
359e86db79SHyon Kim
36*c1ba8596SToomas Soome struct sun_sas_hba *global_hba_head;
37*c1ba8596SToomas Soome
389e86db79SHyon Kim /* free hba port info for the given hba */
399e86db79SHyon Kim static void
free_hba_port(struct sun_sas_hba * hba_ptr)409e86db79SHyon Kim free_hba_port(struct sun_sas_hba *hba_ptr)
419e86db79SHyon Kim {
429e86db79SHyon Kim struct sun_sas_port *hba_port = NULL;
439e86db79SHyon Kim struct sun_sas_port *last_hba_port = NULL;
449e86db79SHyon Kim struct sun_sas_port *tgt_port = NULL;
459e86db79SHyon Kim struct sun_sas_port *last_tgt_port = NULL;
469e86db79SHyon Kim struct ScsiEntryList *scsi_info = NULL;
479e86db79SHyon Kim struct ScsiEntryList *last_scsi_info = NULL;
489e86db79SHyon Kim struct phy_info *phy_ptr = NULL;
499e86db79SHyon Kim struct phy_info *last_phy = NULL;
509e86db79SHyon Kim
519e86db79SHyon Kim /* Free the nested structures (port and attached port) */
529e86db79SHyon Kim hba_port = hba_ptr->first_port;
539e86db79SHyon Kim while (hba_port != NULL) {
549e86db79SHyon Kim /* Free discovered port structure list. */
559e86db79SHyon Kim tgt_port = hba_port->first_attached_port;
569e86db79SHyon Kim while (tgt_port != NULL) {
579e86db79SHyon Kim /* Free target mapping data list first. */
589e86db79SHyon Kim scsi_info = tgt_port->scsiInfo;
599e86db79SHyon Kim while (scsi_info != NULL) {
609e86db79SHyon Kim last_scsi_info = scsi_info;
619e86db79SHyon Kim scsi_info = scsi_info->next;
629e86db79SHyon Kim free(last_scsi_info);
639e86db79SHyon Kim }
649e86db79SHyon Kim last_tgt_port = tgt_port;
659e86db79SHyon Kim tgt_port = tgt_port->next;
669e86db79SHyon Kim free(last_tgt_port->port_attributes.\
679e86db79SHyon Kim PortSpecificAttribute.SASPort);
689e86db79SHyon Kim free(last_tgt_port);
699e86db79SHyon Kim }
709e86db79SHyon Kim hba_port->first_attached_port = NULL;
719e86db79SHyon Kim
729e86db79SHyon Kim phy_ptr = hba_port->first_phy;
739e86db79SHyon Kim while (phy_ptr != NULL) {
749e86db79SHyon Kim last_phy = phy_ptr;
759e86db79SHyon Kim phy_ptr = phy_ptr->next;
769e86db79SHyon Kim free(last_phy);
779e86db79SHyon Kim }
789e86db79SHyon Kim hba_port->first_phy = NULL;
799e86db79SHyon Kim
809e86db79SHyon Kim last_hba_port = hba_port;
819e86db79SHyon Kim hba_port = hba_port->next;
829e86db79SHyon Kim free(last_hba_port->port_attributes.\
839e86db79SHyon Kim PortSpecificAttribute.SASPort);
849e86db79SHyon Kim free(last_hba_port);
859e86db79SHyon Kim }
869e86db79SHyon Kim
879e86db79SHyon Kim hba_ptr->first_port = NULL;
889e86db79SHyon Kim }
899e86db79SHyon Kim
909e86db79SHyon Kim /*
919e86db79SHyon Kim * Internal routine for adding an HBA port
929e86db79SHyon Kim */
939e86db79SHyon Kim static HBA_STATUS
add_hba_port_info(di_node_t portNode,struct sun_sas_hba * hba_ptr,int protocol)949e86db79SHyon Kim add_hba_port_info(di_node_t portNode, struct sun_sas_hba *hba_ptr, int protocol)
959e86db79SHyon Kim {
969e86db79SHyon Kim const char ROUTINE[] = "add_hba_port_info";
979e86db79SHyon Kim struct sun_sas_port *port_ptr;
989e86db79SHyon Kim char *portDevpath;
999e86db79SHyon Kim int *propIntData;
1009e86db79SHyon Kim char *propStringData;
1019e86db79SHyon Kim uint64_t tmpAddr;
1029e86db79SHyon Kim char *charptr, cntlLink[MAXPATHLEN] = {'\0'};
1039e86db79SHyon Kim int rval;
104f94d63efSHyon Kim di_node_t branchNode;
1059e86db79SHyon Kim uint_t state = HBA_PORTSTATE_UNKNOWN;
1069e86db79SHyon Kim
1079e86db79SHyon Kim if (hba_ptr == NULL) {
1089e86db79SHyon Kim log(LOG_DEBUG, ROUTINE,
1099e86db79SHyon Kim "Sun_sas handle ptr set to NULL.");
1109e86db79SHyon Kim return (HBA_STATUS_ERROR_ARG);
1119e86db79SHyon Kim }
1129e86db79SHyon Kim
1139e86db79SHyon Kim if ((port_ptr = (struct sun_sas_port *)calloc(1,
1149e86db79SHyon Kim sizeof (struct sun_sas_port))) == NULL) {
1159e86db79SHyon Kim OUT_OF_MEMORY(ROUTINE);
1169e86db79SHyon Kim return (HBA_STATUS_ERROR);
1179e86db79SHyon Kim }
1189e86db79SHyon Kim
1199e86db79SHyon Kim if ((port_ptr->port_attributes.PortSpecificAttribute.SASPort =
1209e86db79SHyon Kim (struct SMHBA_SAS_Port *)calloc(1, sizeof (struct SMHBA_SAS_Port)))
1219e86db79SHyon Kim == NULL) {
1229e86db79SHyon Kim OUT_OF_MEMORY(ROUTINE);
1239e86db79SHyon Kim return (HBA_STATUS_ERROR);
1249e86db79SHyon Kim }
1259e86db79SHyon Kim
1269e86db79SHyon Kim if ((portDevpath = di_devfs_path(portNode)) == NULL) {
1279e86db79SHyon Kim log(LOG_DEBUG, ROUTINE,
1289e86db79SHyon Kim "Unable to get device path from HBA Port Node.");
1299e86db79SHyon Kim S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
1309e86db79SHyon Kim S_FREE(port_ptr);
1319e86db79SHyon Kim return (HBA_STATUS_ERROR);
1329e86db79SHyon Kim }
1339e86db79SHyon Kim
134f94d63efSHyon Kim /*
135f94d63efSHyon Kim * Let's take a branch snap shot for pulling attributes.
136f94d63efSHyon Kim * The attribute change doesn't invalidate devinfo cache snapshot.
137f94d63efSHyon Kim * Phy info prop and num-phys can be obsolate when the same hba
138f94d63efSHyon Kim * connected to the same expander(SIM) thus phy numbers are increased.
139f94d63efSHyon Kim * Also the phy number may get decreased when a connection is removed
140f94d63efSHyon Kim * while the iport still exist through another connection.
141f94d63efSHyon Kim */
142f94d63efSHyon Kim branchNode = di_init(portDevpath, DINFOPROP);
143f94d63efSHyon Kim if (branchNode == DI_NODE_NIL) {
144f94d63efSHyon Kim /* something is wrong here. */
145f94d63efSHyon Kim di_fini(branchNode);
146f94d63efSHyon Kim log(LOG_DEBUG, ROUTINE,
147f94d63efSHyon Kim "Unable to take devinfoi branch snapshot on HBA port \"%s\""
148f94d63efSHyon Kim " due to %s", portDevpath, strerror(errno));
149f94d63efSHyon Kim S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
150f94d63efSHyon Kim S_FREE(port_ptr);
151f94d63efSHyon Kim return (HBA_STATUS_ERROR);
152f94d63efSHyon Kim }
153f94d63efSHyon Kim
1549e86db79SHyon Kim state = di_state(portNode);
1559e86db79SHyon Kim if (((state & DI_DRIVER_DETACHED) == DI_DRIVER_DETACHED) ||
1569e86db79SHyon Kim ((state & DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE)) {
1579e86db79SHyon Kim log(LOG_DEBUG, ROUTINE,
1589e86db79SHyon Kim "HBA port node %s is either OFFLINE or DETACHED",
1599e86db79SHyon Kim portDevpath);
1609e86db79SHyon Kim port_ptr->port_attributes.PortState = HBA_PORTSTATE_OFFLINE;
1619e86db79SHyon Kim } else {
1629e86db79SHyon Kim port_ptr->port_attributes.PortState = HBA_PORTSTATE_ONLINE;
1639e86db79SHyon Kim }
1649e86db79SHyon Kim
1659e86db79SHyon Kim port_ptr->port_attributes.PortType = HBA_PORTTYPE_SASDEVICE;
1669e86db79SHyon Kim
1679e86db79SHyon Kim (void) strlcpy(port_ptr->device_path, portDevpath, MAXPATHLEN + 1);
1689e86db79SHyon Kim
1699e86db79SHyon Kim if (lookupControllerLink(portDevpath, (char *)cntlLink) ==
1709e86db79SHyon Kim HBA_STATUS_OK) {
1719e86db79SHyon Kim (void) strlcpy(port_ptr->port_attributes.OSDeviceName, cntlLink,
1729e86db79SHyon Kim sizeof (port_ptr->port_attributes.OSDeviceName));
1739e86db79SHyon Kim if ((charptr = strrchr(cntlLink, '/')) != NULL) {
1749e86db79SHyon Kim charptr++;
1759e86db79SHyon Kim }
1769e86db79SHyon Kim if (charptr[0] == 'c') {
1779e86db79SHyon Kim port_ptr->cntlNumber = atoi(++charptr);
1789e86db79SHyon Kim } else {
1799e86db79SHyon Kim port_ptr->cntlNumber = -1;
1809e86db79SHyon Kim }
1819e86db79SHyon Kim } else {
1829e86db79SHyon Kim (void) snprintf(port_ptr->port_attributes.OSDeviceName,
1839e86db79SHyon Kim sizeof (port_ptr->port_attributes.OSDeviceName),
1849e86db79SHyon Kim "%s%s%s", DEVICES_DIR, portDevpath, SCSI_SUFFIX);
1859e86db79SHyon Kim }
1869e86db79SHyon Kim
1879e86db79SHyon Kim di_devfs_path_free(portDevpath);
1889e86db79SHyon Kim
1899e86db79SHyon Kim port_ptr->port_attributes.PortSpecificAttribute.
1909e86db79SHyon Kim SASPort->PortProtocol = protocol;
1919e86db79SHyon Kim
192f94d63efSHyon Kim rval = di_prop_lookup_strings(DDI_DEV_T_ANY, branchNode,
1939e86db79SHyon Kim "initiator-port", &propStringData);
1949e86db79SHyon Kim if (rval < 0) {
1959e86db79SHyon Kim log(LOG_DEBUG, ROUTINE,
1969e86db79SHyon Kim "Unable to get initiator-port from HBA port node %s.",
1979e86db79SHyon Kim port_ptr->port_attributes.OSDeviceName);
198f94d63efSHyon Kim di_fini(branchNode);
1999e86db79SHyon Kim S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
2009e86db79SHyon Kim S_FREE(port_ptr);
2019e86db79SHyon Kim return (HBA_STATUS_ERROR);
2029e86db79SHyon Kim } else {
2039e86db79SHyon Kim for (charptr = propStringData; *charptr != '\0'; charptr++) {
2049e86db79SHyon Kim if (isxdigit(*charptr)) {
2059e86db79SHyon Kim break;
2069e86db79SHyon Kim }
2079e86db79SHyon Kim }
2089e86db79SHyon Kim if (*charptr != '\0') {
2099e86db79SHyon Kim tmpAddr = htonll(strtoll(charptr, NULL, 16));
2109e86db79SHyon Kim (void) memcpy(port_ptr->port_attributes.
2119e86db79SHyon Kim PortSpecificAttribute.SASPort->LocalSASAddress.wwn,
2129e86db79SHyon Kim &tmpAddr, 8);
2139e86db79SHyon Kim } else {
2149e86db79SHyon Kim log(LOG_DEBUG, ROUTINE,
2159e86db79SHyon Kim "No proper intiator-port prop value on HBA port %s",
2169e86db79SHyon Kim port_ptr->port_attributes.OSDeviceName);
2179e86db79SHyon Kim }
2189e86db79SHyon Kim }
2199e86db79SHyon Kim
220f94d63efSHyon Kim rval = di_prop_lookup_strings(DDI_DEV_T_ANY, branchNode,
2219e86db79SHyon Kim "attached-port", &propStringData);
2229e86db79SHyon Kim if (rval < 0) {
2239e86db79SHyon Kim log(LOG_DEBUG, ROUTINE,
2249e86db79SHyon Kim "Unable to get attached-port from HBA port node %s.",
2259e86db79SHyon Kim port_ptr->port_attributes.OSDeviceName);
226f94d63efSHyon Kim di_fini(branchNode);
2279e86db79SHyon Kim S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
2289e86db79SHyon Kim S_FREE(port_ptr);
2299e86db79SHyon Kim return (HBA_STATUS_ERROR);
2309e86db79SHyon Kim } else {
2319e86db79SHyon Kim for (charptr = propStringData; *charptr != '\0'; charptr++) {
2329e86db79SHyon Kim if (isxdigit(*charptr)) {
2339e86db79SHyon Kim break;
2349e86db79SHyon Kim }
2359e86db79SHyon Kim }
2369e86db79SHyon Kim if (*charptr != '\0') {
2379e86db79SHyon Kim tmpAddr = htonll(strtoll(charptr, NULL, 16));
2389e86db79SHyon Kim (void) memcpy(port_ptr->port_attributes.
2399e86db79SHyon Kim PortSpecificAttribute.SASPort->
2409e86db79SHyon Kim AttachedSASAddress.wwn, &tmpAddr, 8);
2419e86db79SHyon Kim } else {
2429e86db79SHyon Kim /* continue even if the attached port is NULL. */
2439e86db79SHyon Kim log(LOG_DEBUG, ROUTINE,
2449e86db79SHyon Kim "No proper attached-port prop value: "
2459e86db79SHyon Kim "HBA port Local SAS Address(%016llx)",
2469e86db79SHyon Kim wwnConversion(port_ptr->port_attributes.
2479e86db79SHyon Kim PortSpecificAttribute.
2489e86db79SHyon Kim SASPort->LocalSASAddress.wwn));
2499e86db79SHyon Kim }
2509e86db79SHyon Kim }
2519e86db79SHyon Kim
252f94d63efSHyon Kim rval = di_prop_lookup_ints(DDI_DEV_T_ANY, branchNode,
2539e86db79SHyon Kim "num-phys", &propIntData);
2549e86db79SHyon Kim if (rval < 0) {
2559e86db79SHyon Kim log(LOG_DEBUG, ROUTINE,
2569e86db79SHyon Kim "Unable to get NumberofPhys from HBA port %s.",
2579e86db79SHyon Kim port_ptr->port_attributes.OSDeviceName);
258f94d63efSHyon Kim di_fini(branchNode);
2599e86db79SHyon Kim S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
2609e86db79SHyon Kim S_FREE(port_ptr);
2619e86db79SHyon Kim return (HBA_STATUS_ERROR);
2629e86db79SHyon Kim } else {
2639e86db79SHyon Kim port_ptr->port_attributes.PortSpecificAttribute.\
2649e86db79SHyon Kim SASPort->NumberofPhys = *propIntData;
2659e86db79SHyon Kim }
2669e86db79SHyon Kim
2679e86db79SHyon Kim if (port_ptr->port_attributes.PortSpecificAttribute.\
2689e86db79SHyon Kim SASPort->NumberofPhys > 0) {
269f94d63efSHyon Kim if (get_phy_info(branchNode, port_ptr) != HBA_STATUS_OK) {
2709e86db79SHyon Kim log(LOG_DEBUG, ROUTINE,
2719e86db79SHyon Kim "Failed to get phy info on HBA port %s.",
2729e86db79SHyon Kim port_ptr->port_attributes.OSDeviceName);
273f94d63efSHyon Kim di_fini(branchNode);
2749e86db79SHyon Kim S_FREE(port_ptr->port_attributes.
2759e86db79SHyon Kim PortSpecificAttribute.SASPort);
2769e86db79SHyon Kim S_FREE(port_ptr);
277f94d63efSHyon Kim return (HBA_STATUS_ERROR);
2789e86db79SHyon Kim }
2799e86db79SHyon Kim }
2809e86db79SHyon Kim
281f94d63efSHyon Kim /* now done with prop checking. remove branchNode. */
282f94d63efSHyon Kim di_fini(branchNode);
283f94d63efSHyon Kim
284f94d63efSHyon Kim /* Construct discovered target port. */
2859e86db79SHyon Kim if (devtree_attached_devices(portNode, port_ptr) != HBA_STATUS_OK) {
2869e86db79SHyon Kim log(LOG_DEBUG, ROUTINE,
2879e86db79SHyon Kim "Failed to get attached device info HBA port %s.",
2889e86db79SHyon Kim port_ptr->port_attributes.OSDeviceName);
2899e86db79SHyon Kim S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
2909e86db79SHyon Kim S_FREE(port_ptr);
291f94d63efSHyon Kim return (HBA_STATUS_ERROR);
2929e86db79SHyon Kim }
2939e86db79SHyon Kim
2949e86db79SHyon Kim fillDomainPortWWN(port_ptr);
2959e86db79SHyon Kim
2969e86db79SHyon Kim /* add new port onto hba handle list */
2979e86db79SHyon Kim if (hba_ptr->first_port == NULL) {
2989e86db79SHyon Kim port_ptr->index = 0;
2999e86db79SHyon Kim hba_ptr->first_port = port_ptr;
3009e86db79SHyon Kim } else {
3019e86db79SHyon Kim port_ptr->index = hba_ptr->first_port->index + 1;
3029e86db79SHyon Kim port_ptr->next = hba_ptr->first_port;
3039e86db79SHyon Kim hba_ptr->first_port = port_ptr;
3049e86db79SHyon Kim }
3059e86db79SHyon Kim
3069e86db79SHyon Kim return (HBA_STATUS_OK);
3079e86db79SHyon Kim }
3089e86db79SHyon Kim
3099e86db79SHyon Kim HBA_STATUS
refresh_hba(di_node_t hbaNode,struct sun_sas_hba * hba_ptr)3109e86db79SHyon Kim refresh_hba(di_node_t hbaNode, struct sun_sas_hba *hba_ptr)
3119e86db79SHyon Kim {
3129e86db79SHyon Kim const char ROUTINE[] = "refresh_hba";
3139e86db79SHyon Kim di_node_t portNode;
3149e86db79SHyon Kim int protocol = 0;
3159e86db79SHyon Kim int *propIntData;
3169e86db79SHyon Kim
3179e86db79SHyon Kim /*
3189e86db79SHyon Kim * clean up existing hba port, discovered target, phy info.
3199e86db79SHyon Kim * leave open handles intact.
3209e86db79SHyon Kim */
3219e86db79SHyon Kim free_hba_port(hba_ptr);
3229e86db79SHyon Kim
3239e86db79SHyon Kim if ((portNode = di_child_node(hbaNode)) == NULL) {
3249e86db79SHyon Kim log(LOG_DEBUG, ROUTINE,
3259e86db79SHyon Kim "HBA node doesn't have iport child.");
3269e86db79SHyon Kim return (HBA_STATUS_ERROR);
3279e86db79SHyon Kim }
3289e86db79SHyon Kim
3299e86db79SHyon Kim if ((di_prop_lookup_ints(DDI_DEV_T_ANY, hbaNode,
3309e86db79SHyon Kim "supported-protocol", &propIntData)) == -1) {
3319e86db79SHyon Kim log(LOG_DEBUG, ROUTINE,
3329e86db79SHyon Kim "Unable to get supported-protocol from HBA node.");
3339e86db79SHyon Kim } else {
3349e86db79SHyon Kim protocol = *propIntData;
3359e86db79SHyon Kim }
3369e86db79SHyon Kim
3379e86db79SHyon Kim while (portNode != DI_NODE_NIL) {
338f2e8686eSxun ni - Sun Microsystems - Beijing China if (di_prop_lookup_ints(DDI_DEV_T_ANY, portNode,
339f2e8686eSxun ni - Sun Microsystems - Beijing China "virtual-port", &propIntData) >= 0) {
340f2e8686eSxun ni - Sun Microsystems - Beijing China if (*propIntData) {
341f2e8686eSxun ni - Sun Microsystems - Beijing China /* ignore a virtual port. */
342f2e8686eSxun ni - Sun Microsystems - Beijing China portNode = di_sibling_node(portNode);
343f2e8686eSxun ni - Sun Microsystems - Beijing China continue;
344f2e8686eSxun ni - Sun Microsystems - Beijing China }
345f2e8686eSxun ni - Sun Microsystems - Beijing China }
3469e86db79SHyon Kim if (add_hba_port_info(portNode, hba_ptr, protocol)
3479e86db79SHyon Kim == HBA_STATUS_ERROR) {
3489e86db79SHyon Kim S_FREE(hba_ptr->first_port);
3499e86db79SHyon Kim S_FREE(hba_ptr);
3509e86db79SHyon Kim return (HBA_STATUS_ERROR);
3519e86db79SHyon Kim }
3529e86db79SHyon Kim portNode = di_sibling_node(portNode);
3539e86db79SHyon Kim }
3549e86db79SHyon Kim
3559e86db79SHyon Kim return (HBA_STATUS_OK);
3569e86db79SHyon Kim }
3579e86db79SHyon Kim
3589e86db79SHyon Kim /*
3599e86db79SHyon Kim * Discover information for one HBA in the device tree.
3609e86db79SHyon Kim * The di_node_t argument should be a node with smhba-supported prop set
3619e86db79SHyon Kim * to true.
3629e86db79SHyon Kim * Without iport support, the devinfo node will represent one port hba.
3639e86db79SHyon Kim * This routine assumes the locks have been taken.
3649e86db79SHyon Kim */
3659e86db79SHyon Kim HBA_STATUS
devtree_get_one_hba(di_node_t hbaNode)3669e86db79SHyon Kim devtree_get_one_hba(di_node_t hbaNode)
3679e86db79SHyon Kim {
3689e86db79SHyon Kim const char ROUTINE[] = "devtree_get_one_hba";
3699e86db79SHyon Kim char *propdata = NULL;
3709e86db79SHyon Kim int *propIntData = NULL;
3719e86db79SHyon Kim struct sun_sas_hba *new_hba, *hba_ptr;
3729e86db79SHyon Kim char *hbaDevpath, *hba_driver;
3739e86db79SHyon Kim int protocol = 0;
3749e86db79SHyon Kim di_node_t portNode;
3759e86db79SHyon Kim int hba_instance = -1;
3769e86db79SHyon Kim
3779e86db79SHyon Kim hba_instance = di_instance(hbaNode);
3789e86db79SHyon Kim if (hba_instance == -1) {
3799e86db79SHyon Kim log(LOG_DEBUG, ROUTINE,
3809e86db79SHyon Kim "portNode has instance of -1");
3819e86db79SHyon Kim return (DI_WALK_CONTINUE);
3829e86db79SHyon Kim }
3839e86db79SHyon Kim
3849e86db79SHyon Kim if ((hbaDevpath = di_devfs_path(hbaNode)) == NULL) {
3859e86db79SHyon Kim log(LOG_DEBUG, ROUTINE, "Unable to get "
3869e86db79SHyon Kim "device path from hbaNode");
3879e86db79SHyon Kim return (HBA_STATUS_ERROR);
3889e86db79SHyon Kim }
3899e86db79SHyon Kim
3909e86db79SHyon Kim /* check to see if this is a repeat HBA */
3919e86db79SHyon Kim if (global_hba_head) {
3929e86db79SHyon Kim for (hba_ptr = global_hba_head;
3939e86db79SHyon Kim hba_ptr != NULL;
3949e86db79SHyon Kim hba_ptr = hba_ptr->next) {
3959e86db79SHyon Kim if ((strncmp(hba_ptr->device_path, hbaDevpath,
3969e86db79SHyon Kim strlen(hbaDevpath))) == 0) {
3979e86db79SHyon Kim if (refresh_hba(hbaNode, hba_ptr) !=
3989e86db79SHyon Kim HBA_STATUS_OK) {
3999e86db79SHyon Kim log(LOG_DEBUG, ROUTINE, "Refresh failed"
4009e86db79SHyon Kim " on hbaNode %s", hbaDevpath);
4019e86db79SHyon Kim }
4029e86db79SHyon Kim di_devfs_path_free(hbaDevpath);
4039e86db79SHyon Kim return (HBA_STATUS_OK);
4049e86db79SHyon Kim }
4059e86db79SHyon Kim }
4069e86db79SHyon Kim }
4079e86db79SHyon Kim
4089e86db79SHyon Kim /* this is a new hba */
4099e86db79SHyon Kim if ((new_hba = (struct sun_sas_hba *)calloc(1,
4109e86db79SHyon Kim sizeof (struct sun_sas_hba))) == NULL) {
4119e86db79SHyon Kim OUT_OF_MEMORY(ROUTINE);
4129e86db79SHyon Kim di_devfs_path_free(hbaDevpath);
4139e86db79SHyon Kim return (HBA_STATUS_ERROR);
4149e86db79SHyon Kim }
4159e86db79SHyon Kim
4169e86db79SHyon Kim (void) strlcpy(new_hba->device_path, hbaDevpath,
4179e86db79SHyon Kim sizeof (new_hba->device_path));
4189e86db79SHyon Kim di_devfs_path_free(hbaDevpath);
4199e86db79SHyon Kim
4209e86db79SHyon Kim (void) snprintf(new_hba->adapter_attributes.HBASymbolicName,
4219e86db79SHyon Kim sizeof (new_hba->adapter_attributes.HBASymbolicName),
4229e86db79SHyon Kim "%s%s", DEVICES_DIR, new_hba->device_path);
4239e86db79SHyon Kim
4249e86db79SHyon Kim /* Manufacturer */
4259e86db79SHyon Kim if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
4269e86db79SHyon Kim "Manufacturer", (char **)&propdata)) == -1) {
4279e86db79SHyon Kim (void) strlcpy(new_hba->adapter_attributes.Manufacturer,
4289e86db79SHyon Kim SUN_MICROSYSTEMS,
4299e86db79SHyon Kim sizeof (new_hba->adapter_attributes.Manufacturer));
4309e86db79SHyon Kim } else {
4319e86db79SHyon Kim (void) strlcpy(new_hba->adapter_attributes.Manufacturer,
4329e86db79SHyon Kim propdata,
4339e86db79SHyon Kim sizeof (new_hba->adapter_attributes.Manufacturer));
4349e86db79SHyon Kim }
4359e86db79SHyon Kim
4369e86db79SHyon Kim /* SerialNumber */
4379e86db79SHyon Kim if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
4389e86db79SHyon Kim "SerialNumber", (char **)&propdata)) == -1) {
4399e86db79SHyon Kim new_hba->adapter_attributes.SerialNumber[0] = '\0';
4409e86db79SHyon Kim } else {
4419e86db79SHyon Kim (void) strlcpy(new_hba->adapter_attributes.SerialNumber,
4429e86db79SHyon Kim propdata,
4439e86db79SHyon Kim sizeof (new_hba->adapter_attributes.SerialNumber));
4449e86db79SHyon Kim }
4459e86db79SHyon Kim
4469e86db79SHyon Kim /* Model */
4479e86db79SHyon Kim if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
4489e86db79SHyon Kim "ModelName", (char **)&propdata)) == -1) {
4499e86db79SHyon Kim new_hba->adapter_attributes.Model[0] = '\0';
4509e86db79SHyon Kim } else {
4519e86db79SHyon Kim (void) strlcpy(new_hba->adapter_attributes.Model,
4529e86db79SHyon Kim propdata,
4539e86db79SHyon Kim sizeof (new_hba->adapter_attributes.Model));
4549e86db79SHyon Kim }
4559e86db79SHyon Kim
4569e86db79SHyon Kim /* FirmwareVersion */
4579e86db79SHyon Kim if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
4589e86db79SHyon Kim "firmware-version", (char **)&propdata)) == -1) {
4599e86db79SHyon Kim log(LOG_DEBUG, ROUTINE,
4609e86db79SHyon Kim "Property \"%s\" not found for device \"%s\"",
4619e86db79SHyon Kim "firmware-version", new_hba->device_path);
4629e86db79SHyon Kim } else {
4639e86db79SHyon Kim (void) strlcpy(new_hba->adapter_attributes.FirmwareVersion,
4649e86db79SHyon Kim propdata,
4659e86db79SHyon Kim sizeof (new_hba->adapter_attributes.FirmwareVersion));
4669e86db79SHyon Kim }
4679e86db79SHyon Kim
4689e86db79SHyon Kim /* HardwareVersion */
4699e86db79SHyon Kim if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
4709e86db79SHyon Kim "hardware-version", (char **)&propdata)) == -1) {
4719e86db79SHyon Kim log(LOG_DEBUG, ROUTINE,
4729e86db79SHyon Kim "Property \"%s\" not found for device \"%s\"",
4739e86db79SHyon Kim "hardware-version", new_hba->device_path);
4749e86db79SHyon Kim } else {
4759e86db79SHyon Kim (void) strlcpy(new_hba->adapter_attributes.HardwareVersion,
4769e86db79SHyon Kim propdata,
4779e86db79SHyon Kim sizeof (new_hba->adapter_attributes.HardwareVersion));
4789e86db79SHyon Kim }
4799e86db79SHyon Kim
4809e86db79SHyon Kim /* DriverVersion */
4819e86db79SHyon Kim if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
4829e86db79SHyon Kim "driver-version", (char **)&propdata)) == -1) {
4839e86db79SHyon Kim log(LOG_DEBUG, ROUTINE,
4849e86db79SHyon Kim "Property \"%s\" not found for device \"%s\"",
4859e86db79SHyon Kim "driver-version", new_hba->device_path);
4869e86db79SHyon Kim } else {
4879e86db79SHyon Kim (void) strlcpy(new_hba->adapter_attributes.DriverVersion,
4889e86db79SHyon Kim propdata,
4899e86db79SHyon Kim sizeof (new_hba->adapter_attributes.DriverVersion));
4909e86db79SHyon Kim }
4919e86db79SHyon Kim
4929e86db79SHyon Kim if ((di_prop_lookup_ints(DDI_DEV_T_ANY, hbaNode,
4939e86db79SHyon Kim "supported-protocol", &propIntData)) == -1) {
4949e86db79SHyon Kim log(LOG_DEBUG, ROUTINE,
4959e86db79SHyon Kim "Unable to get supported-protocol from HBA node.");
4969e86db79SHyon Kim } else {
4979e86db79SHyon Kim protocol = *propIntData;
4989e86db79SHyon Kim }
4999e86db79SHyon Kim
5009e86db79SHyon Kim /* We don't use these */
5019e86db79SHyon Kim new_hba->adapter_attributes.OptionROMVersion[0] = '\0';
5029e86db79SHyon Kim new_hba->adapter_attributes.RedundantOptionROMVersion[0] = '\0';
5039e86db79SHyon Kim new_hba->adapter_attributes.RedundantFirmwareVersion[0] = '\0';
5049e86db79SHyon Kim new_hba->adapter_attributes.VendorSpecificID = 0;
5059e86db79SHyon Kim
5069e86db79SHyon Kim if ((hba_driver = di_driver_name(hbaNode)) != NULL) {
5079e86db79SHyon Kim (void) strlcpy(new_hba->adapter_attributes.DriverName,
5089e86db79SHyon Kim hba_driver,
5099e86db79SHyon Kim sizeof (new_hba->adapter_attributes.DriverName));
5109e86db79SHyon Kim } else {
5119e86db79SHyon Kim log(LOG_DEBUG, ROUTINE,
5129e86db79SHyon Kim "HBA driver name not found for device \"%s\"",
5139e86db79SHyon Kim new_hba->device_path);
5149e86db79SHyon Kim }
5159e86db79SHyon Kim
5169e86db79SHyon Kim /*
5179e86db79SHyon Kim * Name the adapter: like SUNW-pmcs-1
5189e86db79SHyon Kim * Using di_instance number as the suffix for the name for persistent
5199e86db79SHyon Kim * among rebooting.
5209e86db79SHyon Kim */
5219e86db79SHyon Kim (void) snprintf(new_hba->handle_name, HANDLE_NAME_LENGTH, "%s-%s-%d",
5229e86db79SHyon Kim "SUNW", new_hba->adapter_attributes.DriverName, hba_instance);
5239e86db79SHyon Kim
5249e86db79SHyon Kim if ((portNode = di_child_node(hbaNode)) == NULL) {
5259e86db79SHyon Kim log(LOG_DEBUG, ROUTINE,
5269e86db79SHyon Kim "HBA driver doesn't have iport child. \"%s\"",
5279e86db79SHyon Kim new_hba->device_path);
5289e86db79SHyon Kim /* continue on with an hba without any port. */
5299e86db79SHyon Kim new_hba->index = hba_count++;
5309e86db79SHyon Kim
5319e86db79SHyon Kim /*
5329e86db79SHyon Kim * add newly created handle into global_hba_head list
5339e86db79SHyon Kim */
5349e86db79SHyon Kim if (global_hba_head != NULL) {
5359e86db79SHyon Kim /*
5369e86db79SHyon Kim * Make sure to move the open_handles list to back to
5379e86db79SHyon Kim * the head if it's there (for refresh scenario)
5389e86db79SHyon Kim */
5399e86db79SHyon Kim if (global_hba_head->open_handles) {
5409e86db79SHyon Kim new_hba->open_handles =
5419e86db79SHyon Kim global_hba_head->open_handles;
5429e86db79SHyon Kim global_hba_head->open_handles = NULL;
5439e86db79SHyon Kim }
5449e86db79SHyon Kim /* Now bump the new one to the head of the list */
5459e86db79SHyon Kim new_hba->next = global_hba_head;
5469e86db79SHyon Kim global_hba_head = new_hba;
5479e86db79SHyon Kim } else {
5489e86db79SHyon Kim global_hba_head = new_hba;
5499e86db79SHyon Kim }
5509e86db79SHyon Kim return (HBA_STATUS_OK);
5519e86db79SHyon Kim }
5529e86db79SHyon Kim
5539e86db79SHyon Kim while (portNode != DI_NODE_NIL) {
554f2e8686eSxun ni - Sun Microsystems - Beijing China if (di_prop_lookup_ints(DDI_DEV_T_ANY, portNode,
555f2e8686eSxun ni - Sun Microsystems - Beijing China "virtual-port", &propIntData) >= 0) {
556f2e8686eSxun ni - Sun Microsystems - Beijing China if (*propIntData) {
557f2e8686eSxun ni - Sun Microsystems - Beijing China /* ignore a virtual port. */
558f2e8686eSxun ni - Sun Microsystems - Beijing China portNode = di_sibling_node(portNode);
559f2e8686eSxun ni - Sun Microsystems - Beijing China continue;
560f2e8686eSxun ni - Sun Microsystems - Beijing China }
561f2e8686eSxun ni - Sun Microsystems - Beijing China }
5629e86db79SHyon Kim if (add_hba_port_info(portNode, new_hba, protocol)
5639e86db79SHyon Kim == HBA_STATUS_ERROR) {
5649e86db79SHyon Kim S_FREE(new_hba->first_port);
5659e86db79SHyon Kim S_FREE(new_hba);
5669e86db79SHyon Kim return (HBA_STATUS_ERROR);
5679e86db79SHyon Kim }
5689e86db79SHyon Kim portNode = di_sibling_node(portNode);
5699e86db79SHyon Kim }
5709e86db79SHyon Kim
5719e86db79SHyon Kim new_hba->index = hba_count++;
5729e86db79SHyon Kim
5739e86db79SHyon Kim /*
5749e86db79SHyon Kim * add newly created handle into global_hba_head list
5759e86db79SHyon Kim */
5769e86db79SHyon Kim if (global_hba_head != NULL) {
5779e86db79SHyon Kim /*
5789e86db79SHyon Kim * Make sure to move the open_handles list to back to the
5799e86db79SHyon Kim * head if it's there (for refresh scenario)
5809e86db79SHyon Kim */
5819e86db79SHyon Kim if (global_hba_head->open_handles) {
5829e86db79SHyon Kim new_hba->open_handles = global_hba_head->open_handles;
5839e86db79SHyon Kim global_hba_head->open_handles = NULL;
5849e86db79SHyon Kim }
5859e86db79SHyon Kim /* Now bump the new one to the head of the list */
5869e86db79SHyon Kim new_hba->next = global_hba_head;
5879e86db79SHyon Kim global_hba_head = new_hba;
5889e86db79SHyon Kim } else {
5899e86db79SHyon Kim global_hba_head = new_hba;
5909e86db79SHyon Kim }
5919e86db79SHyon Kim
5929e86db79SHyon Kim return (HBA_STATUS_OK);
5939e86db79SHyon Kim }
5949e86db79SHyon Kim
5959e86db79SHyon Kim /*
5969e86db79SHyon Kim * Discover information for all HBAs found on the system.
5979e86db79SHyon Kim * The di_node_t argument should be the root of the device tree.
5989e86db79SHyon Kim * This routine assumes the locks have been taken
5999e86db79SHyon Kim */
6009e86db79SHyon Kim static int
lookup_smhba_sas_hba(di_node_t node,void * arg)6019e86db79SHyon Kim lookup_smhba_sas_hba(di_node_t node, void *arg)
6029e86db79SHyon Kim {
60300f453f4SRob Johnston const char ROUTINE[] = "lookup_smhba_sas_hba";
60400f453f4SRob Johnston int *propData, rval;
60500f453f4SRob Johnston walkarg_t *wa = (walkarg_t *)arg;
6069e86db79SHyon Kim
6079e86db79SHyon Kim /* Skip stub(instance -1) nodes */
6089e86db79SHyon Kim if (IS_STUB_NODE(node)) {
6099e86db79SHyon Kim log(LOG_DEBUG, ROUTINE, "Walk continue");
6109e86db79SHyon Kim return (DI_WALK_CONTINUE);
6119e86db79SHyon Kim }
6129e86db79SHyon Kim
6139e86db79SHyon Kim rval = di_prop_lookup_ints(DDI_DEV_T_ANY, node,
6149e86db79SHyon Kim "sm-hba-supported", &propData);
6159e86db79SHyon Kim if (rval >= 0) {
6169e86db79SHyon Kim if (*propData) {
6179e86db79SHyon Kim /* add the hba to the hba list */
6189e86db79SHyon Kim if (devtree_get_one_hba(node) != HBA_STATUS_OK) {
6199e86db79SHyon Kim *(wa->flag) = B_TRUE;
6209e86db79SHyon Kim }
6219e86db79SHyon Kim /* Found a node. No need to walk the child. */
6229e86db79SHyon Kim log(LOG_DEBUG, ROUTINE, "Walk prunechild");
6239e86db79SHyon Kim return (DI_WALK_PRUNECHILD);
6249e86db79SHyon Kim }
6259e86db79SHyon Kim }
6269e86db79SHyon Kim
6279e86db79SHyon Kim return (DI_WALK_CONTINUE);
6289e86db79SHyon Kim }
6299e86db79SHyon Kim
6309e86db79SHyon Kim /*
6319e86db79SHyon Kim * Discover information for all HBAs found on the system.
6329e86db79SHyon Kim * The di_node_t argument should be the root of the device tree.
6339e86db79SHyon Kim * This routine assumes the locks have been taken
6349e86db79SHyon Kim */
6359e86db79SHyon Kim HBA_STATUS
devtree_get_all_hbas(di_node_t root)6369e86db79SHyon Kim devtree_get_all_hbas(di_node_t root)
6379e86db79SHyon Kim {
6389e86db79SHyon Kim const char ROUTINE[] = "devtree_get_all_hbas";
6399e86db79SHyon Kim int rv, ret = HBA_STATUS_ERROR;
6409e86db79SHyon Kim walkarg_t wa;
6419e86db79SHyon Kim
6429e86db79SHyon Kim wa.devpath = NULL;
6439e86db79SHyon Kim if ((wa.flag = (boolean_t *)calloc(1,
6449e86db79SHyon Kim sizeof (boolean_t))) == NULL) {
6459e86db79SHyon Kim OUT_OF_MEMORY(ROUTINE);
6469e86db79SHyon Kim return (HBA_STATUS_ERROR);
6479e86db79SHyon Kim }
6489e86db79SHyon Kim *wa.flag = B_FALSE;
6499e86db79SHyon Kim rv = di_walk_node(root, DI_WALK_SIBFIRST, &wa, lookup_smhba_sas_hba);
6509e86db79SHyon Kim
6519e86db79SHyon Kim if (rv == 0) {
6529e86db79SHyon Kim /*
6539e86db79SHyon Kim * Now determine what status code to return, taking
6549e86db79SHyon Kim * partial failure scenarios into consideration.
6559e86db79SHyon Kim *
6569e86db79SHyon Kim * If we have at least one working HBA, then we return an
6579e86db79SHyon Kim * OK status. If we have no good HBAs, but at least one
6589e86db79SHyon Kim * failed HBA, we return an ERROR status. If we have
6599e86db79SHyon Kim * no HBAs and no failures, we return OK.
6609e86db79SHyon Kim */
6619e86db79SHyon Kim if (global_hba_head) {
6629e86db79SHyon Kim /*
6639e86db79SHyon Kim * We've got at least one HBA and possibly some
6649e86db79SHyon Kim * failures.
6659e86db79SHyon Kim */
6669e86db79SHyon Kim ret = HBA_STATUS_OK;
6679e86db79SHyon Kim } else if (*(wa.flag)) {
6689e86db79SHyon Kim /* We have no HBAs but have failures */
6699e86db79SHyon Kim ret = HBA_STATUS_ERROR;
6709e86db79SHyon Kim } else {
6719e86db79SHyon Kim /* We have no HBAs and no failures */
6729e86db79SHyon Kim ret = HBA_STATUS_OK;
6739e86db79SHyon Kim }
6749e86db79SHyon Kim }
6759e86db79SHyon Kim
6769e86db79SHyon Kim
6779e86db79SHyon Kim S_FREE(wa.flag);
6789e86db79SHyon Kim
6799e86db79SHyon Kim if (ret == HBA_STATUS_OK)
6809e86db79SHyon Kim (void) registerSysevent();
6819e86db79SHyon Kim
6829e86db79SHyon Kim return (ret);
6839e86db79SHyon Kim }
684