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