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 <TgtFCHBA.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/fctio.h>
  42 #include <sys/fibre-channel/impl/fc_error.h>
  43 #include <TgtFCHBAPort.h>
  44 #include <HBAList.h>
  45 #include <sun_fc.h>
  46 #include <cstdlib>
  47 
  48 using namespace std;
  49 const string TgtFCHBA::FCT_DRIVER_PATH = "/devices/pseudo/fct@0:admin";
  50 const string TgtFCHBA::FCT_ADAPTER_NAME_PREFIX = "/devices/pseudo/fct@0";
  51 const string TgtFCHBA::FCT_DRIVER_PKG   = "SUNWfct";
  52 const int TgtFCHBA::MAX_FCTIO_MSG_LEN = 256;
  53 
  54 TgtFCHBA::TgtFCHBA(string path) : HBA()
  55 {
  56     Trace log("TgtFCHBA::TgtFCHBA");
  57     log.debug("Constructing new Target mode HBA (%s)", path.c_str());
  58 
  59     // Add a target FCHBA port. With fct driver architecuture, all target mode
  60     // FCHBA will have a single port regardless of the multiport support on
  61     // FCA layer.
  62     addPort(new TgtFCHBAPort(path));
  63     name = "INTERNAL-FAILURE"; // Just in case things go wrong
  64     try {
  65             HBA_ADAPTERATTRIBUTES attrs = getHBAAttributes();
  66             name = attrs.Manufacturer;
  67             name += "-";
  68             name += attrs.Model;
  69             name += "-Tgt";
  70 
  71     } catch (HBAException &e) {
  72             log.debug(
  73                 "Failed to get HBA attribute for %s", path.c_str());
  74             throw e;
  75     }
  76 }
  77 
  78 std::string TgtFCHBA::getName()
  79 {
  80     Trace log("TgtFCHBA::getName");
  81     return (name);
  82 }
  83 
  84 HBA_ADAPTERATTRIBUTES TgtFCHBA::getHBAAttributes()
  85 {
  86     Trace log("TgtFCHBA::getHBAAttributes");
  87     int fd;
  88 
  89     errno = 0;
  90     HBAPort *port = getPortByIndex(0);
  91 
  92     HBA_ADAPTERATTRIBUTES attributes;
  93     fctio_t                         fctio;
  94     fc_tgt_hba_adapter_attributes_t         attrs;
  95     uint64_t    portwwn;
  96 
  97     if ((fd = open(FCT_DRIVER_PATH.c_str(), O_NDELAY | O_RDONLY)) == -1) {
  98         // Why did we fail?
  99         if (errno == EBUSY) {
 100             throw BusyException();
 101         } else if (errno == EAGAIN) {
 102             throw TryAgainException();
 103         } else if (errno == ENOTSUP) {
 104             throw NotSupportedException();
 105         } else {
 106             throw IOError(port);
 107         }
 108     }
 109 
 110     try {
 111             std::string path = port->getPath();
 112             string::size_type offset = path.find_last_of(".");
 113             if (offset >= 0) {
 114                 string portwwnString = path.substr(offset+1);
 115                 portwwn = strtoull(portwwnString.c_str(), NULL, 16);
 116             }
 117     } catch (...) {
 118             throw BadArgumentException();
 119     }
 120 
 121     uint64_t en_wwn = htonll(portwwn);
 122 
 123     memset(&fctio, 0, sizeof (fctio));
 124     fctio.fctio_cmd = FCTIO_GET_ADAPTER_ATTRIBUTES;
 125     fctio.fctio_olen = (uint32_t)(sizeof (attrs));
 126     fctio.fctio_xfer = FCTIO_XFER_READ;
 127     fctio.fctio_obuf = (uint64_t)(uintptr_t)&attrs;
 128     fctio.fctio_ilen = 8;
 129     fctio.fctio_ibuf = (uint64_t)(uintptr_t)&en_wwn;
 130 
 131     errno = 0;
 132     if (ioctl(fd, FCTIO_CMD, &fctio) != 0) {
 133         close(fd);
 134         if (errno == EBUSY) {
 135             throw BusyException();
 136         } else if (errno == EAGAIN) {
 137             throw TryAgainException();
 138         } else if (errno == ENOTSUP) {
 139             throw NotSupportedException();
 140         } else {
 141             throw IOError("Unable to fetch adapter attributes");
 142         }
 143     }
 144     close(fd);
 145 
 146     /* Now copy over the payload */
 147     attributes.NumberOfPorts = attrs.NumberOfPorts;
 148     attributes.VendorSpecificID = attrs.VendorSpecificID;
 149     memcpy(attributes.Manufacturer, attrs.Manufacturer, 64);
 150     memcpy(attributes.SerialNumber, attrs.SerialNumber, 64);
 151     memcpy(attributes.Model, attrs.Model, 256);
 152     memcpy(attributes.ModelDescription, attrs.ModelDescription, 256);
 153     memcpy(attributes.NodeSymbolicName, attrs.NodeSymbolicName, 256);
 154     memcpy(attributes.HardwareVersion, attrs.HardwareVersion, 256);
 155     memcpy(attributes.DriverVersion, attrs.DriverVersion, 256);
 156     memcpy(attributes.OptionROMVersion, attrs.OptionROMVersion, 256);
 157     memcpy(attributes.FirmwareVersion, attrs.FirmwareVersion, 256);
 158     memcpy(attributes.DriverName, attrs.DriverName, 256);
 159     memcpy(&attributes.NodeWWN, &attrs.NodeWWN, 8);
 160 
 161     return (attributes);
 162 }
 163 
 164 int TgtFCHBA::doForceLip()
 165 {
 166     Trace        log("TgtFCHBA::doForceLip");
 167     int          fd;
 168     HBAPort     *port = getPortByIndex(0);
 169     fctio_t      fctio;
 170     uint64_t     portwwn;
 171 
 172     errno = 0;
 173     if ((fd = open(FCT_DRIVER_PATH.c_str(), O_NDELAY | O_RDONLY)) == -1) {
 174         if (errno == EBUSY) {
 175             throw BusyException();
 176         } else if (errno == EAGAIN) {
 177             throw TryAgainException();
 178         } else if (errno == ENOTSUP) {
 179             throw NotSupportedException();
 180         } else {
 181             throw IOError(port);
 182         }
 183     }
 184 
 185     try {
 186             std::string path = port->getPath();
 187             string::size_type offset = path.find_last_of(".");
 188             if (offset >= 0) {
 189                 string portwwnString = path.substr(offset+1);
 190                 portwwn = strtoull(portwwnString.c_str(), NULL, 16);
 191             }
 192     } catch (...) {
 193             throw BadArgumentException();
 194     }
 195 
 196     uint64_t en_wwn = htonll(portwwn);
 197     memset(&fctio, 0, sizeof (fctio));
 198     fctio.fctio_cmd = FCTIO_FORCE_LIP;
 199     fctio.fctio_xfer = FCTIO_XFER_READ;
 200     fctio.fctio_ilen = 8;
 201     fctio.fctio_ibuf = (uint64_t)(uintptr_t)&en_wwn;
 202 
 203     errno = 0;
 204     if (ioctl(fd, FCTIO_CMD, &fctio) != 0) {
 205         close(fd);
 206         if (errno == EBUSY) {
 207             throw BusyException();
 208         } else if (errno == EAGAIN) {
 209             throw TryAgainException();
 210         } else if (errno == ENOTSUP) {
 211             throw NotSupportedException();
 212         } else {
 213             throw IOError("Unable to reinitialize the link");
 214         }
 215     } else {
 216         close(fd);
 217         return ((int)fctio.fctio_errno);
 218     }
 219 }
 220 
 221 void TgtFCHBA::loadAdapters(vector<HBA*> &list)
 222 {
 223     Trace log("TgtFCHBA::loadAdapters");
 224     fctio_t                     fctio;
 225     fc_tgt_hba_list_t           *tgthbaList;
 226     int                 fd;
 227     int                 size = 64; // default first attempt
 228     bool                retry = false;
 229     struct stat         sb;
 230     int bufSize;
 231     char wwnStr[17];
 232 
 233     /* Before we do anything, let's see if FCT is on the system */
 234     errno = 0;
 235     if (stat(FCT_DRIVER_PATH.c_str(), &sb) != 0) {
 236         if (errno == ENOENT) {
 237             log.genericIOError(
 238                 "The %s driver is not present."
 239                 " Please install the %s package.",
 240                 FCT_DRIVER_PATH.c_str(), FCT_DRIVER_PKG.c_str());
 241             throw NotSupportedException();
 242         } else {
 243             log.genericIOError(
 244                 "Can not stat the %s driver for reason \"%s\" "
 245                 "Unable to get target mode FC adapters.",
 246                 FCT_DRIVER_PATH.c_str(), strerror(errno));
 247             throw IOError("Unable to stat FCSM driver");
 248         }
 249     }
 250 
 251 
 252     /* construct fcio struct */
 253     memset(&fctio, 0, sizeof (fctio_t));
 254     fctio.fctio_cmd     = FCTIO_ADAPTER_LIST;
 255     fctio.fctio_xfer    = FCTIO_XFER_RW;
 256 
 257     /* open the fcsm node so we can send the ioctl to */
 258     errno = 0;
 259     if ((fd = open(FCT_DRIVER_PATH.c_str(), O_RDONLY)) < 0) {
 260         if (errno == EBUSY) {
 261             throw BusyException();
 262         } else if (errno == EAGAIN) {
 263             throw TryAgainException();
 264         } else if (errno == ENOTSUP) {
 265             throw NotSupportedException();
 266         } else if (errno == ENOENT) {
 267             throw UnavailableException();
 268         } else {
 269             throw IOError("Unable to open FCT driver");
 270         }
 271     }
 272 
 273     do {
 274         retry = false;
 275         errno = 0;
 276         bufSize = 8 * (size - 1) + (int) sizeof (fc_tgt_hba_list_t);
 277         tgthbaList = (fc_tgt_hba_list_t *)new uchar_t[bufSize];
 278         tgthbaList->numPorts = size;
 279         fctio.fctio_olen        = bufSize;
 280         fctio.fctio_obuf        = (uint64_t)(uintptr_t)tgthbaList;
 281         if (ioctl(fd, FCTIO_CMD, &fctio) != 0) {
 282             /* Interpret the fcio error code */
 283             char fcioErrorString[MAX_FCTIO_MSG_LEN] = "";
 284 
 285             log.genericIOError(
 286                 "TGT_ADAPTER_LIST failed: "
 287                 "Errno: \"%s\"",
 288                 strerror(errno));
 289             delete (tgthbaList);
 290             close(fd);
 291             if (errno == EBUSY) {
 292                 throw BusyException();
 293             } else if (errno == EAGAIN) {
 294                 throw TryAgainException();
 295             } else if (errno == ENOTSUP) {
 296                 throw NotSupportedException();
 297             } else if (errno == ENOENT) {
 298                 throw UnavailableException();
 299             } else {
 300                 throw IOError("Unable to build HBA list");
 301             }
 302         }
 303         if (tgthbaList->numPorts > size) {
 304             log.debug(
 305                 "Buffer too small for number of target mode HBAs. Retrying.");
 306             size = tgthbaList->numPorts;
 307             retry = true;
 308             delete (tgthbaList);
 309         }
 310     } while (retry);
 311 
 312     close(fd);
 313     log.debug("Detected %d target mode adapters", tgthbaList->numPorts);
 314     for (int i = 0; i < tgthbaList->numPorts; i++) {
 315         try {
 316             std::string hbapath = FCT_ADAPTER_NAME_PREFIX.c_str();
 317             hbapath += ".";
 318             // move the row with two dimentional uint8 array for WWN
 319             uint64_t tmp = ntohll(*((uint64_t *)&tgthbaList->port_wwn[i][0]));
 320             sprintf(wwnStr, "%llx", tmp);
 321             hbapath += wwnStr;
 322 
 323             HBA *hba = new TgtFCHBA(hbapath);
 324             list.insert(list.begin(), hba);
 325         } catch (...) {
 326             log.debug(
 327                 "Ignoring partial failure while loading an HBA");
 328         }
 329     }
 330     if (tgthbaList->numPorts > HBAList::HBA_MAX_PER_LIST) {
 331         delete(tgthbaList);
 332         throw InternalError(
 333             "Exceeds max number of adatpers that VSL supports.");
 334     }
 335     delete (tgthbaList);
 336 }