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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 #include <TgtFCHBAPort.h>
29 #include <Exceptions.h>
34 #include <sys/types.h>
35 #include <sys/mkdev.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>
56 const int TgtFCHBAPort::MAX_FCTIO_MSG_LEN
= 256;
57 const string
TgtFCHBAPort::FCT_DRIVER_PATH
= "/devices/pseudo/fct@0:admin";
60 * Interpret the error code in the fctio_t structure
62 * message must be at least MAX_FCTIO_MSG_LEN in length.
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");
72 switch (fctio_errno
) {
73 case (uint32_t)FC_FAILURE
:
74 fcioErrorString
= "general failure";
76 case (uint32_t)FC_FAILURE_SILENT
:
77 fcioErrorString
= "general failure but fail silently";
80 fcioErrorString
= "successful completion";
83 fcioErrorString
= "FCA capability error";
86 fcioErrorString
= "FCA capability unsettable";
89 fcioErrorString
= "FCA capability settable";
92 fcioErrorString
= "unbound stuff";
95 fcioErrorString
= "allocation error";
98 fcioErrorString
= "invalid packet specified/supplied";
101 fcioErrorString
= "I/O resource unavailable";
104 fcioErrorString
= "operation on non-loop port";
107 fcioErrorString
= "requested map unavailable";
109 case FC_TRANSPORT_ERROR
:
110 fcioErrorString
= "unable to transport I/O";
113 fcioErrorString
= "ELS rejected by a Fabric";
116 fcioErrorString
= "ELS rejected by an N_port";
119 fcioErrorString
= "ELS rejected by FCA/fctl";
121 case FC_ELS_MALFORMED
:
122 fcioErrorString
= "poorly formed ELS request";
125 fcioErrorString
= "resource request too large";
128 fcioErrorString
= "invalid unsolicited buffer token";
131 fcioErrorString
= "invalid unsol buf request";
134 fcioErrorString
= "buffer already in use";
137 fcioErrorString
= "Unknown ulp";
140 fcioErrorString
= "ULP not registered to handle this FC4 type";
143 fcioErrorString
= "request or data not claimed";
145 case FC_ULP_SAMEMODULE
:
146 fcioErrorString
= "module already in use";
148 case FC_ULP_SAMETYPE
:
149 fcioErrorString
= "FC4 module already in use";
152 fcioErrorString
= "request aborted";
154 case FC_ABORT_FAILED
:
155 fcioErrorString
= "abort request failed";
158 fcioErrorString
= "exchange doesnÕt exist";
161 fcioErrorString
= "WWN not recognized";
164 fcioErrorString
= "device unrecognized";
167 fcioErrorString
= "invalid command issued";
170 fcioErrorString
= "invalid object requested";
173 fcioErrorString
= "invalid port specified";
176 fcioErrorString
= "resource not at this port";
179 fcioErrorString
= "reject at remote N_Port";
182 fcioErrorString
= "reject at remote Fabric";
185 fcioErrorString
= "remote N_Port busy";
188 fcioErrorString
= "remote Fabric busy";
191 fcioErrorString
= "already logged in";
194 fcioErrorString
= "login required";
197 fcioErrorString
= "reset failed";
199 case FC_INVALID_REQUEST
:
200 fcioErrorString
= "request is invalid";
203 fcioErrorString
= "port number is out of bounds";
206 fcioErrorString
= "command transport busy";
209 fcioErrorString
= "port driver currently busy";
212 fcioErrorString
= "transport working on this device";
214 case FC_DEVICE_NOT_TGT
:
215 fcioErrorString
= "device is not a SCSI target";
218 snprintf(message
, MAX_FCTIO_MSG_LEN
, "Unknown error code 0x%x",
222 snprintf(message
, MAX_FCTIO_MSG_LEN
, "%s", fcioErrorString
.c_str());
225 TgtFCHBAPort::TgtFCHBAPort(string thePath
) : HBAPort() {
226 Trace
log("TgtFCHBAPort::TgtFCHBAPort");
227 log
.debug("Initializing HBA port %s", path
.c_str());
230 // This routine is not index based, so we can discard stateChange
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
);
238 // For reference, here's how to dump WWN's through C++ streams.
239 // cout << "\tPort WWN: " << hex << setfill('0') << setw(16) << portWWN
241 // cout << "\tNode WWN: " << hex << setfill('0') << setw(16) << nodeWWN
245 HBA_PORTATTRIBUTES
TgtFCHBAPort::getPortAttributes(uint64_t &stateChange
) {
246 Trace
log("TgtFCHBAPort::getPortAttributes");
248 HBA_PORTATTRIBUTES attributes
;
250 fc_tgt_hba_port_attributes_t attrs
;
252 memset(&fctio
, 0, sizeof (fctio
));
253 memset(&attributes
, 0, sizeof (attributes
));
255 uint64_t portwwn
= 0;
257 string::size_type offset
= path
.find_last_of(".");
259 string portwwnString
= path
.substr(offset
+1);
260 portwwn
= strtoull(portwwnString
.c_str(), NULL
, 16);
263 throw BadArgumentException();
266 uint64_t en_wwn
= htonll(portwwn
);
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
;
275 fct_ioctl(FCTIO_CMD
, &fctio
);
277 stateChange
= attrs
.lastChange
;
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);
294 strncpy((char *)attributes
.OSDeviceName
, "Not Applicable", 15);
298 HBA_PORTATTRIBUTES
TgtFCHBAPort::getDiscoveredAttributes(
299 HBA_UINT32 discoveredport
, uint64_t &stateChange
) {
300 Trace
log("TgtFCHBAPort::getDiscoverdAttributes(i)");
302 HBA_PORTATTRIBUTES attributes
;
304 fc_tgt_hba_port_attributes_t attrs
;
306 memset(&fctio
, 0, sizeof (fctio
));
307 memset(&attributes
, 0, sizeof (attributes
));
309 uint64_t portwwn
= 0;
311 string::size_type offset
= path
.find_last_of(".");
313 string portwwnString
= path
.substr(offset
+1);
314 portwwn
= strtoull(portwwnString
.c_str(), NULL
, 16);
317 throw BadArgumentException();
320 uint64_t en_wwn
= htonll(portwwn
);
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
;
331 fct_ioctl(FCTIO_CMD
, &fctio
);
333 stateChange
= attrs
.lastChange
;
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);
354 HBA_PORTATTRIBUTES
TgtFCHBAPort::getDiscoveredAttributes(
355 uint64_t wwn
, uint64_t &stateChange
) {
356 Trace
log("TgtFCHBAPort::getDiscoverdAttributes(p)");
358 HBA_PORTATTRIBUTES attributes
;
360 fc_tgt_hba_port_attributes_t attrs
;
362 memset(&fctio
, 0, sizeof (fctio
));
363 memset(&attributes
, 0, sizeof (attributes
));
365 uint64_t en_wwn
= htonll(wwn
);
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
;
374 fct_ioctl(FCTIO_CMD
, &fctio
);
376 stateChange
= attrs
.lastChange
;
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);
397 void TgtFCHBAPort::sendRLS(uint64_t destWWN
,
399 HBA_UINT32
*pRspBufferSize
) {
400 Trace
log("FCHBAPort::sendRLS");
403 // fc_hba_adapter_port_stats_t fc_port_stat;
407 // Validate the arguments
408 if (pRspBuffer
== NULL
||
409 pRspBufferSize
== NULL
) {
410 log
.userError("NULL hba");
411 throw BadArgumentException();
414 // check to see if we are sending RLS to the HBA
415 HBA_PORTATTRIBUTES attrs
;
417 portWWN
= getPortWWN();
418 en_portWWN
= htonll(portWWN
);
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
));
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
;
436 if (fctio
.fctio_obuf
== 0) {
438 throw InternalError();
441 fct_ioctl(FCTIO_CMD
, &fctio
);
442 memcpy(pRspBuffer
, (uchar_t
*)(uintptr_t)fctio
.fctio_obuf
,
444 if (fctio
.fctio_obuf
!= 0) {
445 delete((uchar_t
*)(uintptr_t)fctio
.fctio_obuf
);
450 * @memo Validate that the port is still present in the system
451 * @exception UnavailableException if the port is not present
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.
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.
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
);
469 HBA::_ioctl(fd
, cmd
, (uchar_t
*)fctio
);
471 if (fctio
->fctio_errno
) {
472 throw IOError("IOCTL transport failure");
476 transportError(fctio
->fctio_errno
, fcioErrorString
);
477 log
.genericIOError("ioctl (0x%x) failed. Transport: \"%s\"", cmd
,
479 switch (fctio
->fctio_errno
) {
481 throw IllegalWWNException();
483 throw IllegalWWNException();
485 throw IllegalIndexException();
491 throw BusyException();