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