diff options
Diffstat (limited to 'usr/src/lib/sun_fc/common/Handle.cc')
-rw-r--r-- | usr/src/lib/sun_fc/common/Handle.cc | 437 |
1 files changed, 437 insertions, 0 deletions
diff --git a/usr/src/lib/sun_fc/common/Handle.cc b/usr/src/lib/sun_fc/common/Handle.cc new file mode 100644 index 0000000000..e9a37348bb --- /dev/null +++ b/usr/src/lib/sun_fc/common/Handle.cc @@ -0,0 +1,437 @@ +/* + * 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 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + + + +#include "Handle.h" +#include "Exceptions.h" +#include "Trace.h" +#include <libdevinfo.h> +#include <iostream> +#include <iomanip> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stropts.h> + +#define MAX_INIT_HANDLE_ID 0x7fff +#define MAX_TGT_HANDLE_ID 0xffff + +using namespace std; + +/** + * Global lock for list of Handles + */ +pthread_mutex_t Handle::staticLock = PTHREAD_MUTEX_INITIALIZER; + +/** + * Tracking for the previous handle we have opened + */ +HBA_HANDLE Handle::prevOpen = 0; + +/** + * Tracking for the previous target HBA handle we have opened + */ +HBA_HANDLE Handle::prevTgtOpen = 0x8000; + +/** + * Global map from HBA_HANDLE to Handle pointers (our global list) + */ +map<HBA_HANDLE, Handle*> Handle::openHandles; + +/** + * @memo Create a new open handle for a specified HBA + * @precondition HBA port(s) must be loaded + * @postcondition An open handle will be present in the global tracking list + * and must be closed at some point to prevent leakage. If no + * handle could be assigned (the track list is full), an + * exception will be thrown. Scope for valid ids in the track + * list is [1, MAX_INIT_HANDLE_ID]. + * @param myhba The HBA to open a handle for + */ +Handle::Handle(HBA *myhba) { + map<HBA_HANDLE, Handle*>::iterator mapend; + Trace log("Handle::Handle"); + modeVal = INITIATOR; + lock(&staticLock); + mapend = openHandles.end(); + /* Start the search for a free id from the previously assigned one */ + id = prevOpen + 1; + while (id != prevOpen) { + /* Exceeds the max valid value, continue the search from 1 */ + if (id > MAX_INIT_HANDLE_ID) + id = 1; + + if (openHandles.find(id) == mapend) { + /* the id is not in use */ + break; + } + id ++; + } + if (id == prevOpen) { + /* no usable id for now */ + unlock(&staticLock); + throw TryAgainException(); + } + prevOpen = id; + hba = myhba; + openHandles[id] = this; + unlock(&staticLock); +} + +/** + * @memo Create a new open handle for a specified HBA + * @precondition HBA port(s) must be loaded + * @postcondition An open handle will be present in the global tracking list + * and must be closed at some point to prevent leakage. If no + * handle could be assigned (the track list is full), an + * exception will be thrown. Scope for valid ids in the track + * list is [0x8000, MAX_TGT_HANDLE_ID]. + * @param myhba The HBA to open a handle for + * m The mode of HBA to open handle for + */ +#if 0 +// appears unused +Handle::Handle(HBA *myhba, MODE m) { + map<HBA_HANDLE, Handle*>::iterator mapend; + Trace log("Handle::Handle"); + lock(&staticLock); + modeVal = m; + + + // if initiator mode call constructor for initiator. + if (m == INITIATOR) { + Handle(myhba, TARGET); + } + + mapend = openHandles.end(); + /* Start the search for a free id from the previously assigned one */ + id = prevTgtOpen + 1; + while (id != prevTgtOpen) { + /* + * Exceeds the max valid target id value, + * continue the search from 1. + */ + if (id > MAX_TGT_HANDLE_ID) + id = 0x8001; + + if (openHandles.find(id) == mapend) { + /* the id is not in use */ + break; + } + id ++; + } + if (id == prevTgtOpen) { + /* no usable id for now */ + unlock(&staticLock); + throw TryAgainException(); + } + prevTgtOpen = id; + hba = myhba; + openHandles[id] = this; + unlock(&staticLock); +} +#endif +/** + * @memo Free up the handle (aka, close it) + * @postcondition This handle will be removed from the global list + * @exception ... underlying exceptions will be thrown + */ +Handle::~Handle() { + Trace log("Handle::~Handle"); + // Remove this handle from the global list + lock(&staticLock); + try { + openHandles.erase(openHandles.find(getHandle())); + unlock(&staticLock); + } catch (...) { + unlock(&staticLock); + throw; + } + + // Now nuke all internal dynamic allocations + typedef map<uint64_t, HandlePort *>::const_iterator CI; + lock(); + try { + for (CI port = portHandles.begin(); port != portHandles.end(); + port++) { + delete port->second; + } + portHandles.clear(); + unlock(); + } catch (...) { + unlock(); + throw; + } +} + +/** + * @memo Locate a handle in the global list of open handles + * @precondition The requested handle must already be open + * @exception InvalidHandleException Thrown if the id does not match + * an open handle + * @return The open Handle + * @param id The id of the handle to fetch + * + * @doc The HBA API uses a simple integer type to represent + * an open Handle, but we use an instance of the Handle + * class. This interface allows a caller to quickly convert + * from the API integer value to related the Handle instance. + */ +Handle* Handle::findHandle(HBA_HANDLE id) { + Trace log("Handle::findHandle(id)"); + Handle *tmp = NULL; + lock(&staticLock); + try { + if (openHandles.find(id) == openHandles.end()) { + throw InvalidHandleException(); + } + tmp = openHandles[id]; + unlock(&staticLock); + return (tmp); + } catch (...) { + unlock(&staticLock); + throw; + } +} + +/** + * @memo Find an open handle based on Node or Port WWN + * @precondition The given HBA must already be open + * @exception IllegalWWNException Thrown if no matching open Handle found + * @return The open handle matching the wwn argument + * @param wwn The Node or Port WWN of the HBA whos open handle + * is requested. + * + */ +Handle* Handle::findHandle(uint64_t wwn) { + Trace log("Handle::findHandle(wwn)"); + Handle *tmp = NULL; + lock(&staticLock); + try { + for (int i = 0; i < openHandles.size(); i++) { + tmp = openHandles[i]; + if (tmp->getHBA()->containsWWN(wwn)) { + unlock(&staticLock); + return (tmp); + } + } + tmp = NULL; + } catch (...) { tmp = NULL; } + unlock(&staticLock); + if (tmp == NULL) { + throw IllegalWWNException(); + } + return (tmp); +} + +/** + * @memo Refresh underlying index values + * @postcondition All HandlePorts will be reset and prior index values + * will be undefined. + * @exception ... underlying exceptions will be thrown + * + * @doc A number of APIs in the standard interface require + * the use of index values for identifying what "thing" + * to operate on. When dynamic reconfiguration occurs + * these indexes may become inconsistent. This routine + * is called to reset the indexes and signify that the caller + * no longer holds or will refer to any old indexes. + */ +void Handle::refresh() { + Trace log("Handle::refresh"); + lock(); + try { + typedef map<uint64_t, HandlePort *>::const_iterator CI; + for (CI port = portHandles.begin(); port != portHandles.end(); + port++) { + port->second->refresh(); + } + unlock(); + } catch (...) { + unlock(); + throw; + } +} + +/** + * @memo Close the specified handle + * @precondition The handle must be open + * @postcondition The handle will be closed and should be discarded. + * @param id The handle to close + */ +void Handle::closeHandle(HBA_HANDLE id) { + Trace log("Handle::closeHandle"); + Handle *myHandle = findHandle(id); + delete myHandle; +} + +/** + * @memo Get the integer value for return to the API + * @exception ... underlying exceptions will be thrown + * @return The integer value representing the handle + * + * @doc The HBA API uses integer values to represent handles. + * Call this routine to convert a Handle instance into + * its representative integer value. + */ +HBA_HANDLE Handle::getHandle() { + Trace log("Handle::getHandle"); + HBA_HANDLE tmp; + lock(); + try { + tmp = (HBA_HANDLE) id; + unlock(); + return (tmp); + } catch (...) { + unlock(); + throw; + } +} + +/** + * @memo Compare two handles for equality + * @return TRUE if the handles are the same + * @return FALSE if the handles are different + */ +bool Handle::operator==(Handle comp) { + Trace log("Handle::operator=="); + return (this->id == comp.id); +} + +/** + * @memo Get the underlying Handle port based on index + * @return The Handle port for the given port index + * @param index The index of the desired port + */ +HandlePort* Handle::getHandlePortByIndex(int index) { + Trace log("Handle::getHandlePortByIndex"); + HBAPort* port = hba->getPortByIndex(index); + return (getHandlePort(port->getPortWWN())); +} + +/** + * @memo Get the underlying Handle port based on Port wwn + * @exception IllegalWWNException thrown if the wwn is not found + * @return The handle port for the specified WWN + * @param wwn The Port WWN of the HBA port + * + */ +HandlePort* Handle::getHandlePort(uint64_t wwn) { + Trace log("Handle::getHandlePort"); + lock(); + try { + // Check to see if the wwn is in the map + if (portHandles.find(wwn) == portHandles.end()) { + // Not found, add a new one + HBAPort* port = hba->getPort(wwn); + portHandles[wwn] = new HandlePort(this, hba, port); + } + HandlePort *portHandle = portHandles[wwn]; + unlock(); + return (portHandle); + } catch (...) { + unlock(); + throw; + } +} + +/** + * @memo Get the HBA attributes from the underlying HBA + * + * @see HBA::getHBAAttributes + */ +HBA_ADAPTERATTRIBUTES Handle::getHBAAttributes() { + Trace log("Handle::getHBAAttributes"); + lock(); + try { + HBA_ADAPTERATTRIBUTES attributes = hba->getHBAAttributes(); + unlock(); + return (attributes); + } catch (...) { + unlock(); + throw; + } +} + +HBA_ADAPTERATTRIBUTES Handle::npivGetHBAAttributes() { + Trace log("Handle::npivGetHBAAttributes"); + lock(); + try { + HBA_ADAPTERATTRIBUTES attributes = hba->npivGetHBAAttributes(); + unlock(); + return (attributes); + } catch (...) { + unlock(); + throw; + } +} + + +/** + * @memo Get the HBA port attributes from the HBA + * @see HBAPort::getPortAttributes + * @see HBAPort::getDisoveredAttributes + * + * @doc This routine will return either HBA port + * attributes, or discovered port attributes + * + */ +HBA_PORTATTRIBUTES Handle::getPortAttributes(uint64_t wwn) { + Trace log("Handle::getPortAttributes"); + uint64_t tmp; + HBA_PORTATTRIBUTES attributes; + + lock(); + try { + // Is this a WWN for one of the adapter ports? + if (hba->containsWWN(wwn)) { + attributes = hba->getPort(wwn)->getPortAttributes(tmp); + unlock(); + return (attributes); + } else { // Is this a target we know about? + // Loop through all ports and look for the first match + + for (int i = 0; i < hba->getNumberOfPorts(); i++) { + try { + attributes = + hba->getPortByIndex(i)->getDiscoveredAttributes( + wwn, tmp); + unlock(); + return (attributes); + } catch (HBAException &e) { + continue; + } + } + + // If we get to here, then we don't see this WWN on this HBA + throw IllegalWWNException(); + } + } catch (...) { + unlock(); + throw; + } +} |