xref: /onnv-gate/usr/src/lib/sun_sas/common/devtree_hba_disco.c (revision 12176:b9e1d921f601)
110652SHyon.Kim@Sun.COM /*
210652SHyon.Kim@Sun.COM  * CDDL HEADER START
310652SHyon.Kim@Sun.COM  *
410652SHyon.Kim@Sun.COM  * The contents of this file are subject to the terms of the
510652SHyon.Kim@Sun.COM  * Common Development and Distribution License (the "License").
610652SHyon.Kim@Sun.COM  * You may not use this file except in compliance with the License.
710652SHyon.Kim@Sun.COM  *
810652SHyon.Kim@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910652SHyon.Kim@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1010652SHyon.Kim@Sun.COM  * See the License for the specific language governing permissions
1110652SHyon.Kim@Sun.COM  * and limitations under the License.
1210652SHyon.Kim@Sun.COM  *
1310652SHyon.Kim@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1410652SHyon.Kim@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510652SHyon.Kim@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1610652SHyon.Kim@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1710652SHyon.Kim@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1810652SHyon.Kim@Sun.COM  *
1910652SHyon.Kim@Sun.COM  * CDDL HEADER END
2010652SHyon.Kim@Sun.COM  */
2110652SHyon.Kim@Sun.COM 
2210652SHyon.Kim@Sun.COM /*
23*12176SXun.Ni@Sun.COM  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2410652SHyon.Kim@Sun.COM  */
2510652SHyon.Kim@Sun.COM 
2610652SHyon.Kim@Sun.COM #include	<sun_sas.h>
2710652SHyon.Kim@Sun.COM #include	<sys/modctl.h>
2810652SHyon.Kim@Sun.COM #include	<sys/types.h>
2910652SHyon.Kim@Sun.COM #include	<netinet/in.h>
3010652SHyon.Kim@Sun.COM #include	<inttypes.h>
3110652SHyon.Kim@Sun.COM #include	<ctype.h>
3210652SHyon.Kim@Sun.COM 
3310652SHyon.Kim@Sun.COM /* free hba port info for the given hba */
3410652SHyon.Kim@Sun.COM static void
free_hba_port(struct sun_sas_hba * hba_ptr)3510652SHyon.Kim@Sun.COM free_hba_port(struct sun_sas_hba *hba_ptr)
3610652SHyon.Kim@Sun.COM {
3710652SHyon.Kim@Sun.COM 	struct sun_sas_port	*hba_port = NULL;
3810652SHyon.Kim@Sun.COM 	struct sun_sas_port	*last_hba_port = NULL;
3910652SHyon.Kim@Sun.COM 	struct sun_sas_port	*tgt_port = NULL;
4010652SHyon.Kim@Sun.COM 	struct sun_sas_port	*last_tgt_port = NULL;
4110652SHyon.Kim@Sun.COM 	struct ScsiEntryList	*scsi_info = NULL;
4210652SHyon.Kim@Sun.COM 	struct ScsiEntryList	*last_scsi_info = NULL;
4310652SHyon.Kim@Sun.COM 	struct phy_info		*phy_ptr = NULL;
4410652SHyon.Kim@Sun.COM 	struct phy_info		*last_phy = NULL;
4510652SHyon.Kim@Sun.COM 
4610652SHyon.Kim@Sun.COM 	/* Free the nested structures (port and attached port) */
4710652SHyon.Kim@Sun.COM 	hba_port = hba_ptr->first_port;
4810652SHyon.Kim@Sun.COM 	while (hba_port != NULL) {
4910652SHyon.Kim@Sun.COM 		/* Free discovered port structure list. */
5010652SHyon.Kim@Sun.COM 		tgt_port = hba_port->first_attached_port;
5110652SHyon.Kim@Sun.COM 		while (tgt_port != NULL) {
5210652SHyon.Kim@Sun.COM 			/* Free target mapping data list first. */
5310652SHyon.Kim@Sun.COM 			scsi_info = tgt_port->scsiInfo;
5410652SHyon.Kim@Sun.COM 			while (scsi_info != NULL) {
5510652SHyon.Kim@Sun.COM 				last_scsi_info = scsi_info;
5610652SHyon.Kim@Sun.COM 				scsi_info = scsi_info->next;
5710652SHyon.Kim@Sun.COM 				free(last_scsi_info);
5810652SHyon.Kim@Sun.COM 			}
5910652SHyon.Kim@Sun.COM 			last_tgt_port = tgt_port;
6010652SHyon.Kim@Sun.COM 			tgt_port = tgt_port->next;
6110652SHyon.Kim@Sun.COM 			free(last_tgt_port->port_attributes.\
6210652SHyon.Kim@Sun.COM 			    PortSpecificAttribute.SASPort);
6310652SHyon.Kim@Sun.COM 			free(last_tgt_port);
6410652SHyon.Kim@Sun.COM 		}
6510652SHyon.Kim@Sun.COM 		hba_port->first_attached_port = NULL;
6610652SHyon.Kim@Sun.COM 
6710652SHyon.Kim@Sun.COM 		phy_ptr = hba_port->first_phy;
6810652SHyon.Kim@Sun.COM 		while (phy_ptr != NULL) {
6910652SHyon.Kim@Sun.COM 			last_phy = phy_ptr;
7010652SHyon.Kim@Sun.COM 			phy_ptr = phy_ptr->next;
7110652SHyon.Kim@Sun.COM 			free(last_phy);
7210652SHyon.Kim@Sun.COM 		}
7310652SHyon.Kim@Sun.COM 		hba_port->first_phy = NULL;
7410652SHyon.Kim@Sun.COM 
7510652SHyon.Kim@Sun.COM 		last_hba_port = hba_port;
7610652SHyon.Kim@Sun.COM 		hba_port = hba_port->next;
7710652SHyon.Kim@Sun.COM 		free(last_hba_port->port_attributes.\
7810652SHyon.Kim@Sun.COM 		    PortSpecificAttribute.SASPort);
7910652SHyon.Kim@Sun.COM 		free(last_hba_port);
8010652SHyon.Kim@Sun.COM 	}
8110652SHyon.Kim@Sun.COM 
8210652SHyon.Kim@Sun.COM 	hba_ptr->first_port = NULL;
8310652SHyon.Kim@Sun.COM }
8410652SHyon.Kim@Sun.COM 
8510652SHyon.Kim@Sun.COM /*
8610652SHyon.Kim@Sun.COM  * Internal routine for adding an HBA port
8710652SHyon.Kim@Sun.COM  */
8810652SHyon.Kim@Sun.COM static HBA_STATUS
add_hba_port_info(di_node_t portNode,struct sun_sas_hba * hba_ptr,int protocol)8910652SHyon.Kim@Sun.COM add_hba_port_info(di_node_t portNode, struct sun_sas_hba *hba_ptr, int protocol)
9010652SHyon.Kim@Sun.COM {
9110652SHyon.Kim@Sun.COM 	const char		    ROUTINE[] = "add_hba_port_info";
9210652SHyon.Kim@Sun.COM 	struct sun_sas_port	    *port_ptr;
9310652SHyon.Kim@Sun.COM 	char			    *portDevpath;
9410652SHyon.Kim@Sun.COM 	int			    *propIntData;
9510652SHyon.Kim@Sun.COM 	char			    *propStringData;
9610652SHyon.Kim@Sun.COM 	uint64_t		    tmpAddr;
9710652SHyon.Kim@Sun.COM 	char			    *charptr, cntlLink[MAXPATHLEN] = {'\0'};
9810652SHyon.Kim@Sun.COM 	int			    rval;
9911243SHyon.Kim@Sun.COM 	di_node_t		    branchNode;
10010652SHyon.Kim@Sun.COM 	uint_t			    state = HBA_PORTSTATE_UNKNOWN;
10110652SHyon.Kim@Sun.COM 
10210652SHyon.Kim@Sun.COM 	if (hba_ptr == NULL) {
10310652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
10410652SHyon.Kim@Sun.COM 		    "Sun_sas handle ptr set to NULL.");
10510652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR_ARG);
10610652SHyon.Kim@Sun.COM 	}
10710652SHyon.Kim@Sun.COM 
10810652SHyon.Kim@Sun.COM 	if ((port_ptr = (struct sun_sas_port *)calloc(1,
10910652SHyon.Kim@Sun.COM 	    sizeof (struct sun_sas_port))) == NULL) {
11010652SHyon.Kim@Sun.COM 		OUT_OF_MEMORY(ROUTINE);
11110652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
11210652SHyon.Kim@Sun.COM 	}
11310652SHyon.Kim@Sun.COM 
11410652SHyon.Kim@Sun.COM 	if ((port_ptr->port_attributes.PortSpecificAttribute.SASPort =
11510652SHyon.Kim@Sun.COM 	    (struct SMHBA_SAS_Port *)calloc(1, sizeof (struct SMHBA_SAS_Port)))
11610652SHyon.Kim@Sun.COM 	    == NULL) {
11710652SHyon.Kim@Sun.COM 		OUT_OF_MEMORY(ROUTINE);
11810652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
11910652SHyon.Kim@Sun.COM 	}
12010652SHyon.Kim@Sun.COM 
12110652SHyon.Kim@Sun.COM 	if ((portDevpath = di_devfs_path(portNode)) == NULL) {
12210652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
12310652SHyon.Kim@Sun.COM 		    "Unable to get device path from HBA Port Node.");
12410652SHyon.Kim@Sun.COM 		S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
12510652SHyon.Kim@Sun.COM 		S_FREE(port_ptr);
12610652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
12710652SHyon.Kim@Sun.COM 	}
12810652SHyon.Kim@Sun.COM 
12911243SHyon.Kim@Sun.COM 	/*
13011243SHyon.Kim@Sun.COM 	 * Let's take a branch snap shot for pulling attributes.
13111243SHyon.Kim@Sun.COM 	 * The attribute change doesn't invalidate devinfo cache snapshot.
13211243SHyon.Kim@Sun.COM 	 * Phy info prop and num-phys can be obsolate when the same hba
13311243SHyon.Kim@Sun.COM 	 * connected to the same expander(SIM) thus phy numbers are increased.
13411243SHyon.Kim@Sun.COM 	 * Also the phy number may get decreased when a connection is removed
13511243SHyon.Kim@Sun.COM 	 * while the iport still exist through another connection.
13611243SHyon.Kim@Sun.COM 	 */
13711243SHyon.Kim@Sun.COM 	branchNode = di_init(portDevpath, DINFOPROP);
13811243SHyon.Kim@Sun.COM 	if (branchNode == DI_NODE_NIL) {
13911243SHyon.Kim@Sun.COM 		/* something is wrong here. */
14011243SHyon.Kim@Sun.COM 		di_fini(branchNode);
14111243SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
14211243SHyon.Kim@Sun.COM 		    "Unable to take devinfoi branch snapshot on HBA port \"%s\""
14311243SHyon.Kim@Sun.COM 		    " due to %s", portDevpath, strerror(errno));
14411243SHyon.Kim@Sun.COM 		S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
14511243SHyon.Kim@Sun.COM 		S_FREE(port_ptr);
14611243SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
14711243SHyon.Kim@Sun.COM 	}
14811243SHyon.Kim@Sun.COM 
14910652SHyon.Kim@Sun.COM 	state = di_state(portNode);
15010652SHyon.Kim@Sun.COM 	if (((state & DI_DRIVER_DETACHED) == DI_DRIVER_DETACHED) ||
15110652SHyon.Kim@Sun.COM 	    ((state & DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE)) {
15210652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
15310652SHyon.Kim@Sun.COM 		    "HBA port node %s is either OFFLINE or DETACHED",
15410652SHyon.Kim@Sun.COM 		    portDevpath);
15510652SHyon.Kim@Sun.COM 		port_ptr->port_attributes.PortState = HBA_PORTSTATE_OFFLINE;
15610652SHyon.Kim@Sun.COM 	} else {
15710652SHyon.Kim@Sun.COM 		port_ptr->port_attributes.PortState = HBA_PORTSTATE_ONLINE;
15810652SHyon.Kim@Sun.COM 	}
15910652SHyon.Kim@Sun.COM 
16010652SHyon.Kim@Sun.COM 	port_ptr->port_attributes.PortType = HBA_PORTTYPE_SASDEVICE;
16110652SHyon.Kim@Sun.COM 
16210652SHyon.Kim@Sun.COM 	(void) strlcpy(port_ptr->device_path, portDevpath, MAXPATHLEN + 1);
16310652SHyon.Kim@Sun.COM 
16410652SHyon.Kim@Sun.COM 	if (lookupControllerLink(portDevpath, (char *)cntlLink) ==
16510652SHyon.Kim@Sun.COM 	    HBA_STATUS_OK) {
16610652SHyon.Kim@Sun.COM 		(void) strlcpy(port_ptr->port_attributes.OSDeviceName, cntlLink,
16710652SHyon.Kim@Sun.COM 		    sizeof (port_ptr->port_attributes.OSDeviceName));
16810652SHyon.Kim@Sun.COM 		if ((charptr = strrchr(cntlLink, '/')) != NULL) {
16910652SHyon.Kim@Sun.COM 			charptr++;
17010652SHyon.Kim@Sun.COM 		}
17110652SHyon.Kim@Sun.COM 		if (charptr[0] ==  'c') {
17210652SHyon.Kim@Sun.COM 			port_ptr->cntlNumber = atoi(++charptr);
17310652SHyon.Kim@Sun.COM 		} else {
17410652SHyon.Kim@Sun.COM 			port_ptr->cntlNumber = -1;
17510652SHyon.Kim@Sun.COM 		}
17610652SHyon.Kim@Sun.COM 	} else {
17710652SHyon.Kim@Sun.COM 		(void) snprintf(port_ptr->port_attributes.OSDeviceName,
17810652SHyon.Kim@Sun.COM 		    sizeof (port_ptr->port_attributes.OSDeviceName),
17910652SHyon.Kim@Sun.COM 		    "%s%s%s", DEVICES_DIR, portDevpath, SCSI_SUFFIX);
18010652SHyon.Kim@Sun.COM 	}
18110652SHyon.Kim@Sun.COM 
18210652SHyon.Kim@Sun.COM 	di_devfs_path_free(portDevpath);
18310652SHyon.Kim@Sun.COM 
18410652SHyon.Kim@Sun.COM 	port_ptr->port_attributes.PortSpecificAttribute.
18510652SHyon.Kim@Sun.COM 	    SASPort->PortProtocol = protocol;
18610652SHyon.Kim@Sun.COM 
18711243SHyon.Kim@Sun.COM 	rval = di_prop_lookup_strings(DDI_DEV_T_ANY, branchNode,
18810652SHyon.Kim@Sun.COM 	    "initiator-port", &propStringData);
18910652SHyon.Kim@Sun.COM 	if (rval < 0) {
19010652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
19110652SHyon.Kim@Sun.COM 		    "Unable to get initiator-port from HBA port node %s.",
19210652SHyon.Kim@Sun.COM 		    port_ptr->port_attributes.OSDeviceName);
19311243SHyon.Kim@Sun.COM 		di_fini(branchNode);
19410652SHyon.Kim@Sun.COM 		S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
19510652SHyon.Kim@Sun.COM 		S_FREE(port_ptr);
19610652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
19710652SHyon.Kim@Sun.COM 	} else {
19810652SHyon.Kim@Sun.COM 		for (charptr = propStringData; *charptr != '\0'; charptr++) {
19910652SHyon.Kim@Sun.COM 			if (isxdigit(*charptr)) {
20010652SHyon.Kim@Sun.COM 				break;
20110652SHyon.Kim@Sun.COM 			}
20210652SHyon.Kim@Sun.COM 		}
20310652SHyon.Kim@Sun.COM 		if (*charptr != '\0') {
20410652SHyon.Kim@Sun.COM 			tmpAddr = htonll(strtoll(charptr, NULL, 16));
20510652SHyon.Kim@Sun.COM 			(void) memcpy(port_ptr->port_attributes.
20610652SHyon.Kim@Sun.COM 			    PortSpecificAttribute.SASPort->LocalSASAddress.wwn,
20710652SHyon.Kim@Sun.COM 			    &tmpAddr, 8);
20810652SHyon.Kim@Sun.COM 		} else {
20910652SHyon.Kim@Sun.COM 			log(LOG_DEBUG, ROUTINE,
21010652SHyon.Kim@Sun.COM 			    "No proper intiator-port prop value on HBA port %s",
21110652SHyon.Kim@Sun.COM 			    port_ptr->port_attributes.OSDeviceName);
21210652SHyon.Kim@Sun.COM 		}
21310652SHyon.Kim@Sun.COM 	}
21410652SHyon.Kim@Sun.COM 
21511243SHyon.Kim@Sun.COM 	rval = di_prop_lookup_strings(DDI_DEV_T_ANY, branchNode,
21610652SHyon.Kim@Sun.COM 	    "attached-port", &propStringData);
21710652SHyon.Kim@Sun.COM 	if (rval < 0) {
21810652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
21910652SHyon.Kim@Sun.COM 		    "Unable to get attached-port from HBA port node %s.",
22010652SHyon.Kim@Sun.COM 		    port_ptr->port_attributes.OSDeviceName);
22111243SHyon.Kim@Sun.COM 		di_fini(branchNode);
22210652SHyon.Kim@Sun.COM 		S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
22310652SHyon.Kim@Sun.COM 		S_FREE(port_ptr);
22410652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
22510652SHyon.Kim@Sun.COM 	} else {
22610652SHyon.Kim@Sun.COM 		for (charptr = propStringData; *charptr != '\0'; charptr++) {
22710652SHyon.Kim@Sun.COM 			if (isxdigit(*charptr)) {
22810652SHyon.Kim@Sun.COM 				break;
22910652SHyon.Kim@Sun.COM 			}
23010652SHyon.Kim@Sun.COM 		}
23110652SHyon.Kim@Sun.COM 		if (*charptr != '\0') {
23210652SHyon.Kim@Sun.COM 			tmpAddr = htonll(strtoll(charptr, NULL, 16));
23310652SHyon.Kim@Sun.COM 			(void) memcpy(port_ptr->port_attributes.
23410652SHyon.Kim@Sun.COM 			    PortSpecificAttribute.SASPort->
23510652SHyon.Kim@Sun.COM 			    AttachedSASAddress.wwn, &tmpAddr, 8);
23610652SHyon.Kim@Sun.COM 		} else {
23710652SHyon.Kim@Sun.COM 			/* continue even if the attached port is NULL. */
23810652SHyon.Kim@Sun.COM 			log(LOG_DEBUG, ROUTINE,
23910652SHyon.Kim@Sun.COM 			    "No proper attached-port prop value: "
24010652SHyon.Kim@Sun.COM 			    "HBA port Local SAS Address(%016llx)",
24110652SHyon.Kim@Sun.COM 			    wwnConversion(port_ptr->port_attributes.
24210652SHyon.Kim@Sun.COM 			    PortSpecificAttribute.
24310652SHyon.Kim@Sun.COM 			    SASPort->LocalSASAddress.wwn));
24410652SHyon.Kim@Sun.COM 		}
24510652SHyon.Kim@Sun.COM 	}
24610652SHyon.Kim@Sun.COM 
24711243SHyon.Kim@Sun.COM 	rval = di_prop_lookup_ints(DDI_DEV_T_ANY, branchNode,
24810652SHyon.Kim@Sun.COM 	    "num-phys", &propIntData);
24910652SHyon.Kim@Sun.COM 	if (rval < 0) {
25010652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
25110652SHyon.Kim@Sun.COM 		    "Unable to get NumberofPhys from HBA port %s.",
25210652SHyon.Kim@Sun.COM 		    port_ptr->port_attributes.OSDeviceName);
25311243SHyon.Kim@Sun.COM 		di_fini(branchNode);
25410652SHyon.Kim@Sun.COM 		S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
25510652SHyon.Kim@Sun.COM 		S_FREE(port_ptr);
25610652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
25710652SHyon.Kim@Sun.COM 	} else {
25810652SHyon.Kim@Sun.COM 		port_ptr->port_attributes.PortSpecificAttribute.\
25910652SHyon.Kim@Sun.COM 		    SASPort->NumberofPhys = *propIntData;
26010652SHyon.Kim@Sun.COM 	}
26110652SHyon.Kim@Sun.COM 
26210652SHyon.Kim@Sun.COM 	if (port_ptr->port_attributes.PortSpecificAttribute.\
26310652SHyon.Kim@Sun.COM 	    SASPort->NumberofPhys > 0) {
26411243SHyon.Kim@Sun.COM 		if (get_phy_info(branchNode, port_ptr) != HBA_STATUS_OK) {
26510652SHyon.Kim@Sun.COM 			log(LOG_DEBUG, ROUTINE,
26610652SHyon.Kim@Sun.COM 			    "Failed to get phy info on HBA port %s.",
26710652SHyon.Kim@Sun.COM 			    port_ptr->port_attributes.OSDeviceName);
26811243SHyon.Kim@Sun.COM 			di_fini(branchNode);
26910652SHyon.Kim@Sun.COM 			S_FREE(port_ptr->port_attributes.
27010652SHyon.Kim@Sun.COM 			    PortSpecificAttribute.SASPort);
27110652SHyon.Kim@Sun.COM 			S_FREE(port_ptr);
27211243SHyon.Kim@Sun.COM 			return (HBA_STATUS_ERROR);
27310652SHyon.Kim@Sun.COM 		}
27410652SHyon.Kim@Sun.COM 	}
27510652SHyon.Kim@Sun.COM 
27611243SHyon.Kim@Sun.COM 	/* now done with prop checking. remove branchNode. */
27711243SHyon.Kim@Sun.COM 	di_fini(branchNode);
27811243SHyon.Kim@Sun.COM 
27911243SHyon.Kim@Sun.COM 	/* Construct discovered target port. */
28010652SHyon.Kim@Sun.COM 	if (devtree_attached_devices(portNode, port_ptr) != HBA_STATUS_OK) {
28110652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
28210652SHyon.Kim@Sun.COM 		    "Failed to get attached device info HBA port %s.",
28310652SHyon.Kim@Sun.COM 		    port_ptr->port_attributes.OSDeviceName);
28410652SHyon.Kim@Sun.COM 		S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
28510652SHyon.Kim@Sun.COM 		S_FREE(port_ptr);
28611243SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
28710652SHyon.Kim@Sun.COM 	}
28810652SHyon.Kim@Sun.COM 
28910652SHyon.Kim@Sun.COM 	fillDomainPortWWN(port_ptr);
29010652SHyon.Kim@Sun.COM 
29110652SHyon.Kim@Sun.COM 	/* add new port onto hba handle list */
29210652SHyon.Kim@Sun.COM 	if (hba_ptr->first_port == NULL) {
29310652SHyon.Kim@Sun.COM 		port_ptr->index = 0;
29410652SHyon.Kim@Sun.COM 		hba_ptr->first_port = port_ptr;
29510652SHyon.Kim@Sun.COM 	} else {
29610652SHyon.Kim@Sun.COM 		port_ptr->index = hba_ptr->first_port->index + 1;
29710652SHyon.Kim@Sun.COM 		port_ptr->next = hba_ptr->first_port;
29810652SHyon.Kim@Sun.COM 		hba_ptr->first_port = port_ptr;
29910652SHyon.Kim@Sun.COM 	}
30010652SHyon.Kim@Sun.COM 
30110652SHyon.Kim@Sun.COM 	return (HBA_STATUS_OK);
30210652SHyon.Kim@Sun.COM }
30310652SHyon.Kim@Sun.COM 
30410652SHyon.Kim@Sun.COM HBA_STATUS
refresh_hba(di_node_t hbaNode,struct sun_sas_hba * hba_ptr)30510652SHyon.Kim@Sun.COM refresh_hba(di_node_t hbaNode, struct sun_sas_hba *hba_ptr)
30610652SHyon.Kim@Sun.COM {
30710652SHyon.Kim@Sun.COM 	const char	ROUTINE[] = "refresh_hba";
30810652SHyon.Kim@Sun.COM 	di_node_t	portNode;
30910652SHyon.Kim@Sun.COM 	int		protocol = 0;
31010652SHyon.Kim@Sun.COM 	int		*propIntData;
31110652SHyon.Kim@Sun.COM 
31210652SHyon.Kim@Sun.COM 	/*
31310652SHyon.Kim@Sun.COM 	 * clean up existing hba port, discovered target, phy info.
31410652SHyon.Kim@Sun.COM 	 * leave open handles intact.
31510652SHyon.Kim@Sun.COM 	 */
31610652SHyon.Kim@Sun.COM 	free_hba_port(hba_ptr);
31710652SHyon.Kim@Sun.COM 
31810652SHyon.Kim@Sun.COM 	if ((portNode = di_child_node(hbaNode)) == NULL) {
31910652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
32010652SHyon.Kim@Sun.COM 		    "HBA node doesn't have iport child.");
32110652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
32210652SHyon.Kim@Sun.COM 	}
32310652SHyon.Kim@Sun.COM 
32410652SHyon.Kim@Sun.COM 	if ((di_prop_lookup_ints(DDI_DEV_T_ANY, hbaNode,
32510652SHyon.Kim@Sun.COM 	    "supported-protocol", &propIntData)) == -1) {
32610652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
32710652SHyon.Kim@Sun.COM 		    "Unable to get supported-protocol from HBA node.");
32810652SHyon.Kim@Sun.COM 	} else {
32910652SHyon.Kim@Sun.COM 		protocol = *propIntData;
33010652SHyon.Kim@Sun.COM 	}
33110652SHyon.Kim@Sun.COM 
33210652SHyon.Kim@Sun.COM 	while (portNode != DI_NODE_NIL) {
333*12176SXun.Ni@Sun.COM 		if (di_prop_lookup_ints(DDI_DEV_T_ANY, portNode,
334*12176SXun.Ni@Sun.COM 		    "virtual-port", &propIntData) >= 0) {
335*12176SXun.Ni@Sun.COM 			if (*propIntData) {
336*12176SXun.Ni@Sun.COM 				/* ignore a virtual port. */
337*12176SXun.Ni@Sun.COM 				portNode = di_sibling_node(portNode);
338*12176SXun.Ni@Sun.COM 				continue;
339*12176SXun.Ni@Sun.COM 			}
340*12176SXun.Ni@Sun.COM 		}
34110652SHyon.Kim@Sun.COM 		if (add_hba_port_info(portNode, hba_ptr, protocol)
34210652SHyon.Kim@Sun.COM 		    == HBA_STATUS_ERROR) {
34310652SHyon.Kim@Sun.COM 			S_FREE(hba_ptr->first_port);
34410652SHyon.Kim@Sun.COM 			S_FREE(hba_ptr);
34510652SHyon.Kim@Sun.COM 			return (HBA_STATUS_ERROR);
34610652SHyon.Kim@Sun.COM 		}
34710652SHyon.Kim@Sun.COM 		portNode = di_sibling_node(portNode);
34810652SHyon.Kim@Sun.COM 	}
34910652SHyon.Kim@Sun.COM 
35010652SHyon.Kim@Sun.COM 	return (HBA_STATUS_OK);
35110652SHyon.Kim@Sun.COM }
35210652SHyon.Kim@Sun.COM 
35310652SHyon.Kim@Sun.COM /*
35410652SHyon.Kim@Sun.COM  * Discover information for one HBA in the device tree.
35510652SHyon.Kim@Sun.COM  * The di_node_t argument should be a node with smhba-supported prop set
35610652SHyon.Kim@Sun.COM  * to true.
35710652SHyon.Kim@Sun.COM  * Without iport support, the devinfo node will represent one port hba.
35810652SHyon.Kim@Sun.COM  * This routine assumes the locks have been taken.
35910652SHyon.Kim@Sun.COM  */
36010652SHyon.Kim@Sun.COM HBA_STATUS
devtree_get_one_hba(di_node_t hbaNode)36110652SHyon.Kim@Sun.COM devtree_get_one_hba(di_node_t hbaNode)
36210652SHyon.Kim@Sun.COM {
36310652SHyon.Kim@Sun.COM 	const char		ROUTINE[] = "devtree_get_one_hba";
36410652SHyon.Kim@Sun.COM 	char			*propdata = NULL;
36510652SHyon.Kim@Sun.COM 	int			*propIntData = NULL;
36610652SHyon.Kim@Sun.COM 	struct sun_sas_hba	*new_hba, *hba_ptr;
36710652SHyon.Kim@Sun.COM 	char			*hbaDevpath, *hba_driver;
36810652SHyon.Kim@Sun.COM 	int			protocol = 0;
36910652SHyon.Kim@Sun.COM 	di_node_t		portNode;
37010652SHyon.Kim@Sun.COM 	int			hba_instance = -1;
37110652SHyon.Kim@Sun.COM 
37210652SHyon.Kim@Sun.COM 	hba_instance = di_instance(hbaNode);
37310652SHyon.Kim@Sun.COM 	if (hba_instance == -1) {
37410652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
37510652SHyon.Kim@Sun.COM 		    "portNode has instance of -1");
37610652SHyon.Kim@Sun.COM 		return (DI_WALK_CONTINUE);
37710652SHyon.Kim@Sun.COM 	}
37810652SHyon.Kim@Sun.COM 
37910652SHyon.Kim@Sun.COM 	if ((hbaDevpath = di_devfs_path(hbaNode)) == NULL) {
38010652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE, "Unable to get "
38110652SHyon.Kim@Sun.COM 		    "device path from hbaNode");
38210652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
38310652SHyon.Kim@Sun.COM 	}
38410652SHyon.Kim@Sun.COM 
38510652SHyon.Kim@Sun.COM 	/* check to see if this is a repeat HBA */
38610652SHyon.Kim@Sun.COM 	if (global_hba_head) {
38710652SHyon.Kim@Sun.COM 		for (hba_ptr = global_hba_head;
38810652SHyon.Kim@Sun.COM 		    hba_ptr != NULL;
38910652SHyon.Kim@Sun.COM 		    hba_ptr = hba_ptr->next) {
39010652SHyon.Kim@Sun.COM 			if ((strncmp(hba_ptr->device_path, hbaDevpath,
39110652SHyon.Kim@Sun.COM 			    strlen(hbaDevpath))) == 0) {
39210652SHyon.Kim@Sun.COM 				if (refresh_hba(hbaNode, hba_ptr) !=
39310652SHyon.Kim@Sun.COM 				    HBA_STATUS_OK) {
39410652SHyon.Kim@Sun.COM 					log(LOG_DEBUG, ROUTINE, "Refresh failed"
39510652SHyon.Kim@Sun.COM 					    " on hbaNode %s", hbaDevpath);
39610652SHyon.Kim@Sun.COM 				}
39710652SHyon.Kim@Sun.COM 				di_devfs_path_free(hbaDevpath);
39810652SHyon.Kim@Sun.COM 				return (HBA_STATUS_OK);
39910652SHyon.Kim@Sun.COM 			}
40010652SHyon.Kim@Sun.COM 		}
40110652SHyon.Kim@Sun.COM 	}
40210652SHyon.Kim@Sun.COM 
40310652SHyon.Kim@Sun.COM 	/* this is a new hba */
40410652SHyon.Kim@Sun.COM 	if ((new_hba = (struct sun_sas_hba *)calloc(1,
40510652SHyon.Kim@Sun.COM 	    sizeof (struct sun_sas_hba))) == NULL) {
40610652SHyon.Kim@Sun.COM 		OUT_OF_MEMORY(ROUTINE);
40710652SHyon.Kim@Sun.COM 		di_devfs_path_free(hbaDevpath);
40810652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
40910652SHyon.Kim@Sun.COM 	}
41010652SHyon.Kim@Sun.COM 
41110652SHyon.Kim@Sun.COM 	(void) strlcpy(new_hba->device_path, hbaDevpath,
41210652SHyon.Kim@Sun.COM 	    sizeof (new_hba->device_path));
41310652SHyon.Kim@Sun.COM 	di_devfs_path_free(hbaDevpath);
41410652SHyon.Kim@Sun.COM 
41510652SHyon.Kim@Sun.COM 	(void) snprintf(new_hba->adapter_attributes.HBASymbolicName,
41610652SHyon.Kim@Sun.COM 	    sizeof (new_hba->adapter_attributes.HBASymbolicName),
41710652SHyon.Kim@Sun.COM 	    "%s%s", DEVICES_DIR, new_hba->device_path);
41810652SHyon.Kim@Sun.COM 
41910652SHyon.Kim@Sun.COM 	/* Manufacturer */
42010652SHyon.Kim@Sun.COM 	if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
42110652SHyon.Kim@Sun.COM 	    "Manufacturer", (char **)&propdata)) == -1) {
42210652SHyon.Kim@Sun.COM 		(void) strlcpy(new_hba->adapter_attributes.Manufacturer,
42310652SHyon.Kim@Sun.COM 		    SUN_MICROSYSTEMS,
42410652SHyon.Kim@Sun.COM 		    sizeof (new_hba->adapter_attributes.Manufacturer));
42510652SHyon.Kim@Sun.COM 	} else {
42610652SHyon.Kim@Sun.COM 		(void) strlcpy(new_hba->adapter_attributes.Manufacturer,
42710652SHyon.Kim@Sun.COM 		    propdata,
42810652SHyon.Kim@Sun.COM 		    sizeof (new_hba->adapter_attributes.Manufacturer));
42910652SHyon.Kim@Sun.COM 	}
43010652SHyon.Kim@Sun.COM 
43110652SHyon.Kim@Sun.COM 	/* SerialNumber */
43210652SHyon.Kim@Sun.COM 	if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
43310652SHyon.Kim@Sun.COM 	    "SerialNumber", (char **)&propdata)) == -1) {
43410652SHyon.Kim@Sun.COM 		new_hba->adapter_attributes.SerialNumber[0] = '\0';
43510652SHyon.Kim@Sun.COM 	} else {
43610652SHyon.Kim@Sun.COM 		(void) strlcpy(new_hba->adapter_attributes.SerialNumber,
43710652SHyon.Kim@Sun.COM 		    propdata,
43810652SHyon.Kim@Sun.COM 		    sizeof (new_hba->adapter_attributes.SerialNumber));
43910652SHyon.Kim@Sun.COM 	}
44010652SHyon.Kim@Sun.COM 
44110652SHyon.Kim@Sun.COM 	/* Model */
44210652SHyon.Kim@Sun.COM 	if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
44310652SHyon.Kim@Sun.COM 	    "ModelName", (char **)&propdata)) == -1) {
44410652SHyon.Kim@Sun.COM 		new_hba->adapter_attributes.Model[0] = '\0';
44510652SHyon.Kim@Sun.COM 	} else {
44610652SHyon.Kim@Sun.COM 		(void) strlcpy(new_hba->adapter_attributes.Model,
44710652SHyon.Kim@Sun.COM 		    propdata,
44810652SHyon.Kim@Sun.COM 		    sizeof (new_hba->adapter_attributes.Model));
44910652SHyon.Kim@Sun.COM 	}
45010652SHyon.Kim@Sun.COM 
45110652SHyon.Kim@Sun.COM 	/* FirmwareVersion */
45210652SHyon.Kim@Sun.COM 	if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
45310652SHyon.Kim@Sun.COM 	    "firmware-version", (char **)&propdata)) == -1) {
45410652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
45510652SHyon.Kim@Sun.COM 		    "Property \"%s\" not found for device \"%s\"",
45610652SHyon.Kim@Sun.COM 		    "firmware-version", new_hba->device_path);
45710652SHyon.Kim@Sun.COM 	} else {
45810652SHyon.Kim@Sun.COM 		(void) strlcpy(new_hba->adapter_attributes.FirmwareVersion,
45910652SHyon.Kim@Sun.COM 		    propdata,
46010652SHyon.Kim@Sun.COM 		    sizeof (new_hba->adapter_attributes.FirmwareVersion));
46110652SHyon.Kim@Sun.COM 	}
46210652SHyon.Kim@Sun.COM 
46310652SHyon.Kim@Sun.COM 	/* HardwareVersion */
46410652SHyon.Kim@Sun.COM 	if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
46510652SHyon.Kim@Sun.COM 	    "hardware-version", (char **)&propdata)) == -1) {
46610652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
46710652SHyon.Kim@Sun.COM 		    "Property \"%s\" not found for device \"%s\"",
46810652SHyon.Kim@Sun.COM 		    "hardware-version", new_hba->device_path);
46910652SHyon.Kim@Sun.COM 	} else {
47010652SHyon.Kim@Sun.COM 		(void) strlcpy(new_hba->adapter_attributes.HardwareVersion,
47110652SHyon.Kim@Sun.COM 		    propdata,
47210652SHyon.Kim@Sun.COM 		    sizeof (new_hba->adapter_attributes.HardwareVersion));
47310652SHyon.Kim@Sun.COM 	}
47410652SHyon.Kim@Sun.COM 
47510652SHyon.Kim@Sun.COM 	/* DriverVersion */
47610652SHyon.Kim@Sun.COM 	if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
47710652SHyon.Kim@Sun.COM 	    "driver-version", (char **)&propdata)) == -1) {
47810652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
47910652SHyon.Kim@Sun.COM 		    "Property \"%s\" not found for device \"%s\"",
48010652SHyon.Kim@Sun.COM 		    "driver-version", new_hba->device_path);
48110652SHyon.Kim@Sun.COM 	} else {
48210652SHyon.Kim@Sun.COM 		(void) strlcpy(new_hba->adapter_attributes.DriverVersion,
48310652SHyon.Kim@Sun.COM 		    propdata,
48410652SHyon.Kim@Sun.COM 		    sizeof (new_hba->adapter_attributes.DriverVersion));
48510652SHyon.Kim@Sun.COM 	}
48610652SHyon.Kim@Sun.COM 
48710652SHyon.Kim@Sun.COM 	if ((di_prop_lookup_ints(DDI_DEV_T_ANY, hbaNode,
48810652SHyon.Kim@Sun.COM 	    "supported-protocol", &propIntData)) == -1) {
48910652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
49010652SHyon.Kim@Sun.COM 		    "Unable to get supported-protocol from HBA node.");
49110652SHyon.Kim@Sun.COM 	} else {
49210652SHyon.Kim@Sun.COM 		protocol = *propIntData;
49310652SHyon.Kim@Sun.COM 	}
49410652SHyon.Kim@Sun.COM 
49510652SHyon.Kim@Sun.COM 	/* We don't use these */
49610652SHyon.Kim@Sun.COM 	new_hba->adapter_attributes.OptionROMVersion[0] = '\0';
49710652SHyon.Kim@Sun.COM 	new_hba->adapter_attributes.RedundantOptionROMVersion[0] = '\0';
49810652SHyon.Kim@Sun.COM 	new_hba->adapter_attributes.RedundantFirmwareVersion[0] = '\0';
49910652SHyon.Kim@Sun.COM 	new_hba->adapter_attributes.VendorSpecificID = 0;
50010652SHyon.Kim@Sun.COM 
50110652SHyon.Kim@Sun.COM 	if ((hba_driver = di_driver_name(hbaNode)) != NULL) {
50210652SHyon.Kim@Sun.COM 		(void) strlcpy(new_hba->adapter_attributes.DriverName,
50310652SHyon.Kim@Sun.COM 		    hba_driver,
50410652SHyon.Kim@Sun.COM 		    sizeof (new_hba->adapter_attributes.DriverName));
50510652SHyon.Kim@Sun.COM 	} else {
50610652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
50710652SHyon.Kim@Sun.COM 		    "HBA driver name not found for device \"%s\"",
50810652SHyon.Kim@Sun.COM 		    new_hba->device_path);
50910652SHyon.Kim@Sun.COM 	}
51010652SHyon.Kim@Sun.COM 
51110652SHyon.Kim@Sun.COM 	/*
51210652SHyon.Kim@Sun.COM 	 * Name the adapter: like SUNW-pmcs-1
51310652SHyon.Kim@Sun.COM 	 * Using di_instance number as the suffix for the name for persistent
51410652SHyon.Kim@Sun.COM 	 * among rebooting.
51510652SHyon.Kim@Sun.COM 	 */
51610652SHyon.Kim@Sun.COM 	(void) snprintf(new_hba->handle_name, HANDLE_NAME_LENGTH, "%s-%s-%d",
51710652SHyon.Kim@Sun.COM 	    "SUNW", new_hba->adapter_attributes.DriverName, hba_instance);
51810652SHyon.Kim@Sun.COM 
51910652SHyon.Kim@Sun.COM 	if ((portNode = di_child_node(hbaNode)) == NULL) {
52010652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
52110652SHyon.Kim@Sun.COM 		    "HBA driver doesn't have iport child. \"%s\"",
52210652SHyon.Kim@Sun.COM 		    new_hba->device_path);
52310652SHyon.Kim@Sun.COM 		/* continue on with an hba without any port. */
52410652SHyon.Kim@Sun.COM 		new_hba->index = hba_count++;
52510652SHyon.Kim@Sun.COM 
52610652SHyon.Kim@Sun.COM 		/*
52710652SHyon.Kim@Sun.COM 		 * add newly created handle into global_hba_head list
52810652SHyon.Kim@Sun.COM 		 */
52910652SHyon.Kim@Sun.COM 		if (global_hba_head != NULL) {
53010652SHyon.Kim@Sun.COM 			/*
53110652SHyon.Kim@Sun.COM 			 * Make sure to move the open_handles list to back to
53210652SHyon.Kim@Sun.COM 			 * the head if it's there (for refresh scenario)
53310652SHyon.Kim@Sun.COM 			 */
53410652SHyon.Kim@Sun.COM 			if (global_hba_head->open_handles) {
53510652SHyon.Kim@Sun.COM 				new_hba->open_handles =
53610652SHyon.Kim@Sun.COM 				    global_hba_head->open_handles;
53710652SHyon.Kim@Sun.COM 				global_hba_head->open_handles = NULL;
53810652SHyon.Kim@Sun.COM 			}
53910652SHyon.Kim@Sun.COM 			/* Now bump the new one to the head of the list */
54010652SHyon.Kim@Sun.COM 			new_hba->next = global_hba_head;
54110652SHyon.Kim@Sun.COM 			global_hba_head = new_hba;
54210652SHyon.Kim@Sun.COM 		} else {
54310652SHyon.Kim@Sun.COM 			global_hba_head = new_hba;
54410652SHyon.Kim@Sun.COM 		}
54510652SHyon.Kim@Sun.COM 		return (HBA_STATUS_OK);
54610652SHyon.Kim@Sun.COM 	}
54710652SHyon.Kim@Sun.COM 
54810652SHyon.Kim@Sun.COM 	while (portNode != DI_NODE_NIL) {
549*12176SXun.Ni@Sun.COM 		if (di_prop_lookup_ints(DDI_DEV_T_ANY, portNode,
550*12176SXun.Ni@Sun.COM 		    "virtual-port", &propIntData) >= 0) {
551*12176SXun.Ni@Sun.COM 			if (*propIntData) {
552*12176SXun.Ni@Sun.COM 				/* ignore a virtual port. */
553*12176SXun.Ni@Sun.COM 				portNode = di_sibling_node(portNode);
554*12176SXun.Ni@Sun.COM 				continue;
555*12176SXun.Ni@Sun.COM 			}
556*12176SXun.Ni@Sun.COM 		}
55710652SHyon.Kim@Sun.COM 		if (add_hba_port_info(portNode, new_hba, protocol)
55810652SHyon.Kim@Sun.COM 		    == HBA_STATUS_ERROR) {
55910652SHyon.Kim@Sun.COM 			S_FREE(new_hba->first_port);
56010652SHyon.Kim@Sun.COM 			S_FREE(new_hba);
56110652SHyon.Kim@Sun.COM 			return (HBA_STATUS_ERROR);
56210652SHyon.Kim@Sun.COM 		}
56310652SHyon.Kim@Sun.COM 		portNode = di_sibling_node(portNode);
56410652SHyon.Kim@Sun.COM 	}
56510652SHyon.Kim@Sun.COM 
56610652SHyon.Kim@Sun.COM 	new_hba->index = hba_count++;
56710652SHyon.Kim@Sun.COM 
56810652SHyon.Kim@Sun.COM 	/*
56910652SHyon.Kim@Sun.COM 	 * add newly created handle into global_hba_head list
57010652SHyon.Kim@Sun.COM 	 */
57110652SHyon.Kim@Sun.COM 	if (global_hba_head != NULL) {
57210652SHyon.Kim@Sun.COM 		/*
57310652SHyon.Kim@Sun.COM 		 * Make sure to move the open_handles list to back to the
57410652SHyon.Kim@Sun.COM 		 * head if it's there (for refresh scenario)
57510652SHyon.Kim@Sun.COM 		 */
57610652SHyon.Kim@Sun.COM 		if (global_hba_head->open_handles) {
57710652SHyon.Kim@Sun.COM 			new_hba->open_handles = global_hba_head->open_handles;
57810652SHyon.Kim@Sun.COM 			global_hba_head->open_handles = NULL;
57910652SHyon.Kim@Sun.COM 		}
58010652SHyon.Kim@Sun.COM 		/* Now bump the new one to the head of the list */
58110652SHyon.Kim@Sun.COM 		new_hba->next = global_hba_head;
58210652SHyon.Kim@Sun.COM 		global_hba_head = new_hba;
58310652SHyon.Kim@Sun.COM 	} else {
58410652SHyon.Kim@Sun.COM 		global_hba_head = new_hba;
58510652SHyon.Kim@Sun.COM 	}
58610652SHyon.Kim@Sun.COM 
58710652SHyon.Kim@Sun.COM 	return (HBA_STATUS_OK);
58810652SHyon.Kim@Sun.COM }
58910652SHyon.Kim@Sun.COM 
59010652SHyon.Kim@Sun.COM /*
59110652SHyon.Kim@Sun.COM  * Discover information for all HBAs found on the system.
59210652SHyon.Kim@Sun.COM  * The di_node_t argument should be the root of the device tree.
59310652SHyon.Kim@Sun.COM  * This routine assumes the locks have been taken
59410652SHyon.Kim@Sun.COM  */
59510652SHyon.Kim@Sun.COM static int
lookup_smhba_sas_hba(di_node_t node,void * arg)59610652SHyon.Kim@Sun.COM lookup_smhba_sas_hba(di_node_t node, void *arg)
59710652SHyon.Kim@Sun.COM {
59810652SHyon.Kim@Sun.COM 	const char	ROUTINE[] = "lookup_smhba_sas_hba";
59910652SHyon.Kim@Sun.COM 	int 		*propData, rval;
60010652SHyon.Kim@Sun.COM 	walkarg_t 	*wa = (walkarg_t *)arg;
60110652SHyon.Kim@Sun.COM 
60210652SHyon.Kim@Sun.COM 	/* Skip stub(instance -1) nodes */
60310652SHyon.Kim@Sun.COM 	if (IS_STUB_NODE(node)) {
60410652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE, "Walk continue");
60510652SHyon.Kim@Sun.COM 		return (DI_WALK_CONTINUE);
60610652SHyon.Kim@Sun.COM 	}
60710652SHyon.Kim@Sun.COM 
60810652SHyon.Kim@Sun.COM 	rval = di_prop_lookup_ints(DDI_DEV_T_ANY, node,
60910652SHyon.Kim@Sun.COM 	    "sm-hba-supported", &propData);
61010652SHyon.Kim@Sun.COM 	if (rval >= 0) {
61110652SHyon.Kim@Sun.COM 		if (*propData) {
61210652SHyon.Kim@Sun.COM 			/* add the hba to the hba list */
61310652SHyon.Kim@Sun.COM 			if (devtree_get_one_hba(node) != HBA_STATUS_OK) {
61410652SHyon.Kim@Sun.COM 				*(wa->flag) = B_TRUE;
61510652SHyon.Kim@Sun.COM 			}
61610652SHyon.Kim@Sun.COM 			/* Found a node. No need to walk the child. */
61710652SHyon.Kim@Sun.COM 			log(LOG_DEBUG, ROUTINE, "Walk prunechild");
61810652SHyon.Kim@Sun.COM 			return (DI_WALK_PRUNECHILD);
61910652SHyon.Kim@Sun.COM 		}
62010652SHyon.Kim@Sun.COM 	}
62110652SHyon.Kim@Sun.COM 
62210652SHyon.Kim@Sun.COM 	return (DI_WALK_CONTINUE);
62310652SHyon.Kim@Sun.COM }
62410652SHyon.Kim@Sun.COM 
62510652SHyon.Kim@Sun.COM /*
62610652SHyon.Kim@Sun.COM  * Discover information for all HBAs found on the system.
62710652SHyon.Kim@Sun.COM  * The di_node_t argument should be the root of the device tree.
62810652SHyon.Kim@Sun.COM  * This routine assumes the locks have been taken
62910652SHyon.Kim@Sun.COM  */
63010652SHyon.Kim@Sun.COM HBA_STATUS
devtree_get_all_hbas(di_node_t root)63110652SHyon.Kim@Sun.COM devtree_get_all_hbas(di_node_t root)
63210652SHyon.Kim@Sun.COM {
63310652SHyon.Kim@Sun.COM 	const char	ROUTINE[] = "devtree_get_all_hbas";
63410652SHyon.Kim@Sun.COM 	int		rv, ret = HBA_STATUS_ERROR;
63510652SHyon.Kim@Sun.COM 	walkarg_t	wa;
63610652SHyon.Kim@Sun.COM 
63710652SHyon.Kim@Sun.COM 	wa.devpath = NULL;
63810652SHyon.Kim@Sun.COM 	if ((wa.flag = (boolean_t *)calloc(1,
63910652SHyon.Kim@Sun.COM 	    sizeof (boolean_t))) == NULL) {
64010652SHyon.Kim@Sun.COM 		OUT_OF_MEMORY(ROUTINE);
64110652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
64210652SHyon.Kim@Sun.COM 	}
64310652SHyon.Kim@Sun.COM 	*wa.flag = B_FALSE;
64410652SHyon.Kim@Sun.COM 	rv = di_walk_node(root, DI_WALK_SIBFIRST, &wa, lookup_smhba_sas_hba);
64510652SHyon.Kim@Sun.COM 
64610652SHyon.Kim@Sun.COM 	if (rv == 0) {
64710652SHyon.Kim@Sun.COM 		/*
64810652SHyon.Kim@Sun.COM 		 * Now determine what status code to return, taking
64910652SHyon.Kim@Sun.COM 		 * partial failure scenarios into consideration.
65010652SHyon.Kim@Sun.COM 		 *
65110652SHyon.Kim@Sun.COM 		 * If we have at least one working HBA, then we return an
65210652SHyon.Kim@Sun.COM 		 * OK status.  If we have no good HBAs, but at least one
65310652SHyon.Kim@Sun.COM 		 * failed HBA, we return an ERROR status.  If we have
65410652SHyon.Kim@Sun.COM 		 * no HBAs and no failures, we return OK.
65510652SHyon.Kim@Sun.COM 		 */
65610652SHyon.Kim@Sun.COM 		if (global_hba_head) {
65710652SHyon.Kim@Sun.COM 			/*
65810652SHyon.Kim@Sun.COM 			 * We've got at least one HBA and possibly some
65910652SHyon.Kim@Sun.COM 			 * failures.
66010652SHyon.Kim@Sun.COM 			 */
66110652SHyon.Kim@Sun.COM 			ret = HBA_STATUS_OK;
66210652SHyon.Kim@Sun.COM 		} else if (*(wa.flag)) {
66310652SHyon.Kim@Sun.COM 			/* We have no HBAs but have failures */
66410652SHyon.Kim@Sun.COM 			ret = HBA_STATUS_ERROR;
66510652SHyon.Kim@Sun.COM 		} else {
66610652SHyon.Kim@Sun.COM 			/* We have no HBAs and no failures */
66710652SHyon.Kim@Sun.COM 			ret = HBA_STATUS_OK;
66810652SHyon.Kim@Sun.COM 		}
66910652SHyon.Kim@Sun.COM 	}
67010652SHyon.Kim@Sun.COM 
67110652SHyon.Kim@Sun.COM 
67210652SHyon.Kim@Sun.COM 	S_FREE(wa.flag);
67310652SHyon.Kim@Sun.COM 
67410652SHyon.Kim@Sun.COM 	if (ret == HBA_STATUS_OK)
67510652SHyon.Kim@Sun.COM 		(void) registerSysevent();
67610652SHyon.Kim@Sun.COM 
67710652SHyon.Kim@Sun.COM 	return (ret);
67810652SHyon.Kim@Sun.COM }
679