xref: /illumos-gate/usr/src/lib/sun_sas/common/Sun_sasGetPhyStatistics.c (revision c65ebfc7045424bd04a6c7719a27b0ad3399ad54)
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  */
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