diff options
Diffstat (limited to 'usr/src/lib/sun_sas/common/Sun_sasGetPhyStatistics.c')
-rw-r--r-- | usr/src/lib/sun_sas/common/Sun_sasGetPhyStatistics.c | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/usr/src/lib/sun_sas/common/Sun_sasGetPhyStatistics.c b/usr/src/lib/sun_sas/common/Sun_sasGetPhyStatistics.c new file mode 100644 index 0000000000..10f73604cf --- /dev/null +++ b/usr/src/lib/sun_sas/common/Sun_sasGetPhyStatistics.c @@ -0,0 +1,258 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <kstat.h> +#include <sun_sas.h> + +/* + * Retrieves the statistics for a specified port.phy on an adapter + */ +HBA_STATUS Sun_sasGetPhyStatistics(HBA_HANDLE handle, + HBA_UINT32 port, HBA_UINT32 phy, SMHBA_PHYSTATISTICS *pStatistics) { + const char ROUTINE[] = "Sun_sasGetPhyStatistics"; + HBA_STATUS status = HBA_STATUS_OK; + struct sun_sas_hba *hba_ptr; + struct sun_sas_port *hba_port_ptr; + struct phy_info *phy_ptr; + PSMHBA_SASPHYSTATISTICS psas; + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *kname; + char *charptr, path[MAXPATHLEN + 1]; + char *driver_name, kstat_name[256]; + di_node_t node; + int instance = 0; + int i; + uint64_t iport_wwn; + + /* Validate the arguments */ + if (pStatistics == NULL) { + log(LOG_DEBUG, ROUTINE, + "NULL Phy Statistics buffer of phyIndex: %08lx", phy); + return (HBA_STATUS_ERROR_ARG); + } + psas = pStatistics->SASPhyStatistics; + if (psas == NULL) { + log(LOG_DEBUG, ROUTINE, + "NULL SAS Phy Statistics buffer of phyIndex: %08lx", phy); + return (HBA_STATUS_ERROR_ARG); + } + + lock(&all_hbas_lock); + + if ((hba_ptr = Retrieve_Sun_sasHandle(handle)) == NULL) { + log(LOG_DEBUG, ROUTINE, + "Invalid HBA handler %08lx of phyIndex: %08lx", + handle, phy); + unlock(&all_hbas_lock); + return (HBA_STATUS_ERROR_INVALID_HANDLE); + } + + /* Check for stale data */ + status = verifyAdapter(hba_ptr); + if (status != HBA_STATUS_OK) { + log(LOG_DEBUG, ROUTINE, + "Verify Adapter failed for phyIndex: %08lx", phy); + unlock(&all_hbas_lock); + return (status); + } + + for (hba_port_ptr = hba_ptr->first_port; + hba_port_ptr != NULL; + hba_port_ptr = hba_port_ptr->next) { + if (hba_port_ptr->index == port) { + break; + } + } + + if (hba_port_ptr == NULL) { + log(LOG_DEBUG, ROUTINE, + "Invalid port index of phyIndex: %08lx", phy); + unlock(&all_hbas_lock); + return (HBA_STATUS_ERROR_ILLEGAL_INDEX); + } + + if (phy >= hba_port_ptr->port_attributes.PortSpecificAttribute. + SASPort->NumberofPhys) { + log(LOG_DEBUG, ROUTINE, "Invalid phy index %08lx", phy); + unlock(&all_hbas_lock); + return (HBA_STATUS_ERROR_ILLEGAL_INDEX); + } + + /* We need to find out the phy identifier. */ + for (phy_ptr = hba_port_ptr->first_phy; + phy_ptr != NULL; + phy_ptr = phy_ptr->next) { + if (phy == phy_ptr->index) + break; + } + + if (phy_ptr == NULL) { + log(LOG_DEBUG, ROUTINE, "Invalid phy index %08lx", phy); + unlock(&all_hbas_lock); + return (HBA_STATUS_ERROR_ILLEGAL_INDEX); + } + + /* + * for statistics that are not supported, its bits should all be + * set to -1 + */ + (void) memset(pStatistics->SASPhyStatistics, 0xff, + sizeof (SMHBA_SASPHYSTATISTICS)); + + + /* First, we need the deivce path to locate the devinfo node. */ + (void *) strlcpy(path, hba_port_ptr->device_path, + sizeof (path)); + charptr = strrchr(path, ':'); + if (charptr) { + *charptr = '\0'; + } + + errno = 0; + + (void *) memset(kstat_name, 0, sizeof (kstat_name)); + node = di_init(path, DINFOCPYONE); + if (node == DI_NODE_NIL) { + di_fini(node); + log(LOG_DEBUG, ROUTINE, + "Unable to take devinfo snapshot on HBA \"%s\" " + "for phyIndex: %08lx due to %s", + path, phy, strerror(errno)); + unlock(&all_hbas_lock); + return (HBA_STATUS_ERROR); + } + + /* + * Then we could fetch the instance number and driver name of this + * device. + */ + instance = di_instance(node); + if (instance == -1) { + di_fini(node); + log(LOG_DEBUG, ROUTINE, + "An instance number has not been assigned to the " + "device \"%s\" when get phyIndex: %08lx", path, phy); + unlock(&all_hbas_lock); + return (HBA_STATUS_ERROR); + } + + driver_name = di_driver_name(node); + if (driver_name == NULL) { + di_fini(node); + log(LOG_DEBUG, ROUTINE, + "No driver bound to this device \"%s\" " + "when get phyIndex: %08lx", + path, phy); + unlock(&all_hbas_lock); + return (HBA_STATUS_ERROR); + } + + di_fini(node); + + iport_wwn = wwnConversion(hba_port_ptr->port_attributes.\ + PortSpecificAttribute.SASPort->LocalSASAddress.wwn); + + /* + * Construct the kstat name here. + */ + (void) snprintf(kstat_name, sizeof (kstat_name), "%s.%016llx.%u.%u", + driver_name, iport_wwn, instance, phy_ptr->phy.PhyIdentifier); + + /* retrieve all the statistics from kstat. */ + kc = kstat_open(); + if (kc == NULL) { + log(LOG_DEBUG, ROUTINE, + "kstat_open failed due to \"%s\" of phyIndex: %08lx", + strerror(errno), phy); + unlock(&all_hbas_lock); + return (HBA_STATUS_ERROR); + } + ksp = kstat_lookup(kc, NULL, -1, kstat_name); + if (ksp == NULL) { + log(LOG_DEBUG, ROUTINE, + "No matching kstat name found for \"%s\" " + "of phyIndex: %08lx", + kstat_name, phy); + unlock(&all_hbas_lock); + (void) kstat_close(kc); + return (HBA_STATUS_ERROR); + } + /* Found the phy we're looking for. */ + if (kstat_read(kc, ksp, NULL) == -1) { + log(LOG_DEBUG, ROUTINE, + "error reading kstat data due to \"%s\" " + "of phyIndex: %08lx", + strerror(errno), phy); + unlock(&all_hbas_lock); + (void) kstat_close(kc); + return (HBA_STATUS_ERROR); + } + + kname = (kstat_named_t *)ksp->ks_data; + for (i = 0; i < ksp->ks_ndata; i++, kname++) { + if (strcmp(kname->name, + "SecondsSinceLastReset") == 0) { + psas->SecondsSinceLastReset = kname->value.ull; + continue; + } + if (strcmp(kname->name, "TxFrames") == 0) { + psas->TxFrames = kname->value.ull; + continue; + } + if (strcmp(kname->name, "RxFrames") == 0) { + psas->RxFrames = kname->value.ull; + continue; + } + if (strcmp(kname->name, "TxWords") == 0) { + psas->TxWords = kname->value.ull; + continue; + } + if (strcmp(kname->name, "RxWords") == 0) { + psas->RxWords = kname->value.ull; + continue; + } + if (strcmp(kname->name, "InvalidDwordCount") == 0) { + psas->InvalidDwordCount = kname->value.ull; + continue; + } + if (strcmp(kname->name, "RunningDisparityErrorCount") == 0) { + psas->RunningDisparityErrorCount = kname->value.ull; + continue; + } + if (strcmp(kname->name, "LossofDwordSyncCount") == 0) { + psas->LossofDwordSyncCount = kname->value.ull; + continue; + } + if (strcmp(kname->name, "PhyResetProblemCount") == 0) { + psas->PhyResetProblemCount = kname->value.ull; + } + } + unlock(&all_hbas_lock); + (void) kstat_close(kc); + + return (HBA_STATUS_OK); +} |