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