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 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 #include <FCHBAPort.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/fibre-channel/fcio.h>
43 #include <sys/fibre-channel/ulp/fcp_util.h>
44 #include <sys/fibre-channel/ulp/fcsm.h>
45 #include <sys/fibre-channel/impl/fc_error.h>
46 #include <sys/fibre-channel/fc_appif.h>
47 #include <sys/scsi/generic/commands.h>
48 #include <sys/scsi/impl/commands.h>
49 #include <sys/scsi/impl/sense.h>
50 #include <sys/scsi/generic/inquiry.h>
51 #include <sys/scsi/generic/status.h>
53 #include <FCHBANPIVPort.h>
58 const int FCHBAPort::MAX_FCIO_MSG_LEN
= 256;
59 const string
FCHBAPort::FCSM_DRIVER_PATH
= "/devices/pseudo/fcsm@0:fcsm";
60 const string
FCHBAPort::FCP_DRIVER_PATH
= "/devices/pseudo/fcp@0:fcp";
63 * Interpret the error code in the fcio_t structure
65 * message must be at least MAX_FCIO_MSG_LEN in length.
68 FCHBAPort::transportError(uint32_t fcio_errno
, char *message
) {
69 Trace
log("transportError");
70 string fcioErrorString
;
71 if (message
== NULL
) {
72 log
.internalError("NULL routine argument");
76 case (uint32_t)FC_FAILURE
:
77 fcioErrorString
= "general failure";
79 case (uint32_t)FC_FAILURE_SILENT
:
80 fcioErrorString
= "general failure but fail silently";
83 fcioErrorString
= "successful completion";
86 fcioErrorString
= "FCA capability error";
89 fcioErrorString
= "FCA capability unsettable";
92 fcioErrorString
= "FCA capability settable";
95 fcioErrorString
= "unbound stuff";
98 fcioErrorString
= "allocation error";
101 fcioErrorString
= "invalid packet specified/supplied";
104 fcioErrorString
= "I/O resource unavailable";
107 fcioErrorString
= "operation on non-loop port";
110 fcioErrorString
= "requested map unavailable";
112 case FC_TRANSPORT_ERROR
:
113 fcioErrorString
= "unable to transport I/O";
116 fcioErrorString
= "ELS rejected by a Fabric";
119 fcioErrorString
= "ELS rejected by an N_port";
122 fcioErrorString
= "ELS rejected by FCA/fctl";
124 case FC_ELS_MALFORMED
:
125 fcioErrorString
= "poorly formed ELS request";
128 fcioErrorString
= "resource request too large";
131 fcioErrorString
= "invalid unsolicited buffer token";
134 fcioErrorString
= "invalid unsol buf request";
137 fcioErrorString
= "buffer already in use";
140 fcioErrorString
= "Unknown ulp";
143 fcioErrorString
= "ULP not registered to handle this FC4 type";
146 fcioErrorString
= "request or data not claimed";
148 case FC_ULP_SAMEMODULE
:
149 fcioErrorString
= "module already in use";
151 case FC_ULP_SAMETYPE
:
152 fcioErrorString
= "FC4 module already in use";
155 fcioErrorString
= "request aborted";
157 case FC_ABORT_FAILED
:
158 fcioErrorString
= "abort request failed";
161 fcioErrorString
= "exchange doesnÕt exist";
164 fcioErrorString
= "WWN not recognized";
167 fcioErrorString
= "device unrecognized";
170 fcioErrorString
= "invalid command issued";
173 fcioErrorString
= "invalid object requested";
176 fcioErrorString
= "invalid port specified";
179 fcioErrorString
= "resource not at this port";
182 fcioErrorString
= "reject at remote N_Port";
185 fcioErrorString
= "reject at remote Fabric";
188 fcioErrorString
= "remote N_Port busy";
191 fcioErrorString
= "remote Fabric busy";
194 fcioErrorString
= "already logged in";
197 fcioErrorString
= "login required";
200 fcioErrorString
= "reset failed";
202 case FC_INVALID_REQUEST
:
203 fcioErrorString
= "request is invalid";
206 fcioErrorString
= "port number is out of bounds";
209 fcioErrorString
= "command transport busy";
212 fcioErrorString
= "port driver currently busy";
215 fcioErrorString
= "transport working on this device";
217 case FC_DEVICE_NOT_TGT
:
218 fcioErrorString
= "device is not a SCSI target";
221 snprintf(message
, MAX_FCIO_MSG_LEN
, "Unknown error code 0x%x",
225 snprintf(message
, MAX_FCIO_MSG_LEN
, "%s", fcioErrorString
.c_str());
229 reportSense(struct scsi_extended_sense
*sense
, const char *routine
) {
230 Trace
log("reportSense");
233 log
.internalError("NULL sense argument passed.");
237 log
.internalError("NULL routine argument passed.");
240 log
.genericIOError("SCSI FAILURE");
241 switch (sense
->es_key
) {
245 case KEY_RECOVERABLE_ERROR
:
246 msg
= "Recoverable error";
251 case KEY_MEDIUM_ERROR
:
252 msg
= "Medium error";
254 case KEY_HARDWARE_ERROR
:
255 msg
= "Hardware error";
257 case KEY_ILLEGAL_REQUEST
:
258 msg
= "Illegal request";
260 case KEY_UNIT_ATTENTION
:
261 msg
= "Unit attention";
263 case KEY_DATA_PROTECT
:
264 msg
= "Data protect";
266 case KEY_BLANK_CHECK
:
269 case KEY_VENDOR_UNIQUE
:
270 msg
= "Vendor Unique";
272 case KEY_COPY_ABORTED
:
273 msg
= "Copy aborted";
275 case KEY_ABORTED_COMMAND
:
276 msg
= "Aborted command";
281 case KEY_VOLUME_OVERFLOW
:
282 msg
= "Volume overflow";
291 msg
= "unknown sense key";
293 log
.genericIOError("\tSense key: %s", msg
.c_str());
294 log
.genericIOError("\tASC = 0x%x", sense
->es_add_code
);
295 log
.genericIOError("\tASCQ = 0x%x", sense
->es_qual_code
);
299 * Issue a SCSI pass thru command.
300 * Returns a scsi status value.
302 void FCHBAPort::sendSCSIPassThru(struct fcp_scsi_cmd
*fscsi
,
303 HBA_UINT32
*responseSize
, HBA_UINT32
*senseSize
,
304 HBA_UINT8
*scsiStatus
) {
305 Trace
log("FCHBAPort::sendSCSIPassThru");
309 char fcioErrorString
[MAX_FCIO_MSG_LEN
] = "";
317 responseSize
== NULL
||
319 scsiStatus
== NULL
) {
320 throw BadArgumentException();
323 memcpy(&wwn
, fscsi
->scsi_fc_pwwn
.raw_wwn
, sizeof (la_wwn_t
));
325 fscsi
->scsi_fc_port_num
= instanceNumber
;
327 fd
= HBA::_open(FCP_DRIVER_PATH
, O_RDONLY
| O_NDELAY
);
331 if (ioctl(fd
, FCP_TGT_SEND_SCSI
, fscsi
) != 0) {
336 * collect SCSI status first regrardless of the value.
337 * 0 is a good status so this should be okay
339 *scsiStatus
= fscsi
->scsi_bufstatus
& STATUS_MASK
;
340 transportError(fscsi
->scsi_fc_status
, fcioErrorString
);
342 /* Did we get a check condition? */
343 if ((fscsi
->scsi_bufstatus
& STATUS_MASK
) == STATUS_CHECK
) {
344 *senseSize
= fscsi
->scsi_rqlen
;
345 throw CheckConditionException();
346 } else if (fscsi
->scsi_fc_status
== FC_DEVICE_NOT_TGT
) {
348 * fcp driver returns FC_DEVICE_NOT_TGT when the node is not
349 * scsi-capable like remote hba nodes.
351 throw NotATargetException();
352 } else if (fscsi
->scsi_fc_status
== FC_INVALID_LUN
) {
353 throw InvalidLUNException();
354 } else if (ioctl_errno
== EBUSY
) {
355 throw BusyException();
356 } else if (ioctl_errno
== EAGAIN
) {
357 throw TryAgainException();
358 } else if (ioctl_errno
== ENOTSUP
) {
359 throw NotSupportedException();
360 } else if (ioctl_errno
== ENOENT
) {
361 throw UnavailableException();
363 throw IOError(this, wwnConversion(wwn
.raw_wwn
),
368 /* Just in case, check for a check-condition state */
369 if ((fscsi
->scsi_bufstatus
& STATUS_MASK
) == STATUS_CHECK
) {
370 *scsiStatus
= fscsi
->scsi_bufstatus
& STATUS_MASK
;
371 *senseSize
= fscsi
->scsi_rqlen
;
372 throw CheckConditionException();
376 /* Record the response data */
377 *scsiStatus
= fscsi
->scsi_bufstatus
& STATUS_MASK
;
378 *responseSize
= fscsi
->scsi_buflen
;
379 *senseSize
= fscsi
->scsi_rqlen
;
381 /* Do some quick duration calcuations */
383 duration
= end
- start
;
384 duration
/= HR_SECOND
;
385 log
.debug("Total SCSI IO time for HBA %s "
386 "target %016llx was %.4f seconds", getPath().c_str(),
387 wwnConversion(wwn
.raw_wwn
), duration
);
390 /* Did we have any failure */
391 if (ret
!= HBA_STATUS_OK
) {
393 "Ioctl failed for device \"%s\" target %016llx."
394 " Errno: \"%s\"(%d), "
395 "Transport: \"%s\", SCSI Status: 0x%x"
396 "responseSize = %d, senseSize = %d",
397 getPath().c_str(), wwnConversion(fscsi
->scsi_fc_pwwn
.raw_wwn
),
398 strerror(ioctl_errno
), ioctl_errno
, fcioErrorString
,
399 *scsiStatus
, *responseSize
, *senseSize
);
400 /* We may or may not have sense data */
401 reportSense((struct scsi_extended_sense
*)fscsi
->scsi_rqbufaddr
,
409 * constructs the fcp_scsi_cmd struct for SCSI_Inquiry, SendReadCapacity, or
413 #include <fcp_util.h>*/
415 scsi_cmd_init(struct fcp_scsi_cmd
*fscsi
, const char *portname
, void *reqbuf
,
416 size_t req_len
, void *responseBuffer
, size_t resp_len
,
417 void *senseBuffer
, size_t sense_len
) {
418 Trace
log("scsi_cmd_init");
419 fscsi
->scsi_fc_rspcode
= 0;
420 fscsi
->scsi_flags
= FCP_SCSI_READ
;
421 fscsi
->scsi_timeout
= 10 /* sec */;
422 fscsi
->scsi_cdbbufaddr
= (char *)reqbuf
;
423 fscsi
->scsi_cdblen
= (uint32_t) req_len
;
424 fscsi
->scsi_bufaddr
= (char *)responseBuffer
;
425 fscsi
->scsi_buflen
= (uint32_t) resp_len
;
426 fscsi
->scsi_bufresid
= 0;
427 fscsi
->scsi_bufstatus
= 0;
428 fscsi
->scsi_rqbufaddr
= (char *)senseBuffer
;
429 fscsi
->scsi_rqlen
= (uint32_t) sense_len
;
430 fscsi
->scsi_rqresid
= 0;
434 FCHBAPort::FCHBAPort(string thePath
) : HBAPort() {
435 Trace
log("FCHBAPort::FCHBAPort");
436 log
.debug("Initializing HBA port %s", thePath
.c_str());
439 fc_hba_npiv_port_list_t
*pathList
;
444 path
= lookupControllerPath(thePath
);
445 sscanf(path
.c_str(), "/dev/cfg/c%d", &controllerNumber
);
447 log
.debug("Unable to lookup controller path and number for %s",
452 controllerNumber
= -1;
455 // Fetch the minor number for later use
457 if (stat(path
.c_str(), &sbuf
) == -1) {
458 throw IOError("Unable to stat device path: " + path
);
460 instanceNumber
= minor(sbuf
.st_rdev
);
462 // This routine is not index based, so we can discard stateChange
464 HBA_PORTATTRIBUTES attrs
= getPortAttributes(tmp
);
465 memcpy(&tmp
, &attrs
.PortWWN
, 8);
466 portWWN
= ntohll(tmp
);
467 memcpy(&tmp
, &attrs
.NodeWWN
, 8);
468 nodeWWN
= ntohll(tmp
);
470 // For reference, here's how to dump WWN's through C++ streams.
471 // cout << "\tPort WWN: " << hex << setfill('0') << setw(16) << portWWN
473 // cout << "\tNode WWN: " << hex << setfill('0') << setw(16) << nodeWWN
476 // we should add code here to build NPIVPORT instance
477 // Get Port's NPIV port list ( include nwwn and pwwn and path)
478 memset((caddr_t
)&fcio
, 0, sizeof (fcio
));
479 fcio
.fcio_cmd
= FCIO_GET_NPIV_PORT_LIST
;
480 fcio
.fcio_xfer
= FCIO_XFER_READ
;
483 bufSize
= MAXPATHLEN
* (size
- 1) + (int) sizeof (fc_hba_npiv_port_list_t
);
484 pathList
= (fc_hba_npiv_port_list_t
*) new uchar_t
[bufSize
];
485 pathList
->numAdapters
= size
;
486 fcio
.fcio_olen
= bufSize
;
487 fcio
.fcio_obuf
= (char *)pathList
;
488 fp_ioctl(getPath(), FCIO_CMD
, &fcio
);
489 if (pathList
->numAdapters
> size
) {
490 log
.debug("Buffer too small for number of NPIV Port.Retry.");
491 size
= pathList
->numAdapters
;
496 log
.debug("Get %d npiv ports", pathList
->numAdapters
);
497 // Make instance for each NPIV Port
498 for ( int i
= 0; i
< pathList
->numAdapters
; i
++) {
500 addPort(new FCHBANPIVPort(pathList
->hbaPaths
[i
]));
502 log
.debug("Ignoring partial failure");
508 uint32_t FCHBAPort::deleteNPIVPort(uint64_t vportwwn
) {
509 Trace
log("FCHBAPort::deleteNPIVPort");
514 memset(&fcio
, 0, sizeof(fcio
));
515 uint64_t en_wwn
= htonll(vportwwn
);
516 memcpy(&lawwn
[0], &en_wwn
, sizeof (en_wwn
));
518 fcio
.fcio_cmd
= FCIO_DELETE_NPIV_PORT
;
519 fcio
.fcio_xfer
= FCIO_XFER_WRITE
;
520 fcio
.fcio_ilen
= sizeof (la_wwn_t
) * 2;
521 fcio
.fcio_ibuf
= (caddr_t
)&lawwn
;
523 fp_ioctl(getPath(), FCIO_CMD
, &fcio
);
528 uint32_t FCHBAPort::createNPIVPort(uint64_t vnodewwn
, uint64_t vportwwn
, uint32_t vindex
) {
529 Trace
log("FCHBAPort::createNPIVPort");
532 uint32_t vportindex
= 0;
533 HBA_NPIVCREATEENTRY entrybuf
;
535 memset(&fcio
, 0, sizeof(fcio
));
536 uint64_t en_wwn
= htonll(vnodewwn
);
537 memcpy(&entrybuf
.VNodeWWN
, &en_wwn
, sizeof (en_wwn
));
538 en_wwn
= htonll(vportwwn
);
539 memcpy(&entrybuf
.VPortWWN
, &en_wwn
, sizeof (en_wwn
));
540 entrybuf
.vindex
= vindex
;
542 fcio
.fcio_cmd
= FCIO_CREATE_NPIV_PORT
;
543 fcio
.fcio_xfer
= FCIO_XFER_READ
;
544 fcio
.fcio_olen
= sizeof (uint32_t);
545 fcio
.fcio_obuf
= (caddr_t
)&vportindex
;
546 fcio
.fcio_ilen
= sizeof (HBA_NPIVCREATEENTRY
);
547 fcio
.fcio_ibuf
= (caddr_t
)&entrybuf
;
549 fp_ioctl(getPath(), FCIO_CMD
, &fcio
);
554 HBA_PORTNPIVATTRIBUTES
FCHBAPort::getPortNPIVAttributes(uint64_t &stateChange
) {
555 Trace
log("FCHBAPort::getPortNPIVAttributes");
557 HBA_PORTNPIVATTRIBUTES attributes
;
558 fc_hba_port_npiv_attributes_t attrs
;
561 memset(&fcio
, 0, sizeof(fcio
));
562 memset(&attributes
, 0, sizeof(attributes
));
564 fcio
.fcio_cmd
= FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES
;
565 fcio
.fcio_olen
= sizeof(attrs
);
566 fcio
.fcio_xfer
= FCIO_XFER_READ
;
567 fcio
.fcio_obuf
= (caddr_t
)&attrs
;
569 fp_ioctl(getPath(), FCIO_CMD
, &fcio
);
571 stateChange
= attrs
.lastChange
;
572 attributes
.npivflag
= attrs
.npivflag
;
573 memcpy(&attributes
.NodeWWN
, &attrs
.NodeWWN
, 8);
574 memcpy(&attributes
.PortWWN
, &attrs
.PortWWN
, 8);
575 attributes
.MaxNumberOfNPIVPorts
= attrs
.MaxNumberOfNPIVPorts
;
576 attributes
.NumberOfNPIVPorts
= attrs
.NumberOfNPIVPorts
;
581 HBA_PORTATTRIBUTES
FCHBAPort::getPortAttributes(uint64_t &stateChange
) {
582 Trace
log("FCHBAPort::getPortAttributes");
584 HBA_PORTATTRIBUTES attributes
;
586 fc_hba_port_attributes_t attrs
;
588 memset(&fcio
, 0, sizeof (fcio
));
589 memset(&attributes
, 0, sizeof (attributes
));
591 fcio
.fcio_cmd
= FCIO_GET_ADAPTER_PORT_ATTRIBUTES
;
592 fcio
.fcio_olen
= sizeof (attrs
);
593 fcio
.fcio_xfer
= FCIO_XFER_READ
;
594 fcio
.fcio_obuf
= (caddr_t
)&attrs
;
596 fp_ioctl(getPath(), FCIO_CMD
, &fcio
);
598 stateChange
= attrs
.lastChange
;
600 attributes
.PortFcId
= attrs
.PortFcId
;
601 attributes
.PortType
= attrs
.PortType
;
602 attributes
.PortState
= attrs
.PortState
;
603 attributes
.PortSupportedClassofService
= attrs
.PortSupportedClassofService
;
604 attributes
.PortSupportedSpeed
= attrs
.PortSupportedSpeed
;
605 attributes
.PortSpeed
= attrs
.PortSpeed
;
606 attributes
.PortMaxFrameSize
= attrs
.PortMaxFrameSize
;
607 attributes
.NumberofDiscoveredPorts
= attrs
.NumberofDiscoveredPorts
;
608 memcpy(&attributes
.NodeWWN
, &attrs
.NodeWWN
, 8);
609 memcpy(&attributes
.PortWWN
, &attrs
.PortWWN
, 8);
610 memcpy(&attributes
.FabricName
, &attrs
.FabricName
, 8);
611 memcpy(&attributes
.PortSupportedFc4Types
, &attrs
.PortSupportedFc4Types
, 32);
612 memcpy(&attributes
.PortActiveFc4Types
, &attrs
.PortActiveFc4Types
, 32);
613 memcpy(&attributes
.PortSymbolicName
, &attrs
.PortSymbolicName
, 256);
615 strncpy((char *)attributes
.OSDeviceName
, getPath().c_str(), 256);
619 HBA_PORTATTRIBUTES
FCHBAPort::getDiscoveredAttributes(
620 HBA_UINT32 discoveredport
, uint64_t &stateChange
) {
621 Trace
log("FCHBAPort::getDiscoverdAttributes(i)");
623 HBA_PORTATTRIBUTES attributes
;
625 fc_hba_port_attributes_t attrs
;
627 memset(&fcio
, 0, sizeof (fcio
));
628 memset(&attributes
, 0, sizeof (attributes
));
630 fcio
.fcio_cmd
= FCIO_GET_DISCOVERED_PORT_ATTRIBUTES
;
631 fcio
.fcio_olen
= sizeof (attrs
);
632 fcio
.fcio_xfer
= FCIO_XFER_READ
;
633 fcio
.fcio_obuf
= (caddr_t
)&attrs
;
634 fcio
.fcio_ilen
= sizeof (discoveredport
);
635 fcio
.fcio_ibuf
= (caddr_t
)&discoveredport
;
637 fp_ioctl(getPath(), FCIO_CMD
, &fcio
);
639 stateChange
= attrs
.lastChange
;
641 attributes
.PortFcId
= attrs
.PortFcId
;
642 attributes
.PortType
= attrs
.PortType
;
643 attributes
.PortState
= attrs
.PortState
;
644 attributes
.PortSupportedClassofService
= attrs
.PortSupportedClassofService
;
645 attributes
.PortSupportedSpeed
= attrs
.PortSupportedSpeed
;
646 attributes
.PortSpeed
= attrs
.PortSpeed
;
647 attributes
.PortMaxFrameSize
= attrs
.PortMaxFrameSize
;
648 attributes
.NumberofDiscoveredPorts
= attrs
.NumberofDiscoveredPorts
;
649 memcpy(&attributes
.NodeWWN
, &attrs
.NodeWWN
, 8);
650 memcpy(&attributes
.PortWWN
, &attrs
.PortWWN
, 8);
651 memcpy(&attributes
.FabricName
, &attrs
.FabricName
, 8);
652 memcpy(&attributes
.PortSupportedFc4Types
, &attrs
.PortSupportedFc4Types
, 32);
653 memcpy(&attributes
.PortActiveFc4Types
, &attrs
.PortActiveFc4Types
, 32);
654 memcpy(&attributes
.PortSymbolicName
, &attrs
.PortSymbolicName
, 256);
660 HBA_PORTATTRIBUTES
FCHBAPort::getDiscoveredAttributes(
661 uint64_t wwn
, uint64_t &stateChange
) {
662 Trace
log("FCHBAPort::getDiscoverdAttributes(p)");
664 HBA_PORTATTRIBUTES attributes
;
666 fc_hba_port_attributes_t attrs
;
669 memset(&fcio
, 0, sizeof (fcio
));
670 memset(&attributes
, 0, sizeof (attributes
));
672 uint64_t en_wwn
= htonll(wwn
);
673 memcpy(&lawwn
, &en_wwn
, sizeof (en_wwn
));
675 fcio
.fcio_cmd
= FCIO_GET_PORT_ATTRIBUTES
;
676 fcio
.fcio_olen
= sizeof (attrs
);
677 fcio
.fcio_xfer
= FCIO_XFER_READ
;
678 fcio
.fcio_obuf
= (caddr_t
)&attrs
;
679 fcio
.fcio_ilen
= sizeof (wwn
);
680 fcio
.fcio_ibuf
= (caddr_t
)&lawwn
;
682 fp_ioctl(getPath(), FCIO_CMD
, &fcio
);
684 stateChange
= attrs
.lastChange
;
686 attributes
.PortFcId
= attrs
.PortFcId
;
687 attributes
.PortType
= attrs
.PortType
;
688 attributes
.PortState
= attrs
.PortState
;
689 attributes
.PortSupportedClassofService
= attrs
.PortSupportedClassofService
;
690 attributes
.PortSupportedSpeed
= attrs
.PortSupportedSpeed
;
691 attributes
.PortSpeed
= attrs
.PortSpeed
;
692 attributes
.PortMaxFrameSize
= attrs
.PortMaxFrameSize
;
693 attributes
.NumberofDiscoveredPorts
= attrs
.NumberofDiscoveredPorts
;
694 memcpy(&attributes
.NodeWWN
, &attrs
.NodeWWN
, 8);
695 memcpy(&attributes
.PortWWN
, &attrs
.PortWWN
, 8);
696 memcpy(&attributes
.FabricName
, &attrs
.FabricName
, 8);
697 memcpy(&attributes
.PortSupportedFc4Types
, &attrs
.PortSupportedFc4Types
, 32);
698 memcpy(&attributes
.PortActiveFc4Types
, &attrs
.PortActiveFc4Types
, 32);
699 memcpy(&attributes
.PortSymbolicName
, &attrs
.PortSymbolicName
, 256);
706 void FCHBAPort::getTargetMappings(PHBA_FCPTARGETMAPPINGV2 userMappings
) {
707 Trace
log("FCHBAPort::getTargetMappings");
709 uint_t total_entries
= 0;
711 struct fcp_ioctl fioctl
;
712 fc_hba_target_mappings_t
*mappings
;
714 bool zeroLength
= false;
717 if (userMappings
== NULL
) {
718 log
.userError("Null mapping argument ");
719 throw BadArgumentException();
722 /* It's possible they didn't give any space */
723 if (userMappings
->NumberOfEntries
== 0) {
725 userMappings
->NumberOfEntries
= 1;
726 /* We have to give the driver at least one space */
729 mappings
= (fc_hba_target_mappings_t
*)new uchar_t
[
730 (sizeof (fc_hba_mapping_entry_t
)) *
731 (userMappings
->NumberOfEntries
- 1) +
732 sizeof (fc_hba_target_mappings_t
)];
733 if (mappings
== NULL
) {
735 throw InternalError();
739 fioctl
.fp_minor
= instanceNumber
;
740 fioctl
.listlen
= ((uint32_t) (sizeof (fc_hba_mapping_entry_t
))) *
741 (userMappings
->NumberOfEntries
- 1) +
742 (uint32_t) sizeof (fc_hba_target_mappings_t
);
743 fioctl
.list
= (caddr_t
)mappings
;
745 fd
= HBA::_open(FCP_DRIVER_PATH
, O_RDONLY
| O_NDELAY
);
747 log
.debug("Performing IOCTL to fetch mappings");
749 if (ioctl(fd
, FCP_GET_TARGET_MAPPINGS
, &fioctl
) != 0) {
752 if (errno
== EBUSY
) {
753 throw BusyException();
754 } else if (errno
== EAGAIN
) {
755 throw TryAgainException();
756 } else if (errno
== ENOTSUP
) {
757 throw NotSupportedException();
758 } else if (errno
== ENOENT
) {
759 throw UnavailableException();
761 throw IOError("Unable to fetch target mappings");
766 // Quickly iterate through and copy the data over to the client
767 for (i
= 0; i
< userMappings
->NumberOfEntries
&& !zeroLength
&&
768 i
< mappings
->numLuns
; i
++) {
769 string raw
= mappings
->entries
[i
].targetDriver
;
772 if (raw
.length() <= 0) {
773 log
.internalError("Bad target mapping without path, truncating.");
777 * Ideally, we'd like to ask some standard Solaris interface
778 * "What is the prefered minor node for this target?"
779 * but no such interface exists today. So, for now,
780 * we just hard-code ":n" for tapes, ":c,raw" for disks,
781 * and ":0" for enclosures.
782 * Devices with other generic names will be presented through
783 * first matching /dev path.
785 if ((raw
.find("/st@") != raw
.npos
) ||
786 (raw
.find("/tape@") != raw
.npos
)) {
788 } else if ((raw
.find("/ssd@") != raw
.npos
) ||
789 (raw
.find("/sd@") != raw
.npos
) ||
790 (raw
.find("/disk@") != raw
.npos
)) {
792 } else if ((raw
.find("/ses@") != raw
.npos
) ||
793 (raw
.find("/enclosure@") != raw
.npos
)) {
797 "Unrecognized target driver (%s), using first matching /dev path",
800 snprintf(userMappings
->entry
[i
].ScsiId
.OSDeviceName
,
801 sizeof (userMappings
->entry
[i
].ScsiId
.OSDeviceName
),
802 "/devices%s", raw
.c_str());
803 userMappings
->entry
[i
].ScsiId
.ScsiBusNumber
=
805 userMappings
->entry
[i
].ScsiId
.ScsiTargetNumber
=
806 mappings
->entries
[i
].targetNumber
;
807 userMappings
->entry
[i
].ScsiId
.ScsiOSLun
=
808 mappings
->entries
[i
].osLUN
;
809 userMappings
->entry
[i
].FcpId
.FcId
=
810 mappings
->entries
[i
].d_id
;
811 memcpy(userMappings
->entry
[i
].FcpId
.NodeWWN
.wwn
,
812 mappings
->entries
[i
].NodeWWN
.raw_wwn
,
814 memcpy(userMappings
->entry
[i
].FcpId
.PortWWN
.wwn
,
815 mappings
->entries
[i
].PortWWN
.raw_wwn
,
818 userMappings
->entry
[i
].FcpId
.FcpLun
=
819 mappings
->entries
[i
].samLUN
;
821 memcpy(userMappings
->entry
[i
].LUID
.buffer
,
822 mappings
->entries
[i
].guid
,
823 sizeof (userMappings
->entry
[i
].LUID
.buffer
));
826 log
.debug("Total mappings: %d %08x %08x",
827 mappings
->numLuns
, mappings
->entries
[i
].osLUN
, mappings
->entries
[i
].samLUN
);
829 // If everything is good, convert paths to sym-links
830 if (mappings
->numLuns
> 0 && !zeroLength
) {
831 if (userMappings
->NumberOfEntries
>= mappings
->numLuns
) {
832 // User buffer is larger than needed. (All is good)
833 userMappings
->NumberOfEntries
= mappings
->numLuns
;
834 convertToShortNames(userMappings
);
836 // User buffer is non zero, but too small. Don't bother with links
837 userMappings
->NumberOfEntries
= mappings
->numLuns
;
839 throw MoreDataException();
841 } else if (mappings
->numLuns
> 0) {
842 // Zero length buffer, but we've got mappings
843 userMappings
->NumberOfEntries
= mappings
->numLuns
;
845 throw MoreDataException();
847 // No mappings, no worries
848 userMappings
->NumberOfEntries
= 0;
855 void FCHBAPort::getRNIDMgmtInfo(PHBA_MGMTINFO info
) {
856 Trace
log("FCHBAPort::getRNIDMgmtInfo");
857 HBA_STATUS status
= HBA_STATUS_OK
;
863 log
.userError("NULL port management info");
864 throw BadArgumentException();
867 // Get the RNID information from the first port
868 memset(&rnid
, 0, sizeof (fc_rnid_t
));
869 memset((caddr_t
)&fcio
, 0, sizeof (fcio
));
871 fcio
.fcio_cmd
= FCIO_GET_NODE_ID
;
872 fcio
.fcio_olen
= sizeof (fc_rnid_t
);
873 fcio
.fcio_xfer
= FCIO_XFER_READ
;
874 fcio
.fcio_obuf
= (caddr_t
)&rnid
;
875 fp_ioctl(getPath(), FCIO_CMD
, &fcio
);
877 // Copy out the struct members of rnid into PHBA_MGMTINFO struct
878 memcpy(&info
->wwn
, &(rnid
.global_id
), sizeof (info
->wwn
));
879 memcpy(&info
->unittype
, &(rnid
.unit_type
), sizeof (info
->unittype
));
880 memcpy(&info
->PortId
, &(rnid
.port_id
), sizeof (info
->PortId
));
881 memcpy(&info
->NumberOfAttachedNodes
, &(rnid
.num_attached
),
882 sizeof (info
->NumberOfAttachedNodes
));
883 memcpy(&info
->IPVersion
, &(rnid
.ip_version
), sizeof (info
->IPVersion
));
884 memcpy(&info
->UDPPort
, &(rnid
.udp_port
), sizeof (info
->UDPPort
));
885 memcpy(&info
->IPAddress
, &(rnid
.ip_addr
), sizeof (info
->IPAddress
));
886 memcpy(&info
->TopologyDiscoveryFlags
, &(rnid
.topo_flags
),
887 sizeof (info
->TopologyDiscoveryFlags
));
890 void FCHBAPort::sendCTPassThru(void *requestBuffer
, HBA_UINT32 requestSize
,
891 void *responseBuffer
, HBA_UINT32
*responseSize
) {
892 Trace
log("FCHBAPort::sendCTPassThru");
899 // Validate the arguments
900 if (requestBuffer
== NULL
) {
901 log
.userError("NULL request buffer");
902 throw BadArgumentException();
904 if (responseBuffer
== NULL
) {
905 log
.userError("NULL response buffer");
906 throw BadArgumentException();
909 minor_node
= instanceNumber
;
911 // construct fcio struct
912 memset(&fcio
, 0, sizeof (fcio_t
));
913 fcio
.fcio_cmd
= FCSMIO_CT_CMD
;
914 fcio
.fcio_xfer
= FCIO_XFER_RW
;
916 fcio
.fcio_ilen
= requestSize
;
917 fcio
.fcio_ibuf
= (char *)requestBuffer
;
918 fcio
.fcio_olen
= *responseSize
;
919 fcio
.fcio_obuf
= (char *)responseBuffer
;
921 fcio
.fcio_alen
= sizeof (minor_t
);
922 fcio
.fcio_abuf
= (char *)&minor_node
;
926 fcsm_ioctl(FCSMIO_CMD
, &fcio
);
928 // Do some calculations on the duration of the ioctl.
930 duration
= end
- start
;
931 duration
/= HR_SECOND
;
933 "Total CTPASS ioctl call for HBA %s was %.4f seconds",
934 getPath().c_str(), duration
);
937 void FCHBAPort::sendRLS(uint64_t destWWN
,
939 HBA_UINT32
*pRspBufferSize
) {
940 Trace
log("FCHBAPort::sendRLS");
946 // Validate the arguments
947 if (pRspBuffer
== NULL
||
948 pRspBufferSize
== NULL
) {
949 log
.userError("NULL hba");
950 throw BadArgumentException();
953 // check to see if we are sending RLS to the HBA
954 HBA_PORTATTRIBUTES attrs
;
956 if (getPortWWN() == destWWN
) {
957 attrs
= getPortAttributes(tmp
);
959 attrs
= getDiscoveredAttributes(destWWN
, tmp
);
962 memcpy(&rls_req
, &attrs
.PortFcId
,
963 sizeof (attrs
.PortFcId
));
965 memset((caddr_t
)&fcio
, 0, sizeof (fcio
));
966 fcio
.fcio_cmd
= FCIO_LINK_STATUS
;
967 fcio
.fcio_ibuf
= (caddr_t
)&rls_req
;
968 fcio
.fcio_ilen
= sizeof (rls_req
);
969 fcio
.fcio_xfer
= FCIO_XFER_RW
;
971 fcio
.fcio_cmd_flags
= FCIO_CFLAGS_RLS_DEST_NPORT
;
972 fcio
.fcio_obuf
= (char *)new uchar_t
[*pRspBufferSize
];
973 fcio
.fcio_olen
= *pRspBufferSize
;
975 if (fcio
.fcio_obuf
== NULL
) {
977 throw InternalError();
980 fp_ioctl(getPath(), FCIO_CMD
, &fcio
);
981 memcpy(pRspBuffer
, fcio
.fcio_obuf
, *pRspBufferSize
);
982 if (fcio
.fcio_obuf
!= NULL
) {
983 delete(fcio
.fcio_obuf
);
987 void FCHBAPort::sendReportLUNs(uint64_t wwn
,
988 void *responseBuffer
, HBA_UINT32
*responseSize
,
989 HBA_UINT8
*scsiStatus
,
990 void *senseBuffer
, HBA_UINT32
*senseSize
) {
991 Trace
log("FCHBAPort::sendReportLUNs");
992 struct fcp_scsi_cmd fscsi
;
993 union scsi_cdb scsi_rl_req
;
994 uint64_t targetWwn
= htonll(wwn
);
996 // Validate the arguments
997 if (responseBuffer
== NULL
||
998 senseBuffer
== NULL
||
999 responseSize
== NULL
||
1000 senseSize
== NULL
) {
1001 throw BadArgumentException();
1004 memset(&fscsi
, 0, sizeof (fscsi
));
1005 memset(&scsi_rl_req
, 0, sizeof (scsi_rl_req
));
1006 memcpy(fscsi
.scsi_fc_pwwn
.raw_wwn
, &targetWwn
, sizeof (la_wwn_t
));
1008 scsi_cmd_init(&fscsi
, getPath().c_str(), &scsi_rl_req
,
1009 sizeof (scsi_rl_req
), responseBuffer
, *responseSize
,
1010 senseBuffer
, *senseSize
);
1013 scsi_rl_req
.scc_cmd
= SCMD_REPORT_LUNS
;
1014 FORMG5COUNT(&scsi_rl_req
, *responseSize
);
1015 sendSCSIPassThru(&fscsi
, responseSize
, senseSize
, scsiStatus
);
1020 * wwn - remote target WWN where the SCSI Inquiry shall be sent
1021 * fcLun - the SCSI LUN to which the SCSI Inquiry shall be sent
1022 * cdb1 - the second byte of the CDB for the SCSI Inquiry
1023 * cdb2 - the third byte of teh CDB for the SCSI Inquiry
1024 * responseBuffer - shall be a pointer to a buffer to receive the SCSI
1025 * Inquiry command response
1026 * responseSize - a pointer to the size of the buffer to receive
1028 * scsiStatus - a pointer to a buffer to receive SCSI status
1029 * senseBuffer - pointer to a buffer to receive SCSI sense data
1030 * seneseSize - pointer to the size of the buffer to receive SCSI sense
1033 void FCHBAPort::sendScsiInquiry(uint64_t wwn
, HBA_UINT64 fcLun
,
1034 HBA_UINT8 cdb1
, HBA_UINT8 cdb2
, void *responseBuffer
,
1035 HBA_UINT32
*responseSize
, HBA_UINT8
*scsiStatus
, void *senseBuffer
,
1036 HBA_UINT32
*senseSize
) {
1037 Trace
log("FCHBAPort::sendScsiInquiry");
1039 struct fcp_scsi_cmd fscsi
;
1040 union scsi_cdb scsi_inq_req
;
1041 uint64_t targetWwn
= htonll(wwn
);
1043 // Validate the arguments
1044 if (responseBuffer
== NULL
||
1045 senseBuffer
== NULL
||
1046 responseSize
== NULL
||
1047 senseSize
== NULL
) {
1048 throw BadArgumentException();
1051 memset(&fscsi
, 0, sizeof (fscsi
));
1052 memset(&scsi_inq_req
, 0, sizeof (scsi_inq_req
));
1053 memcpy(fscsi
.scsi_fc_pwwn
.raw_wwn
, &targetWwn
, sizeof (la_wwn_t
));
1056 scsi_cmd_init(&fscsi
, getPath().c_str(), &scsi_inq_req
,
1057 sizeof (scsi_inq_req
), responseBuffer
, *responseSize
,
1058 senseBuffer
, *senseSize
);
1059 fscsi
.scsi_lun
= fcLun
;
1061 scsi_inq_req
.scc_cmd
= SCMD_INQUIRY
;
1062 scsi_inq_req
.g0_addr1
= cdb2
;
1063 scsi_inq_req
.g0_addr2
= cdb1
;
1064 scsi_inq_req
.g0_count0
= *responseSize
;
1067 sendSCSIPassThru(&fscsi
, responseSize
, senseSize
, scsiStatus
);
1071 void FCHBAPort::sendReadCapacity(uint64_t pwwn
,
1072 HBA_UINT64 fcLun
, void *responseBuffer
,
1073 HBA_UINT32
*responseSize
, HBA_UINT8
*scsiStatus
,
1074 void *senseBuffer
, HBA_UINT32
*senseSize
) {
1075 Trace
log("FCHBAPort::sendReadCapacity");
1077 struct fcp_scsi_cmd fscsi
;
1078 union scsi_cdb scsi_rc_req
;
1079 uint64_t targetWwn
= htonll(pwwn
);
1081 // Validate the arguments
1082 if (responseBuffer
== NULL
||
1083 senseBuffer
== NULL
||
1084 responseSize
== NULL
||
1085 senseSize
== NULL
||
1086 scsiStatus
== NULL
) {
1087 throw BadArgumentException();
1090 memset(&fscsi
, 0, sizeof (fscsi
));
1091 memset(&scsi_rc_req
, 0, sizeof (scsi_rc_req
));
1093 scsi_cmd_init(&fscsi
, getPath().c_str(), &scsi_rc_req
,
1094 sizeof (scsi_rc_req
), responseBuffer
, *responseSize
,
1095 senseBuffer
, *senseSize
);
1097 memcpy(fscsi
.scsi_fc_pwwn
.raw_wwn
, &targetWwn
, sizeof (la_wwn_t
));
1098 fscsi
.scsi_lun
= fcLun
;
1100 scsi_rc_req
.scc_cmd
= SCMD_READ_CAPACITY
;
1101 scsi_rc_req
.g1_reladdr
= 0;
1103 scsi_rc_req
.g1_addr3
= 0;
1104 scsi_rc_req
.g1_count0
= 0;
1106 sendSCSIPassThru(&fscsi
, responseSize
, senseSize
, scsiStatus
);
1109 void FCHBAPort::sendRNID(uint64_t destwwn
, HBA_UINT32 destfcid
,
1110 HBA_UINT32 nodeIdDataFormat
, void *pRspBuffer
,
1111 HBA_UINT32
*RspBufferSize
) {
1112 Trace
log("FCHBAPort::sendRNID");
1113 int localportfound
, remoteportfound
, send
;
1116 // Validate the arguments
1117 if (pRspBuffer
== NULL
||
1118 RspBufferSize
== NULL
) {
1119 throw BadArgumentException();
1121 // NodeIdDataFormat must be within the range of 0x00 and 0xff
1122 if (nodeIdDataFormat
> 0xff) {
1124 "NodeIdDataFormat must be within the range of 0x00 "
1126 throw BadArgumentException();
1130 remoteportfound
= 0;
1131 if (destfcid
!= 0) {
1134 HBA_PORTATTRIBUTES attrs
= getDiscoveredAttributes(destwwn
,
1136 if (attrs
.PortFcId
== destfcid
) {
1138 remoteportfound
= 1;
1141 remoteportfound
= 1;
1143 } catch (HBAException
&e
) {
1145 * Send RNID if destination port not
1146 * present in the discovered ports table
1149 if (remoteportfound
== 0) {
1157 // Can we log something so we can figure out why?
1158 throw BadArgumentException();
1161 memset((caddr_t
)&fcio
, 0, sizeof (fcio
));
1162 uint64_t netdestwwn
= htonll(destwwn
);
1163 fcio
.fcio_cmd
= FCIO_SEND_NODE_ID
;
1164 fcio
.fcio_xfer
= FCIO_XFER_READ
;
1165 fcio
.fcio_cmd_flags
= nodeIdDataFormat
;
1166 fcio
.fcio_ilen
= sizeof (la_wwn_t
);
1167 fcio
.fcio_ibuf
= (caddr_t
)&netdestwwn
;
1168 fcio
.fcio_olen
= *RspBufferSize
;
1169 fcio
.fcio_obuf
= (char *)new uchar_t
[*RspBufferSize
];
1172 if (fcio
.fcio_obuf
== NULL
) {
1174 throw InternalError();
1177 fp_ioctl(getPath(), FCIO_CMD
, &fcio
);
1179 memcpy(pRspBuffer
, fcio
.fcio_obuf
, *RspBufferSize
);
1181 if (fcio
.fcio_obuf
!= NULL
) {
1182 delete(fcio
.fcio_obuf
);
1186 void FCHBAPort::setRNID(HBA_MGMTINFO info
) {
1187 Trace
log("FCHBAPort::setRNID");
1191 memset(&rnid
, 0, sizeof (fc_rnid_t
));
1192 memset((caddr_t
)&fcio
, 0, sizeof (fcio
));
1195 fcio
.fcio_cmd
= FCIO_SET_NODE_ID
;
1196 fcio
.fcio_ilen
= sizeof (fc_rnid_t
);
1197 fcio
.fcio_xfer
= FCIO_XFER_WRITE
;
1198 fcio
.fcio_ibuf
= (caddr_t
)&rnid
;
1201 // Copy the HBA_MGMTINFO into fc_rnid_t struct
1202 memcpy(&(rnid
.unit_type
), &(info
.unittype
), sizeof (rnid
.unit_type
));
1203 memcpy(&(rnid
.port_id
), &(info
.PortId
), sizeof (rnid
.port_id
));
1204 memcpy(&(rnid
.global_id
), &(info
.wwn
), sizeof (info
.wwn
));
1205 memcpy(&(rnid
.num_attached
), &(info
.NumberOfAttachedNodes
),
1206 sizeof (rnid
.num_attached
));
1207 memcpy(&(rnid
.ip_version
), &(info
.IPVersion
), sizeof (rnid
.ip_version
));
1208 memcpy(&(rnid
.udp_port
), &(info
.UDPPort
), sizeof (rnid
.udp_port
));
1209 memcpy(&(rnid
.ip_addr
), &info
.IPAddress
, sizeof (rnid
.ip_addr
));
1210 memcpy(&(rnid
.topo_flags
), &(info
.TopologyDiscoveryFlags
),
1211 sizeof (rnid
.topo_flags
));
1213 fp_ioctl(getPath(), FCIO_CMD
, &fcio
, O_NDELAY
| O_RDONLY
| O_EXCL
);
1216 void FCHBAPort::fp_ioctl(string path
, int cmd
, fcio_t
*fcio
, int openflag
) {
1217 Trace
log("FCHBAPort::fp_ioctl with openflag");
1218 char fcioErrorString
[MAX_FCIO_MSG_LEN
] = "";
1219 int fd
= HBA::_open(path
, openflag
);
1222 HBA::_ioctl(fd
, cmd
, (uchar_t
*)fcio
);
1223 while (fcio
->fcio_errno
== FC_STATEC_BUSY
) {
1225 HBA::_ioctl(fd
, cmd
, (uchar_t
*)fcio
);
1231 if (fcio
->fcio_errno
) {
1232 throw IOError("IOCTL transport failure");
1236 transportError(fcio
->fcio_errno
, fcioErrorString
);
1237 log
.genericIOError("ioctl (0x%x) failed. Transport: \"%s\"", cmd
,
1239 switch (fcio
->fcio_errno
) {
1241 throw IllegalWWNException();
1243 throw IllegalWWNException();
1244 case FC_OUTOFBOUNDS
:
1245 throw IllegalIndexException();
1249 case FC_STATEC_BUSY
:
1250 case FC_DEVICE_BUSY
:
1251 throw BusyException();
1259 void FCHBAPort::fp_ioctl(string path
, int cmd
, fcio_t
*fcio
) {
1260 Trace
log("FCHBAPort::fp_ioctl");
1261 fp_ioctl(path
, cmd
, fcio
, O_NDELAY
| O_RDONLY
);
1264 void FCHBAPort::fcsm_ioctl(int cmd
, fcio_t
*fcio
) {
1265 // We use the same error handling as fp, so just re-use
1266 fp_ioctl(FCSM_DRIVER_PATH
, cmd
, fcio
);