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.
28 #include <sys/types.h>
32 #include <libdevinfo.h>
33 #include <netinet/in.h>
37 * structure for di_devlink_walk
39 typedef struct walk_devlink
{
46 * Free the phy allocation.
49 free_phy_info(struct sun_sas_port
*port_ptr
)
51 struct phy_info
*phy_ptr
, *last_phy
;
53 phy_ptr
= port_ptr
->first_phy
;
54 while (phy_ptr
!= NULL
) {
56 phy_ptr
= phy_ptr
->next
;
60 port_ptr
->first_phy
= NULL
;
65 * callback funtion for di_devlink_walk
66 * Find matching /dev link for the given path argument.
67 * devlink element and callback function argument.
68 * The input path is expected to not have "/devices".
71 get_phy_info(di_node_t node
, struct sun_sas_port
*port_ptr
)
73 const char ROUTINE
[] = "get_phy_info";
74 char *portDevpath
= NULL
;
75 uchar_t
*propByteData
= NULL
;
76 struct phy_info
*phy_ptr
;
79 nvlist_t
*nvl
, **phyInfoVal
;
81 int8_t negoRate
, prgmMinRate
, prgmMaxRate
, hwMinRate
, hwMaxRate
;
84 * When path is specified, it doesn't have minor
85 * name. Therefore, the ../.. prefixes needs to be stripped.
87 if ((portDevpath
= di_devfs_path(node
)) == NULL
) {
88 log(LOG_DEBUG
, ROUTINE
,
89 "Unable to get device path from portNode.");
92 count
= di_prop_lookup_bytes(DDI_DEV_T_ANY
, node
, "phy-info",
93 (uchar_t
**)&propByteData
);
96 log(LOG_DEBUG
, ROUTINE
,
97 "Property phy-info not found on port %s%s",
98 DEVICES_DIR
, portDevpath
);
99 di_devfs_path_free(portDevpath
);
101 log(LOG_DEBUG
, ROUTINE
, "Property phy-info not found.");
103 return (HBA_STATUS_ERROR
);
105 rval
= nvlist_unpack((char *)propByteData
, count
, &nvl
, 0);
108 log(LOG_DEBUG
, ROUTINE
,
109 "nvlist_unpack failed on port %s%s",
110 DEVICES_DIR
, portDevpath
);
111 di_devfs_path_free(portDevpath
);
113 log(LOG_DEBUG
, ROUTINE
,
114 "nvlist_unpack failed.");
116 return (HBA_STATUS_ERROR
);
118 rval
= nvlist_lookup_nvlist_array(nvl
, "phy-info-nvl",
119 &phyInfoVal
, &nvcount
);
122 log(LOG_DEBUG
, ROUTINE
,
123 "nvlist array phy-info-nvl not\
124 found on port %s%s", DEVICES_DIR
,
126 di_devfs_path_free(portDevpath
);
128 log(LOG_DEBUG
, ROUTINE
,
129 "nvlist array phy-info-nvl not\
133 return (HBA_STATUS_ERROR
);
135 /* indentation moved */
136 for (i
= 0; i
< nvcount
; i
++) {
137 if (nvlist_lookup_uint8(phyInfoVal
[i
],
138 "PhyIdentifier", &phyId
) != 0) {
139 /* Indicate a failure : no better way to set */
142 if (nvlist_lookup_int8(phyInfoVal
[i
],
143 "NegotiatedLinkRate", &negoRate
) != 0) {
144 negoRate
= HBA_SASSTATE_UNKNOWN
;
146 if (nvlist_lookup_int8(phyInfoVal
[i
],
147 "ProgrammedMinLinkRate", &prgmMinRate
) != 0) {
148 prgmMinRate
= HBA_SASSTATE_UNKNOWN
;
150 if (nvlist_lookup_int8(phyInfoVal
[i
],
151 "ProgrammedMaxLinkRate", &prgmMaxRate
) != 0) {
152 prgmMaxRate
= HBA_SASSTATE_UNKNOWN
;
154 if (nvlist_lookup_int8(phyInfoVal
[i
],
155 "HardwareMinLinkRate", &hwMinRate
) != 0) {
156 hwMinRate
= HBA_SASSTATE_UNKNOWN
;
158 if (nvlist_lookup_int8(phyInfoVal
[i
],
159 "HardwareMaxLinkRate", &hwMaxRate
) != 0) {
160 hwMaxRate
= HBA_SASSTATE_UNKNOWN
;
163 if ((phy_ptr
= (struct phy_info
*)calloc(1,
164 sizeof (struct phy_info
))) == NULL
) {
165 OUT_OF_MEMORY(ROUTINE
);
167 di_devfs_path_free(portDevpath
);
168 free_phy_info(port_ptr
);
170 return (HBA_STATUS_ERROR
);
172 phy_ptr
->phy
.PhyIdentifier
= phyId
;
173 phy_ptr
->phy
.NegotiatedLinkRate
= negoRate
;
174 phy_ptr
->phy
.ProgrammedMinLinkRate
= prgmMinRate
;
175 phy_ptr
->phy
.ProgrammedMaxLinkRate
= prgmMaxRate
;
176 phy_ptr
->phy
.HardwareMinLinkRate
= hwMinRate
;
177 phy_ptr
->phy
.HardwareMaxLinkRate
= hwMaxRate
;
179 * we will fill domain port later.
181 (void) memset(phy_ptr
->phy
.domainPortWWN
.wwn
, 0, 8);
183 if (port_ptr
->first_phy
== NULL
) {
184 port_ptr
->first_phy
= phy_ptr
;
186 phy_ptr
->next
= port_ptr
->first_phy
;
187 port_ptr
->first_phy
= phy_ptr
;
192 /* end of indentation move */
198 di_devfs_path_free(portDevpath
);
201 return (HBA_STATUS_OK
);