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
=
283 attrs
.PortSupportedClassofService
;
284 attributes
.PortSupportedSpeed
= attrs
.PortSupportedSpeed
;
285 attributes
.PortSpeed
= attrs
.PortSpeed
;
286 attributes
.PortMaxFrameSize
= attrs
.PortMaxFrameSize
;
287 attributes
.NumberofDiscoveredPorts
= attrs
.NumberofDiscoveredPorts
;
288 memcpy(&attributes
.NodeWWN
, &attrs
.NodeWWN
, 8);
289 memcpy(&attributes
.PortWWN
, &attrs
.PortWWN
, 8);
290 memcpy(&attributes
.FabricName
, &attrs
.FabricName
, 8);
291 memcpy(&attributes
.PortSupportedFc4Types
,
292 &attrs
.PortSupportedFc4Types
, 32);
293 memcpy(&attributes
.PortActiveFc4Types
, &attrs
.PortActiveFc4Types
, 32);
294 memcpy(&attributes
.PortSymbolicName
, &attrs
.PortSymbolicName
, 256);
296 strncpy((char *)attributes
.OSDeviceName
, "Not Applicable", 15);
300 HBA_PORTATTRIBUTES
TgtFCHBAPort::getDiscoveredAttributes(
301 HBA_UINT32 discoveredport
, uint64_t &stateChange
) {
302 Trace
log("TgtFCHBAPort::getDiscoverdAttributes(i)");
304 HBA_PORTATTRIBUTES attributes
;
306 fc_tgt_hba_port_attributes_t attrs
;
308 memset(&fctio
, 0, sizeof (fctio
));
309 memset(&attributes
, 0, sizeof (attributes
));
311 uint64_t portwwn
= 0;
313 string::size_type offset
= path
.find_last_of(".");
315 string portwwnString
= path
.substr(offset
+1);
316 portwwn
= strtoull(portwwnString
.c_str(), NULL
, 16);
319 throw BadArgumentException();
322 uint64_t en_wwn
= htonll(portwwn
);
324 fctio
.fctio_cmd
= FCTIO_GET_DISCOVERED_PORT_ATTRIBUTES
;
325 fctio
.fctio_ilen
= 8;
326 fctio
.fctio_ibuf
= (uint64_t)(uintptr_t)&en_wwn
;
327 fctio
.fctio_xfer
= FCTIO_XFER_READ
;
328 fctio
.fctio_olen
= (uint32_t)(sizeof (attrs
));
329 fctio
.fctio_obuf
= (uint64_t)(uintptr_t)&attrs
;
330 fctio
.fctio_alen
= (uint32_t)(sizeof (discoveredport
));
331 fctio
.fctio_abuf
= (uint64_t)(uintptr_t)&discoveredport
;
333 fct_ioctl(FCTIO_CMD
, &fctio
);
335 stateChange
= attrs
.lastChange
;
337 attributes
.PortFcId
= attrs
.PortFcId
;
338 attributes
.PortType
= attrs
.PortType
;
339 attributes
.PortState
= attrs
.PortState
;
340 attributes
.PortSupportedClassofService
=
341 attrs
.PortSupportedClassofService
;
342 attributes
.PortSupportedSpeed
= attrs
.PortSupportedSpeed
;
343 attributes
.PortSpeed
= attrs
.PortSpeed
;
344 attributes
.PortMaxFrameSize
= attrs
.PortMaxFrameSize
;
345 attributes
.NumberofDiscoveredPorts
= attrs
.NumberofDiscoveredPorts
;
346 memcpy(&attributes
.NodeWWN
, &attrs
.NodeWWN
, 8);
347 memcpy(&attributes
.PortWWN
, &attrs
.PortWWN
, 8);
348 memcpy(&attributes
.FabricName
, &attrs
.FabricName
, 8);
349 memcpy(&attributes
.PortSupportedFc4Types
,
350 &attrs
.PortSupportedFc4Types
, 32);
351 memcpy(&attributes
.PortActiveFc4Types
, &attrs
.PortActiveFc4Types
, 32);
352 memcpy(&attributes
.PortSymbolicName
, &attrs
.PortSymbolicName
, 256);
358 HBA_PORTATTRIBUTES
TgtFCHBAPort::getDiscoveredAttributes(
359 uint64_t wwn
, uint64_t &stateChange
) {
360 Trace
log("TgtFCHBAPort::getDiscoverdAttributes(p)");
362 HBA_PORTATTRIBUTES attributes
;
364 fc_tgt_hba_port_attributes_t attrs
;
366 memset(&fctio
, 0, sizeof (fctio
));
367 memset(&attributes
, 0, sizeof (attributes
));
369 uint64_t en_wwn
= htonll(wwn
);
371 fctio
.fctio_cmd
= FCTIO_GET_PORT_ATTRIBUTES
;
372 fctio
.fctio_olen
= (uint32_t)(sizeof (attrs
));
373 fctio
.fctio_xfer
= FCTIO_XFER_READ
;
374 fctio
.fctio_obuf
= (uint64_t)(uintptr_t)&attrs
;
375 fctio
.fctio_ilen
= (uint32_t)(sizeof (wwn
));
376 fctio
.fctio_ibuf
= (uint64_t)(uintptr_t)&en_wwn
;
378 fct_ioctl(FCTIO_CMD
, &fctio
);
380 stateChange
= attrs
.lastChange
;
382 attributes
.PortFcId
= attrs
.PortFcId
;
383 attributes
.PortType
= attrs
.PortType
;
384 attributes
.PortState
= attrs
.PortState
;
385 attributes
.PortSupportedClassofService
=
386 attrs
.PortSupportedClassofService
;
387 attributes
.PortSupportedSpeed
= attrs
.PortSupportedSpeed
;
388 attributes
.PortSpeed
= attrs
.PortSpeed
;
389 attributes
.PortMaxFrameSize
= attrs
.PortMaxFrameSize
;
390 attributes
.NumberofDiscoveredPorts
= attrs
.NumberofDiscoveredPorts
;
391 memcpy(&attributes
.NodeWWN
, &attrs
.NodeWWN
, 8);
392 memcpy(&attributes
.PortWWN
, &attrs
.PortWWN
, 8);
393 memcpy(&attributes
.FabricName
, &attrs
.FabricName
, 8);
394 memcpy(&attributes
.PortSupportedFc4Types
,
395 &attrs
.PortSupportedFc4Types
, 32);
396 memcpy(&attributes
.PortActiveFc4Types
, &attrs
.PortActiveFc4Types
, 32);
397 memcpy(&attributes
.PortSymbolicName
, &attrs
.PortSymbolicName
, 256);
403 void TgtFCHBAPort::sendRLS(uint64_t destWWN
,
405 HBA_UINT32
*pRspBufferSize
) {
406 Trace
log("FCHBAPort::sendRLS");
409 // fc_hba_adapter_port_stats_t fc_port_stat;
413 // Validate the arguments
414 if (pRspBuffer
== NULL
||
415 pRspBufferSize
== NULL
) {
416 log
.userError("NULL hba");
417 throw BadArgumentException();
420 // check to see if we are sending RLS to the HBA
421 HBA_PORTATTRIBUTES attrs
;
423 portWWN
= getPortWWN();
424 en_portWWN
= htonll(portWWN
);
426 /* The destWWN is either the adapter port or a discovered port. */
427 memset(&fctio
, 0, sizeof (fctio
));
428 fctio
.fctio_cmd
= FCTIO_GET_LINK_STATUS
;
429 fctio
.fctio_ibuf
= (uint64_t)(uintptr_t)&en_portWWN
;
430 fctio
.fctio_ilen
= (uint32_t)(sizeof (en_portWWN
));
431 if (portWWN
!= destWWN
) {
432 attrs
= getDiscoveredAttributes(destWWN
, tmp
);
433 DestPortID
= (uint64_t)attrs
.PortFcId
;
434 fctio
.fctio_abuf
= (uint64_t)(uintptr_t)&DestPortID
;
435 fctio
.fctio_alen
= (uint32_t)(sizeof (DestPortID
));
437 fctio
.fctio_xfer
= FCTIO_XFER_READ
;
438 fctio
.fctio_flags
= 0;
439 fctio
.fctio_obuf
= (uint64_t)(uintptr_t)new uchar_t
[*pRspBufferSize
];
440 fctio
.fctio_olen
= *pRspBufferSize
;
442 if (fctio
.fctio_obuf
== (uintptr_t)NULL
) {
444 throw InternalError();
447 fct_ioctl(FCTIO_CMD
, &fctio
);
448 memcpy(pRspBuffer
, (uchar_t
*)(uintptr_t)fctio
.fctio_obuf
,
450 if (fctio
.fctio_obuf
!= (uintptr_t)NULL
) {
451 delete((uchar_t
*)(uintptr_t)fctio
.fctio_obuf
);
456 * @memo Validate that the port is still present in the system
457 * @exception UnavailableException if the port is not present
460 * @doc If the port is still present on the system, the routine
461 * will return normally. If the port is not present
462 * an exception will be thrown.
464 void TgtFCHBAPort::validatePresent() {
465 Trace
log("TgtFCHBAPort::validatePresent");
466 // We already got the adapter list through the ioctl
467 // so calling it again to validate it is too expensive.
470 void TgtFCHBAPort::fct_ioctl(int cmd
, fctio_t
*fctio
) {
471 Trace
log("TgtFCHBAPort::fct_ioctl");
472 char fcioErrorString
[MAX_FCTIO_MSG_LEN
] = "";
473 int fd
= HBA::_open(FCT_DRIVER_PATH
, O_NDELAY
| O_RDONLY
);
475 HBA::_ioctl(fd
, cmd
, (uchar_t
*)fctio
);
477 if (fctio
->fctio_errno
) {
478 throw IOError("IOCTL transport failure");
482 transportError(fctio
->fctio_errno
, fcioErrorString
);
483 log
.genericIOError("ioctl (0x%x) failed. Transport: \"%s\"", cmd
,
485 switch (fctio
->fctio_errno
) {
487 throw IllegalWWNException();
489 throw IllegalWWNException();
491 throw IllegalIndexException();
497 throw BusyException();