xref: /onnv-gate/usr/src/lib/sun_fc/common/HBA.cc (revision 7836:4e95154b5b7a)
1*7836SJohn.Forte@Sun.COM /*
2*7836SJohn.Forte@Sun.COM  * CDDL HEADER START
3*7836SJohn.Forte@Sun.COM  *
4*7836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
5*7836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
6*7836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
7*7836SJohn.Forte@Sun.COM  *
8*7836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*7836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*7836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
11*7836SJohn.Forte@Sun.COM  * and limitations under the License.
12*7836SJohn.Forte@Sun.COM  *
13*7836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*7836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*7836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*7836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*7836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*7836SJohn.Forte@Sun.COM  *
19*7836SJohn.Forte@Sun.COM  * CDDL HEADER END
20*7836SJohn.Forte@Sun.COM  */
21*7836SJohn.Forte@Sun.COM /*
22*7836SJohn.Forte@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*7836SJohn.Forte@Sun.COM  * Use is subject to license terms.
24*7836SJohn.Forte@Sun.COM  */
25*7836SJohn.Forte@Sun.COM 
26*7836SJohn.Forte@Sun.COM 
27*7836SJohn.Forte@Sun.COM 
28*7836SJohn.Forte@Sun.COM #include "HBA.h"
29*7836SJohn.Forte@Sun.COM #include "Exceptions.h"
30*7836SJohn.Forte@Sun.COM #include "Trace.h"
31*7836SJohn.Forte@Sun.COM #include <iostream>
32*7836SJohn.Forte@Sun.COM #include <iomanip>
33*7836SJohn.Forte@Sun.COM #include <sys/types.h>
34*7836SJohn.Forte@Sun.COM #include <sys/stat.h>
35*7836SJohn.Forte@Sun.COM #include <time.h>
36*7836SJohn.Forte@Sun.COM #include <fcntl.h>
37*7836SJohn.Forte@Sun.COM #include <unistd.h>
38*7836SJohn.Forte@Sun.COM #include <stropts.h>
39*7836SJohn.Forte@Sun.COM #include <errno.h>
40*7836SJohn.Forte@Sun.COM 
41*7836SJohn.Forte@Sun.COM #define	    NSECS_PER_SEC	1000000000l
42*7836SJohn.Forte@Sun.COM #define	    BUSY_SLEEP		NSECS_PER_SEC/10 /* 1/10 second */
43*7836SJohn.Forte@Sun.COM #define	    BUSY_RETRY_TIMER	3000000000UL /* Retry for 3 seconds */
44*7836SJohn.Forte@Sun.COM 
45*7836SJohn.Forte@Sun.COM using namespace std;
46*7836SJohn.Forte@Sun.COM 
47*7836SJohn.Forte@Sun.COM /**
48*7836SJohn.Forte@Sun.COM  * Max number of Adatper ports per HBA that VSL supports.
49*7836SJohn.Forte@Sun.COM  *
50*7836SJohn.Forte@Sun.COM  */
51*7836SJohn.Forte@Sun.COM const uint8_t HBA::HBA_PORT_MAX = UCHAR_MAX;
52*7836SJohn.Forte@Sun.COM 
53*7836SJohn.Forte@Sun.COM /**
54*7836SJohn.Forte@Sun.COM  * @memo	    Add a new port to this HBA
55*7836SJohn.Forte@Sun.COM  * @precondition    Port must be a valid port on this HBA
56*7836SJohn.Forte@Sun.COM  * @postcondition   Port will be exposed as one of the ports on this HBA
57*7836SJohn.Forte@Sun.COM  * @exception	    Throws InternalError when the HBA port count exceeds
58*7836SJohn.Forte@Sun.COM  *		    max number of ports and throws any underlying exception
59*7836SJohn.Forte@Sun.COM  * @param	    port The Port to add to this HBA
60*7836SJohn.Forte@Sun.COM  *
61*7836SJohn.Forte@Sun.COM  * @doc		    When discovering HBAs and their ports, use this
62*7836SJohn.Forte@Sun.COM  *		    routine to add a port to its existing HBA instance.
63*7836SJohn.Forte@Sun.COM  */
64*7836SJohn.Forte@Sun.COM void HBA::addPort(HBAPort* port) {
65*7836SJohn.Forte@Sun.COM 	Trace log("HBA::addPort");
66*7836SJohn.Forte@Sun.COM 	lock();
67*7836SJohn.Forte@Sun.COM 	// support hba with up to UCHAR_MAX number of ports.
68*7836SJohn.Forte@Sun.COM 	if (portsByIndex.size() + 1 > HBA_PORT_MAX) {
69*7836SJohn.Forte@Sun.COM 	    unlock();
70*7836SJohn.Forte@Sun.COM 	    throw InternalError("HBA Port count exceeds max number of ports");
71*7836SJohn.Forte@Sun.COM 	}
72*7836SJohn.Forte@Sun.COM 
73*7836SJohn.Forte@Sun.COM 	try {
74*7836SJohn.Forte@Sun.COM 	    portsByWWN[port->getPortWWN()] = port;
75*7836SJohn.Forte@Sun.COM 	    portsByIndex.insert(portsByIndex.end(), port);
76*7836SJohn.Forte@Sun.COM 	    unlock();
77*7836SJohn.Forte@Sun.COM 	} catch (...) {
78*7836SJohn.Forte@Sun.COM 	    unlock();
79*7836SJohn.Forte@Sun.COM 	    throw;
80*7836SJohn.Forte@Sun.COM 	}
81*7836SJohn.Forte@Sun.COM }
82*7836SJohn.Forte@Sun.COM 
83*7836SJohn.Forte@Sun.COM /**
84*7836SJohn.Forte@Sun.COM  * @memo	    Return number of ports to this HBA
85*7836SJohn.Forte@Sun.COM  * @exception	    No exception for this method.
86*7836SJohn.Forte@Sun.COM  *
87*7836SJohn.Forte@Sun.COM  * @doc		    Returns the number of ports on this HBA. The max
88*7836SJohn.Forte@Sun.COM  *		    number of ports that VSL support is up to max uint8_t
89*7836SJohn.Forte@Sun.COM  *		    size.
90*7836SJohn.Forte@Sun.COM  */
91*7836SJohn.Forte@Sun.COM uint8_t HBA::getNumberOfPorts() {
92*7836SJohn.Forte@Sun.COM 	Trace log("HBA::getNumberOfPorts");
93*7836SJohn.Forte@Sun.COM 	return (uint8_t)portsByIndex.size();
94*7836SJohn.Forte@Sun.COM }
95*7836SJohn.Forte@Sun.COM 
96*7836SJohn.Forte@Sun.COM /**
97*7836SJohn.Forte@Sun.COM  * @memo	    Retrieve an HBA port based on a Port WWN
98*7836SJohn.Forte@Sun.COM  * @exception	    IllegalWWNException Thrown if WWN does not match any
99*7836SJohn.Forte@Sun.COM  *		    known HBA port.
100*7836SJohn.Forte@Sun.COM  * @return	    HBAPort* to the port with a matching Port WWN
101*7836SJohn.Forte@Sun.COM  * @param	    wwn The wwn of the desired HBA port
102*7836SJohn.Forte@Sun.COM  *
103*7836SJohn.Forte@Sun.COM  * @doc		    Fetch an HBA port based on WWN.  If the port is not
104*7836SJohn.Forte@Sun.COM  *		    found, an exception will be thrown.  NULL will never
105*7836SJohn.Forte@Sun.COM  *		    be returned.
106*7836SJohn.Forte@Sun.COM  */
107*7836SJohn.Forte@Sun.COM HBAPort* HBA::getPort(uint64_t wwn) {
108*7836SJohn.Forte@Sun.COM 	Trace log("HBA::getPort");
109*7836SJohn.Forte@Sun.COM 	HBAPort *port = NULL;
110*7836SJohn.Forte@Sun.COM 	lock();
111*7836SJohn.Forte@Sun.COM 
112*7836SJohn.Forte@Sun.COM 	log.debug("getPort(wwn): WWN %016llx", wwn);
113*7836SJohn.Forte@Sun.COM 
114*7836SJohn.Forte@Sun.COM 	try {
115*7836SJohn.Forte@Sun.COM 	    // Make sure it is in the map
116*7836SJohn.Forte@Sun.COM 	    if (portsByWWN.find(wwn) == portsByWWN.end()) {
117*7836SJohn.Forte@Sun.COM 		throw IllegalWWNException();
118*7836SJohn.Forte@Sun.COM 	    }
119*7836SJohn.Forte@Sun.COM 	    port = portsByWWN[wwn];
120*7836SJohn.Forte@Sun.COM 	    unlock();
121*7836SJohn.Forte@Sun.COM 	    return (port);
122*7836SJohn.Forte@Sun.COM 	} catch (...) {
123*7836SJohn.Forte@Sun.COM 	    unlock();
124*7836SJohn.Forte@Sun.COM 	    throw;
125*7836SJohn.Forte@Sun.COM 	}
126*7836SJohn.Forte@Sun.COM }
127*7836SJohn.Forte@Sun.COM 
128*7836SJohn.Forte@Sun.COM /**
129*7836SJohn.Forte@Sun.COM  * Iterator for WWN to HBAPort map type
130*7836SJohn.Forte@Sun.COM  */
131*7836SJohn.Forte@Sun.COM typedef map<uint64_t, HBAPort *>::const_iterator CI;
132*7836SJohn.Forte@Sun.COM 
133*7836SJohn.Forte@Sun.COM /**
134*7836SJohn.Forte@Sun.COM  * @memo	    Return true if this HBA contains the stated WWN
135*7836SJohn.Forte@Sun.COM  *		    (node or port)
136*7836SJohn.Forte@Sun.COM  * @exception	    ... underlying exceptions will be thrown
137*7836SJohn.Forte@Sun.COM  * @return	    TRUE if the wwn is found
138*7836SJohn.Forte@Sun.COM  * @return	    FALSE if the wwn is not found
139*7836SJohn.Forte@Sun.COM  * @param	    wwn The wwn to look for
140*7836SJohn.Forte@Sun.COM  *
141*7836SJohn.Forte@Sun.COM  */
142*7836SJohn.Forte@Sun.COM bool HBA::containsWWN(uint64_t wwn) {
143*7836SJohn.Forte@Sun.COM 	Trace log("HBA::containsWWN");
144*7836SJohn.Forte@Sun.COM 	lock();
145*7836SJohn.Forte@Sun.COM 
146*7836SJohn.Forte@Sun.COM 	try {
147*7836SJohn.Forte@Sun.COM 	    for (CI port = portsByWWN.begin(); port != portsByWWN.end();
148*7836SJohn.Forte@Sun.COM 		    port++) {
149*7836SJohn.Forte@Sun.COM 		if (port->second->getPortWWN() == wwn) {
150*7836SJohn.Forte@Sun.COM 		    unlock();
151*7836SJohn.Forte@Sun.COM 		    return (true);
152*7836SJohn.Forte@Sun.COM 		}
153*7836SJohn.Forte@Sun.COM 		if (port->second->getNodeWWN() == wwn) {
154*7836SJohn.Forte@Sun.COM 		    unlock();
155*7836SJohn.Forte@Sun.COM 		    return (true);
156*7836SJohn.Forte@Sun.COM 		}
157*7836SJohn.Forte@Sun.COM 	    }
158*7836SJohn.Forte@Sun.COM 	    unlock();
159*7836SJohn.Forte@Sun.COM 	    return (false);
160*7836SJohn.Forte@Sun.COM 	} catch (...) {
161*7836SJohn.Forte@Sun.COM 	    unlock();
162*7836SJohn.Forte@Sun.COM 	    throw;
163*7836SJohn.Forte@Sun.COM 	}
164*7836SJohn.Forte@Sun.COM }
165*7836SJohn.Forte@Sun.COM 
166*7836SJohn.Forte@Sun.COM /**
167*7836SJohn.Forte@Sun.COM  * @memo	    Fetch the port based on index.
168*7836SJohn.Forte@Sun.COM  * @exception	    IllegalIndexException Thrown if the index is not valid
169*7836SJohn.Forte@Sun.COM  * @return	    HBAPort* the port matching the index
170*7836SJohn.Forte@Sun.COM  * @param	    index - the zero based index of the port to retrieve
171*7836SJohn.Forte@Sun.COM  *
172*7836SJohn.Forte@Sun.COM  */
173*7836SJohn.Forte@Sun.COM HBAPort* HBA::getPortByIndex(int index) {
174*7836SJohn.Forte@Sun.COM 	Trace log("HBA::getPortByIndex");
175*7836SJohn.Forte@Sun.COM 	lock();
176*7836SJohn.Forte@Sun.COM 	try {
177*7836SJohn.Forte@Sun.COM 	    log.debug("Port index size %d index %d ", portsByIndex.size(),
178*7836SJohn.Forte@Sun.COM 		    index);
179*7836SJohn.Forte@Sun.COM 
180*7836SJohn.Forte@Sun.COM 	    if (index >= portsByIndex.size() || index < 0) {
181*7836SJohn.Forte@Sun.COM 		throw IllegalIndexException();
182*7836SJohn.Forte@Sun.COM 	    }
183*7836SJohn.Forte@Sun.COM 
184*7836SJohn.Forte@Sun.COM 	    HBAPort *tmp = portsByIndex[index];
185*7836SJohn.Forte@Sun.COM 	    unlock();
186*7836SJohn.Forte@Sun.COM 	    return (tmp);
187*7836SJohn.Forte@Sun.COM 	} catch (...) {
188*7836SJohn.Forte@Sun.COM 	    unlock();
189*7836SJohn.Forte@Sun.COM 	    throw;
190*7836SJohn.Forte@Sun.COM 	}
191*7836SJohn.Forte@Sun.COM }
192*7836SJohn.Forte@Sun.COM 
193*7836SJohn.Forte@Sun.COM /**
194*7836SJohn.Forte@Sun.COM  * @memo	    Compare two HBAs for equality
195*7836SJohn.Forte@Sun.COM  * @precondition    Both HBAs should be fully discovered (all ports added)
196*7836SJohn.Forte@Sun.COM  * @exception	    ... underlying exceptions will be thrown
197*7836SJohn.Forte@Sun.COM  * @return	    TRUE The two HBA instances represent the same HBA
198*7836SJohn.Forte@Sun.COM  * @return	    FALSE The two HBA instances are different
199*7836SJohn.Forte@Sun.COM  *
200*7836SJohn.Forte@Sun.COM  * @doc		    This routine will compare each port within both
201*7836SJohn.Forte@Sun.COM  *		    HBAs and verify they are the same.  The ports must
202*7836SJohn.Forte@Sun.COM  *		    have been added in the same order.
203*7836SJohn.Forte@Sun.COM  */
204*7836SJohn.Forte@Sun.COM bool HBA::operator==(HBA &comp) {
205*7836SJohn.Forte@Sun.COM 	Trace log("HBA::operator==");
206*7836SJohn.Forte@Sun.COM 	lock();
207*7836SJohn.Forte@Sun.COM 
208*7836SJohn.Forte@Sun.COM 	try {
209*7836SJohn.Forte@Sun.COM 	    bool ret = false;
210*7836SJohn.Forte@Sun.COM 	    if (portsByIndex.size() == comp.portsByIndex.size()) {
211*7836SJohn.Forte@Sun.COM 		if (portsByIndex.size() > 0) {
212*7836SJohn.Forte@Sun.COM 		    ret = (*portsByIndex[0] == *comp.portsByIndex[0]);
213*7836SJohn.Forte@Sun.COM 		}
214*7836SJohn.Forte@Sun.COM 	    }
215*7836SJohn.Forte@Sun.COM 	    unlock();
216*7836SJohn.Forte@Sun.COM 	    return (ret);
217*7836SJohn.Forte@Sun.COM 	} catch (...) {
218*7836SJohn.Forte@Sun.COM 	    unlock();
219*7836SJohn.Forte@Sun.COM 	    throw;
220*7836SJohn.Forte@Sun.COM 	}
221*7836SJohn.Forte@Sun.COM }
222*7836SJohn.Forte@Sun.COM 
223*7836SJohn.Forte@Sun.COM /**
224*7836SJohn.Forte@Sun.COM  * @memo	    Set the RNID data for all the ports in this HBA
225*7836SJohn.Forte@Sun.COM  * @precondition    All ports must be added
226*7836SJohn.Forte@Sun.COM  * @postcondition   Each port will have the same RNID value set
227*7836SJohn.Forte@Sun.COM  * @exception	    ... underlying exceptions will be thrown.  Partial failure
228*7836SJohn.Forte@Sun.COM  *		    is possible and will not be cleaned up.
229*7836SJohn.Forte@Sun.COM  * @param	    info The RNID information to program for each HBA port
230*7836SJohn.Forte@Sun.COM  * @see		    HBAPort::setRNID
231*7836SJohn.Forte@Sun.COM  *
232*7836SJohn.Forte@Sun.COM  */
233*7836SJohn.Forte@Sun.COM void HBA::setRNID(HBA_MGMTINFO info) {
234*7836SJohn.Forte@Sun.COM 	Trace log("HBA::setRNID");
235*7836SJohn.Forte@Sun.COM 	lock();
236*7836SJohn.Forte@Sun.COM 
237*7836SJohn.Forte@Sun.COM 	try {
238*7836SJohn.Forte@Sun.COM 	    for (CI port = portsByWWN.begin(); port != portsByWWN.end();
239*7836SJohn.Forte@Sun.COM 		    port++) {
240*7836SJohn.Forte@Sun.COM 		port->second->setRNID(info);
241*7836SJohn.Forte@Sun.COM 	    }
242*7836SJohn.Forte@Sun.COM 	    unlock();
243*7836SJohn.Forte@Sun.COM 	} catch (...) {
244*7836SJohn.Forte@Sun.COM 	    unlock();
245*7836SJohn.Forte@Sun.COM 	    throw;
246*7836SJohn.Forte@Sun.COM 	}
247*7836SJohn.Forte@Sun.COM }
248*7836SJohn.Forte@Sun.COM 
249*7836SJohn.Forte@Sun.COM /**
250*7836SJohn.Forte@Sun.COM  * @memo	    Verify that this HBA is present on the system
251*7836SJohn.Forte@Sun.COM  * @exception	    UnavailableException Thrown when HBA not present
252*7836SJohn.Forte@Sun.COM  * @see		    HBAPort::validatePresent
253*7836SJohn.Forte@Sun.COM  *
254*7836SJohn.Forte@Sun.COM  * @doc		    This routine is used to verify that a given HBA
255*7836SJohn.Forte@Sun.COM  *		    has not been removed through dynamic reconfiguration.
256*7836SJohn.Forte@Sun.COM  *		    If the HBA is present, the routine will return.
257*7836SJohn.Forte@Sun.COM  *		    If the HBA is not present (if any port is not present)
258*7836SJohn.Forte@Sun.COM  *		    an exception will be thrown
259*7836SJohn.Forte@Sun.COM  */
260*7836SJohn.Forte@Sun.COM void HBA::validatePresent() {
261*7836SJohn.Forte@Sun.COM 	Trace log("HBA::validatePresent");
262*7836SJohn.Forte@Sun.COM 	lock();
263*7836SJohn.Forte@Sun.COM 	try {
264*7836SJohn.Forte@Sun.COM 	    for (CI port = portsByWWN.begin(); port != portsByWWN.end();
265*7836SJohn.Forte@Sun.COM 		    port++) {
266*7836SJohn.Forte@Sun.COM 		port->second->validatePresent();
267*7836SJohn.Forte@Sun.COM 	    }
268*7836SJohn.Forte@Sun.COM 	    unlock();
269*7836SJohn.Forte@Sun.COM 	} catch (...) {
270*7836SJohn.Forte@Sun.COM 	    unlock();
271*7836SJohn.Forte@Sun.COM 	    throw;
272*7836SJohn.Forte@Sun.COM 	}
273*7836SJohn.Forte@Sun.COM }
274*7836SJohn.Forte@Sun.COM 
275*7836SJohn.Forte@Sun.COM /**
276*7836SJohn.Forte@Sun.COM  * Opens a file, throwing exceptions on error.
277*7836SJohn.Forte@Sun.COM  */
278*7836SJohn.Forte@Sun.COM int HBA::_open(std::string path, int flag) {
279*7836SJohn.Forte@Sun.COM 	Trace log("HBA::open");
280*7836SJohn.Forte@Sun.COM 	int fd;
281*7836SJohn.Forte@Sun.COM 	errno = 0;
282*7836SJohn.Forte@Sun.COM 	if ((fd = open(path.c_str(), flag)) < 0) {
283*7836SJohn.Forte@Sun.COM 	    log.debug("Unable to open \"%s\" - reason (%d) %s",
284*7836SJohn.Forte@Sun.COM 		path.c_str(), errno, strerror(errno));
285*7836SJohn.Forte@Sun.COM 	    if (errno == EBUSY) {
286*7836SJohn.Forte@Sun.COM 		throw BusyException();
287*7836SJohn.Forte@Sun.COM 	    } else if (errno == EAGAIN) {
288*7836SJohn.Forte@Sun.COM 		throw TryAgainException();
289*7836SJohn.Forte@Sun.COM 	    } else if (errno == ENOTSUP) {
290*7836SJohn.Forte@Sun.COM 		throw NotSupportedException();
291*7836SJohn.Forte@Sun.COM 	    } else if (errno == ENOENT) {
292*7836SJohn.Forte@Sun.COM 		throw UnavailableException();
293*7836SJohn.Forte@Sun.COM 	    } else {
294*7836SJohn.Forte@Sun.COM 		string msg = "Unable to open ";
295*7836SJohn.Forte@Sun.COM 		msg += path;
296*7836SJohn.Forte@Sun.COM 		throw IOError(msg);
297*7836SJohn.Forte@Sun.COM 	    }
298*7836SJohn.Forte@Sun.COM 	}
299*7836SJohn.Forte@Sun.COM 	return (fd);
300*7836SJohn.Forte@Sun.COM }
301*7836SJohn.Forte@Sun.COM 
302*7836SJohn.Forte@Sun.COM /**
303*7836SJohn.Forte@Sun.COM  * Issues IOCTL, throwing exceptions on error.
304*7836SJohn.Forte@Sun.COM  * Note, if the IOCTL succeeds, but some IOCTL specific
305*7836SJohn.Forte@Sun.COM  * error is recorded in the response, this routine
306*7836SJohn.Forte@Sun.COM  * will not throw an exception.
307*7836SJohn.Forte@Sun.COM  */
308*7836SJohn.Forte@Sun.COM void HBA::_ioctl(int fd, int type, uchar_t *arg) {
309*7836SJohn.Forte@Sun.COM 	Trace log("HBA::ioctl");
310*7836SJohn.Forte@Sun.COM 	hrtime_t	    cur;
311*7836SJohn.Forte@Sun.COM 	int		    saved_errno = 0;
312*7836SJohn.Forte@Sun.COM 	struct timespec	    ts;
313*7836SJohn.Forte@Sun.COM 
314*7836SJohn.Forte@Sun.COM 	errno = 0;
315*7836SJohn.Forte@Sun.COM 	hrtime_t start = gethrtime();
316*7836SJohn.Forte@Sun.COM 	hrtime_t end = start + BUSY_RETRY_TIMER;
317*7836SJohn.Forte@Sun.COM 	ts.tv_sec = 0;
318*7836SJohn.Forte@Sun.COM 	ts.tv_nsec = BUSY_SLEEP;
319*7836SJohn.Forte@Sun.COM 	for (cur = start; cur < end; cur = gethrtime()) {
320*7836SJohn.Forte@Sun.COM 		if (ioctl(fd, type, arg) != 0) {
321*7836SJohn.Forte@Sun.COM 			if (errno == EAGAIN) {
322*7836SJohn.Forte@Sun.COM 				saved_errno = errno;
323*7836SJohn.Forte@Sun.COM 				nanosleep(&ts, NULL);
324*7836SJohn.Forte@Sun.COM 				continue;
325*7836SJohn.Forte@Sun.COM 			} else if (errno == EBUSY) {
326*7836SJohn.Forte@Sun.COM 				saved_errno = errno;
327*7836SJohn.Forte@Sun.COM 				nanosleep(&ts, NULL);
328*7836SJohn.Forte@Sun.COM 				continue;
329*7836SJohn.Forte@Sun.COM 			} else if (errno == ENOTSUP) {
330*7836SJohn.Forte@Sun.COM 				throw NotSupportedException();
331*7836SJohn.Forte@Sun.COM 			} else if (errno == ENOENT) {
332*7836SJohn.Forte@Sun.COM 				throw UnavailableException();
333*7836SJohn.Forte@Sun.COM 			} else {
334*7836SJohn.Forte@Sun.COM 				throw IOError("IOCTL failed");
335*7836SJohn.Forte@Sun.COM 			}
336*7836SJohn.Forte@Sun.COM 		} else {
337*7836SJohn.Forte@Sun.COM 			break;
338*7836SJohn.Forte@Sun.COM 		}
339*7836SJohn.Forte@Sun.COM 	}
340*7836SJohn.Forte@Sun.COM 	if (cur >= end) {
341*7836SJohn.Forte@Sun.COM 		if (saved_errno == EAGAIN) {
342*7836SJohn.Forte@Sun.COM 			throw TryAgainException();
343*7836SJohn.Forte@Sun.COM 		} else if (saved_errno == EBUSY) {
344*7836SJohn.Forte@Sun.COM 			throw BusyException();
345*7836SJohn.Forte@Sun.COM 		} else {
346*7836SJohn.Forte@Sun.COM 			throw IOError("IOCTL failed");
347*7836SJohn.Forte@Sun.COM 		}
348*7836SJohn.Forte@Sun.COM 	}
349*7836SJohn.Forte@Sun.COM }
350*7836SJohn.Forte@Sun.COM 
351*7836SJohn.Forte@Sun.COM HBA::~HBA() {
352*7836SJohn.Forte@Sun.COM 	Trace log("HBA::~HBA");
353*7836SJohn.Forte@Sun.COM 	for (int i = 0; i < getNumberOfPorts(); i++) {
354*7836SJohn.Forte@Sun.COM 	    delete (getPortByIndex(i));
355*7836SJohn.Forte@Sun.COM 	}
356*7836SJohn.Forte@Sun.COM }
357*7836SJohn.Forte@Sun.COM 
358