xref: /onnv-gate/usr/src/lib/sun_fc/common/HBA.cc (revision 11156:fa5f12909da7)
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