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.
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.
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]
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.
29 #include <sys/types.h>
30 #include <netinet/in.h>
33 #include <sys/scsi/scsi_address.h>
37 * Get the preferred minor node for the given path.
38 * ":n" for tapes, ":c,raw" for disks,
39 * and ":0" for enclosures.
42 get_minor(char *devpath
, char *minor
)
44 const char ROUTINE
[] = "get_minor";
45 char fullpath
[MAXPATHLEN
];
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
,
57 (void) snprintf(fullpath
, MAXPATHLEN
, "%s%s%s", DEVICES_DIR
,
59 /* reset errno to 0 */
61 if ((fd
= open(fullpath
, O_RDONLY
)) == -1) {
63 * :0 minor doesn't exist. assume bound to sgen driver
64 * and :ses minor exist.
66 if (errno
== ENOENT
) {
67 (void) strcpy(minor
, ":ses");
70 (void) strcpy(minor
, ":0");
74 log(LOG_DEBUG
, ROUTINE
, "Unrecognized target (%s)",
82 * Free the attached port allocation.
85 free_attached_port(struct sun_sas_port
*port_ptr
)
87 struct sun_sas_port
*tgt_port
, *last_tgt_port
;
88 struct ScsiEntryList
*scsi_info
= NULL
, *last_scsi_info
= NULL
;
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
;
99 last_tgt_port
= tgt_port
;
100 tgt_port
= tgt_port
->next
;
101 free(last_tgt_port
->port_attributes
.\
102 PortSpecificAttribute
.SASPort
);
106 port_ptr
->first_attached_port
= NULL
;
107 port_ptr
->port_attributes
.PortSpecificAttribute
.\
108 SASPort
->NumberofDiscoveredPorts
= 0;
112 * Fill domainPortWWN.
113 * should be called after completing discovered port discovery.
116 fillDomainPortWWN(struct sun_sas_port
*port_ptr
)
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
;
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);
142 if (domainPort
== 0) {
143 if (port_ptr
->first_attached_port
) {
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
149 * Set the SAS address of direct attached target.
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);
163 * SAS address is not upstream connected.
164 * domainPortWWN stays as 0.
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
));
180 * There existss an iport without properly configured
181 * child smp ndoes or child node or pathinfo.
182 * domainPortWWN stays as 0.
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
));
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);
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
;
206 mapping_ptr
= mapping_ptr
->next
) {
207 (void) memcpy(mapping_ptr
->entry
.PortLun
.
208 domainPortWWN
.wwn
, &domainPort
, 8);
214 * Finds attached device(target) from devinfo node.
217 get_attached_devices_info(di_node_t node
, struct sun_sas_port
*port_ptr
)
219 const char ROUTINE
[] = "get_attached_devices_info";
220 char *propStringData
= NULL
;
221 int *propIntData
= NULL
;
222 int64_t *propInt64Data
= NULL
;
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
;
235 int portfound
, rval
, size
;
236 int port_state
= HBA_PORTSTATE_ONLINE
;
239 if (port_ptr
== NULL
) {
240 log(LOG_DEBUG
, ROUTINE
, "NULL port_ptr argument");
241 return (HBA_STATUS_ERROR
);
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
);
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
);
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",
264 port_state
= HBA_PORTSTATE_OFFLINE
;
267 /* add the "/devices" in the begining at the end */
268 (void) snprintf(fullpath
, sizeof (fullpath
), "%s%s",
269 DEVICES_DIR
, devpath
);
271 (void) memset(&SASAddress
, 0, sizeof (SASAddress
));
272 if ((unit_address
= di_bus_addr(node
)) != NULL
) {
273 if ((charptr
= strchr(unit_address
, ',')) != NULL
) {
276 for (charptr
= unit_address
; *charptr
!= '\0'; charptr
++) {
277 if (isxdigit(*charptr
)) {
281 if (*charptr
!= '\0') {
282 tmpAddr
= htonll(strtoll(charptr
, NULL
, 16));
283 (void) memcpy(&SASAddress
.wwn
[0], &tmpAddr
, 8);
285 log(LOG_DEBUG
, ROUTINE
,
286 "No proper target port info on unit address of %s",
288 di_devfs_path_free(devpath
);
289 return (HBA_STATUS_ERROR
);
292 log(LOG_DEBUG
, ROUTINE
,
293 "Fail to get unit address of %s.",
295 di_devfs_path_free(devpath
);
296 return (HBA_STATUS_ERROR
);
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
)) {
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
,
315 * When attached-port is set from iport
316 * attached-port prop, we do the cross check
317 * with device's own SAS address.
319 * If not set, we store device's own SAS
320 * address to iport attached SAS address.
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. */
345 (void) memcpy(port_ptr
->port_attributes
.
346 PortSpecificAttribute
.
347 SASPort
->AttachedSASAddress
.wwn
,
348 &SASAddress
.wwn
[0], 8);
352 log(LOG_DEBUG
, ROUTINE
,
353 "No proper attached SAS address value on device %s",
355 di_devfs_path_free(devpath
);
356 free_attached_port(port_ptr
);
357 return (HBA_STATUS_ERROR
);
360 log(LOG_DEBUG
, ROUTINE
,
361 "Property AttachedSASAddress not found for device \"%s\"",
363 di_devfs_path_free(devpath
);
364 free_attached_port(port_ptr
);
365 return (HBA_STATUS_ERROR
);
369 * walk the disco list to make sure that there isn't a matching
370 * port and node wwn or a matching device path
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)) {
381 * found matching disco_port
382 * look for matching device path
385 for (mapping_ptr
= disco_port_ptr
->scsiInfo
;
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
);
397 if (portfound
== 1) {
403 if (portfound
== 0) {
405 * there are no matching SAS address.
406 * this must be a new device
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
);
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
);
425 (void) memcpy(disco_port_ptr
->port_attributes
.
426 PortSpecificAttribute
.SASPort
->LocalSASAddress
.wwn
,
428 (void) memcpy(disco_port_ptr
->port_attributes
.
429 PortSpecificAttribute
.SASPort
->AttachedSASAddress
.wwn
,
430 AttachedSASAddress
.wwn
, 8);
432 /* Default to unknown until we figure out otherwise */
433 rval
= di_prop_lookup_strings(DDI_DEV_T_ANY
, node
,
434 "variant", &propStringData
);
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
) ==
448 /* indentation changed here. */
449 (void) strlcpy(disco_port_ptr
->port_attributes
.
451 sizeof (disco_port_ptr
->port_attributes
.OSDeviceName
));
452 /* indentation change ends here. */
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. */
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
;
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
;
480 log(LOG_DEBUG
, ROUTINE
,
481 "Unexpected variant prop value %s found on",
482 " device %s", propStringData
, fullpath
);
484 * Port type will be 0
485 * which is not valid type.
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
);
498 /* add new discovered port into the list */
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;
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
++;
514 disco_port_ptr
->port_attributes
.PortState
= port_state
;
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
);
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
);
532 if (di_prop_lookup_ints(DDI_DEV_T_ANY
, node
, "lun",
533 &propIntData
) != -1) {
534 mapping_ptr
->entry
.ScsiId
.ScsiOSLun
= *propIntData
;
536 if ((charptr
= strchr(unit_address
, ',')) != NULL
) {
538 mapping_ptr
->entry
.ScsiId
.ScsiOSLun
=
539 strtoull(charptr
, NULL
, 10);
541 log(LOG_DEBUG
, ROUTINE
,
542 "Failed to get LUN from the unit address of device "
544 di_devfs_path_free(devpath
);
545 free_attached_port(port_ptr
);
546 return (HBA_STATUS_ERROR
);
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
,
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
);
564 if (di_prop_lookup_ints(DDI_DEV_T_ANY
, node
,
565 "target", &propIntData
) != -1) {
566 mapping_ptr
->entry
.ScsiId
.ScsiTargetNumber
= *propIntData
;
568 mapping_ptr
->entry
.ScsiId
.ScsiTargetNumber
= di_instance(node
);
571 /* get ScsiBusNumber */
572 mapping_ptr
->entry
.ScsiId
.ScsiBusNumber
= port_ptr
->cntlNumber
;
574 (void) memcpy(mapping_ptr
->entry
.PortLun
.PortWWN
.wwn
,
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
);
583 /* reset errno to 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
,
592 sizeof (mapping_ptr
->entry
.LUID
.buffer
));
593 devid_free_guid(guidStr
);
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.
601 log(LOG_DEBUG
, ROUTINE
,
602 "failed to get devid guid on (%s) : %s",
603 devpath
, strerror(errno
));
609 * device may not support proper page 83 id descriptor.
610 * leave LUID attribute to NULL and continue.
612 log(LOG_DEBUG
, ROUTINE
,
613 "failed to decode devid prop on (%s) : %s",
614 devpath
, strerror(errno
));
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
));
623 if (disco_port_ptr
->scsiInfo
== NULL
) {
624 disco_port_ptr
->scsiInfo
= mapping_ptr
;
626 mapping_ptr
->next
= disco_port_ptr
->scsiInfo
;
627 disco_port_ptr
->scsiInfo
= mapping_ptr
;
630 di_devfs_path_free(devpath
);
632 return (HBA_STATUS_OK
);
636 * Finds attached device(target) from pathinfo node.
639 get_attached_paths_info(di_path_t path
, struct sun_sas_port
*port_ptr
)
641 char ROUTINE
[] = "get_attached_paths_info";
642 char *propStringData
= NULL
;
643 int *propIntData
= NULL
;
644 int64_t *propInt64Data
= NULL
;
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
;
660 int port_state
= HBA_PORTSTATE_ONLINE
;
663 if (port_ptr
== NULL
) {
664 log(LOG_DEBUG
, ROUTINE
, "NULL port_ptr argument");
665 return (HBA_STATUS_ERROR
);
668 /* if not null, free before return. */
669 pathdevpath
= di_path_devfs_path(path
);
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
;
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
);
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
);
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
);
707 /* add the "/devices" in the begining and the :devctl at the end */
708 (void) snprintf(fullpath
, sizeof (fullpath
), "%s%s", DEVICES_DIR
,
711 (void) memset(&SASAddress
, 0, sizeof (SASAddress
));
712 if ((unit_address
= di_path_bus_addr(path
)) != NULL
) {
713 if ((charptr
= strchr(unit_address
, ',')) != NULL
) {
716 for (charptr
= unit_address
; *charptr
!= '\0'; charptr
++) {
717 if (isxdigit(*charptr
)) {
721 if (charptr
!= '\0') {
722 tmpAddr
= htonll(strtoll(charptr
, NULL
, 16));
723 (void) memcpy(&SASAddress
.wwn
[0], &tmpAddr
, 8);
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
);
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
);
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
)) {
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
));
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. */
782 /* store the Attaached SAS Addr. */
783 (void) memcpy(port_ptr
->port_attributes
.
784 PortSpecificAttribute
.
785 SASPort
->AttachedSASAddress
.wwn
,
786 &SASAddress
.wwn
[0], 8);
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
);
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
);
811 * walk the disco list to make sure that there isn't a matching
812 * port and node wwn or a matching device path
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)) {
824 * found matching disco_port
825 * look for matching device path
828 for (mapping_ptr
= disco_port_ptr
->scsiInfo
;
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
);
837 di_devfs_path_free(pathdevpath
);
838 di_devfs_path_free(clientdevpath
);
839 return (HBA_STATUS_OK
);
842 if (portfound
== 1) {
848 if (portfound
== 0) {
850 * there are no matching SAS address.
851 * this must be a new device
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
);
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
);
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);
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
;
890 log(LOG_DEBUG
, ROUTINE
,
891 "Unexpected variant prop value %s found on",
892 " path (%s)", propStringData
,
893 pathdevpath
? pathdevpath
:
894 "(missing device path)");
896 * Port type will be 0
897 * which is not valid type.
901 disco_port_ptr
->port_attributes
.PortType
=
902 HBA_PORTTYPE_SASDEVICE
;
903 disco_port_ptr
->port_attributes
.PortSpecificAttribute
.\
904 SASPort
->PortProtocol
= HBA_SASPORTPROTOCOL_SSP
;
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
);
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;
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
++;
931 disco_port_ptr
->port_attributes
.PortState
= port_state
;
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
);
943 if (di_path_prop_lookup_ints(path
, "lun", &propIntData
) != -1) {
944 mapping_ptr
->entry
.ScsiId
.ScsiOSLun
= *propIntData
;
946 if ((charptr
= strchr(unit_address
, ',')) != NULL
) {
948 mapping_ptr
->entry
.ScsiId
.ScsiOSLun
=
949 strtoull(charptr
, NULL
, 10);
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
);
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
,
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
);
977 if (di_path_prop_lookup_ints(path
, "target", &propIntData
) != -1) {
978 mapping_ptr
->entry
.ScsiId
.ScsiTargetNumber
= *propIntData
;
980 mapping_ptr
->entry
.ScsiId
.ScsiTargetNumber
=
981 di_path_instance(path
);
984 /* get ScsiBusNumber */
985 mapping_ptr
->entry
.ScsiId
.ScsiBusNumber
= port_ptr
->cntlNumber
;
987 (void) memcpy(mapping_ptr
->entry
.PortLun
.PortWWN
.wwn
,
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
);
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
,
1005 sizeof (mapping_ptr
->entry
.LUID
.buffer
));
1006 devid_free_guid(guidStr
);
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.
1014 log(LOG_DEBUG
, ROUTINE
,
1015 "failed to get devid guid on (%s)",
1016 " associated with path(%s) : %s",
1018 pathdevpath
? pathdevpath
:
1019 "(missing device path)",
1026 * device may not support proper page 83 id descriptor.
1027 * leave LUID attribute to NULL and continue.
1029 log(LOG_DEBUG
, ROUTINE
,
1030 "failed to decode devid prop on (%s)",
1031 " associated with path(%s) : %s",
1033 pathdevpath
? pathdevpath
:
1034 "(missing device path)",
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)",
1045 if (disco_port_ptr
->scsiInfo
== NULL
) {
1046 disco_port_ptr
->scsiInfo
= mapping_ptr
;
1048 mapping_ptr
->next
= disco_port_ptr
->scsiInfo
;
1049 disco_port_ptr
->scsiInfo
= mapping_ptr
;
1052 if (pathdevpath
) di_devfs_path_free(pathdevpath
);
1053 di_devfs_path_free(clientdevpath
);
1055 return (HBA_STATUS_OK
);
1059 * walks the devinfo tree retrieving all hba information
1062 devtree_attached_devices(di_node_t node
, struct sun_sas_port
*port_ptr
)
1064 const char ROUTINE
[] = "devtree_attached_devices";
1065 di_node_t nodechild
= DI_NODE_NIL
;
1066 di_path_t path
= DI_PATH_NIL
;
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.");
1074 if ((path
= di_path_phci_next_path(node
, path
)) ==
1076 log(LOG_DEBUG
, ROUTINE
,
1077 "No pathinfo node on the HBA port node.");
1080 if ((nodechild
== DI_NODE_NIL
) && (path
== DI_PATH_NIL
)) {
1081 return (HBA_STATUS_OK
);
1084 while (nodechild
!= DI_NODE_NIL
) {
1085 if (get_attached_devices_info(nodechild
, port_ptr
)
1089 nodechild
= di_sibling_node(nodechild
);
1093 while (path
!= DI_PATH_NIL
) {
1094 if (get_attached_paths_info(path
, port_ptr
)
1098 path
= di_path_phci_next_path(node
, path
);
1101 return (HBA_STATUS_OK
);