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 adapters that VSL supports."); 334 } 335 delete (tgthbaList); 336 } 337