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 2008 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 void TgtFCHBA::loadAdapters(vector<HBA*> &list) 164 { 165 Trace log("TgtFCHBA::loadAdapters"); 166 fctio_t fctio; 167 fc_tgt_hba_list_t *tgthbaList; 168 int fd; 169 int size = 64; // default first attempt 170 bool retry = false; 171 struct stat sb; 172 int bufSize; 173 char wwnStr[17]; 174 175 /* Before we do anything, let's see if FCT is on the system */ 176 errno = 0; 177 if (stat(FCT_DRIVER_PATH.c_str(), &sb) != 0) { 178 if (errno == ENOENT) { 179 log.genericIOError( 180 "The %s driver is not present." 181 " Please install the %s package.", 182 FCT_DRIVER_PATH.c_str(), FCT_DRIVER_PKG.c_str()); 183 throw NotSupportedException(); 184 } else { 185 log.genericIOError( 186 "Can not stat the %s driver for reason \"%s\" " 187 "Unable to get target mode FC adapters.", 188 FCT_DRIVER_PATH.c_str(), strerror(errno)); 189 throw IOError("Unable to stat FCSM driver"); 190 } 191 } 192 193 194 /* construct fcio struct */ 195 memset(&fctio, 0, sizeof (fctio_t)); 196 fctio.fctio_cmd = FCTIO_ADAPTER_LIST; 197 fctio.fctio_xfer = FCTIO_XFER_RW; 198 199 /* open the fcsm node so we can send the ioctl to */ 200 errno = 0; 201 if ((fd = open(FCT_DRIVER_PATH.c_str(), O_RDONLY)) < 0) { 202 if (errno == EBUSY) { 203 throw BusyException(); 204 } else if (errno == EAGAIN) { 205 throw TryAgainException(); 206 } else if (errno == ENOTSUP) { 207 throw NotSupportedException(); 208 } else if (errno == ENOENT) { 209 throw UnavailableException(); 210 } else { 211 throw IOError("Unable to open FCT driver"); 212 } 213 } 214 215 do { 216 retry = false; 217 errno = 0; 218 bufSize = 8 * (size - 1) + (int) sizeof (fc_tgt_hba_list_t); 219 tgthbaList = (fc_tgt_hba_list_t *)new uchar_t[bufSize]; 220 tgthbaList->numPorts = size; 221 fctio.fctio_olen = bufSize; 222 fctio.fctio_obuf = (uint64_t)(uintptr_t)tgthbaList; 223 if (ioctl(fd, FCTIO_CMD, &fctio) != 0) { 224 /* Interpret the fcio error code */ 225 char fcioErrorString[MAX_FCTIO_MSG_LEN] = ""; 226 227 log.genericIOError( 228 "TGT_ADAPTER_LIST failed: " 229 "Errno: \"%s\"", 230 strerror(errno)); 231 delete (tgthbaList); 232 close(fd); 233 if (errno == EBUSY) { 234 throw BusyException(); 235 } else if (errno == EAGAIN) { 236 throw TryAgainException(); 237 } else if (errno == ENOTSUP) { 238 throw NotSupportedException(); 239 } else if (errno == ENOENT) { 240 throw UnavailableException(); 241 } else { 242 throw IOError("Unable to build HBA list"); 243 } 244 } 245 if (tgthbaList->numPorts > size) { 246 log.debug( 247 "Buffer too small for number of target mode HBAs. Retrying."); 248 size = tgthbaList->numPorts; 249 retry = true; 250 delete (tgthbaList); 251 } 252 } while (retry); 253 254 close(fd); 255 log.debug("Detected %d target mode adapters", tgthbaList->numPorts); 256 for (int i = 0; i < tgthbaList->numPorts; i++) { 257 try { 258 std::string hbapath = FCT_ADAPTER_NAME_PREFIX.c_str(); 259 hbapath += "."; 260 // move the row with two dimentional uint8 array for WWN 261 uint64_t tmp = ntohll(*((uint64_t *)&tgthbaList->port_wwn[i][0])); 262 sprintf(wwnStr, "%llx", tmp); 263 hbapath += wwnStr; 264 265 HBA *hba = new TgtFCHBA(hbapath); 266 list.insert(list.begin(), hba); 267 } catch (...) { 268 log.debug( 269 "Ignoring partial failure while loading an HBA"); 270 } 271 } 272 if (tgthbaList->numPorts > HBAList::HBA_MAX_PER_LIST) { 273 delete(tgthbaList); 274 throw InternalError( 275 "Exceeds max number of adatpers that VSL supports."); 276 } 277 delete (tgthbaList); 278 } 279