xref: /illumos-gate/usr/src/lib/sun_sas/common/devtree_device_disco.c (revision e998e519114d9176339a9115abd802dfdebde87f)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include	<sun_sas.h>
28 #include	<sys/types.h>
29 #include	<netinet/in.h>
30 #include	<inttypes.h>
31 #include	<ctype.h>
32 #include	<sys/scsi/scsi_address.h>
33 #include	<libdevid.h>
34 
35 /*
36  * Get the preferred minor node for the given path.
37  * ":n" for tapes, ":c,raw" for disks,
38  * and ":0" for enclosures.
39  */
40 static void
41 get_minor(char *devpath, char *minor)
42 {
43 	const char	ROUTINE[] = "get_minor";
44 	char	fullpath[MAXPATHLEN];
45 	int	fd;
46 
47 	if ((strstr(devpath, "/st@")) || (strstr(devpath, "/tape@"))) {
48 		(void) strcpy(minor, ":n");
49 	} else if (strstr(devpath, "/smp@")) {
50 		(void) strcpy(minor, ":smp");
51 	} else if ((strstr(devpath, "/ssd@")) || (strstr(devpath, "/sd@")) ||
52 	    (strstr(devpath, "/disk@"))) {
53 		(void) strcpy(minor, ":c,raw");
54 	} else if ((strstr(devpath, "/ses@")) || (strstr(devpath,
55 	    "/enclosure@"))) {
56 		(void) snprintf(fullpath, MAXPATHLEN, "%s%s%s", DEVICES_DIR,
57 		    devpath, ":0");
58 		/* reset errno to 0 */
59 		errno = 0;
60 		if ((fd = open(fullpath, O_RDONLY)) == -1) {
61 			/*
62 			 * :0 minor doesn't exist. assume bound to sgen driver
63 			 * and :ses minor exist.
64 			 */
65 			if (errno == ENOENT) {
66 				(void) strcpy(minor, ":ses");
67 			}
68 		} else {
69 			(void) strcpy(minor, ":0");
70 			(void) close(fd);
71 		}
72 	} else {
73 		log(LOG_DEBUG, ROUTINE, "Unrecognized target (%s)",
74 		    devpath);
75 		minor[0] = '\0';
76 	}
77 
78 }
79 
80 /*
81  * Get the LUID through libdevid.
82  *
83  * devpath: /devices path for the devices.
84  * luidi: devid string.
85  */
86 static void
87 get_luid(char *devpath, char *luid)
88 {
89 	const char	ROUTINE[] = "get_luid";
90 	int 		fd;
91 	ddi_devid_t 	devid = NULL;
92 	char 		*devidstr;
93 
94 	/* reset errno. */
95 	errno = 0;
96 	if ((fd = open(devpath,  O_RDONLY|O_NDELAY)) >= 0) {
97 		if (devid_get(fd, &devid) == 0) {
98 			if ((devidstr = devid_to_guid(devid)) != NULL) {
99 				(void) strlcpy(luid, devidstr, 256);
100 				devid_free_guid(devidstr);
101 			} else {
102 				log(LOG_DEBUG, ROUTINE,
103 				    "failed to get devid guid on (%s) : %s",
104 				    devpath, strerror(errno));
105 			}
106 			devid_free(devid);
107 		} else {
108 			log(LOG_DEBUG, ROUTINE,
109 			    "failed to get devid on (%s)", devpath);
110 		}
111 		(void) close(fd);
112 	} else {
113 		log(LOG_DEBUG, ROUTINE, "open failed on (%s) error: %s",
114 		    devpath, strerror(errno));
115 	}
116 }
117 
118 /*
119  * Free the attached port allocation.
120  */
121 static void
122 free_attached_port(struct sun_sas_port *port_ptr)
123 {
124 	struct sun_sas_port 	*tgt_port, *last_tgt_port;
125 	struct ScsiEntryList	*scsi_info = NULL, *last_scsi_info = NULL;
126 
127 	tgt_port = port_ptr->first_attached_port;
128 	while (tgt_port != NULL) {
129 		/* Free target mapping data list first. */
130 		scsi_info = tgt_port->scsiInfo;
131 		while (scsi_info != NULL) {
132 			last_scsi_info = scsi_info;
133 			scsi_info = scsi_info->next;
134 			free(last_scsi_info);
135 		}
136 		last_tgt_port = tgt_port;
137 		tgt_port = tgt_port->next;
138 		free(last_tgt_port->port_attributes.\
139 		    PortSpecificAttribute.SASPort);
140 		free(last_tgt_port);
141 	}
142 
143 	port_ptr->first_attached_port = NULL;
144 	port_ptr->port_attributes.PortSpecificAttribute.\
145 	    SASPort->NumberofDiscoveredPorts = 0;
146 }
147 
148 /*
149  * Fill domainPortWWN.
150  * should be called after completing discovered port discovery.
151  */
152 void
153 fillDomainPortWWN(struct sun_sas_port *port_ptr)
154 {
155 	const char    ROUTINE[] = "fillDomainPortWWN";
156 	struct sun_sas_port *disco_port_ptr;
157 	struct phy_info *phy_ptr;
158 	uint64_t    domainPort = 0;
159 	struct ScsiEntryList	    *mapping_ptr;
160 
161 	for (disco_port_ptr = port_ptr->first_attached_port;
162 	    disco_port_ptr != NULL; disco_port_ptr = disco_port_ptr->next) {
163 		if (disco_port_ptr->port_attributes.PortType ==
164 		    HBA_PORTTYPE_SASEXPANDER &&
165 		    wwnConversion(disco_port_ptr->port_attributes.
166 		    PortSpecificAttribute.SASPort->
167 		    AttachedSASAddress.wwn) ==
168 		    wwnConversion(port_ptr->port_attributes.
169 		    PortSpecificAttribute.SASPort->
170 		    LocalSASAddress.wwn)) {
171 			(void) memcpy(&domainPort,
172 			    disco_port_ptr->port_attributes.
173 			    PortSpecificAttribute.
174 			    SASPort->LocalSASAddress.wwn, 8);
175 			break;
176 		}
177 	}
178 
179 	if (domainPort == 0) {
180 		if (port_ptr->first_attached_port) {
181 			/*
182 			 * there is no expander device attached on an HBA port
183 			 * domainPortWWN should not stay to 0 since multiple
184 			 * hba ports can have the same LocalSASAddres within
185 			 * the same HBA.
186 			 * Set the SAS address of direct attached target.
187 			 */
188 			if (wwnConversion(port_ptr->port_attributes.
189 			    PortSpecificAttribute.SASPort->
190 			    LocalSASAddress.wwn) ==
191 			    wwnConversion(port_ptr->first_attached_port->
192 			    port_attributes.PortSpecificAttribute.
193 			    SASPort->AttachedSASAddress.wwn)) {
194 				(void) memcpy(&domainPort,
195 				    port_ptr->first_attached_port->
196 				    port_attributes.PortSpecificAttribute.
197 				    SASPort->LocalSASAddress.wwn, 8);
198 			} else {
199 				/*
200 				 * SAS address is not upstream connected.
201 				 * domainPortWWN stays as 0.
202 				 */
203 				log(LOG_DEBUG, ROUTINE,
204 				    "DomainPortWWN is not set. "
205 				    "Device(s) are visible on the HBA port "
206 				    "but there is no expander or directly "
207 				    "attached port with matching upsteam "
208 				    "attached SAS address for "
209 				    "HBA port (Local SAS Address: %016llx).",
210 				    wwnConversion(port_ptr->port_attributes.
211 				    PortSpecificAttribute.
212 				    SASPort->LocalSASAddress.wwn));
213 				return;
214 			}
215 		} else {
216 			/*
217 			 * There existss an iport without properly configured
218 			 * child smp ndoes or  child node or pathinfo.
219 			 * domainPortWWN stays as 0.
220 			 */
221 			log(LOG_DEBUG, ROUTINE,
222 			    "DomainPortWWN is not set.  No properly "
223 			    "configured smp or directly attached port "
224 			    "found on HBA port(Local SAS Address: %016llx).",
225 			    wwnConversion(port_ptr->port_attributes.
226 			    PortSpecificAttribute.
227 			    SASPort->LocalSASAddress.wwn));
228 			return;
229 		}
230 	}
231 
232 	/* fill up phy info */
233 	for (phy_ptr = port_ptr->first_phy; phy_ptr != NULL;
234 	    phy_ptr = phy_ptr->next) {
235 		(void) memcpy(phy_ptr->phy.domainPortWWN.wwn, &domainPort, 8);
236 	}
237 
238 	/* fill up target mapping */
239 	for (disco_port_ptr = port_ptr->first_attached_port;
240 	    disco_port_ptr != NULL; disco_port_ptr = disco_port_ptr->next) {
241 		for (mapping_ptr = disco_port_ptr->scsiInfo;
242 		    mapping_ptr != NULL;
243 		    mapping_ptr = mapping_ptr->next) {
244 			(void) memcpy(mapping_ptr->entry.PortLun.
245 			    domainPortWWN.wwn, &domainPort, 8);
246 		}
247 	}
248 }
249 
250 /*
251  * Finds attached device(target) from devinfo node.
252  */
253 static HBA_STATUS
254 get_attached_devices_info(di_node_t node, struct sun_sas_port *port_ptr)
255 {
256 	const char		    ROUTINE[] = "get_attached_devices_info";
257 	char			    *propStringData = NULL;
258 	int			    *propIntData = NULL;
259 	int64_t			    *propInt64Data = NULL;
260 	uchar_t			    *propByteData = NULL;
261 	scsi_lun_t		    samLun;
262 	char			    *unit_address;
263 	char			    *charptr;
264 	char			    *devpath, link[MAXNAMELEN];
265 	char			    fullpath[MAXPATHLEN+1];
266 	char			    minorname[MAXNAMELEN+1];
267 	struct ScsiEntryList	    *mapping_ptr;
268 	HBA_WWN			    SASAddress, AttachedSASAddress;
269 	struct sun_sas_port	    *disco_port_ptr;
270 	uint_t			    state = 0;
271 	int			    portfound, rval, size, count, i;
272 	int			    port_state = HBA_PORTSTATE_ONLINE;
273 	uint64_t		    tmpAddr;
274 
275 	if (port_ptr == NULL) {
276 		log(LOG_DEBUG, ROUTINE, "NULL port_ptr argument");
277 		return (HBA_STATUS_ERROR);
278 	}
279 
280 	if ((devpath = di_devfs_path(node)) == NULL) {
281 		log(LOG_DEBUG, ROUTINE,
282 		    "Device in device tree has no path. Skipping.");
283 		return (HBA_STATUS_ERROR);
284 	}
285 
286 	if ((di_instance(node) == -1) || di_retired(node)) {
287 		log(LOG_DEBUG, ROUTINE,
288 		    "dev node (%s) returned instance of -1 or is retired. "
289 		    " Skipping.", devpath);
290 		di_devfs_path_free(devpath);
291 		return (HBA_STATUS_OK);
292 	}
293 	state = di_state(node);
294 	/* when node is not attached and online, set the state to offline. */
295 	if (((state & DI_DRIVER_DETACHED) == DI_DRIVER_DETACHED) ||
296 	    ((state & DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE)) {
297 		log(LOG_DEBUG, ROUTINE,
298 		    "dev node (%s) is either OFFLINE or DETACHED",
299 		    devpath);
300 		port_state = HBA_PORTSTATE_OFFLINE;
301 	}
302 
303 	/* add the "/devices" in the begining at the end */
304 	(void) snprintf(fullpath, sizeof (fullpath), "%s%s",
305 	    DEVICES_DIR, devpath);
306 
307 	(void) memset(&SASAddress, 0, sizeof (SASAddress));
308 	if ((unit_address = di_bus_addr(node)) != NULL) {
309 		if ((charptr = strchr(unit_address, ',')) != NULL) {
310 			*charptr = '\0';
311 		}
312 		for (charptr = unit_address; *charptr != '\0'; charptr++) {
313 			if (isxdigit(*charptr)) {
314 				break;
315 			}
316 		}
317 		if (*charptr != '\0') {
318 			tmpAddr = htonll(strtoll(charptr, NULL, 16));
319 			(void) memcpy(&SASAddress.wwn[0], &tmpAddr, 8);
320 		} else {
321 			log(LOG_DEBUG, ROUTINE,
322 			    "No proper target port info on unit address of %s",
323 			    fullpath);
324 			di_devfs_path_free(devpath);
325 			return (HBA_STATUS_ERROR);
326 		}
327 	} else {
328 		log(LOG_DEBUG, ROUTINE,
329 		    "Fail to get unit address of %s.",
330 		    fullpath);
331 		di_devfs_path_free(devpath);
332 		return (HBA_STATUS_ERROR);
333 	}
334 
335 	(void) memset(&AttachedSASAddress, 0, sizeof (AttachedSASAddress));
336 	if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "attached-port",
337 	    &propStringData) != -1) {
338 		for (charptr = propStringData; *charptr != '\0'; charptr++) {
339 			if (isxdigit(*charptr)) {
340 				break;
341 			}
342 		}
343 		if (*charptr != '\0') {
344 			tmpAddr = htonll(strtoll(charptr, NULL, 16));
345 			(void) memcpy(AttachedSASAddress.wwn, &tmpAddr, 8);
346 			/* check the attached address of hba port. */
347 			if (memcmp(port_ptr->port_attributes.
348 			    PortSpecificAttribute.SASPort->LocalSASAddress.wwn,
349 			    &tmpAddr, 8) == 0) {
350 				/*
351 				 * When attached-port is set from iport
352 				 * attached-port prop, we do the cross check
353 				 * with device's own SAS address.
354 				 *
355 				 * If not set, we store device's own SAS
356 				 * address to iport attached SAS address.
357 				 */
358 				if (wwnConversion(port_ptr->port_attributes.
359 				    PortSpecificAttribute.SASPort->
360 				    AttachedSASAddress.wwn)) {
361 					/* verify the Attaached SAS Addr. */
362 					if (memcmp(port_ptr->port_attributes.
363 					    PortSpecificAttribute.SASPort->
364 					    AttachedSASAddress.wwn,
365 					    SASAddress.wwn, 8) != 0) {
366 				/* indentation move begin. */
367 				log(LOG_DEBUG, ROUTINE,
368 				    "iport attached-port(%016llx) do not"
369 				    " match with level 1 Local"
370 				    " SAS address(%016llx).",
371 				    wwnConversion(port_ptr->port_attributes.
372 				    PortSpecificAttribute.
373 				    SASPort->AttachedSASAddress.wwn),
374 				    wwnConversion(SASAddress.wwn));
375 				di_devfs_path_free(devpath);
376 				free_attached_port(port_ptr);
377 				return (HBA_STATUS_ERROR);
378 				/* indentation move ends. */
379 					}
380 				} else {
381 					(void) memcpy(port_ptr->port_attributes.
382 					    PortSpecificAttribute.
383 					    SASPort->AttachedSASAddress.wwn,
384 					    &SASAddress.wwn[0], 8);
385 				}
386 			}
387 		} else {
388 			log(LOG_DEBUG, ROUTINE,
389 			    "No proper attached SAS address value on device %s",
390 			    fullpath);
391 			di_devfs_path_free(devpath);
392 			free_attached_port(port_ptr);
393 			return (HBA_STATUS_ERROR);
394 		}
395 	} else {
396 		log(LOG_DEBUG, ROUTINE,
397 		    "Property AttachedSASAddress not found for device \"%s\"",
398 		    fullpath);
399 		di_devfs_path_free(devpath);
400 		free_attached_port(port_ptr);
401 		return (HBA_STATUS_ERROR);
402 	}
403 
404 	/*
405 	 * walk the disco list to make sure that there isn't a matching
406 	 * port and node wwn or a matching device path
407 	 */
408 	portfound = 0;
409 	for (disco_port_ptr = port_ptr->first_attached_port;
410 	    disco_port_ptr != NULL;
411 	    disco_port_ptr = disco_port_ptr->next) {
412 		if ((disco_port_ptr->port_attributes.PortState !=
413 		    HBA_PORTSTATE_ERROR) && (memcmp(disco_port_ptr->
414 		    port_attributes.PortSpecificAttribute.
415 		    SASPort->LocalSASAddress.wwn, SASAddress.wwn, 8) == 0)) {
416 			/*
417 			 * found matching disco_port
418 			 * look for matching device path
419 			 */
420 			portfound = 1;
421 			for (mapping_ptr = disco_port_ptr->scsiInfo;
422 			    mapping_ptr != NULL;
423 			    mapping_ptr = mapping_ptr->next) {
424 				if (strstr(mapping_ptr-> entry.ScsiId.
425 				    OSDeviceName, devpath) != 0) {
426 					log(LOG_DEBUG, ROUTINE,
427 					    "Found an already discovered "
428 					    "device %s.", fullpath);
429 					di_devfs_path_free(devpath);
430 					return (HBA_STATUS_OK);
431 				}
432 			}
433 			if (portfound == 1) {
434 				break;
435 			}
436 		}
437 	}
438 
439 	if (portfound == 0) {
440 		/*
441 		 * there are no matching SAS address.
442 		 * this must be a new device
443 		 */
444 		if ((disco_port_ptr = (struct sun_sas_port *)calloc(1,
445 		    sizeof (struct sun_sas_port))) == NULL)  {
446 			OUT_OF_MEMORY(ROUTINE);
447 			di_devfs_path_free(devpath);
448 			free_attached_port(port_ptr);
449 			return (HBA_STATUS_ERROR);
450 		}
451 
452 		if ((disco_port_ptr->port_attributes.PortSpecificAttribute.\
453 		    SASPort = (struct SMHBA_SAS_Port *)calloc(1,
454 		    sizeof (struct SMHBA_SAS_Port))) == NULL) {
455 			OUT_OF_MEMORY("add_hba_port_info");
456 			di_devfs_path_free(devpath);
457 			free_attached_port(port_ptr);
458 			return (HBA_STATUS_ERROR);
459 		}
460 
461 		(void) memcpy(disco_port_ptr->port_attributes.
462 		    PortSpecificAttribute.SASPort->LocalSASAddress.wwn,
463 		    SASAddress.wwn, 8);
464 		(void) memcpy(disco_port_ptr->port_attributes.
465 		    PortSpecificAttribute.SASPort->AttachedSASAddress.wwn,
466 		    AttachedSASAddress.wwn, 8);
467 
468 		/* Default to unknown until we figure out otherwise */
469 		rval = di_prop_lookup_strings(DDI_DEV_T_ANY, node,
470 		    "variant", &propStringData);
471 		if (rval < 0) {
472 			/* check if it is SMP target */
473 			charptr = di_driver_name(node);
474 			if (charptr != NULL && (strncmp(charptr, "smp",
475 			    strlen(charptr)) == 0)) {
476 				disco_port_ptr->port_attributes.PortType =
477 				    HBA_PORTTYPE_SASEXPANDER;
478 				disco_port_ptr->port_attributes.
479 				    PortSpecificAttribute.
480 				    SASPort->PortProtocol =
481 				    HBA_SASPORTPROTOCOL_SMP;
482 				if (lookupSMPLink(devpath, (char *)link) ==
483 				    HBA_STATUS_OK) {
484 		/* indentation changed here. */
485 		(void) strlcpy(disco_port_ptr->port_attributes.
486 		    OSDeviceName, link,
487 		    sizeof (disco_port_ptr->port_attributes.OSDeviceName));
488 		/* indentation change ends here. */
489 				} else {
490 		/* indentation changed here. */
491 		get_minor(devpath, minorname);
492 		(void) snprintf(fullpath, sizeof (fullpath), "%s%s%s",
493 		    DEVICES_DIR, devpath, minorname);
494 		(void) strlcpy(disco_port_ptr->port_attributes.
495 		    OSDeviceName, fullpath,
496 		    sizeof (disco_port_ptr->port_attributes.OSDeviceName));
497 		/* indentation change ends here. */
498 				}
499 			} else {
500 				disco_port_ptr->port_attributes.PortType =
501 				    HBA_PORTTYPE_SASDEVICE;
502 				disco_port_ptr->port_attributes.\
503 				    PortSpecificAttribute.\
504 				    SASPort->PortProtocol =
505 				    HBA_SASPORTPROTOCOL_SSP;
506 			}
507 		} else {
508 			if ((strcmp(propStringData, "sata") == 0) ||
509 			    (strcmp(propStringData, "atapi") == 0)) {
510 				disco_port_ptr->port_attributes.PortType =
511 				    HBA_PORTTYPE_SATADEVICE;
512 				disco_port_ptr->port_attributes.\
513 				    PortSpecificAttribute.SASPort->PortProtocol
514 				    = HBA_SASPORTPROTOCOL_SATA;
515 			} else {
516 				log(LOG_DEBUG, ROUTINE,
517 				    "Unexpected variant prop value %s found on",
518 				    " device %s", propStringData, fullpath);
519 				/*
520 				 * Port type will be 0
521 				 * which is not valid type.
522 				 */
523 			}
524 		}
525 
526 		/* SMP device was handled already */
527 		if (disco_port_ptr->port_attributes.OSDeviceName[0] == '\0') {
528 		/* indentation change due to ctysle check on sizeof. */
529 		size = sizeof (disco_port_ptr->port_attributes.OSDeviceName);
530 			(void) strlcpy(disco_port_ptr->port_attributes.
531 			    OSDeviceName, fullpath, size);
532 		}
533 
534 		/* add new discovered port into the list */
535 
536 		if (port_ptr->first_attached_port == NULL) {
537 			port_ptr->first_attached_port = disco_port_ptr;
538 			disco_port_ptr->index = 0;
539 			port_ptr->port_attributes.PortSpecificAttribute.\
540 			    SASPort->NumberofDiscoveredPorts = 1;
541 		} else {
542 			disco_port_ptr->next = port_ptr->first_attached_port;
543 			port_ptr->first_attached_port = disco_port_ptr;
544 			disco_port_ptr->index = port_ptr->port_attributes.\
545 			    PortSpecificAttribute.\
546 			    SASPort->NumberofDiscoveredPorts;
547 			port_ptr->port_attributes.PortSpecificAttribute.\
548 			    SASPort->NumberofDiscoveredPorts++;
549 		}
550 		disco_port_ptr->port_attributes.PortState = port_state;
551 	}
552 
553 	if (disco_port_ptr->port_attributes.PortType ==
554 	    HBA_PORTTYPE_SASEXPANDER) {
555 	    /* No mapping data for expander device.  return ok here. */
556 		di_devfs_path_free(devpath);
557 		return (HBA_STATUS_OK);
558 	}
559 
560 	if ((mapping_ptr = (struct ScsiEntryList *)calloc
561 		    (1, sizeof (struct ScsiEntryList))) == NULL) {
562 		OUT_OF_MEMORY(ROUTINE);
563 		di_devfs_path_free(devpath);
564 		free_attached_port(port_ptr);
565 		return (HBA_STATUS_ERROR);
566 	}
567 
568 	if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "lun",
569 	    &propIntData) != -1) {
570 		mapping_ptr->entry.ScsiId.ScsiOSLun = *propIntData;
571 	} else {
572 		if ((charptr = strchr(unit_address, ',')) != NULL) {
573 			charptr++;
574 			mapping_ptr->entry.ScsiId.ScsiOSLun =
575 			    strtoull(charptr, NULL, 10);
576 		} else {
577 			log(LOG_DEBUG, ROUTINE,
578 			    "Failed to get LUN from the unit address of device "
579 			    " %s.", fullpath);
580 			di_devfs_path_free(devpath);
581 			free_attached_port(port_ptr);
582 			return (HBA_STATUS_ERROR);
583 		}
584 	}
585 
586 	/* get TargetLun(SAM-LUN). */
587 	if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, "lun64",
588 	    &propInt64Data) != -1) {
589 		samLun = scsi_lun64_to_lun(*propInt64Data);
590 		(void) memcpy(&mapping_ptr->entry.PortLun.TargetLun,
591 		    &samLun, 8);
592 	} else {
593 		log(LOG_DEBUG, "get_attached_devices_info",
594 		    "No lun64 prop found on device %s.", fullpath);
595 		di_devfs_path_free(devpath);
596 		free_attached_port(port_ptr);
597 		return (HBA_STATUS_ERROR);
598 	}
599 
600 	if (di_prop_lookup_ints(DDI_DEV_T_ANY, node,
601 	    "target", &propIntData) != -1) {
602 		mapping_ptr->entry.ScsiId.ScsiTargetNumber = *propIntData;
603 	} else {
604 		mapping_ptr->entry.ScsiId.ScsiTargetNumber = di_instance(node);
605 	}
606 
607 	/* get ScsiBusNumber */
608 	mapping_ptr->entry.ScsiId.ScsiBusNumber = port_ptr->cntlNumber;
609 
610 	(void) memcpy(mapping_ptr->entry.PortLun.PortWWN.wwn,
611 	    SASAddress.wwn, 8);
612 
613 	/* Store the devices path for now.  We'll convert to /dev later */
614 	get_minor(devpath, minorname);
615 	(void) snprintf(mapping_ptr->entry.ScsiId.OSDeviceName,
616 	    sizeof (mapping_ptr->entry.ScsiId.OSDeviceName),
617 	    "%s%s%s", DEVICES_DIR, devpath, minorname);
618 
619 	count = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, "inquiry-page-83",
620 	    (uchar_t **)&propByteData);
621 	if (count < 0) {
622 		get_luid(mapping_ptr->entry.ScsiId.OSDeviceName,
623 		    mapping_ptr->entry.LUID.buffer);
624 	} else {
625 		for (i = 0, charptr = mapping_ptr->entry.LUID.buffer; i < count;
626 		    i++, charptr += 2) {
627 			(void) sprintf(charptr, "%02x", propByteData[i]);
628 		}
629 		*charptr = '\0';
630 	}
631 
632 	if (disco_port_ptr->scsiInfo == NULL) {
633 		disco_port_ptr->scsiInfo = mapping_ptr;
634 	} else {
635 		mapping_ptr->next = disco_port_ptr->scsiInfo;
636 		disco_port_ptr->scsiInfo = mapping_ptr;
637 	}
638 
639 	di_devfs_path_free(devpath);
640 
641 	return (HBA_STATUS_OK);
642 }
643 
644 /*
645  * Finds attached device(target) from pathinfo node.
646  */
647 static HBA_STATUS
648 get_attached_paths_info(di_path_t path, struct sun_sas_port *port_ptr)
649 {
650 	char			    ROUTINE[] = "get_attached_paths_info";
651 	char			    *propStringData = NULL;
652 	int			    *propIntData = NULL;
653 	int64_t			    *propInt64Data = NULL;
654 	scsi_lun_t		    samLun;
655 	char			    *unit_address;
656 	char			    *charptr;
657 	char			    *clientdevpath = NULL;
658 	char			    *pathdevpath = NULL;
659 	char			    fullpath[MAXPATHLEN+1];
660 	char			    minorname[MAXNAMELEN+1];
661 	struct ScsiEntryList	    *mapping_ptr;
662 	HBA_WWN			    SASAddress, AttachedSASAddress;
663 	struct sun_sas_port	    *disco_port_ptr;
664 	di_path_state_t		    state = 0;
665 	di_node_t		    clientnode;
666 	int			    portfound, size;
667 	int			    port_state = HBA_PORTSTATE_ONLINE;
668 	uint64_t		    tmpAddr;
669 
670 	if (port_ptr == NULL) {
671 		log(LOG_DEBUG, ROUTINE, "NULL port_ptr argument");
672 		return (HBA_STATUS_ERROR);
673 	}
674 
675 	/* if not null, free before return. */
676 	pathdevpath = di_path_devfs_path(path);
677 
678 	state = di_path_state(path);
679 	/* when node is not attached and online, set the state to offline. */
680 	if ((state == DI_PATH_STATE_OFFLINE) ||
681 	    (state == DI_PATH_STATE_FAULT)) {
682 		log(LOG_DEBUG, ROUTINE,
683 		    "path node (%s) is either OFFLINE or FAULT state",
684 		    pathdevpath ?  pathdevpath : "(missing device path)");
685 		port_state = HBA_PORTSTATE_OFFLINE;
686 	}
687 
688 	if (clientnode = di_path_client_node(path)) {
689 		if (di_retired(clientnode)) {
690 			log(LOG_DEBUG, ROUTINE,
691 			    "client node of path (%s) is retired. Skipping.",
692 			    pathdevpath ?  pathdevpath :
693 			    "(missing device path)");
694 			if (pathdevpath) di_devfs_path_free(pathdevpath);
695 			return (HBA_STATUS_OK);
696 		}
697 		if ((clientdevpath = di_devfs_path(clientnode)) == NULL) {
698 			log(LOG_DEBUG, ROUTINE,
699 			    "Client device of path (%s) has no path. Skipping.",
700 			    pathdevpath ?  pathdevpath :
701 			    "(missing device path)");
702 			if (pathdevpath) di_devfs_path_free(pathdevpath);
703 			return (HBA_STATUS_ERROR);
704 		}
705 	} else {
706 		log(LOG_DEBUG, ROUTINE,
707 		    "Failed to get client device from a path (%s).",
708 		    pathdevpath ?  pathdevpath :
709 		    "(missing device path)");
710 		if (pathdevpath) di_devfs_path_free(pathdevpath);
711 		return (HBA_STATUS_ERROR);
712 	}
713 
714 	/* add the "/devices" in the begining and the :devctl at the end */
715 	(void) snprintf(fullpath, sizeof (fullpath), "%s%s", DEVICES_DIR,
716 	    clientdevpath);
717 
718 	(void) memset(&SASAddress, 0, sizeof (SASAddress));
719 	if ((unit_address = di_path_bus_addr(path)) != NULL) {
720 		if ((charptr = strchr(unit_address, ',')) != NULL) {
721 			*charptr = '\0';
722 		}
723 		for (charptr = unit_address; *charptr != '\0'; charptr++) {
724 			if (isxdigit(*charptr)) {
725 				break;
726 			}
727 		}
728 		if (charptr != '\0') {
729 			tmpAddr = htonll(strtoll(charptr, NULL, 16));
730 			(void) memcpy(&SASAddress.wwn[0], &tmpAddr, 8);
731 		} else {
732 			log(LOG_DEBUG, ROUTINE,
733 			    "No proper target port info on unit address of "
734 			    "path (%s).", pathdevpath ?  pathdevpath :
735 			    "(missing device path)");
736 			if (pathdevpath) di_devfs_path_free(pathdevpath);
737 			di_devfs_path_free(clientdevpath);
738 			return (HBA_STATUS_ERROR);
739 		}
740 	} else {
741 		log(LOG_DEBUG, ROUTINE, "Fail to get unit address of path(%s).",
742 		    "path (%s).", pathdevpath ?  pathdevpath :
743 		    "(missing device path)");
744 		if (pathdevpath) di_devfs_path_free(pathdevpath);
745 		di_devfs_path_free(clientdevpath);
746 		return (HBA_STATUS_ERROR);
747 	}
748 
749 	(void) memset(&AttachedSASAddress, 0, sizeof (AttachedSASAddress));
750 	if (di_path_prop_lookup_strings(path, "attached-port",
751 	    &propStringData) != -1) {
752 		for (charptr = propStringData; *charptr != '\0'; charptr++) {
753 			if (isxdigit(*charptr)) {
754 				break;
755 			}
756 		}
757 		if (*charptr != '\0') {
758 			tmpAddr = htonll(strtoll(charptr, NULL, 16));
759 			(void) memcpy(AttachedSASAddress.wwn, &tmpAddr, 8);
760 			/*  check the attached address of hba port. */
761 			if (memcmp(port_ptr->port_attributes.
762 			    PortSpecificAttribute.SASPort->
763 			    LocalSASAddress.wwn, &tmpAddr, 8) == 0) {
764 				if (wwnConversion(port_ptr->port_attributes.
765 				    PortSpecificAttribute.SASPort->
766 				    AttachedSASAddress.wwn)) {
767 					/* verify the attaached SAS Addr. */
768 					if (memcmp(port_ptr->port_attributes.
769 					    PortSpecificAttribute.SASPort->
770 					    AttachedSASAddress.wwn,
771 					    SASAddress.wwn, 8) != 0) {
772 				/* indentation move begin. */
773 				log(LOG_DEBUG, ROUTINE,
774 				    "iport attached-port(%016llx) do not"
775 				    " match with level 1 Local"
776 				    " SAS address(%016llx).",
777 				    wwnConversion(port_ptr->port_attributes.
778 				    PortSpecificAttribute.
779 				    SASPort->AttachedSASAddress.wwn),
780 				    wwnConversion(SASAddress.wwn));
781 				if (pathdevpath)
782 					di_devfs_path_free(pathdevpath);
783 				di_devfs_path_free(clientdevpath);
784 				free_attached_port(port_ptr);
785 				return (HBA_STATUS_ERROR);
786 				/* indentation move ends. */
787 					}
788 				} else {
789 					/* store the Attaached SAS Addr. */
790 					(void) memcpy(port_ptr->port_attributes.
791 					    PortSpecificAttribute.
792 					    SASPort->AttachedSASAddress.wwn,
793 					    &SASAddress.wwn[0], 8);
794 				}
795 			}
796 		} else {
797 			log(LOG_DEBUG, ROUTINE,
798 			    "No proper attached SAS address value of path (%s)",
799 			    pathdevpath ?  pathdevpath :
800 			    "(missing device path)");
801 			if (pathdevpath) di_devfs_path_free(pathdevpath);
802 			di_devfs_path_free(clientdevpath);
803 			free_attached_port(port_ptr);
804 			return (HBA_STATUS_ERROR);
805 		}
806 	} else {
807 		log(LOG_DEBUG, ROUTINE,
808 		    "Property attached-port not found for path (%s)",
809 		    pathdevpath ?  pathdevpath :
810 		    "(missing device path)");
811 		if (pathdevpath) di_devfs_path_free(pathdevpath);
812 		di_devfs_path_free(clientdevpath);
813 		free_attached_port(port_ptr);
814 		return (HBA_STATUS_ERROR);
815 	}
816 
817 	/*
818 	 * walk the disco list to make sure that there isn't a matching
819 	 * port and node wwn or a matching device path
820 	 */
821 	portfound = 0;
822 	for (disco_port_ptr = port_ptr->first_attached_port;
823 	    disco_port_ptr != NULL;
824 	    disco_port_ptr = disco_port_ptr->next) {
825 		if ((disco_port_ptr->port_attributes.PortState !=
826 		    HBA_PORTSTATE_ERROR) &&
827 		    (memcmp(disco_port_ptr->port_attributes.
828 		    PortSpecificAttribute.SASPort->LocalSASAddress.wwn,
829 		    SASAddress.wwn, 8) == 0)) {
830 			/*
831 			 * found matching disco_port
832 			 * look for matching device path
833 			 */
834 			portfound = 1;
835 			for (mapping_ptr = disco_port_ptr->scsiInfo;
836 			    mapping_ptr != NULL;
837 			    mapping_ptr = mapping_ptr->next) {
838 				if (strstr(mapping_ptr-> entry.ScsiId.
839 				    OSDeviceName, clientdevpath) != 0) {
840 					log(LOG_DEBUG, ROUTINE,
841 					    "Found an already discovered "
842 					    "device %s.", clientdevpath);
843 					if (pathdevpath)
844 						di_devfs_path_free(pathdevpath);
845 					di_devfs_path_free(clientdevpath);
846 					return (HBA_STATUS_OK);
847 				}
848 			}
849 			if (portfound == 1) {
850 				break;
851 			}
852 		}
853 	}
854 
855 	if (portfound == 0) {
856 		/*
857 		 * there are no matching SAS address.
858 		 * this must be a new device
859 		 */
860 		if ((disco_port_ptr = (struct sun_sas_port *)calloc(1,
861 				    sizeof (struct sun_sas_port))) == NULL)  {
862 			OUT_OF_MEMORY(ROUTINE);
863 			if (pathdevpath) di_devfs_path_free(pathdevpath);
864 			di_devfs_path_free(clientdevpath);
865 			free_attached_port(port_ptr);
866 			return (HBA_STATUS_ERROR);
867 		}
868 
869 		if ((disco_port_ptr->port_attributes.PortSpecificAttribute.\
870 		    SASPort = (struct SMHBA_SAS_Port *)calloc(1,
871 		    sizeof (struct SMHBA_SAS_Port))) == NULL) {
872 			OUT_OF_MEMORY("add_hba_port_info");
873 			if (pathdevpath) di_devfs_path_free(pathdevpath);
874 			di_devfs_path_free(clientdevpath);
875 			free_attached_port(port_ptr);
876 			return (HBA_STATUS_ERROR);
877 		}
878 
879 		(void) memcpy(disco_port_ptr->port_attributes.
880 		    PortSpecificAttribute.
881 		    SASPort->LocalSASAddress.wwn, SASAddress.wwn, 8);
882 		(void) memcpy(disco_port_ptr->port_attributes.
883 		    PortSpecificAttribute.
884 		    SASPort->AttachedSASAddress.wwn, AttachedSASAddress.wwn, 8);
885 
886 		/* Default to unknown until we figure out otherwise */
887 		if (di_path_prop_lookup_strings(path, "variant",
888 		    &propStringData) != -1) {
889 			if ((strcmp(propStringData, "sata") == 0) ||
890 			    (strcmp(propStringData, "atapi") == 0)) {
891 				disco_port_ptr->port_attributes.PortType =
892 				    HBA_PORTTYPE_SATADEVICE;
893 				disco_port_ptr->port_attributes.\
894 				    PortSpecificAttribute.SASPort->PortProtocol
895 				    = HBA_SASPORTPROTOCOL_SATA;
896 			} else {
897 				log(LOG_DEBUG, ROUTINE,
898 				    "Unexpected variant prop value %s found on",
899 				    " path (%s)", propStringData,
900 				    pathdevpath ?  pathdevpath :
901 				    "(missing device path)");
902 				/*
903 				 * Port type will be 0
904 				 * which is not valid type.
905 				 */
906 			}
907 		} else {
908 			disco_port_ptr->port_attributes.PortType =
909 			    HBA_PORTTYPE_SASDEVICE;
910 			disco_port_ptr->port_attributes.PortSpecificAttribute.\
911 			    SASPort->PortProtocol = HBA_SASPORTPROTOCOL_SSP;
912 		}
913 
914 		if (disco_port_ptr->port_attributes.OSDeviceName[0] == '\0') {
915 		/* indentation change due to ctysle check on sizeof. */
916 		size = sizeof (disco_port_ptr->port_attributes.OSDeviceName);
917 			if (pathdevpath != NULL) {
918 				(void) strlcpy(disco_port_ptr->port_attributes.
919 				    OSDeviceName, pathdevpath, size);
920 			}
921 		}
922 
923 		/* add new discovered port into the list */
924 		if (port_ptr->first_attached_port == NULL) {
925 			port_ptr->first_attached_port = disco_port_ptr;
926 			disco_port_ptr->index = 0;
927 			port_ptr->port_attributes.PortSpecificAttribute.\
928 			    SASPort->NumberofDiscoveredPorts = 1;
929 		} else {
930 			disco_port_ptr->next = port_ptr->first_attached_port;
931 			port_ptr->first_attached_port = disco_port_ptr;
932 			disco_port_ptr->index = port_ptr->port_attributes.\
933 			    PortSpecificAttribute.\
934 			    SASPort->NumberofDiscoveredPorts;
935 			port_ptr->port_attributes.PortSpecificAttribute.\
936 			    SASPort->NumberofDiscoveredPorts++;
937 		}
938 		disco_port_ptr->port_attributes.PortState = port_state;
939 	}
940 
941 	if ((mapping_ptr = (struct ScsiEntryList *)calloc
942 		    (1, sizeof (struct ScsiEntryList))) == NULL) {
943 		OUT_OF_MEMORY(ROUTINE);
944 		if (pathdevpath) di_devfs_path_free(pathdevpath);
945 		di_devfs_path_free(clientdevpath);
946 		free_attached_port(port_ptr);
947 		return (HBA_STATUS_ERROR);
948 	}
949 
950 	if (di_path_prop_lookup_ints(path, "lun", &propIntData) != -1) {
951 		mapping_ptr->entry.ScsiId.ScsiOSLun = *propIntData;
952 	} else {
953 		if ((charptr = strchr(unit_address, ',')) != NULL) {
954 			charptr++;
955 			mapping_ptr->entry.ScsiId.ScsiOSLun =
956 			    strtoull(charptr, NULL, 10);
957 		} else {
958 			log(LOG_DEBUG, ROUTINE,
959 			    "Failed to get LUN from unit address of path(%s).",
960 			    pathdevpath ?  pathdevpath :
961 			    "(missing device path)");
962 			if (pathdevpath) di_devfs_path_free(pathdevpath);
963 			di_devfs_path_free(clientdevpath);
964 			free_attached_port(port_ptr);
965 			return (HBA_STATUS_ERROR);
966 		}
967 	}
968 
969 	/* Get TargetLun(SAM LUN). */
970 	if (di_path_prop_lookup_int64s(path, "lun64", &propInt64Data) != -1) {
971 		samLun = scsi_lun64_to_lun(*propInt64Data);
972 		(void) memcpy(&mapping_ptr->entry.PortLun.TargetLun,
973 		    &samLun, 8);
974 	} else {
975 		log(LOG_DEBUG, ROUTINE, "No lun64 prop found on path (%s)",
976 		    pathdevpath ?  pathdevpath :
977 		    "(missing device path)");
978 		if (pathdevpath) di_devfs_path_free(pathdevpath);
979 		di_devfs_path_free(clientdevpath);
980 		free_attached_port(port_ptr);
981 		return (HBA_STATUS_ERROR);
982 	}
983 
984 	if (di_path_prop_lookup_ints(path, "target", &propIntData) != -1) {
985 		mapping_ptr->entry.ScsiId.ScsiTargetNumber = *propIntData;
986 	} else {
987 		mapping_ptr->entry.ScsiId.ScsiTargetNumber =
988 		    di_path_instance(path);
989 	}
990 
991 	/* get ScsiBusNumber */
992 	mapping_ptr->entry.ScsiId.ScsiBusNumber = port_ptr->cntlNumber;
993 
994 	(void) memcpy(mapping_ptr->entry.PortLun.PortWWN.wwn,
995 	    SASAddress.wwn, 8);
996 
997 	/* Store the devices path for now.  We'll convert to /dev later */
998 	get_minor(clientdevpath, minorname);
999 	(void) snprintf(mapping_ptr->entry.ScsiId.OSDeviceName,
1000 	    sizeof (mapping_ptr->entry.ScsiId.OSDeviceName),
1001 	    "%s%s%s", DEVICES_DIR, clientdevpath, minorname);
1002 
1003 	/* get luid. */
1004 	if (di_prop_lookup_strings(DDI_DEV_T_ANY, clientnode,
1005 	    "client-guid", &propStringData) != -1) {
1006 		(void) strlcpy(mapping_ptr->entry.LUID.buffer, propStringData,
1007 		    sizeof (mapping_ptr->entry.LUID.buffer));
1008 	} else {
1009 		log(LOG_DEBUG, ROUTINE, "No client-guid prop found on path(%s)",
1010 		    pathdevpath ?  pathdevpath :
1011 		    "(missing device path)");
1012 		if (pathdevpath) di_devfs_path_free(pathdevpath);
1013 		di_devfs_path_free(clientdevpath);
1014 		free_attached_port(port_ptr);
1015 		return (HBA_STATUS_ERROR);
1016 	}
1017 
1018 	if (disco_port_ptr->scsiInfo == NULL) {
1019 		disco_port_ptr->scsiInfo = mapping_ptr;
1020 	} else {
1021 		mapping_ptr->next = disco_port_ptr->scsiInfo;
1022 		disco_port_ptr->scsiInfo = mapping_ptr;
1023 	}
1024 
1025 	if (pathdevpath) di_devfs_path_free(pathdevpath);
1026 	di_devfs_path_free(clientdevpath);
1027 
1028 	return (HBA_STATUS_OK);
1029 }
1030 
1031 /*
1032  * walks the devinfo tree retrieving all hba information
1033  */
1034 extern HBA_STATUS
1035 devtree_attached_devices(di_node_t node, struct sun_sas_port *port_ptr)
1036 {
1037 	const char		ROUTINE[] = "devtree_attached_devices";
1038 	di_node_t		nodechild = DI_NODE_NIL;
1039 	di_path_t		path = DI_PATH_NIL;
1040 
1041 	/* child should be device */
1042 	if ((nodechild = di_child_node(node)) == DI_NODE_NIL) {
1043 		log(LOG_DEBUG, ROUTINE,
1044 		    "No devinfo child on the HBA port node.");
1045 	}
1046 
1047 	if ((path = di_path_phci_next_path(node, path)) ==
1048 	    DI_PATH_NIL) {
1049 		log(LOG_DEBUG, ROUTINE,
1050 		    "No pathinfo node on the HBA port node.");
1051 	}
1052 
1053 	if ((nodechild == DI_NODE_NIL) && (path == DI_PATH_NIL)) {
1054 		return (HBA_STATUS_OK);
1055 	}
1056 
1057 	while (nodechild != DI_NODE_NIL) {
1058 		if (get_attached_devices_info(nodechild, port_ptr)
1059 		    != HBA_STATUS_OK) {
1060 			break;
1061 		}
1062 		nodechild = di_sibling_node(nodechild);
1063 	}
1064 
1065 
1066 	while (path != DI_PATH_NIL) {
1067 		if (get_attached_paths_info(path, port_ptr)
1068 		    != HBA_STATUS_OK) {
1069 			break;
1070 		}
1071 		path = di_path_phci_next_path(node, path);
1072 	}
1073 
1074 	return (HBA_STATUS_OK);
1075 }
1076