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