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