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 28 #include <TgtFCHBAPort.h> 29 #include <Exceptions.h> 30 #include <Trace.h> 31 #include <sun_fc.h> 32 #include <iostream> 33 #include <iomanip> 34 #include <sys/types.h> 35 #include <sys/mkdev.h> 36 #include <sys/stat.h> 37 #include <fcntl.h> 38 #include <unistd.h> 39 #include <stropts.h> 40 #include <dirent.h> 41 #include <sys/fibre-channel/fc.h> 42 #include <sys/fctio.h> 43 #include <sys/fibre-channel/impl/fc_error.h> 44 #include <sys/fibre-channel/fc_appif.h> 45 #include <sys/scsi/generic/commands.h> 46 #include <sys/scsi/impl/commands.h> 47 #include <sys/scsi/impl/sense.h> 48 #include <sys/scsi/generic/inquiry.h> 49 #include <sys/scsi/generic/status.h> 50 #include <errno.h> 51 52 53 using namespace std; 54 55 const int TgtFCHBAPort::MAX_FCTIO_MSG_LEN = 256; 56 const string TgtFCHBAPort::FCT_DRIVER_PATH = "/devices/pseudo/fct@0:admin"; 57 58 /* 59 * Interpret the error code in the fctio_t structure 60 * 61 * message must be at least MAX_FCTIO_MSG_LEN in length. 62 */ 63 void 64 TgtFCHBAPort::transportError(uint32_t fctio_errno, char *message) { 65 Trace log("transportError"); 66 string fcioErrorString; 67 if (message == NULL) { 68 log.internalError("NULL routine argument"); 69 return; 70 } 71 switch (fctio_errno) { 72 case (uint32_t)FC_FAILURE: 73 fcioErrorString = "general failure"; 74 break; 75 case (uint32_t)FC_FAILURE_SILENT: 76 fcioErrorString = "general failure but fail silently"; 77 break; 78 case FC_SUCCESS: 79 fcioErrorString = "successful completion"; 80 break; 81 case FC_CAP_ERROR: 82 fcioErrorString = "FCA capability error"; 83 break; 84 case FC_CAP_FOUND: 85 fcioErrorString = "FCA capability unsettable"; 86 break; 87 case FC_CAP_SETTABLE: 88 fcioErrorString = "FCA capability settable"; 89 break; 90 case FC_UNBOUND: 91 fcioErrorString = "unbound stuff"; 92 break; 93 case FC_NOMEM: 94 fcioErrorString = "allocation error"; 95 break; 96 case FC_BADPACKET: 97 fcioErrorString = "invalid packet specified/supplied"; 98 break; 99 case FC_OFFLINE: 100 fcioErrorString = "I/O resource unavailable"; 101 break; 102 case FC_OLDPORT: 103 fcioErrorString = "operation on non-loop port"; 104 break; 105 case FC_NO_MAP: 106 fcioErrorString = "requested map unavailable"; 107 break; 108 case FC_TRANSPORT_ERROR: 109 fcioErrorString = "unable to transport I/O"; 110 break; 111 case FC_ELS_FREJECT: 112 fcioErrorString = "ELS rejected by a Fabric"; 113 break; 114 case FC_ELS_PREJECT: 115 fcioErrorString = "ELS rejected by an N_port"; 116 break; 117 case FC_ELS_BAD: 118 fcioErrorString = "ELS rejected by FCA/fctl"; 119 break; 120 case FC_ELS_MALFORMED: 121 fcioErrorString = "poorly formed ELS request"; 122 break; 123 case FC_TOOMANY: 124 fcioErrorString = "resource request too large"; 125 break; 126 case FC_UB_BADTOKEN: 127 fcioErrorString = "invalid unsolicited buffer token"; 128 break; 129 case FC_UB_ERROR: 130 fcioErrorString = "invalid unsol buf request"; 131 break; 132 case FC_UB_BUSY: 133 fcioErrorString = "buffer already in use"; 134 break; 135 case FC_BADULP: 136 fcioErrorString = "Unknown ulp"; 137 break; 138 case FC_BADTYPE: 139 fcioErrorString = "ULP not registered to handle this FC4 type"; 140 break; 141 case FC_UNCLAIMED: 142 fcioErrorString = "request or data not claimed"; 143 break; 144 case FC_ULP_SAMEMODULE: 145 fcioErrorString = "module already in use"; 146 break; 147 case FC_ULP_SAMETYPE: 148 fcioErrorString = "FC4 module already in use"; 149 break; 150 case FC_ABORTED: 151 fcioErrorString = "request aborted"; 152 break; 153 case FC_ABORT_FAILED: 154 fcioErrorString = "abort request failed"; 155 break; 156 case FC_BADEXCHANGE: 157 fcioErrorString = "exchange doesn�t exist"; 158 break; 159 case FC_BADWWN: 160 fcioErrorString = "WWN not recognized"; 161 break; 162 case FC_BADDEV: 163 fcioErrorString = "device unrecognized"; 164 break; 165 case FC_BADCMD: 166 fcioErrorString = "invalid command issued"; 167 break; 168 case FC_BADOBJECT: 169 fcioErrorString = "invalid object requested"; 170 break; 171 case FC_BADPORT: 172 fcioErrorString = "invalid port specified"; 173 break; 174 case FC_NOTTHISPORT: 175 fcioErrorString = "resource not at this port"; 176 break; 177 case FC_PREJECT: 178 fcioErrorString = "reject at remote N_Port"; 179 break; 180 case FC_FREJECT: 181 fcioErrorString = "reject at remote Fabric"; 182 break; 183 case FC_PBUSY: 184 fcioErrorString = "remote N_Port busy"; 185 break; 186 case FC_FBUSY: 187 fcioErrorString = "remote Fabric busy"; 188 break; 189 case FC_ALREADY: 190 fcioErrorString = "already logged in"; 191 break; 192 case FC_LOGINREQ: 193 fcioErrorString = "login required"; 194 break; 195 case FC_RESETFAIL: 196 fcioErrorString = "reset failed"; 197 break; 198 case FC_INVALID_REQUEST: 199 fcioErrorString = "request is invalid"; 200 break; 201 case FC_OUTOFBOUNDS: 202 fcioErrorString = "port number is out of bounds"; 203 break; 204 case FC_TRAN_BUSY: 205 fcioErrorString = "command transport busy"; 206 break; 207 case FC_STATEC_BUSY: 208 fcioErrorString = "port driver currently busy"; 209 break; 210 case FC_DEVICE_BUSY: 211 fcioErrorString = "transport working on this device"; 212 break; 213 case FC_DEVICE_NOT_TGT: 214 fcioErrorString = "device is not a SCSI target"; 215 break; 216 default: 217 snprintf(message, MAX_FCTIO_MSG_LEN, "Unknown error code 0x%x", 218 fctio_errno); 219 return; 220 } 221 snprintf(message, MAX_FCTIO_MSG_LEN, "%s", fcioErrorString.c_str()); 222 } 223 224 TgtFCHBAPort::TgtFCHBAPort(string thePath) : HBAPort() { 225 Trace log("TgtFCHBAPort::TgtFCHBAPort"); 226 log.debug("Initializing HBA port %s", path.c_str()); 227 path = thePath; 228 229 // This routine is not index based, so we can discard stateChange 230 uint64_t tmp; 231 HBA_PORTATTRIBUTES attrs = getPortAttributes(tmp); 232 memcpy(&tmp, &attrs.PortWWN, 8); 233 portWWN = ntohll(tmp); 234 memcpy(&tmp, &attrs.NodeWWN, 8); 235 nodeWWN = ntohll(tmp); 236 237 // For reference, here's how to dump WWN's through C++ streams. 238 // cout << "\tPort WWN: " << hex << setfill('0') << setw(16) << portWWN 239 // << endl; 240 // cout << "\tNode WWN: " << hex << setfill('0') << setw(16) << nodeWWN 241 // << endl; 242 } 243 244 HBA_PORTATTRIBUTES TgtFCHBAPort::getPortAttributes(uint64_t &stateChange) { 245 Trace log("TgtFCHBAPort::getPortAttributes"); 246 247 HBA_PORTATTRIBUTES attributes; 248 fctio_t fctio; 249 fc_tgt_hba_port_attributes_t attrs; 250 251 memset(&fctio, 0, sizeof (fctio)); 252 memset(&attributes, 0, sizeof (attributes)); 253 254 uint64_t portwwn = 0; 255 try { 256 string::size_type offset = path.find_last_of("."); 257 if (offset >= 0) { 258 string portwwnString = path.substr(offset+1); 259 portwwn = strtoull(portwwnString.c_str(), NULL, 16); 260 } 261 } catch (...) { 262 throw BadArgumentException(); 263 } 264 265 uint64_t en_wwn = htonll(portwwn); 266 267 fctio.fctio_cmd = FCTIO_GET_ADAPTER_PORT_ATTRIBUTES; 268 fctio.fctio_ilen = 8; 269 fctio.fctio_ibuf = (uint64_t)(uintptr_t)&en_wwn; 270 fctio.fctio_xfer = FCTIO_XFER_READ; 271 fctio.fctio_olen = (uint32_t)(sizeof (attrs)); 272 fctio.fctio_obuf = (uint64_t)(uintptr_t)&attrs; 273 274 fct_ioctl(FCTIO_CMD, &fctio); 275 276 stateChange = attrs.lastChange; 277 278 attributes.PortFcId = attrs.PortFcId; 279 attributes.PortType = attrs.PortType; 280 attributes.PortState = attrs.PortState; 281 attributes.PortSupportedClassofService = attrs.PortSupportedClassofService; 282 attributes.PortSupportedSpeed = attrs.PortSupportedSpeed; 283 attributes.PortSpeed = attrs.PortSpeed; 284 attributes.PortMaxFrameSize = attrs.PortMaxFrameSize; 285 attributes.NumberofDiscoveredPorts = attrs.NumberofDiscoveredPorts; 286 memcpy(&attributes.NodeWWN, &attrs.NodeWWN, 8); 287 memcpy(&attributes.PortWWN, &attrs.PortWWN, 8); 288 memcpy(&attributes.FabricName, &attrs.FabricName, 8); 289 memcpy(&attributes.PortSupportedFc4Types, &attrs.PortSupportedFc4Types, 32); 290 memcpy(&attributes.PortActiveFc4Types, &attrs.PortActiveFc4Types, 32); 291 memcpy(&attributes.PortSymbolicName, &attrs.PortSymbolicName, 256); 292 293 strncpy((char *)attributes.OSDeviceName, "Not Applicable", 15); 294 return (attributes); 295 } 296 297 HBA_PORTATTRIBUTES TgtFCHBAPort::getDiscoveredAttributes( 298 HBA_UINT32 discoveredport, uint64_t &stateChange) { 299 Trace log("TgtFCHBAPort::getDiscoverdAttributes(i)"); 300 301 HBA_PORTATTRIBUTES attributes; 302 fctio_t fctio; 303 fc_tgt_hba_port_attributes_t attrs; 304 305 memset(&fctio, 0, sizeof (fctio)); 306 memset(&attributes, 0, sizeof (attributes)); 307 308 uint64_t portwwn = 0; 309 try { 310 string::size_type offset = path.find_last_of("."); 311 if (offset >= 0) { 312 string portwwnString = path.substr(offset+1); 313 portwwn = strtoull(portwwnString.c_str(), NULL, 16); 314 } 315 } catch (...) { 316 throw BadArgumentException(); 317 } 318 319 uint64_t en_wwn = htonll(portwwn); 320 321 fctio.fctio_cmd = FCTIO_GET_DISCOVERED_PORT_ATTRIBUTES; 322 fctio.fctio_ilen = 8; 323 fctio.fctio_ibuf = (uint64_t)(uintptr_t)&en_wwn; 324 fctio.fctio_xfer = FCTIO_XFER_READ; 325 fctio.fctio_olen = (uint32_t)(sizeof (attrs)); 326 fctio.fctio_obuf = (uint64_t)(uintptr_t)&attrs; 327 fctio.fctio_alen = (uint32_t)(sizeof (discoveredport)); 328 fctio.fctio_abuf = (uint64_t)(uintptr_t)&discoveredport; 329 330 fct_ioctl(FCTIO_CMD, &fctio); 331 332 stateChange = attrs.lastChange; 333 334 attributes.PortFcId = attrs.PortFcId; 335 attributes.PortType = attrs.PortType; 336 attributes.PortState = attrs.PortState; 337 attributes.PortSupportedClassofService = attrs.PortSupportedClassofService; 338 attributes.PortSupportedSpeed = attrs.PortSupportedSpeed; 339 attributes.PortSpeed = attrs.PortSpeed; 340 attributes.PortMaxFrameSize = attrs.PortMaxFrameSize; 341 attributes.NumberofDiscoveredPorts = attrs.NumberofDiscoveredPorts; 342 memcpy(&attributes.NodeWWN, &attrs.NodeWWN, 8); 343 memcpy(&attributes.PortWWN, &attrs.PortWWN, 8); 344 memcpy(&attributes.FabricName, &attrs.FabricName, 8); 345 memcpy(&attributes.PortSupportedFc4Types, &attrs.PortSupportedFc4Types, 32); 346 memcpy(&attributes.PortActiveFc4Types, &attrs.PortActiveFc4Types, 32); 347 memcpy(&attributes.PortSymbolicName, &attrs.PortSymbolicName, 256); 348 349 350 return (attributes); 351 } 352 353 HBA_PORTATTRIBUTES TgtFCHBAPort::getDiscoveredAttributes( 354 uint64_t wwn, uint64_t &stateChange) { 355 Trace log("TgtFCHBAPort::getDiscoverdAttributes(p)"); 356 357 HBA_PORTATTRIBUTES attributes; 358 fctio_t fctio; 359 fc_tgt_hba_port_attributes_t attrs; 360 361 memset(&fctio, 0, sizeof (fctio)); 362 memset(&attributes, 0, sizeof (attributes)); 363 364 uint64_t en_wwn = htonll(wwn); 365 366 fctio.fctio_cmd = FCTIO_GET_PORT_ATTRIBUTES; 367 fctio.fctio_olen = (uint32_t)(sizeof (attrs)); 368 fctio.fctio_xfer = FCTIO_XFER_READ; 369 fctio.fctio_obuf = (uint64_t)(uintptr_t)&attrs; 370 fctio.fctio_ilen = (uint32_t)(sizeof (wwn)); 371 fctio.fctio_ibuf = (uint64_t)(uintptr_t)&en_wwn; 372 373 fct_ioctl(FCTIO_CMD, &fctio); 374 375 stateChange = attrs.lastChange; 376 377 attributes.PortFcId = attrs.PortFcId; 378 attributes.PortType = attrs.PortType; 379 attributes.PortState = attrs.PortState; 380 attributes.PortSupportedClassofService = attrs.PortSupportedClassofService; 381 attributes.PortSupportedSpeed = attrs.PortSupportedSpeed; 382 attributes.PortSpeed = attrs.PortSpeed; 383 attributes.PortMaxFrameSize = attrs.PortMaxFrameSize; 384 attributes.NumberofDiscoveredPorts = attrs.NumberofDiscoveredPorts; 385 memcpy(&attributes.NodeWWN, &attrs.NodeWWN, 8); 386 memcpy(&attributes.PortWWN, &attrs.PortWWN, 8); 387 memcpy(&attributes.FabricName, &attrs.FabricName, 8); 388 memcpy(&attributes.PortSupportedFc4Types, &attrs.PortSupportedFc4Types, 32); 389 memcpy(&attributes.PortActiveFc4Types, &attrs.PortActiveFc4Types, 32); 390 memcpy(&attributes.PortSymbolicName, &attrs.PortSymbolicName, 256); 391 392 393 return (attributes); 394 } 395 396 void TgtFCHBAPort::sendRLS(uint64_t destWWN, 397 void *pRspBuffer, 398 HBA_UINT32 *pRspBufferSize) { 399 Trace log("FCHBAPort::sendRLS"); 400 401 fctio_t fctio; 402 // fc_hba_adapter_port_stats_t fc_port_stat; 403 uint64_t en_portWWN; 404 uint64_t DestPortID; 405 406 // Validate the arguments 407 if (pRspBuffer == NULL || 408 pRspBufferSize == NULL) { 409 log.userError("NULL hba"); 410 throw BadArgumentException(); 411 } 412 413 // check to see if we are sending RLS to the HBA 414 HBA_PORTATTRIBUTES attrs; 415 uint64_t tmp; 416 portWWN = getPortWWN(); 417 en_portWWN = htonll(portWWN); 418 419 /* The destWWN is either the adapter port or a discovered port. */ 420 memset(&fctio, 0, sizeof (fctio)); 421 fctio.fctio_cmd = FCTIO_GET_LINK_STATUS; 422 fctio.fctio_ibuf = (uint64_t)(uintptr_t)&en_portWWN; 423 fctio.fctio_ilen = (uint32_t)(sizeof (en_portWWN)); 424 if (portWWN != destWWN) { 425 attrs = getDiscoveredAttributes(destWWN, tmp); 426 DestPortID = (uint64_t)attrs.PortFcId; 427 fctio.fctio_abuf = (uint64_t)(uintptr_t)&DestPortID; 428 fctio.fctio_alen = (uint32_t)(sizeof (DestPortID)); 429 } 430 fctio.fctio_xfer = FCTIO_XFER_READ; 431 fctio.fctio_flags = 0; 432 fctio.fctio_obuf = (uint64_t)(uintptr_t)new uchar_t[*pRspBufferSize]; 433 fctio.fctio_olen = *pRspBufferSize; 434 435 if (fctio.fctio_obuf == NULL) { 436 log.noMemory(); 437 throw InternalError(); 438 } 439 440 fct_ioctl(FCTIO_CMD, &fctio); 441 memcpy(pRspBuffer, (uchar_t *)(uintptr_t)fctio.fctio_obuf, 442 *pRspBufferSize); 443 if (fctio.fctio_obuf != NULL) { 444 delete((uchar_t *)(uintptr_t)fctio.fctio_obuf); 445 } 446 } 447 448 /** 449 * @memo Validate that the port is still present in the system 450 * @exception UnavailableException if the port is not present 451 * @version 1.7 452 * 453 * @doc If the port is still present on the system, the routine 454 * will return normally. If the port is not present 455 * an exception will be thrown. 456 */ 457 void TgtFCHBAPort::validatePresent() { 458 Trace log("TgtFCHBAPort::validatePresent"); 459 // We already got the adapter list through the ioctl 460 // so calling it again to validate it is too expensive. 461 } 462 463 void TgtFCHBAPort::fct_ioctl(int cmd, fctio_t *fctio) { 464 Trace log("TgtFCHBAPort::fct_ioctl"); 465 char fcioErrorString[MAX_FCTIO_MSG_LEN] = ""; 466 int fd = HBA::_open(FCT_DRIVER_PATH, O_NDELAY | O_RDONLY); 467 try { 468 HBA::_ioctl(fd, cmd, (uchar_t *)fctio); 469 close(fd); 470 if (fctio->fctio_errno) { 471 throw IOError("IOCTL transport failure"); 472 } 473 } catch (...) { 474 close(fd); 475 transportError(fctio->fctio_errno, fcioErrorString); 476 log.genericIOError("ioctl (0x%x) failed. Transport: \"%s\"", cmd, 477 fcioErrorString); 478 switch (fctio->fctio_errno) { 479 case FC_BADWWN: 480 throw IllegalWWNException(); 481 case FC_BADPORT: 482 throw IllegalWWNException(); 483 case FC_OUTOFBOUNDS: 484 throw IllegalIndexException(); 485 case FC_PBUSY: 486 case FC_FBUSY: 487 case FC_TRAN_BUSY: 488 case FC_STATEC_BUSY: 489 case FC_DEVICE_BUSY: 490 throw BusyException(); 491 case FC_SUCCESS: 492 default: 493 throw; 494 } 495 } 496 } 497