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