xref: /onnv-gate/usr/src/lib/sun_sas/common/devtree_device_disco.c (revision 11243:3a7c9b3f8ef6)
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 /*
2310652SHyon.Kim@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2410652SHyon.Kim@Sun.COM  * Use is subject to license terms.
2510652SHyon.Kim@Sun.COM  */
2610652SHyon.Kim@Sun.COM 
2710652SHyon.Kim@Sun.COM #include	<sun_sas.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 #include	<sys/scsi/scsi_address.h>
3310652SHyon.Kim@Sun.COM #include	<libdevid.h>
3410652SHyon.Kim@Sun.COM 
3510652SHyon.Kim@Sun.COM /*
3610652SHyon.Kim@Sun.COM  * Get the preferred minor node for the given path.
3710652SHyon.Kim@Sun.COM  * ":n" for tapes, ":c,raw" for disks,
3810652SHyon.Kim@Sun.COM  * and ":0" for enclosures.
3910652SHyon.Kim@Sun.COM  */
4010652SHyon.Kim@Sun.COM static void
get_minor(char * devpath,char * minor)4110652SHyon.Kim@Sun.COM get_minor(char *devpath, char *minor)
4210652SHyon.Kim@Sun.COM {
4310652SHyon.Kim@Sun.COM 	const char	ROUTINE[] = "get_minor";
4410652SHyon.Kim@Sun.COM 	char	fullpath[MAXPATHLEN];
4510652SHyon.Kim@Sun.COM 	int	fd;
4610652SHyon.Kim@Sun.COM 
4710652SHyon.Kim@Sun.COM 	if ((strstr(devpath, "/st@")) || (strstr(devpath, "/tape@"))) {
4810652SHyon.Kim@Sun.COM 		(void) strcpy(minor, ":n");
4910652SHyon.Kim@Sun.COM 	} else if (strstr(devpath, "/smp@")) {
5010652SHyon.Kim@Sun.COM 		(void) strcpy(minor, ":smp");
5110652SHyon.Kim@Sun.COM 	} else if ((strstr(devpath, "/ssd@")) || (strstr(devpath, "/sd@")) ||
5210652SHyon.Kim@Sun.COM 	    (strstr(devpath, "/disk@"))) {
5310652SHyon.Kim@Sun.COM 		(void) strcpy(minor, ":c,raw");
5410652SHyon.Kim@Sun.COM 	} else if ((strstr(devpath, "/ses@")) || (strstr(devpath,
5510652SHyon.Kim@Sun.COM 	    "/enclosure@"))) {
5610652SHyon.Kim@Sun.COM 		(void) snprintf(fullpath, MAXPATHLEN, "%s%s%s", DEVICES_DIR,
5710652SHyon.Kim@Sun.COM 		    devpath, ":0");
5810652SHyon.Kim@Sun.COM 		/* reset errno to 0 */
5910652SHyon.Kim@Sun.COM 		errno = 0;
6010652SHyon.Kim@Sun.COM 		if ((fd = open(fullpath, O_RDONLY)) == -1) {
6110652SHyon.Kim@Sun.COM 			/*
6210652SHyon.Kim@Sun.COM 			 * :0 minor doesn't exist. assume bound to sgen driver
6310652SHyon.Kim@Sun.COM 			 * and :ses minor exist.
6410652SHyon.Kim@Sun.COM 			 */
6510652SHyon.Kim@Sun.COM 			if (errno == ENOENT) {
6610652SHyon.Kim@Sun.COM 				(void) strcpy(minor, ":ses");
6710652SHyon.Kim@Sun.COM 			}
6810652SHyon.Kim@Sun.COM 		} else {
6910652SHyon.Kim@Sun.COM 			(void) strcpy(minor, ":0");
7010652SHyon.Kim@Sun.COM 			(void) close(fd);
7110652SHyon.Kim@Sun.COM 		}
7210652SHyon.Kim@Sun.COM 	} else {
7310652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE, "Unrecognized target (%s)",
7410652SHyon.Kim@Sun.COM 		    devpath);
7510652SHyon.Kim@Sun.COM 		minor[0] = '\0';
7610652SHyon.Kim@Sun.COM 	}
7710652SHyon.Kim@Sun.COM 
7810652SHyon.Kim@Sun.COM }
7910652SHyon.Kim@Sun.COM 
8010652SHyon.Kim@Sun.COM /*
8110652SHyon.Kim@Sun.COM  * Free the attached port allocation.
8210652SHyon.Kim@Sun.COM  */
8310652SHyon.Kim@Sun.COM static void
free_attached_port(struct sun_sas_port * port_ptr)8410652SHyon.Kim@Sun.COM free_attached_port(struct sun_sas_port *port_ptr)
8510652SHyon.Kim@Sun.COM {
8610652SHyon.Kim@Sun.COM 	struct sun_sas_port 	*tgt_port, *last_tgt_port;
8710652SHyon.Kim@Sun.COM 	struct ScsiEntryList	*scsi_info = NULL, *last_scsi_info = NULL;
8810652SHyon.Kim@Sun.COM 
8910652SHyon.Kim@Sun.COM 	tgt_port = port_ptr->first_attached_port;
9010652SHyon.Kim@Sun.COM 	while (tgt_port != NULL) {
9110652SHyon.Kim@Sun.COM 		/* Free target mapping data list first. */
9210652SHyon.Kim@Sun.COM 		scsi_info = tgt_port->scsiInfo;
9310652SHyon.Kim@Sun.COM 		while (scsi_info != NULL) {
9410652SHyon.Kim@Sun.COM 			last_scsi_info = scsi_info;
9510652SHyon.Kim@Sun.COM 			scsi_info = scsi_info->next;
9610652SHyon.Kim@Sun.COM 			free(last_scsi_info);
9710652SHyon.Kim@Sun.COM 		}
9810652SHyon.Kim@Sun.COM 		last_tgt_port = tgt_port;
9910652SHyon.Kim@Sun.COM 		tgt_port = tgt_port->next;
10010652SHyon.Kim@Sun.COM 		free(last_tgt_port->port_attributes.\
10110652SHyon.Kim@Sun.COM 		    PortSpecificAttribute.SASPort);
10210652SHyon.Kim@Sun.COM 		free(last_tgt_port);
10310652SHyon.Kim@Sun.COM 	}
10410652SHyon.Kim@Sun.COM 
10510652SHyon.Kim@Sun.COM 	port_ptr->first_attached_port = NULL;
10610652SHyon.Kim@Sun.COM 	port_ptr->port_attributes.PortSpecificAttribute.\
10710652SHyon.Kim@Sun.COM 	    SASPort->NumberofDiscoveredPorts = 0;
10810652SHyon.Kim@Sun.COM }
10910652SHyon.Kim@Sun.COM 
11010652SHyon.Kim@Sun.COM /*
11110652SHyon.Kim@Sun.COM  * Fill domainPortWWN.
11210652SHyon.Kim@Sun.COM  * should be called after completing discovered port discovery.
11310652SHyon.Kim@Sun.COM  */
11410652SHyon.Kim@Sun.COM void
fillDomainPortWWN(struct sun_sas_port * port_ptr)11510652SHyon.Kim@Sun.COM fillDomainPortWWN(struct sun_sas_port *port_ptr)
11610652SHyon.Kim@Sun.COM {
11710652SHyon.Kim@Sun.COM 	const char    ROUTINE[] = "fillDomainPortWWN";
11810652SHyon.Kim@Sun.COM 	struct sun_sas_port *disco_port_ptr;
11910652SHyon.Kim@Sun.COM 	struct phy_info *phy_ptr;
12010652SHyon.Kim@Sun.COM 	uint64_t    domainPort = 0;
12110652SHyon.Kim@Sun.COM 	struct ScsiEntryList	    *mapping_ptr;
12210652SHyon.Kim@Sun.COM 
12310652SHyon.Kim@Sun.COM 	for (disco_port_ptr = port_ptr->first_attached_port;
12410652SHyon.Kim@Sun.COM 	    disco_port_ptr != NULL; disco_port_ptr = disco_port_ptr->next) {
12510652SHyon.Kim@Sun.COM 		if (disco_port_ptr->port_attributes.PortType ==
12610652SHyon.Kim@Sun.COM 		    HBA_PORTTYPE_SASEXPANDER &&
12710652SHyon.Kim@Sun.COM 		    wwnConversion(disco_port_ptr->port_attributes.
12810652SHyon.Kim@Sun.COM 		    PortSpecificAttribute.SASPort->
12910652SHyon.Kim@Sun.COM 		    AttachedSASAddress.wwn) ==
13010652SHyon.Kim@Sun.COM 		    wwnConversion(port_ptr->port_attributes.
13110652SHyon.Kim@Sun.COM 		    PortSpecificAttribute.SASPort->
13210652SHyon.Kim@Sun.COM 		    LocalSASAddress.wwn)) {
13310652SHyon.Kim@Sun.COM 			(void) memcpy(&domainPort,
13410652SHyon.Kim@Sun.COM 			    disco_port_ptr->port_attributes.
13510652SHyon.Kim@Sun.COM 			    PortSpecificAttribute.
13610652SHyon.Kim@Sun.COM 			    SASPort->LocalSASAddress.wwn, 8);
13710652SHyon.Kim@Sun.COM 			break;
13810652SHyon.Kim@Sun.COM 		}
13910652SHyon.Kim@Sun.COM 	}
14010652SHyon.Kim@Sun.COM 
14110652SHyon.Kim@Sun.COM 	if (domainPort == 0) {
14210652SHyon.Kim@Sun.COM 		if (port_ptr->first_attached_port) {
14310652SHyon.Kim@Sun.COM 			/*
14410652SHyon.Kim@Sun.COM 			 * there is no expander device attached on an HBA port
14510652SHyon.Kim@Sun.COM 			 * domainPortWWN should not stay to 0 since multiple
14610652SHyon.Kim@Sun.COM 			 * hba ports can have the same LocalSASAddres within
14710652SHyon.Kim@Sun.COM 			 * the same HBA.
14810652SHyon.Kim@Sun.COM 			 * Set the SAS address of direct attached target.
14910652SHyon.Kim@Sun.COM 			 */
15010652SHyon.Kim@Sun.COM 			if (wwnConversion(port_ptr->port_attributes.
15110652SHyon.Kim@Sun.COM 			    PortSpecificAttribute.SASPort->
15210652SHyon.Kim@Sun.COM 			    LocalSASAddress.wwn) ==
15310652SHyon.Kim@Sun.COM 			    wwnConversion(port_ptr->first_attached_port->
15410652SHyon.Kim@Sun.COM 			    port_attributes.PortSpecificAttribute.
15510652SHyon.Kim@Sun.COM 			    SASPort->AttachedSASAddress.wwn)) {
15610652SHyon.Kim@Sun.COM 				(void) memcpy(&domainPort,
15710652SHyon.Kim@Sun.COM 				    port_ptr->first_attached_port->
15810652SHyon.Kim@Sun.COM 				    port_attributes.PortSpecificAttribute.
15910652SHyon.Kim@Sun.COM 				    SASPort->LocalSASAddress.wwn, 8);
16010652SHyon.Kim@Sun.COM 			} else {
16110652SHyon.Kim@Sun.COM 				/*
16210652SHyon.Kim@Sun.COM 				 * SAS address is not upstream connected.
16310652SHyon.Kim@Sun.COM 				 * domainPortWWN stays as 0.
16410652SHyon.Kim@Sun.COM 				 */
16510652SHyon.Kim@Sun.COM 				log(LOG_DEBUG, ROUTINE,
16610652SHyon.Kim@Sun.COM 				    "DomainPortWWN is not set. "
16710652SHyon.Kim@Sun.COM 				    "Device(s) are visible on the HBA port "
16810652SHyon.Kim@Sun.COM 				    "but there is no expander or directly "
16910652SHyon.Kim@Sun.COM 				    "attached port with matching upsteam "
17010652SHyon.Kim@Sun.COM 				    "attached SAS address for "
17110652SHyon.Kim@Sun.COM 				    "HBA port (Local SAS Address: %016llx).",
17210652SHyon.Kim@Sun.COM 				    wwnConversion(port_ptr->port_attributes.
17310652SHyon.Kim@Sun.COM 				    PortSpecificAttribute.
17410652SHyon.Kim@Sun.COM 				    SASPort->LocalSASAddress.wwn));
17510652SHyon.Kim@Sun.COM 				return;
17610652SHyon.Kim@Sun.COM 			}
17710652SHyon.Kim@Sun.COM 		} else {
17810652SHyon.Kim@Sun.COM 			/*
17910652SHyon.Kim@Sun.COM 			 * There existss an iport without properly configured
18010652SHyon.Kim@Sun.COM 			 * child smp ndoes or  child node or pathinfo.
18110652SHyon.Kim@Sun.COM 			 * domainPortWWN stays as 0.
18210652SHyon.Kim@Sun.COM 			 */
18310652SHyon.Kim@Sun.COM 			log(LOG_DEBUG, ROUTINE,
18410652SHyon.Kim@Sun.COM 			    "DomainPortWWN is not set.  No properly "
18510652SHyon.Kim@Sun.COM 			    "configured smp or directly attached port "
18610652SHyon.Kim@Sun.COM 			    "found on HBA port(Local SAS Address: %016llx).",
18710652SHyon.Kim@Sun.COM 			    wwnConversion(port_ptr->port_attributes.
18810652SHyon.Kim@Sun.COM 			    PortSpecificAttribute.
18910652SHyon.Kim@Sun.COM 			    SASPort->LocalSASAddress.wwn));
19010652SHyon.Kim@Sun.COM 			return;
19110652SHyon.Kim@Sun.COM 		}
19210652SHyon.Kim@Sun.COM 	}
19310652SHyon.Kim@Sun.COM 
19410652SHyon.Kim@Sun.COM 	/* fill up phy info */
19510652SHyon.Kim@Sun.COM 	for (phy_ptr = port_ptr->first_phy; phy_ptr != NULL;
19610652SHyon.Kim@Sun.COM 	    phy_ptr = phy_ptr->next) {
19710652SHyon.Kim@Sun.COM 		(void) memcpy(phy_ptr->phy.domainPortWWN.wwn, &domainPort, 8);
19810652SHyon.Kim@Sun.COM 	}
19910652SHyon.Kim@Sun.COM 
20010652SHyon.Kim@Sun.COM 	/* fill up target mapping */
20110652SHyon.Kim@Sun.COM 	for (disco_port_ptr = port_ptr->first_attached_port;
20210652SHyon.Kim@Sun.COM 	    disco_port_ptr != NULL; disco_port_ptr = disco_port_ptr->next) {
20310652SHyon.Kim@Sun.COM 		for (mapping_ptr = disco_port_ptr->scsiInfo;
20410652SHyon.Kim@Sun.COM 		    mapping_ptr != NULL;
20510652SHyon.Kim@Sun.COM 		    mapping_ptr = mapping_ptr->next) {
20610652SHyon.Kim@Sun.COM 			(void) memcpy(mapping_ptr->entry.PortLun.
20710652SHyon.Kim@Sun.COM 			    domainPortWWN.wwn, &domainPort, 8);
20810652SHyon.Kim@Sun.COM 		}
20910652SHyon.Kim@Sun.COM 	}
21010652SHyon.Kim@Sun.COM }
21110652SHyon.Kim@Sun.COM 
21210652SHyon.Kim@Sun.COM /*
21310652SHyon.Kim@Sun.COM  * Finds attached device(target) from devinfo node.
21410652SHyon.Kim@Sun.COM  */
21510652SHyon.Kim@Sun.COM static HBA_STATUS
get_attached_devices_info(di_node_t node,struct sun_sas_port * port_ptr)21610652SHyon.Kim@Sun.COM get_attached_devices_info(di_node_t node, struct sun_sas_port *port_ptr)
21710652SHyon.Kim@Sun.COM {
21810652SHyon.Kim@Sun.COM 	const char		    ROUTINE[] = "get_attached_devices_info";
21910652SHyon.Kim@Sun.COM 	char			    *propStringData = NULL;
22010652SHyon.Kim@Sun.COM 	int			    *propIntData = NULL;
22110652SHyon.Kim@Sun.COM 	int64_t			    *propInt64Data = NULL;
22210652SHyon.Kim@Sun.COM 	scsi_lun_t		    samLun;
223*11243SHyon.Kim@Sun.COM 	ddi_devid_t		    devid;
224*11243SHyon.Kim@Sun.COM 	char			    *guidStr;
22510652SHyon.Kim@Sun.COM 	char			    *unit_address;
22610652SHyon.Kim@Sun.COM 	char			    *charptr;
22710652SHyon.Kim@Sun.COM 	char			    *devpath, link[MAXNAMELEN];
22810652SHyon.Kim@Sun.COM 	char			    fullpath[MAXPATHLEN+1];
22910652SHyon.Kim@Sun.COM 	char			    minorname[MAXNAMELEN+1];
23010652SHyon.Kim@Sun.COM 	struct ScsiEntryList	    *mapping_ptr;
23110652SHyon.Kim@Sun.COM 	HBA_WWN			    SASAddress, AttachedSASAddress;
23210652SHyon.Kim@Sun.COM 	struct sun_sas_port	    *disco_port_ptr;
23310652SHyon.Kim@Sun.COM 	uint_t			    state = 0;
234*11243SHyon.Kim@Sun.COM 	int			    portfound, rval, size;
23510652SHyon.Kim@Sun.COM 	int			    port_state = HBA_PORTSTATE_ONLINE;
23610652SHyon.Kim@Sun.COM 	uint64_t		    tmpAddr;
23710652SHyon.Kim@Sun.COM 
23810652SHyon.Kim@Sun.COM 	if (port_ptr == NULL) {
23910652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE, "NULL port_ptr argument");
24010652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
24110652SHyon.Kim@Sun.COM 	}
24210652SHyon.Kim@Sun.COM 
24310652SHyon.Kim@Sun.COM 	if ((devpath = di_devfs_path(node)) == NULL) {
24410652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
24510652SHyon.Kim@Sun.COM 		    "Device in device tree has no path. Skipping.");
24610652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
24710652SHyon.Kim@Sun.COM 	}
24810652SHyon.Kim@Sun.COM 
24910652SHyon.Kim@Sun.COM 	if ((di_instance(node) == -1) || di_retired(node)) {
25010652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
25110652SHyon.Kim@Sun.COM 		    "dev node (%s) returned instance of -1 or is retired. "
25210652SHyon.Kim@Sun.COM 		    " Skipping.", devpath);
25310652SHyon.Kim@Sun.COM 		di_devfs_path_free(devpath);
25410652SHyon.Kim@Sun.COM 		return (HBA_STATUS_OK);
25510652SHyon.Kim@Sun.COM 	}
25610652SHyon.Kim@Sun.COM 	state = di_state(node);
25710652SHyon.Kim@Sun.COM 	/* when node is not attached and online, set the state to offline. */
25810652SHyon.Kim@Sun.COM 	if (((state & DI_DRIVER_DETACHED) == DI_DRIVER_DETACHED) ||
25910652SHyon.Kim@Sun.COM 	    ((state & DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE)) {
26010652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
26110652SHyon.Kim@Sun.COM 		    "dev node (%s) is either OFFLINE or DETACHED",
26210652SHyon.Kim@Sun.COM 		    devpath);
26310652SHyon.Kim@Sun.COM 		port_state = HBA_PORTSTATE_OFFLINE;
26410652SHyon.Kim@Sun.COM 	}
26510652SHyon.Kim@Sun.COM 
26610652SHyon.Kim@Sun.COM 	/* add the "/devices" in the begining at the end */
26710652SHyon.Kim@Sun.COM 	(void) snprintf(fullpath, sizeof (fullpath), "%s%s",
26810652SHyon.Kim@Sun.COM 	    DEVICES_DIR, devpath);
26910652SHyon.Kim@Sun.COM 
27010652SHyon.Kim@Sun.COM 	(void) memset(&SASAddress, 0, sizeof (SASAddress));
27110652SHyon.Kim@Sun.COM 	if ((unit_address = di_bus_addr(node)) != NULL) {
27210652SHyon.Kim@Sun.COM 		if ((charptr = strchr(unit_address, ',')) != NULL) {
27310652SHyon.Kim@Sun.COM 			*charptr = '\0';
27410652SHyon.Kim@Sun.COM 		}
27510652SHyon.Kim@Sun.COM 		for (charptr = unit_address; *charptr != '\0'; charptr++) {
27610652SHyon.Kim@Sun.COM 			if (isxdigit(*charptr)) {
27710652SHyon.Kim@Sun.COM 				break;
27810652SHyon.Kim@Sun.COM 			}
27910652SHyon.Kim@Sun.COM 		}
28010652SHyon.Kim@Sun.COM 		if (*charptr != '\0') {
28110652SHyon.Kim@Sun.COM 			tmpAddr = htonll(strtoll(charptr, NULL, 16));
28210652SHyon.Kim@Sun.COM 			(void) memcpy(&SASAddress.wwn[0], &tmpAddr, 8);
28310652SHyon.Kim@Sun.COM 		} else {
28410652SHyon.Kim@Sun.COM 			log(LOG_DEBUG, ROUTINE,
28510652SHyon.Kim@Sun.COM 			    "No proper target port info on unit address of %s",
28610652SHyon.Kim@Sun.COM 			    fullpath);
28710652SHyon.Kim@Sun.COM 			di_devfs_path_free(devpath);
28810652SHyon.Kim@Sun.COM 			return (HBA_STATUS_ERROR);
28910652SHyon.Kim@Sun.COM 		}
29010652SHyon.Kim@Sun.COM 	} else {
29110652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
29210652SHyon.Kim@Sun.COM 		    "Fail to get unit address of %s.",
29310652SHyon.Kim@Sun.COM 		    fullpath);
29410652SHyon.Kim@Sun.COM 		di_devfs_path_free(devpath);
29510652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
29610652SHyon.Kim@Sun.COM 	}
29710652SHyon.Kim@Sun.COM 
29810652SHyon.Kim@Sun.COM 	(void) memset(&AttachedSASAddress, 0, sizeof (AttachedSASAddress));
29910652SHyon.Kim@Sun.COM 	if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "attached-port",
30010652SHyon.Kim@Sun.COM 	    &propStringData) != -1) {
30110652SHyon.Kim@Sun.COM 		for (charptr = propStringData; *charptr != '\0'; charptr++) {
30210652SHyon.Kim@Sun.COM 			if (isxdigit(*charptr)) {
30310652SHyon.Kim@Sun.COM 				break;
30410652SHyon.Kim@Sun.COM 			}
30510652SHyon.Kim@Sun.COM 		}
30610652SHyon.Kim@Sun.COM 		if (*charptr != '\0') {
30710652SHyon.Kim@Sun.COM 			tmpAddr = htonll(strtoll(charptr, NULL, 16));
30810652SHyon.Kim@Sun.COM 			(void) memcpy(AttachedSASAddress.wwn, &tmpAddr, 8);
30910652SHyon.Kim@Sun.COM 			/* check the attached address of hba port. */
31010652SHyon.Kim@Sun.COM 			if (memcmp(port_ptr->port_attributes.
31110652SHyon.Kim@Sun.COM 			    PortSpecificAttribute.SASPort->LocalSASAddress.wwn,
31210652SHyon.Kim@Sun.COM 			    &tmpAddr, 8) == 0) {
31310652SHyon.Kim@Sun.COM 				/*
31410652SHyon.Kim@Sun.COM 				 * When attached-port is set from iport
31510652SHyon.Kim@Sun.COM 				 * attached-port prop, we do the cross check
31610652SHyon.Kim@Sun.COM 				 * with device's own SAS address.
31710652SHyon.Kim@Sun.COM 				 *
31810652SHyon.Kim@Sun.COM 				 * If not set, we store device's own SAS
31910652SHyon.Kim@Sun.COM 				 * address to iport attached SAS address.
32010652SHyon.Kim@Sun.COM 				 */
32110652SHyon.Kim@Sun.COM 				if (wwnConversion(port_ptr->port_attributes.
32210652SHyon.Kim@Sun.COM 				    PortSpecificAttribute.SASPort->
32310652SHyon.Kim@Sun.COM 				    AttachedSASAddress.wwn)) {
32410652SHyon.Kim@Sun.COM 					/* verify the Attaached SAS Addr. */
32510652SHyon.Kim@Sun.COM 					if (memcmp(port_ptr->port_attributes.
32610652SHyon.Kim@Sun.COM 					    PortSpecificAttribute.SASPort->
32710652SHyon.Kim@Sun.COM 					    AttachedSASAddress.wwn,
32810652SHyon.Kim@Sun.COM 					    SASAddress.wwn, 8) != 0) {
32910652SHyon.Kim@Sun.COM 				/* indentation move begin. */
33010652SHyon.Kim@Sun.COM 				log(LOG_DEBUG, ROUTINE,
33110652SHyon.Kim@Sun.COM 				    "iport attached-port(%016llx) do not"
33210652SHyon.Kim@Sun.COM 				    " match with level 1 Local"
33310652SHyon.Kim@Sun.COM 				    " SAS address(%016llx).",
33410652SHyon.Kim@Sun.COM 				    wwnConversion(port_ptr->port_attributes.
33510652SHyon.Kim@Sun.COM 				    PortSpecificAttribute.
33610652SHyon.Kim@Sun.COM 				    SASPort->AttachedSASAddress.wwn),
33710652SHyon.Kim@Sun.COM 				    wwnConversion(SASAddress.wwn));
33810652SHyon.Kim@Sun.COM 				di_devfs_path_free(devpath);
33910652SHyon.Kim@Sun.COM 				free_attached_port(port_ptr);
34010652SHyon.Kim@Sun.COM 				return (HBA_STATUS_ERROR);
34110652SHyon.Kim@Sun.COM 				/* indentation move ends. */
34210652SHyon.Kim@Sun.COM 					}
34310652SHyon.Kim@Sun.COM 				} else {
34410652SHyon.Kim@Sun.COM 					(void) memcpy(port_ptr->port_attributes.
34510652SHyon.Kim@Sun.COM 					    PortSpecificAttribute.
34610652SHyon.Kim@Sun.COM 					    SASPort->AttachedSASAddress.wwn,
34710652SHyon.Kim@Sun.COM 					    &SASAddress.wwn[0], 8);
34810652SHyon.Kim@Sun.COM 				}
34910652SHyon.Kim@Sun.COM 			}
35010652SHyon.Kim@Sun.COM 		} else {
35110652SHyon.Kim@Sun.COM 			log(LOG_DEBUG, ROUTINE,
35210652SHyon.Kim@Sun.COM 			    "No proper attached SAS address value on device %s",
35310652SHyon.Kim@Sun.COM 			    fullpath);
35410652SHyon.Kim@Sun.COM 			di_devfs_path_free(devpath);
35510652SHyon.Kim@Sun.COM 			free_attached_port(port_ptr);
35610652SHyon.Kim@Sun.COM 			return (HBA_STATUS_ERROR);
35710652SHyon.Kim@Sun.COM 		}
35810652SHyon.Kim@Sun.COM 	} else {
35910652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
36010652SHyon.Kim@Sun.COM 		    "Property AttachedSASAddress not found for device \"%s\"",
36110652SHyon.Kim@Sun.COM 		    fullpath);
36210652SHyon.Kim@Sun.COM 		di_devfs_path_free(devpath);
36310652SHyon.Kim@Sun.COM 		free_attached_port(port_ptr);
36410652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
36510652SHyon.Kim@Sun.COM 	}
36610652SHyon.Kim@Sun.COM 
36710652SHyon.Kim@Sun.COM 	/*
36810652SHyon.Kim@Sun.COM 	 * walk the disco list to make sure that there isn't a matching
36910652SHyon.Kim@Sun.COM 	 * port and node wwn or a matching device path
37010652SHyon.Kim@Sun.COM 	 */
37110652SHyon.Kim@Sun.COM 	portfound = 0;
37210652SHyon.Kim@Sun.COM 	for (disco_port_ptr = port_ptr->first_attached_port;
37310652SHyon.Kim@Sun.COM 	    disco_port_ptr != NULL;
37410652SHyon.Kim@Sun.COM 	    disco_port_ptr = disco_port_ptr->next) {
37510652SHyon.Kim@Sun.COM 		if ((disco_port_ptr->port_attributes.PortState !=
37610652SHyon.Kim@Sun.COM 		    HBA_PORTSTATE_ERROR) && (memcmp(disco_port_ptr->
37710652SHyon.Kim@Sun.COM 		    port_attributes.PortSpecificAttribute.
37810652SHyon.Kim@Sun.COM 		    SASPort->LocalSASAddress.wwn, SASAddress.wwn, 8) == 0)) {
37910652SHyon.Kim@Sun.COM 			/*
38010652SHyon.Kim@Sun.COM 			 * found matching disco_port
38110652SHyon.Kim@Sun.COM 			 * look for matching device path
38210652SHyon.Kim@Sun.COM 			 */
38310652SHyon.Kim@Sun.COM 			portfound = 1;
38410652SHyon.Kim@Sun.COM 			for (mapping_ptr = disco_port_ptr->scsiInfo;
38510652SHyon.Kim@Sun.COM 			    mapping_ptr != NULL;
38610652SHyon.Kim@Sun.COM 			    mapping_ptr = mapping_ptr->next) {
38710652SHyon.Kim@Sun.COM 				if (strstr(mapping_ptr-> entry.ScsiId.
38810652SHyon.Kim@Sun.COM 				    OSDeviceName, devpath) != 0) {
38910652SHyon.Kim@Sun.COM 					log(LOG_DEBUG, ROUTINE,
39010652SHyon.Kim@Sun.COM 					    "Found an already discovered "
39110652SHyon.Kim@Sun.COM 					    "device %s.", fullpath);
39210652SHyon.Kim@Sun.COM 					di_devfs_path_free(devpath);
39310652SHyon.Kim@Sun.COM 					return (HBA_STATUS_OK);
39410652SHyon.Kim@Sun.COM 				}
39510652SHyon.Kim@Sun.COM 			}
39610652SHyon.Kim@Sun.COM 			if (portfound == 1) {
39710652SHyon.Kim@Sun.COM 				break;
39810652SHyon.Kim@Sun.COM 			}
39910652SHyon.Kim@Sun.COM 		}
40010652SHyon.Kim@Sun.COM 	}
40110652SHyon.Kim@Sun.COM 
40210652SHyon.Kim@Sun.COM 	if (portfound == 0) {
40310652SHyon.Kim@Sun.COM 		/*
40410652SHyon.Kim@Sun.COM 		 * there are no matching SAS address.
40510652SHyon.Kim@Sun.COM 		 * this must be a new device
40610652SHyon.Kim@Sun.COM 		 */
40710652SHyon.Kim@Sun.COM 		if ((disco_port_ptr = (struct sun_sas_port *)calloc(1,
40810652SHyon.Kim@Sun.COM 		    sizeof (struct sun_sas_port))) == NULL)  {
40910652SHyon.Kim@Sun.COM 			OUT_OF_MEMORY(ROUTINE);
41010652SHyon.Kim@Sun.COM 			di_devfs_path_free(devpath);
41110652SHyon.Kim@Sun.COM 			free_attached_port(port_ptr);
41210652SHyon.Kim@Sun.COM 			return (HBA_STATUS_ERROR);
41310652SHyon.Kim@Sun.COM 		}
41410652SHyon.Kim@Sun.COM 
41510652SHyon.Kim@Sun.COM 		if ((disco_port_ptr->port_attributes.PortSpecificAttribute.\
41610652SHyon.Kim@Sun.COM 		    SASPort = (struct SMHBA_SAS_Port *)calloc(1,
41710652SHyon.Kim@Sun.COM 		    sizeof (struct SMHBA_SAS_Port))) == NULL) {
41810652SHyon.Kim@Sun.COM 			OUT_OF_MEMORY("add_hba_port_info");
41910652SHyon.Kim@Sun.COM 			di_devfs_path_free(devpath);
42010652SHyon.Kim@Sun.COM 			free_attached_port(port_ptr);
42110652SHyon.Kim@Sun.COM 			return (HBA_STATUS_ERROR);
42210652SHyon.Kim@Sun.COM 		}
42310652SHyon.Kim@Sun.COM 
42410652SHyon.Kim@Sun.COM 		(void) memcpy(disco_port_ptr->port_attributes.
42510652SHyon.Kim@Sun.COM 		    PortSpecificAttribute.SASPort->LocalSASAddress.wwn,
42610652SHyon.Kim@Sun.COM 		    SASAddress.wwn, 8);
42710652SHyon.Kim@Sun.COM 		(void) memcpy(disco_port_ptr->port_attributes.
42810652SHyon.Kim@Sun.COM 		    PortSpecificAttribute.SASPort->AttachedSASAddress.wwn,
42910652SHyon.Kim@Sun.COM 		    AttachedSASAddress.wwn, 8);
43010652SHyon.Kim@Sun.COM 
43110652SHyon.Kim@Sun.COM 		/* Default to unknown until we figure out otherwise */
43210652SHyon.Kim@Sun.COM 		rval = di_prop_lookup_strings(DDI_DEV_T_ANY, node,
43310652SHyon.Kim@Sun.COM 		    "variant", &propStringData);
43410652SHyon.Kim@Sun.COM 		if (rval < 0) {
43510652SHyon.Kim@Sun.COM 			/* check if it is SMP target */
43610652SHyon.Kim@Sun.COM 			charptr = di_driver_name(node);
43710652SHyon.Kim@Sun.COM 			if (charptr != NULL && (strncmp(charptr, "smp",
43810652SHyon.Kim@Sun.COM 			    strlen(charptr)) == 0)) {
43910652SHyon.Kim@Sun.COM 				disco_port_ptr->port_attributes.PortType =
44010652SHyon.Kim@Sun.COM 				    HBA_PORTTYPE_SASEXPANDER;
44110652SHyon.Kim@Sun.COM 				disco_port_ptr->port_attributes.
44210652SHyon.Kim@Sun.COM 				    PortSpecificAttribute.
44310652SHyon.Kim@Sun.COM 				    SASPort->PortProtocol =
44410652SHyon.Kim@Sun.COM 				    HBA_SASPORTPROTOCOL_SMP;
44510652SHyon.Kim@Sun.COM 				if (lookupSMPLink(devpath, (char *)link) ==
44610652SHyon.Kim@Sun.COM 				    HBA_STATUS_OK) {
44710652SHyon.Kim@Sun.COM 		/* indentation changed here. */
44810652SHyon.Kim@Sun.COM 		(void) strlcpy(disco_port_ptr->port_attributes.
44910652SHyon.Kim@Sun.COM 		    OSDeviceName, link,
45010652SHyon.Kim@Sun.COM 		    sizeof (disco_port_ptr->port_attributes.OSDeviceName));
45110652SHyon.Kim@Sun.COM 		/* indentation change ends here. */
45210652SHyon.Kim@Sun.COM 				} else {
45310652SHyon.Kim@Sun.COM 		/* indentation changed here. */
45410652SHyon.Kim@Sun.COM 		get_minor(devpath, minorname);
45510652SHyon.Kim@Sun.COM 		(void) snprintf(fullpath, sizeof (fullpath), "%s%s%s",
45610652SHyon.Kim@Sun.COM 		    DEVICES_DIR, devpath, minorname);
45710652SHyon.Kim@Sun.COM 		(void) strlcpy(disco_port_ptr->port_attributes.
45810652SHyon.Kim@Sun.COM 		    OSDeviceName, fullpath,
45910652SHyon.Kim@Sun.COM 		    sizeof (disco_port_ptr->port_attributes.OSDeviceName));
46010652SHyon.Kim@Sun.COM 		/* indentation change ends here. */
46110652SHyon.Kim@Sun.COM 				}
46210652SHyon.Kim@Sun.COM 			} else {
46310652SHyon.Kim@Sun.COM 				disco_port_ptr->port_attributes.PortType =
46410652SHyon.Kim@Sun.COM 				    HBA_PORTTYPE_SASDEVICE;
46510652SHyon.Kim@Sun.COM 				disco_port_ptr->port_attributes.\
46610652SHyon.Kim@Sun.COM 				    PortSpecificAttribute.\
46710652SHyon.Kim@Sun.COM 				    SASPort->PortProtocol =
46810652SHyon.Kim@Sun.COM 				    HBA_SASPORTPROTOCOL_SSP;
46910652SHyon.Kim@Sun.COM 			}
47010652SHyon.Kim@Sun.COM 		} else {
47110652SHyon.Kim@Sun.COM 			if ((strcmp(propStringData, "sata") == 0) ||
47210652SHyon.Kim@Sun.COM 			    (strcmp(propStringData, "atapi") == 0)) {
47310652SHyon.Kim@Sun.COM 				disco_port_ptr->port_attributes.PortType =
47410652SHyon.Kim@Sun.COM 				    HBA_PORTTYPE_SATADEVICE;
47510652SHyon.Kim@Sun.COM 				disco_port_ptr->port_attributes.\
47610652SHyon.Kim@Sun.COM 				    PortSpecificAttribute.SASPort->PortProtocol
47710652SHyon.Kim@Sun.COM 				    = HBA_SASPORTPROTOCOL_SATA;
47810652SHyon.Kim@Sun.COM 			} else {
47910652SHyon.Kim@Sun.COM 				log(LOG_DEBUG, ROUTINE,
48010652SHyon.Kim@Sun.COM 				    "Unexpected variant prop value %s found on",
48110652SHyon.Kim@Sun.COM 				    " device %s", propStringData, fullpath);
48210652SHyon.Kim@Sun.COM 				/*
48310652SHyon.Kim@Sun.COM 				 * Port type will be 0
48410652SHyon.Kim@Sun.COM 				 * which is not valid type.
48510652SHyon.Kim@Sun.COM 				 */
48610652SHyon.Kim@Sun.COM 			}
48710652SHyon.Kim@Sun.COM 		}
48810652SHyon.Kim@Sun.COM 
48910652SHyon.Kim@Sun.COM 		/* SMP device was handled already */
49010652SHyon.Kim@Sun.COM 		if (disco_port_ptr->port_attributes.OSDeviceName[0] == '\0') {
49110652SHyon.Kim@Sun.COM 		/* indentation change due to ctysle check on sizeof. */
49210652SHyon.Kim@Sun.COM 		size = sizeof (disco_port_ptr->port_attributes.OSDeviceName);
49310652SHyon.Kim@Sun.COM 			(void) strlcpy(disco_port_ptr->port_attributes.
49410652SHyon.Kim@Sun.COM 			    OSDeviceName, fullpath, size);
49510652SHyon.Kim@Sun.COM 		}
49610652SHyon.Kim@Sun.COM 
49710652SHyon.Kim@Sun.COM 		/* add new discovered port into the list */
49810652SHyon.Kim@Sun.COM 
49910652SHyon.Kim@Sun.COM 		if (port_ptr->first_attached_port == NULL) {
50010652SHyon.Kim@Sun.COM 			port_ptr->first_attached_port = disco_port_ptr;
50110652SHyon.Kim@Sun.COM 			disco_port_ptr->index = 0;
50210652SHyon.Kim@Sun.COM 			port_ptr->port_attributes.PortSpecificAttribute.\
50310652SHyon.Kim@Sun.COM 			    SASPort->NumberofDiscoveredPorts = 1;
50410652SHyon.Kim@Sun.COM 		} else {
50510652SHyon.Kim@Sun.COM 			disco_port_ptr->next = port_ptr->first_attached_port;
50610652SHyon.Kim@Sun.COM 			port_ptr->first_attached_port = disco_port_ptr;
50710652SHyon.Kim@Sun.COM 			disco_port_ptr->index = port_ptr->port_attributes.\
50810652SHyon.Kim@Sun.COM 			    PortSpecificAttribute.\
50910652SHyon.Kim@Sun.COM 			    SASPort->NumberofDiscoveredPorts;
51010652SHyon.Kim@Sun.COM 			port_ptr->port_attributes.PortSpecificAttribute.\
51110652SHyon.Kim@Sun.COM 			    SASPort->NumberofDiscoveredPorts++;
51210652SHyon.Kim@Sun.COM 		}
51310652SHyon.Kim@Sun.COM 		disco_port_ptr->port_attributes.PortState = port_state;
51410652SHyon.Kim@Sun.COM 	}
51510652SHyon.Kim@Sun.COM 
51610652SHyon.Kim@Sun.COM 	if (disco_port_ptr->port_attributes.PortType ==
51710652SHyon.Kim@Sun.COM 	    HBA_PORTTYPE_SASEXPANDER) {
51810652SHyon.Kim@Sun.COM 	    /* No mapping data for expander device.  return ok here. */
51910652SHyon.Kim@Sun.COM 		di_devfs_path_free(devpath);
52010652SHyon.Kim@Sun.COM 		return (HBA_STATUS_OK);
52110652SHyon.Kim@Sun.COM 	}
52210652SHyon.Kim@Sun.COM 
52310652SHyon.Kim@Sun.COM 	if ((mapping_ptr = (struct ScsiEntryList *)calloc
52410652SHyon.Kim@Sun.COM 		    (1, sizeof (struct ScsiEntryList))) == NULL) {
52510652SHyon.Kim@Sun.COM 		OUT_OF_MEMORY(ROUTINE);
52610652SHyon.Kim@Sun.COM 		di_devfs_path_free(devpath);
52710652SHyon.Kim@Sun.COM 		free_attached_port(port_ptr);
52810652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
52910652SHyon.Kim@Sun.COM 	}
53010652SHyon.Kim@Sun.COM 
53110652SHyon.Kim@Sun.COM 	if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "lun",
53210652SHyon.Kim@Sun.COM 	    &propIntData) != -1) {
53310652SHyon.Kim@Sun.COM 		mapping_ptr->entry.ScsiId.ScsiOSLun = *propIntData;
53410652SHyon.Kim@Sun.COM 	} else {
53510652SHyon.Kim@Sun.COM 		if ((charptr = strchr(unit_address, ',')) != NULL) {
53610652SHyon.Kim@Sun.COM 			charptr++;
53710652SHyon.Kim@Sun.COM 			mapping_ptr->entry.ScsiId.ScsiOSLun =
53810652SHyon.Kim@Sun.COM 			    strtoull(charptr, NULL, 10);
53910652SHyon.Kim@Sun.COM 		} else {
54010652SHyon.Kim@Sun.COM 			log(LOG_DEBUG, ROUTINE,
54110652SHyon.Kim@Sun.COM 			    "Failed to get LUN from the unit address of device "
54210652SHyon.Kim@Sun.COM 			    " %s.", fullpath);
54310652SHyon.Kim@Sun.COM 			di_devfs_path_free(devpath);
54410652SHyon.Kim@Sun.COM 			free_attached_port(port_ptr);
54510652SHyon.Kim@Sun.COM 			return (HBA_STATUS_ERROR);
54610652SHyon.Kim@Sun.COM 		}
54710652SHyon.Kim@Sun.COM 	}
54810652SHyon.Kim@Sun.COM 
54910652SHyon.Kim@Sun.COM 	/* get TargetLun(SAM-LUN). */
55010652SHyon.Kim@Sun.COM 	if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, "lun64",
55110652SHyon.Kim@Sun.COM 	    &propInt64Data) != -1) {
55210652SHyon.Kim@Sun.COM 		samLun = scsi_lun64_to_lun(*propInt64Data);
55310652SHyon.Kim@Sun.COM 		(void) memcpy(&mapping_ptr->entry.PortLun.TargetLun,
55410652SHyon.Kim@Sun.COM 		    &samLun, 8);
55510652SHyon.Kim@Sun.COM 	} else {
55610652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, "get_attached_devices_info",
55710652SHyon.Kim@Sun.COM 		    "No lun64 prop found on device %s.", fullpath);
55810652SHyon.Kim@Sun.COM 		di_devfs_path_free(devpath);
55910652SHyon.Kim@Sun.COM 		free_attached_port(port_ptr);
56010652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
56110652SHyon.Kim@Sun.COM 	}
56210652SHyon.Kim@Sun.COM 
56310652SHyon.Kim@Sun.COM 	if (di_prop_lookup_ints(DDI_DEV_T_ANY, node,
56410652SHyon.Kim@Sun.COM 	    "target", &propIntData) != -1) {
56510652SHyon.Kim@Sun.COM 		mapping_ptr->entry.ScsiId.ScsiTargetNumber = *propIntData;
56610652SHyon.Kim@Sun.COM 	} else {
56710652SHyon.Kim@Sun.COM 		mapping_ptr->entry.ScsiId.ScsiTargetNumber = di_instance(node);
56810652SHyon.Kim@Sun.COM 	}
56910652SHyon.Kim@Sun.COM 
57010652SHyon.Kim@Sun.COM 	/* get ScsiBusNumber */
57110652SHyon.Kim@Sun.COM 	mapping_ptr->entry.ScsiId.ScsiBusNumber = port_ptr->cntlNumber;
57210652SHyon.Kim@Sun.COM 
57310652SHyon.Kim@Sun.COM 	(void) memcpy(mapping_ptr->entry.PortLun.PortWWN.wwn,
57410652SHyon.Kim@Sun.COM 	    SASAddress.wwn, 8);
57510652SHyon.Kim@Sun.COM 
57610652SHyon.Kim@Sun.COM 	/* Store the devices path for now.  We'll convert to /dev later */
57710652SHyon.Kim@Sun.COM 	get_minor(devpath, minorname);
57810652SHyon.Kim@Sun.COM 	(void) snprintf(mapping_ptr->entry.ScsiId.OSDeviceName,
57910652SHyon.Kim@Sun.COM 	    sizeof (mapping_ptr->entry.ScsiId.OSDeviceName),
58010652SHyon.Kim@Sun.COM 	    "%s%s%s", DEVICES_DIR, devpath, minorname);
58110652SHyon.Kim@Sun.COM 
582*11243SHyon.Kim@Sun.COM 	/* reset errno to 0 */
583*11243SHyon.Kim@Sun.COM 	errno = 0;
584*11243SHyon.Kim@Sun.COM 	if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "devid",
585*11243SHyon.Kim@Sun.COM 	    &propStringData) != -1) {
586*11243SHyon.Kim@Sun.COM 		if (devid_str_decode(propStringData, &devid, NULL) != -1) {
587*11243SHyon.Kim@Sun.COM 			guidStr = devid_to_guid(devid);
588*11243SHyon.Kim@Sun.COM 			if (guidStr != NULL) {
589*11243SHyon.Kim@Sun.COM 				(void) strlcpy(mapping_ptr->entry.LUID.buffer,
590*11243SHyon.Kim@Sun.COM 				    guidStr, 256);
591*11243SHyon.Kim@Sun.COM 				devid_free_guid(guidStr);
592*11243SHyon.Kim@Sun.COM 			} else {
593*11243SHyon.Kim@Sun.COM 				/*
594*11243SHyon.Kim@Sun.COM 				 * Note:
595*11243SHyon.Kim@Sun.COM 				 * if logical unit associated page 83 id
596*11243SHyon.Kim@Sun.COM 				 * descriptor is not avaialble for the device
597*11243SHyon.Kim@Sun.COM 				 * devid_to_guid returns NULl with errno 0.
598*11243SHyon.Kim@Sun.COM 				 */
599*11243SHyon.Kim@Sun.COM 				log(LOG_DEBUG, ROUTINE,
600*11243SHyon.Kim@Sun.COM 				    "failed to get devid guid on (%s) : %s",
601*11243SHyon.Kim@Sun.COM 				    devpath, strerror(errno));
602*11243SHyon.Kim@Sun.COM 			}
603*11243SHyon.Kim@Sun.COM 		} else {
604*11243SHyon.Kim@Sun.COM 			/*
605*11243SHyon.Kim@Sun.COM 			 * device may not support proper page 83 id descriptor.
606*11243SHyon.Kim@Sun.COM 			 * leave LUID attribute to NULL and continue.
607*11243SHyon.Kim@Sun.COM 			 */
608*11243SHyon.Kim@Sun.COM 			log(LOG_DEBUG, ROUTINE,
609*11243SHyon.Kim@Sun.COM 			    "failed to decode devid prop on (%s) : %s",
610*11243SHyon.Kim@Sun.COM 			    devpath, strerror(errno));
611*11243SHyon.Kim@Sun.COM 		}
61210652SHyon.Kim@Sun.COM 	} else {
613*11243SHyon.Kim@Sun.COM 		/* leave LUID attribute to NULL and continue. */
614*11243SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
615*11243SHyon.Kim@Sun.COM 		    "failed to get devid prop on (%s) : %s",
616*11243SHyon.Kim@Sun.COM 		    devpath, strerror(errno));
61710652SHyon.Kim@Sun.COM 	}
61810652SHyon.Kim@Sun.COM 
61910652SHyon.Kim@Sun.COM 	if (disco_port_ptr->scsiInfo == NULL) {
62010652SHyon.Kim@Sun.COM 		disco_port_ptr->scsiInfo = mapping_ptr;
62110652SHyon.Kim@Sun.COM 	} else {
62210652SHyon.Kim@Sun.COM 		mapping_ptr->next = disco_port_ptr->scsiInfo;
62310652SHyon.Kim@Sun.COM 		disco_port_ptr->scsiInfo = mapping_ptr;
62410652SHyon.Kim@Sun.COM 	}
62510652SHyon.Kim@Sun.COM 
62610652SHyon.Kim@Sun.COM 	di_devfs_path_free(devpath);
62710652SHyon.Kim@Sun.COM 
62810652SHyon.Kim@Sun.COM 	return (HBA_STATUS_OK);
62910652SHyon.Kim@Sun.COM }
63010652SHyon.Kim@Sun.COM 
63110652SHyon.Kim@Sun.COM /*
63210652SHyon.Kim@Sun.COM  * Finds attached device(target) from pathinfo node.
63310652SHyon.Kim@Sun.COM  */
63410652SHyon.Kim@Sun.COM static HBA_STATUS
get_attached_paths_info(di_path_t path,struct sun_sas_port * port_ptr)63510652SHyon.Kim@Sun.COM get_attached_paths_info(di_path_t path, struct sun_sas_port *port_ptr)
63610652SHyon.Kim@Sun.COM {
63710652SHyon.Kim@Sun.COM 	char			    ROUTINE[] = "get_attached_paths_info";
63810652SHyon.Kim@Sun.COM 	char			    *propStringData = NULL;
63910652SHyon.Kim@Sun.COM 	int			    *propIntData = NULL;
64010652SHyon.Kim@Sun.COM 	int64_t			    *propInt64Data = NULL;
64110652SHyon.Kim@Sun.COM 	scsi_lun_t		    samLun;
642*11243SHyon.Kim@Sun.COM 	ddi_devid_t		    devid;
643*11243SHyon.Kim@Sun.COM 	char			    *guidStr;
64410652SHyon.Kim@Sun.COM 	char			    *unit_address;
64510652SHyon.Kim@Sun.COM 	char			    *charptr;
64610652SHyon.Kim@Sun.COM 	char			    *clientdevpath = NULL;
64710652SHyon.Kim@Sun.COM 	char			    *pathdevpath = NULL;
64810652SHyon.Kim@Sun.COM 	char			    fullpath[MAXPATHLEN+1];
64910652SHyon.Kim@Sun.COM 	char			    minorname[MAXNAMELEN+1];
65010652SHyon.Kim@Sun.COM 	struct ScsiEntryList	    *mapping_ptr;
65110652SHyon.Kim@Sun.COM 	HBA_WWN			    SASAddress, AttachedSASAddress;
65210652SHyon.Kim@Sun.COM 	struct sun_sas_port	    *disco_port_ptr;
65310652SHyon.Kim@Sun.COM 	di_path_state_t		    state = 0;
65410652SHyon.Kim@Sun.COM 	di_node_t		    clientnode;
65510652SHyon.Kim@Sun.COM 	int			    portfound, size;
65610652SHyon.Kim@Sun.COM 	int			    port_state = HBA_PORTSTATE_ONLINE;
65710652SHyon.Kim@Sun.COM 	uint64_t		    tmpAddr;
65810652SHyon.Kim@Sun.COM 
65910652SHyon.Kim@Sun.COM 	if (port_ptr == NULL) {
66010652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE, "NULL port_ptr argument");
66110652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
66210652SHyon.Kim@Sun.COM 	}
66310652SHyon.Kim@Sun.COM 
66410652SHyon.Kim@Sun.COM 	/* if not null, free before return. */
66510652SHyon.Kim@Sun.COM 	pathdevpath = di_path_devfs_path(path);
66610652SHyon.Kim@Sun.COM 
66710652SHyon.Kim@Sun.COM 	state = di_path_state(path);
66810652SHyon.Kim@Sun.COM 	/* when node is not attached and online, set the state to offline. */
66910652SHyon.Kim@Sun.COM 	if ((state == DI_PATH_STATE_OFFLINE) ||
67010652SHyon.Kim@Sun.COM 	    (state == DI_PATH_STATE_FAULT)) {
67110652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
67210652SHyon.Kim@Sun.COM 		    "path node (%s) is either OFFLINE or FAULT state",
67310652SHyon.Kim@Sun.COM 		    pathdevpath ?  pathdevpath : "(missing device path)");
67410652SHyon.Kim@Sun.COM 		port_state = HBA_PORTSTATE_OFFLINE;
67510652SHyon.Kim@Sun.COM 	}
67610652SHyon.Kim@Sun.COM 
67710652SHyon.Kim@Sun.COM 	if (clientnode = di_path_client_node(path)) {
67810652SHyon.Kim@Sun.COM 		if (di_retired(clientnode)) {
67910652SHyon.Kim@Sun.COM 			log(LOG_DEBUG, ROUTINE,
68010652SHyon.Kim@Sun.COM 			    "client node of path (%s) is retired. Skipping.",
68110652SHyon.Kim@Sun.COM 			    pathdevpath ?  pathdevpath :
68210652SHyon.Kim@Sun.COM 			    "(missing device path)");
68310652SHyon.Kim@Sun.COM 			if (pathdevpath) di_devfs_path_free(pathdevpath);
68410652SHyon.Kim@Sun.COM 			return (HBA_STATUS_OK);
68510652SHyon.Kim@Sun.COM 		}
68610652SHyon.Kim@Sun.COM 		if ((clientdevpath = di_devfs_path(clientnode)) == NULL) {
68710652SHyon.Kim@Sun.COM 			log(LOG_DEBUG, ROUTINE,
68810652SHyon.Kim@Sun.COM 			    "Client device of path (%s) has no path. Skipping.",
68910652SHyon.Kim@Sun.COM 			    pathdevpath ?  pathdevpath :
69010652SHyon.Kim@Sun.COM 			    "(missing device path)");
69110652SHyon.Kim@Sun.COM 			if (pathdevpath) di_devfs_path_free(pathdevpath);
69210652SHyon.Kim@Sun.COM 			return (HBA_STATUS_ERROR);
69310652SHyon.Kim@Sun.COM 		}
69410652SHyon.Kim@Sun.COM 	} else {
69510652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
69610652SHyon.Kim@Sun.COM 		    "Failed to get client device from a path (%s).",
69710652SHyon.Kim@Sun.COM 		    pathdevpath ?  pathdevpath :
69810652SHyon.Kim@Sun.COM 		    "(missing device path)");
69910652SHyon.Kim@Sun.COM 		if (pathdevpath) di_devfs_path_free(pathdevpath);
70010652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
70110652SHyon.Kim@Sun.COM 	}
70210652SHyon.Kim@Sun.COM 
70310652SHyon.Kim@Sun.COM 	/* add the "/devices" in the begining and the :devctl at the end */
70410652SHyon.Kim@Sun.COM 	(void) snprintf(fullpath, sizeof (fullpath), "%s%s", DEVICES_DIR,
70510652SHyon.Kim@Sun.COM 	    clientdevpath);
70610652SHyon.Kim@Sun.COM 
70710652SHyon.Kim@Sun.COM 	(void) memset(&SASAddress, 0, sizeof (SASAddress));
70810652SHyon.Kim@Sun.COM 	if ((unit_address = di_path_bus_addr(path)) != NULL) {
70910652SHyon.Kim@Sun.COM 		if ((charptr = strchr(unit_address, ',')) != NULL) {
71010652SHyon.Kim@Sun.COM 			*charptr = '\0';
71110652SHyon.Kim@Sun.COM 		}
71210652SHyon.Kim@Sun.COM 		for (charptr = unit_address; *charptr != '\0'; charptr++) {
71310652SHyon.Kim@Sun.COM 			if (isxdigit(*charptr)) {
71410652SHyon.Kim@Sun.COM 				break;
71510652SHyon.Kim@Sun.COM 			}
71610652SHyon.Kim@Sun.COM 		}
71710652SHyon.Kim@Sun.COM 		if (charptr != '\0') {
71810652SHyon.Kim@Sun.COM 			tmpAddr = htonll(strtoll(charptr, NULL, 16));
71910652SHyon.Kim@Sun.COM 			(void) memcpy(&SASAddress.wwn[0], &tmpAddr, 8);
72010652SHyon.Kim@Sun.COM 		} else {
72110652SHyon.Kim@Sun.COM 			log(LOG_DEBUG, ROUTINE,
72210652SHyon.Kim@Sun.COM 			    "No proper target port info on unit address of "
72310652SHyon.Kim@Sun.COM 			    "path (%s).", pathdevpath ?  pathdevpath :
72410652SHyon.Kim@Sun.COM 			    "(missing device path)");
72510652SHyon.Kim@Sun.COM 			if (pathdevpath) di_devfs_path_free(pathdevpath);
72610652SHyon.Kim@Sun.COM 			di_devfs_path_free(clientdevpath);
72710652SHyon.Kim@Sun.COM 			return (HBA_STATUS_ERROR);
72810652SHyon.Kim@Sun.COM 		}
72910652SHyon.Kim@Sun.COM 	} else {
73010652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE, "Fail to get unit address of path(%s).",
73110652SHyon.Kim@Sun.COM 		    "path (%s).", pathdevpath ?  pathdevpath :
73210652SHyon.Kim@Sun.COM 		    "(missing device path)");
73310652SHyon.Kim@Sun.COM 		if (pathdevpath) di_devfs_path_free(pathdevpath);
73410652SHyon.Kim@Sun.COM 		di_devfs_path_free(clientdevpath);
73510652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
73610652SHyon.Kim@Sun.COM 	}
73710652SHyon.Kim@Sun.COM 
73810652SHyon.Kim@Sun.COM 	(void) memset(&AttachedSASAddress, 0, sizeof (AttachedSASAddress));
73910652SHyon.Kim@Sun.COM 	if (di_path_prop_lookup_strings(path, "attached-port",
74010652SHyon.Kim@Sun.COM 	    &propStringData) != -1) {
74110652SHyon.Kim@Sun.COM 		for (charptr = propStringData; *charptr != '\0'; charptr++) {
74210652SHyon.Kim@Sun.COM 			if (isxdigit(*charptr)) {
74310652SHyon.Kim@Sun.COM 				break;
74410652SHyon.Kim@Sun.COM 			}
74510652SHyon.Kim@Sun.COM 		}
74610652SHyon.Kim@Sun.COM 		if (*charptr != '\0') {
74710652SHyon.Kim@Sun.COM 			tmpAddr = htonll(strtoll(charptr, NULL, 16));
74810652SHyon.Kim@Sun.COM 			(void) memcpy(AttachedSASAddress.wwn, &tmpAddr, 8);
74910652SHyon.Kim@Sun.COM 			/*  check the attached address of hba port. */
75010652SHyon.Kim@Sun.COM 			if (memcmp(port_ptr->port_attributes.
75110652SHyon.Kim@Sun.COM 			    PortSpecificAttribute.SASPort->
75210652SHyon.Kim@Sun.COM 			    LocalSASAddress.wwn, &tmpAddr, 8) == 0) {
75310652SHyon.Kim@Sun.COM 				if (wwnConversion(port_ptr->port_attributes.
75410652SHyon.Kim@Sun.COM 				    PortSpecificAttribute.SASPort->
75510652SHyon.Kim@Sun.COM 				    AttachedSASAddress.wwn)) {
75610652SHyon.Kim@Sun.COM 					/* verify the attaached SAS Addr. */
75710652SHyon.Kim@Sun.COM 					if (memcmp(port_ptr->port_attributes.
75810652SHyon.Kim@Sun.COM 					    PortSpecificAttribute.SASPort->
75910652SHyon.Kim@Sun.COM 					    AttachedSASAddress.wwn,
76010652SHyon.Kim@Sun.COM 					    SASAddress.wwn, 8) != 0) {
76110652SHyon.Kim@Sun.COM 				/* indentation move begin. */
76210652SHyon.Kim@Sun.COM 				log(LOG_DEBUG, ROUTINE,
76310652SHyon.Kim@Sun.COM 				    "iport attached-port(%016llx) do not"
76410652SHyon.Kim@Sun.COM 				    " match with level 1 Local"
76510652SHyon.Kim@Sun.COM 				    " SAS address(%016llx).",
76610652SHyon.Kim@Sun.COM 				    wwnConversion(port_ptr->port_attributes.
76710652SHyon.Kim@Sun.COM 				    PortSpecificAttribute.
76810652SHyon.Kim@Sun.COM 				    SASPort->AttachedSASAddress.wwn),
76910652SHyon.Kim@Sun.COM 				    wwnConversion(SASAddress.wwn));
77010652SHyon.Kim@Sun.COM 				if (pathdevpath)
77110652SHyon.Kim@Sun.COM 					di_devfs_path_free(pathdevpath);
77210652SHyon.Kim@Sun.COM 				di_devfs_path_free(clientdevpath);
77310652SHyon.Kim@Sun.COM 				free_attached_port(port_ptr);
77410652SHyon.Kim@Sun.COM 				return (HBA_STATUS_ERROR);
77510652SHyon.Kim@Sun.COM 				/* indentation move ends. */
77610652SHyon.Kim@Sun.COM 					}
77710652SHyon.Kim@Sun.COM 				} else {
77810652SHyon.Kim@Sun.COM 					/* store the Attaached SAS Addr. */
77910652SHyon.Kim@Sun.COM 					(void) memcpy(port_ptr->port_attributes.
78010652SHyon.Kim@Sun.COM 					    PortSpecificAttribute.
78110652SHyon.Kim@Sun.COM 					    SASPort->AttachedSASAddress.wwn,
78210652SHyon.Kim@Sun.COM 					    &SASAddress.wwn[0], 8);
78310652SHyon.Kim@Sun.COM 				}
78410652SHyon.Kim@Sun.COM 			}
78510652SHyon.Kim@Sun.COM 		} else {
78610652SHyon.Kim@Sun.COM 			log(LOG_DEBUG, ROUTINE,
78710652SHyon.Kim@Sun.COM 			    "No proper attached SAS address value of path (%s)",
78810652SHyon.Kim@Sun.COM 			    pathdevpath ?  pathdevpath :
78910652SHyon.Kim@Sun.COM 			    "(missing device path)");
79010652SHyon.Kim@Sun.COM 			if (pathdevpath) di_devfs_path_free(pathdevpath);
79110652SHyon.Kim@Sun.COM 			di_devfs_path_free(clientdevpath);
79210652SHyon.Kim@Sun.COM 			free_attached_port(port_ptr);
79310652SHyon.Kim@Sun.COM 			return (HBA_STATUS_ERROR);
79410652SHyon.Kim@Sun.COM 		}
79510652SHyon.Kim@Sun.COM 	} else {
79610652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
79710652SHyon.Kim@Sun.COM 		    "Property attached-port not found for path (%s)",
79810652SHyon.Kim@Sun.COM 		    pathdevpath ?  pathdevpath :
79910652SHyon.Kim@Sun.COM 		    "(missing device path)");
80010652SHyon.Kim@Sun.COM 		if (pathdevpath) di_devfs_path_free(pathdevpath);
80110652SHyon.Kim@Sun.COM 		di_devfs_path_free(clientdevpath);
80210652SHyon.Kim@Sun.COM 		free_attached_port(port_ptr);
80310652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
80410652SHyon.Kim@Sun.COM 	}
80510652SHyon.Kim@Sun.COM 
80610652SHyon.Kim@Sun.COM 	/*
80710652SHyon.Kim@Sun.COM 	 * walk the disco list to make sure that there isn't a matching
80810652SHyon.Kim@Sun.COM 	 * port and node wwn or a matching device path
80910652SHyon.Kim@Sun.COM 	 */
81010652SHyon.Kim@Sun.COM 	portfound = 0;
81110652SHyon.Kim@Sun.COM 	for (disco_port_ptr = port_ptr->first_attached_port;
81210652SHyon.Kim@Sun.COM 	    disco_port_ptr != NULL;
81310652SHyon.Kim@Sun.COM 	    disco_port_ptr = disco_port_ptr->next) {
81410652SHyon.Kim@Sun.COM 		if ((disco_port_ptr->port_attributes.PortState !=
81510652SHyon.Kim@Sun.COM 		    HBA_PORTSTATE_ERROR) &&
81610652SHyon.Kim@Sun.COM 		    (memcmp(disco_port_ptr->port_attributes.
81710652SHyon.Kim@Sun.COM 		    PortSpecificAttribute.SASPort->LocalSASAddress.wwn,
81810652SHyon.Kim@Sun.COM 		    SASAddress.wwn, 8) == 0)) {
81910652SHyon.Kim@Sun.COM 			/*
82010652SHyon.Kim@Sun.COM 			 * found matching disco_port
82110652SHyon.Kim@Sun.COM 			 * look for matching device path
82210652SHyon.Kim@Sun.COM 			 */
82310652SHyon.Kim@Sun.COM 			portfound = 1;
82410652SHyon.Kim@Sun.COM 			for (mapping_ptr = disco_port_ptr->scsiInfo;
82510652SHyon.Kim@Sun.COM 			    mapping_ptr != NULL;
82610652SHyon.Kim@Sun.COM 			    mapping_ptr = mapping_ptr->next) {
82710652SHyon.Kim@Sun.COM 				if (strstr(mapping_ptr-> entry.ScsiId.
82810652SHyon.Kim@Sun.COM 				    OSDeviceName, clientdevpath) != 0) {
82910652SHyon.Kim@Sun.COM 					log(LOG_DEBUG, ROUTINE,
83010652SHyon.Kim@Sun.COM 					    "Found an already discovered "
83110652SHyon.Kim@Sun.COM 					    "device %s.", clientdevpath);
83210652SHyon.Kim@Sun.COM 					if (pathdevpath)
83310652SHyon.Kim@Sun.COM 						di_devfs_path_free(pathdevpath);
83410652SHyon.Kim@Sun.COM 					di_devfs_path_free(clientdevpath);
83510652SHyon.Kim@Sun.COM 					return (HBA_STATUS_OK);
83610652SHyon.Kim@Sun.COM 				}
83710652SHyon.Kim@Sun.COM 			}
83810652SHyon.Kim@Sun.COM 			if (portfound == 1) {
83910652SHyon.Kim@Sun.COM 				break;
84010652SHyon.Kim@Sun.COM 			}
84110652SHyon.Kim@Sun.COM 		}
84210652SHyon.Kim@Sun.COM 	}
84310652SHyon.Kim@Sun.COM 
84410652SHyon.Kim@Sun.COM 	if (portfound == 0) {
84510652SHyon.Kim@Sun.COM 		/*
84610652SHyon.Kim@Sun.COM 		 * there are no matching SAS address.
84710652SHyon.Kim@Sun.COM 		 * this must be a new device
84810652SHyon.Kim@Sun.COM 		 */
84910652SHyon.Kim@Sun.COM 		if ((disco_port_ptr = (struct sun_sas_port *)calloc(1,
85010652SHyon.Kim@Sun.COM 				    sizeof (struct sun_sas_port))) == NULL)  {
85110652SHyon.Kim@Sun.COM 			OUT_OF_MEMORY(ROUTINE);
85210652SHyon.Kim@Sun.COM 			if (pathdevpath) di_devfs_path_free(pathdevpath);
85310652SHyon.Kim@Sun.COM 			di_devfs_path_free(clientdevpath);
85410652SHyon.Kim@Sun.COM 			free_attached_port(port_ptr);
85510652SHyon.Kim@Sun.COM 			return (HBA_STATUS_ERROR);
85610652SHyon.Kim@Sun.COM 		}
85710652SHyon.Kim@Sun.COM 
85810652SHyon.Kim@Sun.COM 		if ((disco_port_ptr->port_attributes.PortSpecificAttribute.\
85910652SHyon.Kim@Sun.COM 		    SASPort = (struct SMHBA_SAS_Port *)calloc(1,
86010652SHyon.Kim@Sun.COM 		    sizeof (struct SMHBA_SAS_Port))) == NULL) {
86110652SHyon.Kim@Sun.COM 			OUT_OF_MEMORY("add_hba_port_info");
86210652SHyon.Kim@Sun.COM 			if (pathdevpath) di_devfs_path_free(pathdevpath);
86310652SHyon.Kim@Sun.COM 			di_devfs_path_free(clientdevpath);
86410652SHyon.Kim@Sun.COM 			free_attached_port(port_ptr);
86510652SHyon.Kim@Sun.COM 			return (HBA_STATUS_ERROR);
86610652SHyon.Kim@Sun.COM 		}
86710652SHyon.Kim@Sun.COM 
86810652SHyon.Kim@Sun.COM 		(void) memcpy(disco_port_ptr->port_attributes.
86910652SHyon.Kim@Sun.COM 		    PortSpecificAttribute.
87010652SHyon.Kim@Sun.COM 		    SASPort->LocalSASAddress.wwn, SASAddress.wwn, 8);
87110652SHyon.Kim@Sun.COM 		(void) memcpy(disco_port_ptr->port_attributes.
87210652SHyon.Kim@Sun.COM 		    PortSpecificAttribute.
87310652SHyon.Kim@Sun.COM 		    SASPort->AttachedSASAddress.wwn, AttachedSASAddress.wwn, 8);
87410652SHyon.Kim@Sun.COM 
87510652SHyon.Kim@Sun.COM 		/* Default to unknown until we figure out otherwise */
87610652SHyon.Kim@Sun.COM 		if (di_path_prop_lookup_strings(path, "variant",
87710652SHyon.Kim@Sun.COM 		    &propStringData) != -1) {
87810652SHyon.Kim@Sun.COM 			if ((strcmp(propStringData, "sata") == 0) ||
87910652SHyon.Kim@Sun.COM 			    (strcmp(propStringData, "atapi") == 0)) {
88010652SHyon.Kim@Sun.COM 				disco_port_ptr->port_attributes.PortType =
88110652SHyon.Kim@Sun.COM 				    HBA_PORTTYPE_SATADEVICE;
88210652SHyon.Kim@Sun.COM 				disco_port_ptr->port_attributes.\
88310652SHyon.Kim@Sun.COM 				    PortSpecificAttribute.SASPort->PortProtocol
88410652SHyon.Kim@Sun.COM 				    = HBA_SASPORTPROTOCOL_SATA;
88510652SHyon.Kim@Sun.COM 			} else {
88610652SHyon.Kim@Sun.COM 				log(LOG_DEBUG, ROUTINE,
88710652SHyon.Kim@Sun.COM 				    "Unexpected variant prop value %s found on",
88810652SHyon.Kim@Sun.COM 				    " path (%s)", propStringData,
88910652SHyon.Kim@Sun.COM 				    pathdevpath ?  pathdevpath :
89010652SHyon.Kim@Sun.COM 				    "(missing device path)");
89110652SHyon.Kim@Sun.COM 				/*
89210652SHyon.Kim@Sun.COM 				 * Port type will be 0
89310652SHyon.Kim@Sun.COM 				 * which is not valid type.
89410652SHyon.Kim@Sun.COM 				 */
89510652SHyon.Kim@Sun.COM 			}
89610652SHyon.Kim@Sun.COM 		} else {
89710652SHyon.Kim@Sun.COM 			disco_port_ptr->port_attributes.PortType =
89810652SHyon.Kim@Sun.COM 			    HBA_PORTTYPE_SASDEVICE;
89910652SHyon.Kim@Sun.COM 			disco_port_ptr->port_attributes.PortSpecificAttribute.\
90010652SHyon.Kim@Sun.COM 			    SASPort->PortProtocol = HBA_SASPORTPROTOCOL_SSP;
90110652SHyon.Kim@Sun.COM 		}
90210652SHyon.Kim@Sun.COM 
90310652SHyon.Kim@Sun.COM 		if (disco_port_ptr->port_attributes.OSDeviceName[0] == '\0') {
90410652SHyon.Kim@Sun.COM 		/* indentation change due to ctysle check on sizeof. */
90510652SHyon.Kim@Sun.COM 		size = sizeof (disco_port_ptr->port_attributes.OSDeviceName);
90610652SHyon.Kim@Sun.COM 			if (pathdevpath != NULL) {
90710652SHyon.Kim@Sun.COM 				(void) strlcpy(disco_port_ptr->port_attributes.
90810652SHyon.Kim@Sun.COM 				    OSDeviceName, pathdevpath, size);
90910652SHyon.Kim@Sun.COM 			}
91010652SHyon.Kim@Sun.COM 		}
91110652SHyon.Kim@Sun.COM 
91210652SHyon.Kim@Sun.COM 		/* add new discovered port into the list */
91310652SHyon.Kim@Sun.COM 		if (port_ptr->first_attached_port == NULL) {
91410652SHyon.Kim@Sun.COM 			port_ptr->first_attached_port = disco_port_ptr;
91510652SHyon.Kim@Sun.COM 			disco_port_ptr->index = 0;
91610652SHyon.Kim@Sun.COM 			port_ptr->port_attributes.PortSpecificAttribute.\
91710652SHyon.Kim@Sun.COM 			    SASPort->NumberofDiscoveredPorts = 1;
91810652SHyon.Kim@Sun.COM 		} else {
91910652SHyon.Kim@Sun.COM 			disco_port_ptr->next = port_ptr->first_attached_port;
92010652SHyon.Kim@Sun.COM 			port_ptr->first_attached_port = disco_port_ptr;
92110652SHyon.Kim@Sun.COM 			disco_port_ptr->index = port_ptr->port_attributes.\
92210652SHyon.Kim@Sun.COM 			    PortSpecificAttribute.\
92310652SHyon.Kim@Sun.COM 			    SASPort->NumberofDiscoveredPorts;
92410652SHyon.Kim@Sun.COM 			port_ptr->port_attributes.PortSpecificAttribute.\
92510652SHyon.Kim@Sun.COM 			    SASPort->NumberofDiscoveredPorts++;
92610652SHyon.Kim@Sun.COM 		}
92710652SHyon.Kim@Sun.COM 		disco_port_ptr->port_attributes.PortState = port_state;
92810652SHyon.Kim@Sun.COM 	}
92910652SHyon.Kim@Sun.COM 
93010652SHyon.Kim@Sun.COM 	if ((mapping_ptr = (struct ScsiEntryList *)calloc
93110652SHyon.Kim@Sun.COM 		    (1, sizeof (struct ScsiEntryList))) == NULL) {
93210652SHyon.Kim@Sun.COM 		OUT_OF_MEMORY(ROUTINE);
93310652SHyon.Kim@Sun.COM 		if (pathdevpath) di_devfs_path_free(pathdevpath);
93410652SHyon.Kim@Sun.COM 		di_devfs_path_free(clientdevpath);
93510652SHyon.Kim@Sun.COM 		free_attached_port(port_ptr);
93610652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
93710652SHyon.Kim@Sun.COM 	}
93810652SHyon.Kim@Sun.COM 
93910652SHyon.Kim@Sun.COM 	if (di_path_prop_lookup_ints(path, "lun", &propIntData) != -1) {
94010652SHyon.Kim@Sun.COM 		mapping_ptr->entry.ScsiId.ScsiOSLun = *propIntData;
94110652SHyon.Kim@Sun.COM 	} else {
94210652SHyon.Kim@Sun.COM 		if ((charptr = strchr(unit_address, ',')) != NULL) {
94310652SHyon.Kim@Sun.COM 			charptr++;
94410652SHyon.Kim@Sun.COM 			mapping_ptr->entry.ScsiId.ScsiOSLun =
94510652SHyon.Kim@Sun.COM 			    strtoull(charptr, NULL, 10);
94610652SHyon.Kim@Sun.COM 		} else {
94710652SHyon.Kim@Sun.COM 			log(LOG_DEBUG, ROUTINE,
94810652SHyon.Kim@Sun.COM 			    "Failed to get LUN from unit address of path(%s).",
94910652SHyon.Kim@Sun.COM 			    pathdevpath ?  pathdevpath :
95010652SHyon.Kim@Sun.COM 			    "(missing device path)");
95110652SHyon.Kim@Sun.COM 			if (pathdevpath) di_devfs_path_free(pathdevpath);
95210652SHyon.Kim@Sun.COM 			di_devfs_path_free(clientdevpath);
95310652SHyon.Kim@Sun.COM 			free_attached_port(port_ptr);
95410652SHyon.Kim@Sun.COM 			return (HBA_STATUS_ERROR);
95510652SHyon.Kim@Sun.COM 		}
95610652SHyon.Kim@Sun.COM 	}
95710652SHyon.Kim@Sun.COM 
95810652SHyon.Kim@Sun.COM 	/* Get TargetLun(SAM LUN). */
95910652SHyon.Kim@Sun.COM 	if (di_path_prop_lookup_int64s(path, "lun64", &propInt64Data) != -1) {
96010652SHyon.Kim@Sun.COM 		samLun = scsi_lun64_to_lun(*propInt64Data);
96110652SHyon.Kim@Sun.COM 		(void) memcpy(&mapping_ptr->entry.PortLun.TargetLun,
96210652SHyon.Kim@Sun.COM 		    &samLun, 8);
96310652SHyon.Kim@Sun.COM 	} else {
96410652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE, "No lun64 prop found on path (%s)",
96510652SHyon.Kim@Sun.COM 		    pathdevpath ?  pathdevpath :
96610652SHyon.Kim@Sun.COM 		    "(missing device path)");
96710652SHyon.Kim@Sun.COM 		if (pathdevpath) di_devfs_path_free(pathdevpath);
96810652SHyon.Kim@Sun.COM 		di_devfs_path_free(clientdevpath);
96910652SHyon.Kim@Sun.COM 		free_attached_port(port_ptr);
97010652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR);
97110652SHyon.Kim@Sun.COM 	}
97210652SHyon.Kim@Sun.COM 
97310652SHyon.Kim@Sun.COM 	if (di_path_prop_lookup_ints(path, "target", &propIntData) != -1) {
97410652SHyon.Kim@Sun.COM 		mapping_ptr->entry.ScsiId.ScsiTargetNumber = *propIntData;
97510652SHyon.Kim@Sun.COM 	} else {
97610652SHyon.Kim@Sun.COM 		mapping_ptr->entry.ScsiId.ScsiTargetNumber =
97710652SHyon.Kim@Sun.COM 		    di_path_instance(path);
97810652SHyon.Kim@Sun.COM 	}
97910652SHyon.Kim@Sun.COM 
98010652SHyon.Kim@Sun.COM 	/* get ScsiBusNumber */
98110652SHyon.Kim@Sun.COM 	mapping_ptr->entry.ScsiId.ScsiBusNumber = port_ptr->cntlNumber;
98210652SHyon.Kim@Sun.COM 
98310652SHyon.Kim@Sun.COM 	(void) memcpy(mapping_ptr->entry.PortLun.PortWWN.wwn,
98410652SHyon.Kim@Sun.COM 	    SASAddress.wwn, 8);
98510652SHyon.Kim@Sun.COM 
98610652SHyon.Kim@Sun.COM 	/* Store the devices path for now.  We'll convert to /dev later */
98710652SHyon.Kim@Sun.COM 	get_minor(clientdevpath, minorname);
98810652SHyon.Kim@Sun.COM 	(void) snprintf(mapping_ptr->entry.ScsiId.OSDeviceName,
98910652SHyon.Kim@Sun.COM 	    sizeof (mapping_ptr->entry.ScsiId.OSDeviceName),
99010652SHyon.Kim@Sun.COM 	    "%s%s%s", DEVICES_DIR, clientdevpath, minorname);
99110652SHyon.Kim@Sun.COM 
99210652SHyon.Kim@Sun.COM 	/* get luid. */
993*11243SHyon.Kim@Sun.COM 	errno = 0; /* reset errno to 0 */
994*11243SHyon.Kim@Sun.COM 	if (di_prop_lookup_strings(DDI_DEV_T_ANY, clientnode, "devid",
995*11243SHyon.Kim@Sun.COM 	    &propStringData) != -1) {
996*11243SHyon.Kim@Sun.COM 		if (devid_str_decode(propStringData, &devid, NULL) != -1) {
997*11243SHyon.Kim@Sun.COM 			guidStr = devid_to_guid(devid);
998*11243SHyon.Kim@Sun.COM 			if (guidStr != NULL) {
999*11243SHyon.Kim@Sun.COM 				(void) strlcpy(mapping_ptr->entry.LUID.buffer,
1000*11243SHyon.Kim@Sun.COM 				    guidStr,
1001*11243SHyon.Kim@Sun.COM 				    sizeof (mapping_ptr->entry.LUID.buffer));
1002*11243SHyon.Kim@Sun.COM 				devid_free_guid(guidStr);
1003*11243SHyon.Kim@Sun.COM 			} else {
1004*11243SHyon.Kim@Sun.COM 				/*
1005*11243SHyon.Kim@Sun.COM 				 * Note:
1006*11243SHyon.Kim@Sun.COM 				 * if logical unit associated page 83 id
1007*11243SHyon.Kim@Sun.COM 				 * descriptor is not avaialble for the device
1008*11243SHyon.Kim@Sun.COM 				 * devid_to_guid returns NULl with errno 0.
1009*11243SHyon.Kim@Sun.COM 				 */
1010*11243SHyon.Kim@Sun.COM 				log(LOG_DEBUG, ROUTINE,
1011*11243SHyon.Kim@Sun.COM 				    "failed to get devid guid on (%s)",
1012*11243SHyon.Kim@Sun.COM 				    " associated with path(%s) : %s",
1013*11243SHyon.Kim@Sun.COM 				    clientdevpath,
1014*11243SHyon.Kim@Sun.COM 				    pathdevpath ?  pathdevpath :
1015*11243SHyon.Kim@Sun.COM 				    "(missing device path)",
1016*11243SHyon.Kim@Sun.COM 				    strerror(errno));
1017*11243SHyon.Kim@Sun.COM 			}
1018*11243SHyon.Kim@Sun.COM 		} else {
1019*11243SHyon.Kim@Sun.COM 			/*
1020*11243SHyon.Kim@Sun.COM 			 * device may not support proper page 83 id descriptor.
1021*11243SHyon.Kim@Sun.COM 			 * leave LUID attribute to NULL and continue.
1022*11243SHyon.Kim@Sun.COM 			 */
1023*11243SHyon.Kim@Sun.COM 			log(LOG_DEBUG, ROUTINE,
1024*11243SHyon.Kim@Sun.COM 			    "failed to decode devid prop on (%s)",
1025*11243SHyon.Kim@Sun.COM 			    " associated with path(%s) : %s",
1026*11243SHyon.Kim@Sun.COM 			    clientdevpath,
1027*11243SHyon.Kim@Sun.COM 			    pathdevpath ?  pathdevpath :
1028*11243SHyon.Kim@Sun.COM 			    "(missing device path)",
1029*11243SHyon.Kim@Sun.COM 			    strerror(errno));
1030*11243SHyon.Kim@Sun.COM 		}
103110652SHyon.Kim@Sun.COM 	} else {
1032*11243SHyon.Kim@Sun.COM 		/* leave LUID attribute to NULL and continue. */
1033*11243SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE, "Failed to get devid on %s"
1034*11243SHyon.Kim@Sun.COM 		    " associated with path(%s) : %s", clientdevpath,
1035*11243SHyon.Kim@Sun.COM 		    pathdevpath ?  pathdevpath : "(missing device path)",
1036*11243SHyon.Kim@Sun.COM 		    strerror(errno));
103710652SHyon.Kim@Sun.COM 	}
103810652SHyon.Kim@Sun.COM 
103910652SHyon.Kim@Sun.COM 	if (disco_port_ptr->scsiInfo == NULL) {
104010652SHyon.Kim@Sun.COM 		disco_port_ptr->scsiInfo = mapping_ptr;
104110652SHyon.Kim@Sun.COM 	} else {
104210652SHyon.Kim@Sun.COM 		mapping_ptr->next = disco_port_ptr->scsiInfo;
104310652SHyon.Kim@Sun.COM 		disco_port_ptr->scsiInfo = mapping_ptr;
104410652SHyon.Kim@Sun.COM 	}
104510652SHyon.Kim@Sun.COM 
104610652SHyon.Kim@Sun.COM 	if (pathdevpath) di_devfs_path_free(pathdevpath);
104710652SHyon.Kim@Sun.COM 	di_devfs_path_free(clientdevpath);
104810652SHyon.Kim@Sun.COM 
104910652SHyon.Kim@Sun.COM 	return (HBA_STATUS_OK);
105010652SHyon.Kim@Sun.COM }
105110652SHyon.Kim@Sun.COM 
105210652SHyon.Kim@Sun.COM /*
105310652SHyon.Kim@Sun.COM  * walks the devinfo tree retrieving all hba information
105410652SHyon.Kim@Sun.COM  */
105510652SHyon.Kim@Sun.COM extern HBA_STATUS
devtree_attached_devices(di_node_t node,struct sun_sas_port * port_ptr)105610652SHyon.Kim@Sun.COM devtree_attached_devices(di_node_t node, struct sun_sas_port *port_ptr)
105710652SHyon.Kim@Sun.COM {
105810652SHyon.Kim@Sun.COM 	const char		ROUTINE[] = "devtree_attached_devices";
105910652SHyon.Kim@Sun.COM 	di_node_t		nodechild = DI_NODE_NIL;
106010652SHyon.Kim@Sun.COM 	di_path_t		path = DI_PATH_NIL;
106110652SHyon.Kim@Sun.COM 
106210652SHyon.Kim@Sun.COM 	/* child should be device */
106310652SHyon.Kim@Sun.COM 	if ((nodechild = di_child_node(node)) == DI_NODE_NIL) {
106410652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
106510652SHyon.Kim@Sun.COM 		    "No devinfo child on the HBA port node.");
106610652SHyon.Kim@Sun.COM 	}
106710652SHyon.Kim@Sun.COM 
106810652SHyon.Kim@Sun.COM 	if ((path = di_path_phci_next_path(node, path)) ==
106910652SHyon.Kim@Sun.COM 	    DI_PATH_NIL) {
107010652SHyon.Kim@Sun.COM 		log(LOG_DEBUG, ROUTINE,
107110652SHyon.Kim@Sun.COM 		    "No pathinfo node on the HBA port node.");
107210652SHyon.Kim@Sun.COM 	}
107310652SHyon.Kim@Sun.COM 
107410652SHyon.Kim@Sun.COM 	if ((nodechild == DI_NODE_NIL) && (path == DI_PATH_NIL)) {
107510652SHyon.Kim@Sun.COM 		return (HBA_STATUS_OK);
107610652SHyon.Kim@Sun.COM 	}
107710652SHyon.Kim@Sun.COM 
107810652SHyon.Kim@Sun.COM 	while (nodechild != DI_NODE_NIL) {
107910652SHyon.Kim@Sun.COM 		if (get_attached_devices_info(nodechild, port_ptr)
108010652SHyon.Kim@Sun.COM 		    != HBA_STATUS_OK) {
108110652SHyon.Kim@Sun.COM 			break;
108210652SHyon.Kim@Sun.COM 		}
108310652SHyon.Kim@Sun.COM 		nodechild = di_sibling_node(nodechild);
108410652SHyon.Kim@Sun.COM 	}
108510652SHyon.Kim@Sun.COM 
108610652SHyon.Kim@Sun.COM 
108710652SHyon.Kim@Sun.COM 	while (path != DI_PATH_NIL) {
108810652SHyon.Kim@Sun.COM 		if (get_attached_paths_info(path, port_ptr)
108910652SHyon.Kim@Sun.COM 		    != HBA_STATUS_OK) {
109010652SHyon.Kim@Sun.COM 			break;
109110652SHyon.Kim@Sun.COM 		}
109210652SHyon.Kim@Sun.COM 		path = di_path_phci_next_path(node, path);
109310652SHyon.Kim@Sun.COM 	}
109410652SHyon.Kim@Sun.COM 
109510652SHyon.Kim@Sun.COM 	return (HBA_STATUS_OK);
109610652SHyon.Kim@Sun.COM }
1097