1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 
  27 #include <unistd.h>
  28 
  29 #include <FCHBA.h>
  30 #include <Exceptions.h>
  31 #include <Trace.h>
  32 #include <iostream>
  33 #include <iomanip>
  34 #include <cerrno>
  35 #include <cstring>
  36 #include <sys/types.h>
  37 #include <sys/stat.h>
  38 #include <fcntl.h>
  39 #include <unistd.h>
  40 #include <stropts.h>
  41 #include <sys/fibre-channel/fcio.h>
  42 #include <sys/fibre-channel/ulp/fcsm.h>
  43 #include <FCHBAPort.h>
  44 #include <HBAList.h>
  45 
  46 #define EXCPT_RETRY_COUNT    10
  47 
  48 using namespace std;
  49 const string FCHBA::FCSM_DRIVER_PATH = "/devices/pseudo/fcsm@0:fcsm";
  50 const string FCHBA::FCSM_DRIVER_PKG     = "SUNWfcsm";
  51 const int FCHBA::MAX_FCIO_MSG_LEN = 256;
  52 
  53 FCHBA::FCHBA(string path) : HBA() {
  54     Trace log("FCHBA::FCHBA");
  55     log.debug("Constructing new HBA (%s)", path.c_str());
  56 
  57     // Add first port
  58     addPort(new FCHBAPort(path));
  59 
  60     name = "INTERNAL-FAILURE"; // Just in case things go wrong
  61     try {
  62         HBA_ADAPTERATTRIBUTES attrs = getHBAAttributes();
  63         name = attrs.Manufacturer;
  64         name += "-";
  65         name += attrs.Model;
  66 
  67         // Grab any other ports on this adapter
  68         for (int i = 1; i < attrs.NumberOfPorts; i++) {
  69             fcio_t                      fcio;
  70             int                 fd;
  71             char                nextPath[MAXPATHLEN];
  72 
  73             log.debug("Fetching other port %d", i);
  74 
  75             // construct fcio struct
  76             memset(&fcio, 0, sizeof (fcio_t));
  77             memset(nextPath, 0, sizeof (nextPath));
  78             fcio.fcio_cmd       = FCIO_GET_OTHER_ADAPTER_PORTS;
  79             fcio.fcio_xfer      = FCIO_XFER_RW;
  80 
  81             fcio.fcio_olen      = MAXPATHLEN;
  82             fcio.fcio_obuf      = (char *)nextPath;
  83             fcio.fcio_ilen      = sizeof (i);
  84             fcio.fcio_ibuf      = (char *)&i;
  85 
  86             // open the fcsm node so we can send the ioctl to
  87             errno = 0;
  88             HBAPort *port = getPortByIndex(0);
  89             if ((fd = open(port->getPath().c_str(), O_NDELAY | O_RDONLY)) ==
  90                     -1) {
  91                 log.debug("Unable to open %d opened (%s)", i,
  92                 port->getPath().c_str());
  93                 if (errno == EBUSY) {
  94                     throw BusyException();
  95                 } else if (errno == EAGAIN) {
  96                     throw TryAgainException();
  97                 } else if (errno == ENOTSUP) {
  98                     throw NotSupportedException();
  99                 } else if (errno == ENOENT) {
 100                     throw UnavailableException();
 101                 } else {
 102                     throw IOError("Unable to open FCSM driver");
 103                 }
 104             }
 105             log.debug("Other port %d opened", i);
 106 
 107             errno = 0;
 108             if (ioctl(fd, FCIO_CMD, &fcio) != 0) {
 109                 // Interpret the fcio error code
 110                 char fcioErrorString[MAX_FCIO_MSG_LEN] = "";
 111 
 112                 log.genericIOError(
 113                     "ADAPTER_LIST failed: "
 114                     "Errno: \"%s\"",
 115                     strerror(errno));
 116                 close(fd);
 117                 if (errno == EBUSY) {
 118                     throw BusyException();
 119                 } else if (errno == EAGAIN) {
 120                     throw TryAgainException();
 121                 } else if (errno == ENOTSUP) {
 122                     throw NotSupportedException();
 123                 } else if (errno == ENOENT) {
 124                     throw UnavailableException();
 125                 } else {
 126                     throw IOError("Unable to build HBA list");
 127                 }
 128             }
 129             close(fd);
 130             log.debug("About to add port %d (%s)", i, nextPath);
 131             addPort(new FCHBAPort(nextPath));
 132         }
 133     } catch (BusyException &e) {
 134         throw e;
 135     } catch (TryAgainException &e) {
 136         throw e;
 137     } catch (UnavailableException &e) {
 138         throw e;
 139     } catch (HBAException &e) {
 140         log.internalError(
 141                 "Unable to construct HBA.");
 142         throw e;
 143     }
 144 }
 145 
 146 std::string FCHBA::getName() {
 147     Trace log("FCHBA::getName");
 148     return (name);
 149 }
 150 
 151 HBA_ADAPTERATTRIBUTES FCHBA::getHBAAttributes() {
 152     Trace log("FCHBA::getHBAAttributes");
 153     int fd;
 154 
 155     errno = 0;
 156     HBAPort *port = getPortByIndex(0);
 157     if ((fd = open(port->getPath().c_str(), O_NDELAY | O_RDONLY)) == -1) {
 158         // Why did we fail?
 159         if (errno == EBUSY) {
 160             throw BusyException();
 161         } else if (errno == EAGAIN) {
 162             throw TryAgainException();
 163         } else if (errno == ENOTSUP) {
 164             throw NotSupportedException();
 165         } else {
 166             throw IOError(port);
 167         }
 168     }
 169 
 170     HBA_ADAPTERATTRIBUTES attributes;
 171     fcio_t                          fcio;
 172     fc_hba_adapter_attributes_t     attrs;
 173 
 174     memset(&fcio, 0, sizeof (fcio));
 175 
 176     fcio.fcio_cmd = FCIO_GET_ADAPTER_ATTRIBUTES;
 177     fcio.fcio_olen = sizeof (attrs);
 178     fcio.fcio_xfer = FCIO_XFER_READ;
 179     fcio.fcio_obuf = (caddr_t)&attrs;
 180 
 181 
 182     errno = 0;
 183     if (ioctl(fd, FCIO_CMD, &fcio) != 0) {
 184         close(fd);
 185         if (errno == EBUSY) {
 186             throw BusyException();
 187         } else if (errno == EAGAIN) {
 188             throw TryAgainException();
 189         } else if (errno == ENOTSUP) {
 190             throw NotSupportedException();
 191         } else {
 192             throw IOError("Unable to fetch adapter attributes");
 193         }
 194     }
 195     close(fd);
 196 
 197     /* Now copy over the payload */
 198     attributes.NumberOfPorts = attrs.NumberOfPorts;
 199     attributes.VendorSpecificID = attrs.VendorSpecificID;
 200     memcpy(attributes.Manufacturer, attrs.Manufacturer, 64);
 201     memcpy(attributes.SerialNumber, attrs.SerialNumber, 64);
 202     memcpy(attributes.Model, attrs.Model, 256);
 203     memcpy(attributes.ModelDescription, attrs.ModelDescription, 256);
 204     memcpy(attributes.NodeSymbolicName, attrs.NodeSymbolicName, 256);
 205     memcpy(attributes.HardwareVersion, attrs.HardwareVersion, 256);
 206     memcpy(attributes.DriverVersion, attrs.DriverVersion, 256);
 207     memcpy(attributes.OptionROMVersion, attrs.OptionROMVersion, 256);
 208     memcpy(attributes.FirmwareVersion, attrs.FirmwareVersion, 256);
 209     memcpy(attributes.DriverName, attrs.DriverName, 256);
 210     memcpy(&attributes.NodeWWN, &attrs.NodeWWN, 8);
 211 
 212     return (attributes);
 213 }
 214 
 215 int FCHBA::doForceLip() {
 216     Trace        log("FCHBA::doForceLip");
 217     int          fd;
 218     fcio_t       fcio;
 219     uint64_t     wwn  = 0;
 220     HBAPort     *port = getPortByIndex(0);
 221 
 222     errno = 0;
 223     if ((fd = open(port->getPath().c_str(), O_RDONLY | O_EXCL)) == -1) {
 224         if (errno == EBUSY) {
 225             throw BusyException();
 226         } else if (errno == EAGAIN) {
 227             throw TryAgainException();
 228         } else if (errno == ENOTSUP) {
 229             throw NotSupportedException();
 230         } else {
 231             throw IOError(port);
 232         }
 233     }
 234 
 235     memset(&fcio, 0, sizeof (fcio));
 236     fcio.fcio_cmd = FCIO_RESET_LINK;
 237     fcio.fcio_xfer = FCIO_XFER_WRITE;
 238     fcio.fcio_ilen = sizeof (wwn);
 239     fcio.fcio_ibuf = (caddr_t)&wwn;
 240 
 241     errno = 0;
 242     if (ioctl(fd, FCIO_CMD, &fcio) != 0) {
 243         close(fd);
 244 
 245         if (errno == EBUSY) {
 246             throw BusyException();
 247         } else if (errno == EAGAIN) {
 248             throw TryAgainException();
 249         } else if (errno == ENOTSUP) {
 250             throw NotSupportedException();
 251         } else {
 252             throw IOError("Unable to reinitialize the link");
 253         }
 254     } else {
 255         close(fd);
 256         return (fcio.fcio_errno);
 257     }
 258 }
 259 
 260 HBA_ADAPTERATTRIBUTES FCHBA::npivGetHBAAttributes() {
 261         Trace log("FCHBA::npivGetHBAAttributes");
 262         int fd;
 263 
 264         errno = 0;
 265         HBAPort *port = getPortByIndex(0);
 266         if ((fd = open(port->getPath().c_str(), O_NDELAY | O_RDONLY)) == -1) {
 267                 // Why did we fail?
 268                 if (errno == EBUSY) {
 269                         throw BusyException();
 270                 } else if (errno == EAGAIN) {
 271                         throw TryAgainException();
 272                 } else if (errno == ENOTSUP) {
 273                         throw NotSupportedException();
 274                 } else {
 275                         throw IOError(port);
 276                 }
 277         }
 278 
 279         HBA_ADAPTERATTRIBUTES attributes;
 280         fcio_t fcio;
 281         fc_hba_adapter_attributes_t attrs;
 282 
 283         memset(&fcio, 0, sizeof (fcio));
 284         fcio.fcio_cmd = FCIO_NPIV_GET_ADAPTER_ATTRIBUTES;
 285         fcio.fcio_olen = sizeof (attrs);
 286         fcio.fcio_xfer = FCIO_XFER_READ;
 287         fcio.fcio_obuf = (caddr_t)&attrs;
 288         errno = 0;
 289 
 290         if (ioctl(fd, FCIO_CMD, &fcio) != 0) {
 291                 close(fd);
 292                 if (errno == EBUSY) {
 293                         throw BusyException();
 294                 } else if (errno == EAGAIN) {
 295                         throw TryAgainException();
 296                 } else if (errno == ENOTSUP) {
 297                         throw NotSupportedException();
 298                 } else {
 299                         throw IOError("Unable to fetch adapter attributes");
 300                 }
 301         }
 302         close(fd);
 303 
 304         /* Now copy over the payload */
 305         attributes.NumberOfPorts = attrs.NumberOfPorts;
 306         attributes.VendorSpecificID = attrs.VendorSpecificID;
 307         memcpy(attributes.Manufacturer, attrs.Manufacturer, 64);
 308         memcpy(attributes.SerialNumber, attrs.SerialNumber, 64);
 309         memcpy(attributes.Model, attrs.Model, 256);
 310         memcpy(attributes.ModelDescription, attrs.ModelDescription, 256);
 311         memcpy(attributes.NodeSymbolicName, attrs.NodeSymbolicName, 256);
 312         memcpy(attributes.HardwareVersion, attrs.HardwareVersion, 256);
 313         memcpy(attributes.DriverVersion, attrs.DriverVersion, 256);
 314         memcpy(attributes.OptionROMVersion, attrs.OptionROMVersion, 256);
 315         memcpy(attributes.FirmwareVersion, attrs.FirmwareVersion, 256);
 316         memcpy(attributes.DriverName, attrs.DriverName, 256);
 317         memcpy(&attributes.NodeWWN, &attrs.NodeWWN, 8);
 318 
 319         return (attributes);
 320 }
 321 
 322 void FCHBA::loadAdapters(vector<HBA*> &list) {
 323     Trace log("FCHBA::loadAdapters");
 324     fcio_t                      fcio;
 325     fc_hba_list_t               *pathList;
 326     int                 fd;
 327     int                 size = 64; // default first attempt
 328     bool                retry = false;
 329     struct stat         sb;
 330     int bufSize;
 331 
 332     /* Before we do anything, let's see if FCSM is on the system */
 333     errno = 0;
 334     if (stat(FCSM_DRIVER_PATH.c_str(), &sb) != 0) {
 335         if (errno == ENOENT) {
 336             log.genericIOError(
 337                 "The %s driver is not present. Unable to issue "
 338                 "CT commands. Please install the %s package.",
 339                 FCSM_DRIVER_PATH.c_str(), FCSM_DRIVER_PKG.c_str());
 340             throw NotSupportedException();
 341         } else {
 342             log.genericIOError(
 343                 "Can not stat the %s driver for reason \"%s\" "
 344                 "Unable to issue CT commands.",
 345                 FCSM_DRIVER_PATH.c_str(), strerror(errno));
 346             throw IOError("Unable to stat FCSM driver");
 347         }
 348     }
 349 
 350 
 351     /* construct fcio struct */
 352     memset(&fcio, 0, sizeof (fcio_t));
 353     fcio.fcio_cmd       = FCSMIO_ADAPTER_LIST;
 354     fcio.fcio_xfer      = FCIO_XFER_RW;
 355 
 356 
 357     /* open the fcsm node so we can send the ioctl to */
 358     errno = 0;
 359     if ((fd = open(FCSM_DRIVER_PATH.c_str(), O_RDONLY)) < 0) {
 360         if (errno == EBUSY) {
 361             throw BusyException();
 362         } else if (errno == EAGAIN) {
 363             throw TryAgainException();
 364         } else if (errno == ENOTSUP) {
 365             throw NotSupportedException();
 366         } else if (errno == ENOENT) {
 367             throw UnavailableException();
 368         } else {
 369             throw IOError("Unable to open FCSM driver");
 370         }
 371     }
 372 
 373     do {
 374         retry = false;
 375         errno = 0;
 376         bufSize = MAXPATHLEN * size + (int) sizeof (fc_hba_list_t) - 1;
 377         pathList = (fc_hba_list_t *)new uchar_t[bufSize];
 378         pathList->numAdapters = size;
 379         fcio.fcio_olen  = bufSize;
 380         fcio.fcio_obuf  = (char *)pathList;
 381         if (ioctl(fd, FCSMIO_CMD, &fcio) != 0) {
 382             /* Interpret the fcio error code */
 383             char fcioErrorString[MAX_FCIO_MSG_LEN] = "";
 384 
 385             log.genericIOError(
 386                 "ADAPTER_LIST failed: "
 387                 "Errno: \"%s\"",
 388                 strerror(errno));
 389             delete (pathList);
 390             close(fd);
 391             if (errno == EBUSY) {
 392                 throw BusyException();
 393             } else if (errno == EAGAIN) {
 394                 throw TryAgainException();
 395             } else if (errno == ENOTSUP) {
 396                 throw NotSupportedException();
 397             } else if (errno == ENOENT) {
 398                 throw UnavailableException();
 399             } else {
 400                 throw IOError("Unable to build HBA list");
 401             }
 402         }
 403         if (pathList->numAdapters > size) {
 404             log.debug(
 405                 "Buffer too small for number of HBAs. Retrying.");
 406             size = pathList->numAdapters;
 407             retry = true;
 408             delete (pathList);
 409         }
 410     } while (retry);
 411 
 412     close(fd);
 413     log.debug("Detected %d adapters", pathList->numAdapters);
 414     for (int i = 0, times =0; i < pathList->numAdapters;) {
 415         try {
 416             HBA *hba = new FCHBA(pathList->hbaPaths[i]);
 417             list.insert(list.begin(), hba);
 418             i++;
 419         } catch (BusyException &e) {
 420             sleep(1);
 421             if (times++ > EXCPT_RETRY_COUNT) {
 422                 i++; 
 423                 times = 0;
 424             }
 425             continue;
 426         } catch (TryAgainException &e) {
 427             sleep(1);
 428             if (times++ > EXCPT_RETRY_COUNT) {
 429                 i++; 
 430                 times = 0;
 431             }  
 432             continue;
 433         } catch (UnavailableException &e) {
 434             sleep(1);
 435             if (times++ > EXCPT_RETRY_COUNT) {
 436                 i++; 
 437                 times = 0;
 438             }  
 439             continue;
 440         } catch (HBAException &e) {
 441             i++;
 442             times = 0;
 443             log.debug(
 444                 "Ignoring partial failure while loading an HBA");
 445         }
 446     }
 447     if (pathList->numAdapters > HBAList::HBA_MAX_PER_LIST) {
 448         delete(pathList);
 449         throw InternalError(
 450             "Exceeds max number of adatpers that VSL supports.");
 451     }
 452     delete (pathList);
 453 }