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