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