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