17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM * CDDL HEADER START
37836SJohn.Forte@Sun.COM *
47836SJohn.Forte@Sun.COM * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM *
87836SJohn.Forte@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM * and limitations under the License.
127836SJohn.Forte@Sun.COM *
137836SJohn.Forte@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM *
197836SJohn.Forte@Sun.COM * CDDL HEADER END
207836SJohn.Forte@Sun.COM */
217836SJohn.Forte@Sun.COM /*
22*11156SRenia.Miao@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237836SJohn.Forte@Sun.COM * Use is subject to license terms.
247836SJohn.Forte@Sun.COM */
257836SJohn.Forte@Sun.COM
267836SJohn.Forte@Sun.COM
277836SJohn.Forte@Sun.COM
287836SJohn.Forte@Sun.COM #include "HBA.h"
297836SJohn.Forte@Sun.COM #include "Exceptions.h"
307836SJohn.Forte@Sun.COM #include "Trace.h"
317836SJohn.Forte@Sun.COM #include <iostream>
327836SJohn.Forte@Sun.COM #include <iomanip>
337836SJohn.Forte@Sun.COM #include <sys/types.h>
347836SJohn.Forte@Sun.COM #include <sys/stat.h>
357836SJohn.Forte@Sun.COM #include <time.h>
367836SJohn.Forte@Sun.COM #include <fcntl.h>
377836SJohn.Forte@Sun.COM #include <unistd.h>
387836SJohn.Forte@Sun.COM #include <stropts.h>
397836SJohn.Forte@Sun.COM #include <errno.h>
407836SJohn.Forte@Sun.COM
417836SJohn.Forte@Sun.COM #define NSECS_PER_SEC 1000000000l
427836SJohn.Forte@Sun.COM #define BUSY_SLEEP NSECS_PER_SEC/10 /* 1/10 second */
437836SJohn.Forte@Sun.COM #define BUSY_RETRY_TIMER 3000000000UL /* Retry for 3 seconds */
447836SJohn.Forte@Sun.COM
457836SJohn.Forte@Sun.COM using namespace std;
467836SJohn.Forte@Sun.COM
477836SJohn.Forte@Sun.COM /**
487836SJohn.Forte@Sun.COM * Max number of Adatper ports per HBA that VSL supports.
497836SJohn.Forte@Sun.COM *
507836SJohn.Forte@Sun.COM */
517836SJohn.Forte@Sun.COM const uint8_t HBA::HBA_PORT_MAX = UCHAR_MAX;
527836SJohn.Forte@Sun.COM
537836SJohn.Forte@Sun.COM /**
547836SJohn.Forte@Sun.COM * @memo Add a new port to this HBA
557836SJohn.Forte@Sun.COM * @precondition Port must be a valid port on this HBA
567836SJohn.Forte@Sun.COM * @postcondition Port will be exposed as one of the ports on this HBA
577836SJohn.Forte@Sun.COM * @exception Throws InternalError when the HBA port count exceeds
587836SJohn.Forte@Sun.COM * max number of ports and throws any underlying exception
597836SJohn.Forte@Sun.COM * @param port The Port to add to this HBA
607836SJohn.Forte@Sun.COM *
617836SJohn.Forte@Sun.COM * @doc When discovering HBAs and their ports, use this
627836SJohn.Forte@Sun.COM * routine to add a port to its existing HBA instance.
637836SJohn.Forte@Sun.COM */
addPort(HBAPort * port)647836SJohn.Forte@Sun.COM void HBA::addPort(HBAPort* port) {
657836SJohn.Forte@Sun.COM Trace log("HBA::addPort");
667836SJohn.Forte@Sun.COM lock();
677836SJohn.Forte@Sun.COM // support hba with up to UCHAR_MAX number of ports.
687836SJohn.Forte@Sun.COM if (portsByIndex.size() + 1 > HBA_PORT_MAX) {
697836SJohn.Forte@Sun.COM unlock();
707836SJohn.Forte@Sun.COM throw InternalError("HBA Port count exceeds max number of ports");
717836SJohn.Forte@Sun.COM }
727836SJohn.Forte@Sun.COM
737836SJohn.Forte@Sun.COM try {
747836SJohn.Forte@Sun.COM portsByWWN[port->getPortWWN()] = port;
757836SJohn.Forte@Sun.COM portsByIndex.insert(portsByIndex.end(), port);
767836SJohn.Forte@Sun.COM unlock();
777836SJohn.Forte@Sun.COM } catch (...) {
787836SJohn.Forte@Sun.COM unlock();
797836SJohn.Forte@Sun.COM throw;
807836SJohn.Forte@Sun.COM }
817836SJohn.Forte@Sun.COM }
827836SJohn.Forte@Sun.COM
837836SJohn.Forte@Sun.COM /**
847836SJohn.Forte@Sun.COM * @memo Return number of ports to this HBA
857836SJohn.Forte@Sun.COM * @exception No exception for this method.
867836SJohn.Forte@Sun.COM *
877836SJohn.Forte@Sun.COM * @doc Returns the number of ports on this HBA. The max
887836SJohn.Forte@Sun.COM * number of ports that VSL support is up to max uint8_t
897836SJohn.Forte@Sun.COM * size.
907836SJohn.Forte@Sun.COM */
getNumberOfPorts()917836SJohn.Forte@Sun.COM uint8_t HBA::getNumberOfPorts() {
927836SJohn.Forte@Sun.COM Trace log("HBA::getNumberOfPorts");
937836SJohn.Forte@Sun.COM return (uint8_t)portsByIndex.size();
947836SJohn.Forte@Sun.COM }
957836SJohn.Forte@Sun.COM
967836SJohn.Forte@Sun.COM /**
977836SJohn.Forte@Sun.COM * @memo Retrieve an HBA port based on a Port WWN
987836SJohn.Forte@Sun.COM * @exception IllegalWWNException Thrown if WWN does not match any
997836SJohn.Forte@Sun.COM * known HBA port.
1007836SJohn.Forte@Sun.COM * @return HBAPort* to the port with a matching Port WWN
1017836SJohn.Forte@Sun.COM * @param wwn The wwn of the desired HBA port
1027836SJohn.Forte@Sun.COM *
1037836SJohn.Forte@Sun.COM * @doc Fetch an HBA port based on WWN. If the port is not
1047836SJohn.Forte@Sun.COM * found, an exception will be thrown. NULL will never
1057836SJohn.Forte@Sun.COM * be returned.
1067836SJohn.Forte@Sun.COM */
getPort(uint64_t wwn)1077836SJohn.Forte@Sun.COM HBAPort* HBA::getPort(uint64_t wwn) {
1087836SJohn.Forte@Sun.COM Trace log("HBA::getPort");
1097836SJohn.Forte@Sun.COM HBAPort *port = NULL;
1107836SJohn.Forte@Sun.COM lock();
1117836SJohn.Forte@Sun.COM
1127836SJohn.Forte@Sun.COM log.debug("getPort(wwn): WWN %016llx", wwn);
1137836SJohn.Forte@Sun.COM
1147836SJohn.Forte@Sun.COM try {
1157836SJohn.Forte@Sun.COM // Make sure it is in the map
1167836SJohn.Forte@Sun.COM if (portsByWWN.find(wwn) == portsByWWN.end()) {
1177836SJohn.Forte@Sun.COM throw IllegalWWNException();
1187836SJohn.Forte@Sun.COM }
1197836SJohn.Forte@Sun.COM port = portsByWWN[wwn];
1207836SJohn.Forte@Sun.COM unlock();
1217836SJohn.Forte@Sun.COM return (port);
1227836SJohn.Forte@Sun.COM } catch (...) {
1237836SJohn.Forte@Sun.COM unlock();
1247836SJohn.Forte@Sun.COM throw;
1257836SJohn.Forte@Sun.COM }
1267836SJohn.Forte@Sun.COM }
1277836SJohn.Forte@Sun.COM
1287836SJohn.Forte@Sun.COM /**
1297836SJohn.Forte@Sun.COM * Iterator for WWN to HBAPort map type
1307836SJohn.Forte@Sun.COM */
1317836SJohn.Forte@Sun.COM typedef map<uint64_t, HBAPort *>::const_iterator CI;
1327836SJohn.Forte@Sun.COM
1337836SJohn.Forte@Sun.COM /**
1347836SJohn.Forte@Sun.COM * @memo Return true if this HBA contains the stated WWN
1357836SJohn.Forte@Sun.COM * (node or port)
1367836SJohn.Forte@Sun.COM * @exception ... underlying exceptions will be thrown
1377836SJohn.Forte@Sun.COM * @return TRUE if the wwn is found
1387836SJohn.Forte@Sun.COM * @return FALSE if the wwn is not found
1397836SJohn.Forte@Sun.COM * @param wwn The wwn to look for
1407836SJohn.Forte@Sun.COM *
1417836SJohn.Forte@Sun.COM */
containsWWN(uint64_t wwn)1427836SJohn.Forte@Sun.COM bool HBA::containsWWN(uint64_t wwn) {
1437836SJohn.Forte@Sun.COM Trace log("HBA::containsWWN");
1447836SJohn.Forte@Sun.COM lock();
1457836SJohn.Forte@Sun.COM
1467836SJohn.Forte@Sun.COM try {
1477836SJohn.Forte@Sun.COM for (CI port = portsByWWN.begin(); port != portsByWWN.end();
1487836SJohn.Forte@Sun.COM port++) {
1497836SJohn.Forte@Sun.COM if (port->second->getPortWWN() == wwn) {
1507836SJohn.Forte@Sun.COM unlock();
1517836SJohn.Forte@Sun.COM return (true);
1527836SJohn.Forte@Sun.COM }
1537836SJohn.Forte@Sun.COM if (port->second->getNodeWWN() == wwn) {
1547836SJohn.Forte@Sun.COM unlock();
1557836SJohn.Forte@Sun.COM return (true);
1567836SJohn.Forte@Sun.COM }
1577836SJohn.Forte@Sun.COM }
1587836SJohn.Forte@Sun.COM unlock();
1597836SJohn.Forte@Sun.COM return (false);
1607836SJohn.Forte@Sun.COM } catch (...) {
1617836SJohn.Forte@Sun.COM unlock();
1627836SJohn.Forte@Sun.COM throw;
1637836SJohn.Forte@Sun.COM }
1647836SJohn.Forte@Sun.COM }
1657836SJohn.Forte@Sun.COM
1667836SJohn.Forte@Sun.COM /**
1677836SJohn.Forte@Sun.COM * @memo Fetch the port based on index.
1687836SJohn.Forte@Sun.COM * @exception IllegalIndexException Thrown if the index is not valid
1697836SJohn.Forte@Sun.COM * @return HBAPort* the port matching the index
1707836SJohn.Forte@Sun.COM * @param index - the zero based index of the port to retrieve
1717836SJohn.Forte@Sun.COM *
1727836SJohn.Forte@Sun.COM */
getPortByIndex(int index)1737836SJohn.Forte@Sun.COM HBAPort* HBA::getPortByIndex(int index) {
1747836SJohn.Forte@Sun.COM Trace log("HBA::getPortByIndex");
1757836SJohn.Forte@Sun.COM lock();
1767836SJohn.Forte@Sun.COM try {
1777836SJohn.Forte@Sun.COM log.debug("Port index size %d index %d ", portsByIndex.size(),
1787836SJohn.Forte@Sun.COM index);
1797836SJohn.Forte@Sun.COM
1807836SJohn.Forte@Sun.COM if (index >= portsByIndex.size() || index < 0) {
1817836SJohn.Forte@Sun.COM throw IllegalIndexException();
1827836SJohn.Forte@Sun.COM }
1837836SJohn.Forte@Sun.COM
1847836SJohn.Forte@Sun.COM HBAPort *tmp = portsByIndex[index];
1857836SJohn.Forte@Sun.COM unlock();
1867836SJohn.Forte@Sun.COM return (tmp);
1877836SJohn.Forte@Sun.COM } catch (...) {
1887836SJohn.Forte@Sun.COM unlock();
1897836SJohn.Forte@Sun.COM throw;
1907836SJohn.Forte@Sun.COM }
1917836SJohn.Forte@Sun.COM }
1927836SJohn.Forte@Sun.COM
1937836SJohn.Forte@Sun.COM /**
1947836SJohn.Forte@Sun.COM * @memo Compare two HBAs for equality
1957836SJohn.Forte@Sun.COM * @precondition Both HBAs should be fully discovered (all ports added)
1967836SJohn.Forte@Sun.COM * @exception ... underlying exceptions will be thrown
1977836SJohn.Forte@Sun.COM * @return TRUE The two HBA instances represent the same HBA
1987836SJohn.Forte@Sun.COM * @return FALSE The two HBA instances are different
1997836SJohn.Forte@Sun.COM *
2007836SJohn.Forte@Sun.COM * @doc This routine will compare each port within both
2017836SJohn.Forte@Sun.COM * HBAs and verify they are the same. The ports must
2027836SJohn.Forte@Sun.COM * have been added in the same order.
2037836SJohn.Forte@Sun.COM */
operator ==(HBA & comp)2047836SJohn.Forte@Sun.COM bool HBA::operator==(HBA &comp) {
2057836SJohn.Forte@Sun.COM Trace log("HBA::operator==");
2067836SJohn.Forte@Sun.COM lock();
2077836SJohn.Forte@Sun.COM
2087836SJohn.Forte@Sun.COM try {
2097836SJohn.Forte@Sun.COM bool ret = false;
2107836SJohn.Forte@Sun.COM if (portsByIndex.size() == comp.portsByIndex.size()) {
2117836SJohn.Forte@Sun.COM if (portsByIndex.size() > 0) {
2127836SJohn.Forte@Sun.COM ret = (*portsByIndex[0] == *comp.portsByIndex[0]);
2137836SJohn.Forte@Sun.COM }
2147836SJohn.Forte@Sun.COM }
2157836SJohn.Forte@Sun.COM unlock();
2167836SJohn.Forte@Sun.COM return (ret);
2177836SJohn.Forte@Sun.COM } catch (...) {
2187836SJohn.Forte@Sun.COM unlock();
2197836SJohn.Forte@Sun.COM throw;
2207836SJohn.Forte@Sun.COM }
2217836SJohn.Forte@Sun.COM }
2227836SJohn.Forte@Sun.COM
2237836SJohn.Forte@Sun.COM /**
2247836SJohn.Forte@Sun.COM * @memo Set the RNID data for all the ports in this HBA
2257836SJohn.Forte@Sun.COM * @precondition All ports must be added
2267836SJohn.Forte@Sun.COM * @postcondition Each port will have the same RNID value set
2277836SJohn.Forte@Sun.COM * @exception ... underlying exceptions will be thrown. Partial failure
2287836SJohn.Forte@Sun.COM * is possible and will not be cleaned up.
2297836SJohn.Forte@Sun.COM * @param info The RNID information to program for each HBA port
2307836SJohn.Forte@Sun.COM * @see HBAPort::setRNID
2317836SJohn.Forte@Sun.COM *
2327836SJohn.Forte@Sun.COM */
setRNID(HBA_MGMTINFO info)2337836SJohn.Forte@Sun.COM void HBA::setRNID(HBA_MGMTINFO info) {
2347836SJohn.Forte@Sun.COM Trace log("HBA::setRNID");
2357836SJohn.Forte@Sun.COM lock();
2367836SJohn.Forte@Sun.COM
2377836SJohn.Forte@Sun.COM try {
2387836SJohn.Forte@Sun.COM for (CI port = portsByWWN.begin(); port != portsByWWN.end();
2397836SJohn.Forte@Sun.COM port++) {
2407836SJohn.Forte@Sun.COM port->second->setRNID(info);
2417836SJohn.Forte@Sun.COM }
2427836SJohn.Forte@Sun.COM unlock();
2437836SJohn.Forte@Sun.COM } catch (...) {
2447836SJohn.Forte@Sun.COM unlock();
2457836SJohn.Forte@Sun.COM throw;
2467836SJohn.Forte@Sun.COM }
2477836SJohn.Forte@Sun.COM }
2487836SJohn.Forte@Sun.COM
2497836SJohn.Forte@Sun.COM /**
2507836SJohn.Forte@Sun.COM * @memo Verify that this HBA is present on the system
2517836SJohn.Forte@Sun.COM * @exception UnavailableException Thrown when HBA not present
2527836SJohn.Forte@Sun.COM * @see HBAPort::validatePresent
2537836SJohn.Forte@Sun.COM *
2547836SJohn.Forte@Sun.COM * @doc This routine is used to verify that a given HBA
2557836SJohn.Forte@Sun.COM * has not been removed through dynamic reconfiguration.
2567836SJohn.Forte@Sun.COM * If the HBA is present, the routine will return.
2577836SJohn.Forte@Sun.COM * If the HBA is not present (if any port is not present)
2587836SJohn.Forte@Sun.COM * an exception will be thrown
2597836SJohn.Forte@Sun.COM */
validatePresent()2607836SJohn.Forte@Sun.COM void HBA::validatePresent() {
2617836SJohn.Forte@Sun.COM Trace log("HBA::validatePresent");
2627836SJohn.Forte@Sun.COM lock();
2637836SJohn.Forte@Sun.COM try {
2647836SJohn.Forte@Sun.COM for (CI port = portsByWWN.begin(); port != portsByWWN.end();
2657836SJohn.Forte@Sun.COM port++) {
2667836SJohn.Forte@Sun.COM port->second->validatePresent();
2677836SJohn.Forte@Sun.COM }
2687836SJohn.Forte@Sun.COM unlock();
2697836SJohn.Forte@Sun.COM } catch (...) {
2707836SJohn.Forte@Sun.COM unlock();
2717836SJohn.Forte@Sun.COM throw;
2727836SJohn.Forte@Sun.COM }
2737836SJohn.Forte@Sun.COM }
2747836SJohn.Forte@Sun.COM
2757836SJohn.Forte@Sun.COM /**
2767836SJohn.Forte@Sun.COM * Opens a file, throwing exceptions on error.
2777836SJohn.Forte@Sun.COM */
_open(std::string path,int flag)2787836SJohn.Forte@Sun.COM int HBA::_open(std::string path, int flag) {
2797836SJohn.Forte@Sun.COM Trace log("HBA::open");
2807836SJohn.Forte@Sun.COM int fd;
2817836SJohn.Forte@Sun.COM errno = 0;
2827836SJohn.Forte@Sun.COM if ((fd = open(path.c_str(), flag)) < 0) {
2837836SJohn.Forte@Sun.COM log.debug("Unable to open \"%s\" - reason (%d) %s",
2847836SJohn.Forte@Sun.COM path.c_str(), errno, strerror(errno));
2857836SJohn.Forte@Sun.COM if (errno == EBUSY) {
2867836SJohn.Forte@Sun.COM throw BusyException();
2877836SJohn.Forte@Sun.COM } else if (errno == EAGAIN) {
2887836SJohn.Forte@Sun.COM throw TryAgainException();
2897836SJohn.Forte@Sun.COM } else if (errno == ENOTSUP) {
2907836SJohn.Forte@Sun.COM throw NotSupportedException();
2917836SJohn.Forte@Sun.COM } else if (errno == ENOENT) {
2927836SJohn.Forte@Sun.COM throw UnavailableException();
2937836SJohn.Forte@Sun.COM } else {
2947836SJohn.Forte@Sun.COM string msg = "Unable to open ";
2957836SJohn.Forte@Sun.COM msg += path;
2967836SJohn.Forte@Sun.COM throw IOError(msg);
2977836SJohn.Forte@Sun.COM }
2987836SJohn.Forte@Sun.COM }
2997836SJohn.Forte@Sun.COM return (fd);
3007836SJohn.Forte@Sun.COM }
3017836SJohn.Forte@Sun.COM
3027836SJohn.Forte@Sun.COM /**
3037836SJohn.Forte@Sun.COM * Issues IOCTL, throwing exceptions on error.
3047836SJohn.Forte@Sun.COM * Note, if the IOCTL succeeds, but some IOCTL specific
3057836SJohn.Forte@Sun.COM * error is recorded in the response, this routine
3067836SJohn.Forte@Sun.COM * will not throw an exception.
3077836SJohn.Forte@Sun.COM */
_ioctl(int fd,int type,uchar_t * arg)3087836SJohn.Forte@Sun.COM void HBA::_ioctl(int fd, int type, uchar_t *arg) {
3097836SJohn.Forte@Sun.COM Trace log("HBA::ioctl");
3107836SJohn.Forte@Sun.COM hrtime_t cur;
3117836SJohn.Forte@Sun.COM int saved_errno = 0;
3127836SJohn.Forte@Sun.COM struct timespec ts;
3137836SJohn.Forte@Sun.COM
3147836SJohn.Forte@Sun.COM hrtime_t start = gethrtime();
3157836SJohn.Forte@Sun.COM hrtime_t end = start + BUSY_RETRY_TIMER;
3167836SJohn.Forte@Sun.COM ts.tv_sec = 0;
3177836SJohn.Forte@Sun.COM ts.tv_nsec = BUSY_SLEEP;
3187836SJohn.Forte@Sun.COM for (cur = start; cur < end; cur = gethrtime()) {
319*11156SRenia.Miao@Sun.COM errno = 0;
3207836SJohn.Forte@Sun.COM if (ioctl(fd, type, arg) != 0) {
3217836SJohn.Forte@Sun.COM if (errno == EAGAIN) {
3227836SJohn.Forte@Sun.COM saved_errno = errno;
3237836SJohn.Forte@Sun.COM nanosleep(&ts, NULL);
3247836SJohn.Forte@Sun.COM continue;
3257836SJohn.Forte@Sun.COM } else if (errno == EBUSY) {
3267836SJohn.Forte@Sun.COM saved_errno = errno;
3277836SJohn.Forte@Sun.COM nanosleep(&ts, NULL);
3287836SJohn.Forte@Sun.COM continue;
3297836SJohn.Forte@Sun.COM } else if (errno == ENOTSUP) {
3307836SJohn.Forte@Sun.COM throw NotSupportedException();
3317836SJohn.Forte@Sun.COM } else if (errno == ENOENT) {
3327836SJohn.Forte@Sun.COM throw UnavailableException();
3337836SJohn.Forte@Sun.COM } else {
3347836SJohn.Forte@Sun.COM throw IOError("IOCTL failed");
3357836SJohn.Forte@Sun.COM }
3367836SJohn.Forte@Sun.COM } else {
3377836SJohn.Forte@Sun.COM break;
3387836SJohn.Forte@Sun.COM }
3397836SJohn.Forte@Sun.COM }
3407836SJohn.Forte@Sun.COM if (cur >= end) {
3417836SJohn.Forte@Sun.COM if (saved_errno == EAGAIN) {
3427836SJohn.Forte@Sun.COM throw TryAgainException();
3437836SJohn.Forte@Sun.COM } else if (saved_errno == EBUSY) {
3447836SJohn.Forte@Sun.COM throw BusyException();
3457836SJohn.Forte@Sun.COM } else {
3467836SJohn.Forte@Sun.COM throw IOError("IOCTL failed");
3477836SJohn.Forte@Sun.COM }
3487836SJohn.Forte@Sun.COM }
3497836SJohn.Forte@Sun.COM }
3507836SJohn.Forte@Sun.COM
~HBA()3517836SJohn.Forte@Sun.COM HBA::~HBA() {
3527836SJohn.Forte@Sun.COM Trace log("HBA::~HBA");
3537836SJohn.Forte@Sun.COM for (int i = 0; i < getNumberOfPorts(); i++) {
3547836SJohn.Forte@Sun.COM delete (getPortByIndex(i));
3557836SJohn.Forte@Sun.COM }
3567836SJohn.Forte@Sun.COM }
3577836SJohn.Forte@Sun.COM
358