1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <kstat.h>
28 #include <sun_sas.h>
29
30 /*
31 * Retrieves the statistics for a specified port.phy on an adapter
32 */
Sun_sasGetPhyStatistics(HBA_HANDLE handle,HBA_UINT32 port,HBA_UINT32 phy,SMHBA_PHYSTATISTICS * pStatistics)33 HBA_STATUS Sun_sasGetPhyStatistics(HBA_HANDLE handle,
34 HBA_UINT32 port, HBA_UINT32 phy, SMHBA_PHYSTATISTICS *pStatistics) {
35 const char ROUTINE[] = "Sun_sasGetPhyStatistics";
36 HBA_STATUS status = HBA_STATUS_OK;
37 struct sun_sas_hba *hba_ptr;
38 struct sun_sas_port *hba_port_ptr;
39 struct phy_info *phy_ptr;
40 PSMHBA_SASPHYSTATISTICS psas;
41 kstat_ctl_t *kc;
42 kstat_t *ksp;
43 kstat_named_t *kname;
44 char *charptr, path[MAXPATHLEN + 1];
45 char *driver_name, kstat_name[256];
46 di_node_t node;
47 int instance = 0;
48 int i;
49 uint64_t iport_wwn;
50
51 /* Validate the arguments */
52 if (pStatistics == NULL) {
53 log(LOG_DEBUG, ROUTINE,
54 "NULL Phy Statistics buffer of phyIndex: %08lx", phy);
55 return (HBA_STATUS_ERROR_ARG);
56 }
57 psas = pStatistics->SASPhyStatistics;
58 if (psas == NULL) {
59 log(LOG_DEBUG, ROUTINE,
60 "NULL SAS Phy Statistics buffer of phyIndex: %08lx", phy);
61 return (HBA_STATUS_ERROR_ARG);
62 }
63
64 lock(&all_hbas_lock);
65
66 if ((hba_ptr = Retrieve_Sun_sasHandle(handle)) == NULL) {
67 log(LOG_DEBUG, ROUTINE,
68 "Invalid HBA handler %08lx of phyIndex: %08lx",
69 handle, phy);
70 unlock(&all_hbas_lock);
71 return (HBA_STATUS_ERROR_INVALID_HANDLE);
72 }
73
74 /* Check for stale data */
75 status = verifyAdapter(hba_ptr);
76 if (status != HBA_STATUS_OK) {
77 log(LOG_DEBUG, ROUTINE,
78 "Verify Adapter failed for phyIndex: %08lx", phy);
79 unlock(&all_hbas_lock);
80 return (status);
81 }
82
83 for (hba_port_ptr = hba_ptr->first_port;
84 hba_port_ptr != NULL;
85 hba_port_ptr = hba_port_ptr->next) {
86 if (hba_port_ptr->index == port) {
87 break;
88 }
89 }
90
91 if (hba_port_ptr == NULL) {
92 log(LOG_DEBUG, ROUTINE,
93 "Invalid port index of phyIndex: %08lx", phy);
94 unlock(&all_hbas_lock);
95 return (HBA_STATUS_ERROR_ILLEGAL_INDEX);
96 }
97
98 if (phy >= hba_port_ptr->port_attributes.PortSpecificAttribute.
99 SASPort->NumberofPhys) {
100 log(LOG_DEBUG, ROUTINE, "Invalid phy index %08lx", phy);
101 unlock(&all_hbas_lock);
102 return (HBA_STATUS_ERROR_ILLEGAL_INDEX);
103 }
104
105 /* We need to find out the phy identifier. */
106 for (phy_ptr = hba_port_ptr->first_phy;
107 phy_ptr != NULL;
108 phy_ptr = phy_ptr->next) {
109 if (phy == phy_ptr->index)
110 break;
111 }
112
113 if (phy_ptr == NULL) {
114 log(LOG_DEBUG, ROUTINE, "Invalid phy index %08lx", phy);
115 unlock(&all_hbas_lock);
116 return (HBA_STATUS_ERROR_ILLEGAL_INDEX);
117 }
118
119 /*
120 * for statistics that are not supported, its bits should all be
121 * set to -1
122 */
123 (void) memset(pStatistics->SASPhyStatistics, 0xff,
124 sizeof (SMHBA_SASPHYSTATISTICS));
125
126
127 /* First, we need the deivce path to locate the devinfo node. */
128 (void *) strlcpy(path, hba_port_ptr->device_path,
129 sizeof (path));
130 charptr = strrchr(path, ':');
131 if (charptr) {
132 *charptr = '\0';
133 }
134
135 errno = 0;
136
137 (void *) memset(kstat_name, 0, sizeof (kstat_name));
138 node = di_init(path, DINFOCPYONE);
139 if (node == DI_NODE_NIL) {
140 di_fini(node);
141 log(LOG_DEBUG, ROUTINE,
142 "Unable to take devinfo snapshot on HBA \"%s\" "
143 "for phyIndex: %08lx due to %s",
144 path, phy, strerror(errno));
145 unlock(&all_hbas_lock);
146 return (HBA_STATUS_ERROR);
147 }
148
149 /*
150 * Then we could fetch the instance number and driver name of this
151 * device.
152 */
153 instance = di_instance(node);
154 if (instance == -1) {
155 di_fini(node);
156 log(LOG_DEBUG, ROUTINE,
157 "An instance number has not been assigned to the "
158 "device \"%s\" when get phyIndex: %08lx", path, phy);
159 unlock(&all_hbas_lock);
160 return (HBA_STATUS_ERROR);
161 }
162
163 driver_name = di_driver_name(node);
164 if (driver_name == NULL) {
165 di_fini(node);
166 log(LOG_DEBUG, ROUTINE,
167 "No driver bound to this device \"%s\" "
168 "when get phyIndex: %08lx",
169 path, phy);
170 unlock(&all_hbas_lock);
171 return (HBA_STATUS_ERROR);
172 }
173
174 di_fini(node);
175
176 iport_wwn = wwnConversion(hba_port_ptr->port_attributes.\
177 PortSpecificAttribute.SASPort->LocalSASAddress.wwn);
178
179 /*
180 * Construct the kstat name here.
181 */
182 (void) snprintf(kstat_name, sizeof (kstat_name), "%s.%016llx.%u.%u",
183 driver_name, iport_wwn, instance, phy_ptr->phy.PhyIdentifier);
184
185 /* retrieve all the statistics from kstat. */
186 kc = kstat_open();
187 if (kc == NULL) {
188 log(LOG_DEBUG, ROUTINE,
189 "kstat_open failed due to \"%s\" of phyIndex: %08lx",
190 strerror(errno), phy);
191 unlock(&all_hbas_lock);
192 return (HBA_STATUS_ERROR);
193 }
194 ksp = kstat_lookup(kc, NULL, -1, kstat_name);
195 if (ksp == NULL) {
196 log(LOG_DEBUG, ROUTINE,
197 "No matching kstat name found for \"%s\" "
198 "of phyIndex: %08lx",
199 kstat_name, phy);
200 unlock(&all_hbas_lock);
201 (void) kstat_close(kc);
202 return (HBA_STATUS_ERROR);
203 }
204 /* Found the phy we're looking for. */
205 if (kstat_read(kc, ksp, NULL) == -1) {
206 log(LOG_DEBUG, ROUTINE,
207 "error reading kstat data due to \"%s\" "
208 "of phyIndex: %08lx",
209 strerror(errno), phy);
210 unlock(&all_hbas_lock);
211 (void) kstat_close(kc);
212 return (HBA_STATUS_ERROR);
213 }
214
215 kname = (kstat_named_t *)ksp->ks_data;
216 for (i = 0; i < ksp->ks_ndata; i++, kname++) {
217 if (strcmp(kname->name,
218 "SecondsSinceLastReset") == 0) {
219 psas->SecondsSinceLastReset = kname->value.ull;
220 continue;
221 }
222 if (strcmp(kname->name, "TxFrames") == 0) {
223 psas->TxFrames = kname->value.ull;
224 continue;
225 }
226 if (strcmp(kname->name, "RxFrames") == 0) {
227 psas->RxFrames = kname->value.ull;
228 continue;
229 }
230 if (strcmp(kname->name, "TxWords") == 0) {
231 psas->TxWords = kname->value.ull;
232 continue;
233 }
234 if (strcmp(kname->name, "RxWords") == 0) {
235 psas->RxWords = kname->value.ull;
236 continue;
237 }
238 if (strcmp(kname->name, "InvalidDwordCount") == 0) {
239 psas->InvalidDwordCount = kname->value.ull;
240 continue;
241 }
242 if (strcmp(kname->name, "RunningDisparityErrorCount") == 0) {
243 psas->RunningDisparityErrorCount = kname->value.ull;
244 continue;
245 }
246 if (strcmp(kname->name, "LossofDwordSyncCount") == 0) {
247 psas->LossofDwordSyncCount = kname->value.ull;
248 continue;
249 }
250 if (strcmp(kname->name, "PhyResetProblemCount") == 0) {
251 psas->PhyResetProblemCount = kname->value.ull;
252 }
253 }
254 unlock(&all_hbas_lock);
255 (void) kstat_close(kc);
256
257 return (HBA_STATUS_OK);
258 }
259