FCHBAPort.cc revision c465437abaf8cc10b6cafec2fc1576bc770537ba
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <FCHBAPort.h>
#include <Exceptions.h>
#include <Trace.h>
#include <sun_fc.h>
#include <iostream>
#include <iomanip>
#include <fcntl.h>
#include <unistd.h>
#include <stropts.h>
#include <dirent.h>
#include <errno.h>
#include <FCHBANPIVPort.h>
using namespace std;
/*
* Interpret the error code in the fcio_t structure
*
* message must be at least MAX_FCIO_MSG_LEN in length.
*/
void
return;
}
switch (fcio_errno) {
case (uint32_t)FC_FAILURE:
fcioErrorString = "general failure";
break;
case (uint32_t)FC_FAILURE_SILENT:
fcioErrorString = "general failure but fail silently";
break;
case FC_SUCCESS:
fcioErrorString = "successful completion";
break;
case FC_CAP_ERROR:
fcioErrorString = "FCA capability error";
break;
case FC_CAP_FOUND:
fcioErrorString = "FCA capability unsettable";
break;
case FC_CAP_SETTABLE:
fcioErrorString = "FCA capability settable";
break;
case FC_UNBOUND:
fcioErrorString = "unbound stuff";
break;
case FC_NOMEM:
fcioErrorString = "allocation error";
break;
case FC_BADPACKET:
fcioErrorString = "invalid packet specified/supplied";
break;
case FC_OFFLINE:
fcioErrorString = "I/O resource unavailable";
break;
case FC_OLDPORT:
fcioErrorString = "operation on non-loop port";
break;
case FC_NO_MAP:
fcioErrorString = "requested map unavailable";
break;
case FC_TRANSPORT_ERROR:
fcioErrorString = "unable to transport I/O";
break;
case FC_ELS_FREJECT:
fcioErrorString = "ELS rejected by a Fabric";
break;
case FC_ELS_PREJECT:
fcioErrorString = "ELS rejected by an N_port";
break;
case FC_ELS_BAD:
fcioErrorString = "ELS rejected by FCA/fctl";
break;
case FC_ELS_MALFORMED:
fcioErrorString = "poorly formed ELS request";
break;
case FC_TOOMANY:
fcioErrorString = "resource request too large";
break;
case FC_UB_BADTOKEN:
fcioErrorString = "invalid unsolicited buffer token";
break;
case FC_UB_ERROR:
fcioErrorString = "invalid unsol buf request";
break;
case FC_UB_BUSY:
fcioErrorString = "buffer already in use";
break;
case FC_BADULP:
fcioErrorString = "Unknown ulp";
break;
case FC_BADTYPE:
fcioErrorString = "ULP not registered to handle this FC4 type";
break;
case FC_UNCLAIMED:
fcioErrorString = "request or data not claimed";
break;
case FC_ULP_SAMEMODULE:
fcioErrorString = "module already in use";
break;
case FC_ULP_SAMETYPE:
fcioErrorString = "FC4 module already in use";
break;
case FC_ABORTED:
fcioErrorString = "request aborted";
break;
case FC_ABORT_FAILED:
fcioErrorString = "abort request failed";
break;
case FC_BADEXCHANGE:
fcioErrorString = "exchange doesn�t exist";
break;
case FC_BADWWN:
fcioErrorString = "WWN not recognized";
break;
case FC_BADDEV:
fcioErrorString = "device unrecognized";
break;
case FC_BADCMD:
fcioErrorString = "invalid command issued";
break;
case FC_BADOBJECT:
fcioErrorString = "invalid object requested";
break;
case FC_BADPORT:
fcioErrorString = "invalid port specified";
break;
case FC_NOTTHISPORT:
fcioErrorString = "resource not at this port";
break;
case FC_PREJECT:
fcioErrorString = "reject at remote N_Port";
break;
case FC_FREJECT:
fcioErrorString = "reject at remote Fabric";
break;
case FC_PBUSY:
fcioErrorString = "remote N_Port busy";
break;
case FC_FBUSY:
fcioErrorString = "remote Fabric busy";
break;
case FC_ALREADY:
fcioErrorString = "already logged in";
break;
case FC_LOGINREQ:
fcioErrorString = "login required";
break;
case FC_RESETFAIL:
fcioErrorString = "reset failed";
break;
case FC_INVALID_REQUEST:
fcioErrorString = "request is invalid";
break;
case FC_OUTOFBOUNDS:
fcioErrorString = "port number is out of bounds";
break;
case FC_TRAN_BUSY:
fcioErrorString = "command transport busy";
break;
case FC_STATEC_BUSY:
fcioErrorString = "port driver currently busy";
break;
case FC_DEVICE_BUSY:
fcioErrorString = "transport working on this device";
break;
case FC_DEVICE_NOT_TGT:
fcioErrorString = "device is not a SCSI target";
break;
default:
return;
}
}
static void
if (!sense) {
return;
}
if (!routine) {
return;
}
case KEY_NO_SENSE:
msg = "No sense";
break;
case KEY_RECOVERABLE_ERROR:
msg = "Recoverable error";
break;
case KEY_NOT_READY:
msg = "Not ready";
break;
case KEY_MEDIUM_ERROR:
msg = "Medium error";
break;
case KEY_HARDWARE_ERROR:
msg = "Hardware error";
break;
case KEY_ILLEGAL_REQUEST:
msg = "Illegal request";
break;
case KEY_UNIT_ATTENTION:
msg = "Unit attention";
break;
case KEY_DATA_PROTECT:
msg = "Data protect";
break;
case KEY_BLANK_CHECK:
msg = "Blank check";
break;
case KEY_VENDOR_UNIQUE:
msg = "Vendor Unique";
break;
case KEY_COPY_ABORTED:
msg = "Copy aborted";
break;
case KEY_ABORTED_COMMAND:
msg = "Aborted command";
break;
case KEY_EQUAL:
msg = "Equal";
break;
case KEY_VOLUME_OVERFLOW:
msg = "Volume overflow";
break;
case KEY_MISCOMPARE:
msg = "Miscompare";
break;
case KEY_RESERVED:
msg = "Reserved";
break;
default:
msg = "unknown sense key";
}
}
/*
* Issue a SCSI pass thru command.
* Returns a scsi status value.
*/
HBA_UINT8 *scsiStatus) {
int fd;
int count;
int ioctl_errno;
double duration;
responseSize == NULL ||
scsiStatus == NULL) {
throw BadArgumentException();
}
count = 0;
ioctl_errno = 0;
/* save off errno */
ioctl_errno = errno;
/*
* collect SCSI status first regrardless of the value.
* 0 is a good status so this should be okay
*/
/* Did we get a check condition? */
throw CheckConditionException();
/*
* fcp driver returns FC_DEVICE_NOT_TGT when the node is not
* scsi-capable like remote hba nodes.
*/
throw NotATargetException();
throw InvalidLUNException();
} else if (ioctl_errno == EBUSY) {
throw BusyException();
} else if (ioctl_errno == EAGAIN) {
throw TryAgainException();
} else if (ioctl_errno == ENOTSUP) {
throw NotSupportedException();
} else if (ioctl_errno == ENOENT) {
throw UnavailableException();
} else {
}
} else {
/* Just in case, check for a check-condition state */
throw CheckConditionException();
}
}
/* Record the response data */
/* Do some quick duration calcuations */
#ifdef DEBUG
/* Did we have any failure */
if (ret != HBA_STATUS_OK) {
"Ioctl failed for device \"%s\" target %016llx."
" Errno: \"%s\"(%d), "
"Transport: \"%s\", SCSI Status: 0x%x"
"responseSize = %d, senseSize = %d",
/* We may or may not have sense data */
ROUTINE);
}
#endif
}
/*
* constructs the fcp_scsi_cmd struct for SCSI_Inquiry, SendReadCapacity, or
* SendReportLUNs
*/
/*#include <fcio.h>
#include <fcp_util.h>*/
inline void
fscsi->scsi_fc_rspcode = 0;
fscsi->scsi_bufresid = 0;
fscsi->scsi_bufstatus = 0;
fscsi->scsi_rqresid = 0;
}
int size = 200;
bool retry = false;
int bufSize;
try {
} catch (...) {
path = "/devices";
path += ":fc";
controllerNumber = -1;
}
// Fetch the minor number for later use
}
// This routine is not index based, so we can discard stateChange
// For reference, here's how to dump WWN's through C++ streams.
// cout << "\tPort WWN: " << hex << setfill('0') << setw(16) << portWWN
// << endl;
// cout << "\tNode WWN: " << hex << setfill('0') << setw(16) << nodeWWN
// << endl;
// we should add code here to build NPIVPORT instance
// Get Port's NPIV port list ( include nwwn and pwwn and path)
do {
retry = false;
retry = true;
delete (pathList);
}
} while (retry);
// Make instance for each NPIV Port
for ( int i = 0; i < pathList->numAdapters; i++) {
try {
} catch (...) {
}
}
delete (pathList);
}
int ret = 0;
return (ret);
}
uint32_t vportindex = 0;
return (vportindex);
}
return (attributes);
}
return (attributes);
}
return (attributes);
}
return (attributes);
}
int i, index;
uint_t total_entries = 0;
int fd;
bool zeroLength = false;
if (userMappings == NULL) {
throw BadArgumentException();
}
/* It's possible they didn't give any space */
if (userMappings->NumberOfEntries == 0) {
zeroLength = true;
/* We have to give the driver at least one space */
}
(sizeof (fc_hba_mapping_entry_t)) *
sizeof (fc_hba_target_mappings_t)];
throw InternalError();
}
(uint32_t) sizeof (fc_hba_target_mappings_t);
delete (mappings);
throw BusyException();
throw TryAgainException();
throw NotSupportedException();
throw UnavailableException();
} else {
throw IOError("Unable to fetch target mappings");
}
}
// Quickly iterate through and copy the data over to the client
break;
}
/*
* Ideally, we'd like to ask some standard Solaris interface
* "What is the prefered minor node for this target?"
* but no such interface exists today. So, for now,
* we just hard-code ":n" for tapes, ":c,raw" for disks,
* and ":0" for enclosures.
* Devices with other generic names will be presented through
* first matching /dev path.
*/
raw += ":n";
raw += ":c,raw";
raw += ":0";
} else {
"Unrecognized target driver (%s), using first matching /dev path",
}
sizeof (la_wwn_t));
sizeof (la_wwn_t));
}
// If everything is good, convert paths to sym-links
// User buffer is larger than needed. (All is good)
} else {
// User buffer is non zero, but too small. Don't bother with links
delete (mappings);
throw MoreDataException();
}
// Zero length buffer, but we've got mappings
delete (mappings);
throw MoreDataException();
} else {
// No mappings, no worries
userMappings->NumberOfEntries = 0;
delete (mappings);
return;
}
delete (mappings);
}
throw BadArgumentException();
}
// Get the RNID information from the first port
// Copy out the struct members of rnid into PHBA_MGMTINFO struct
sizeof (info->NumberOfAttachedNodes));
sizeof (info->TopologyDiscoveryFlags));
}
double duration;
// Validate the arguments
if (requestBuffer == NULL) {
throw BadArgumentException();
}
if (responseBuffer == NULL) {
throw BadArgumentException();
}
// construct fcio struct
// Do some calculations on the duration of the ioctl.
"Total CTPASS ioctl call for HBA %s was %.4f seconds",
}
void *pRspBuffer,
// Validate the arguments
if (pRspBuffer == NULL ||
pRspBufferSize == NULL) {
throw BadArgumentException();
}
// check to see if we are sending RLS to the HBA
if (getPortWWN() == destWWN) {
} else {
}
fcio.fcio_flags = 0;
throw InternalError();
}
}
}
struct fcp_scsi_cmd fscsi;
union scsi_cdb scsi_rl_req;
// Validate the arguments
if (responseBuffer == NULL ||
senseBuffer == NULL ||
responseSize == NULL ||
throw BadArgumentException();
}
senseBuffer, *senseSize);
}
/*
* arguments:
* wwn - remote target WWN where the SCSI Inquiry shall be sent
* fcLun - the SCSI LUN to which the SCSI Inquiry shall be sent
* cdb1 - the second byte of the CDB for the SCSI Inquiry
* cdb2 - the third byte of teh CDB for the SCSI Inquiry
* responseBuffer - shall be a pointer to a buffer to receive the SCSI
* Inquiry command response
* responseSize - a pointer to the size of the buffer to receive
* the SCSI Inquiry.
* scsiStatus - a pointer to a buffer to receive SCSI status
* senseBuffer - pointer to a buffer to receive SCSI sense data
* seneseSize - pointer to the size of the buffer to receive SCSI sense
* data
*/
HBA_UINT32 *senseSize) {
struct fcp_scsi_cmd fscsi;
union scsi_cdb scsi_inq_req;
// Validate the arguments
if (responseBuffer == NULL ||
senseBuffer == NULL ||
responseSize == NULL ||
throw BadArgumentException();
}
senseBuffer, *senseSize);
}
struct fcp_scsi_cmd fscsi;
union scsi_cdb scsi_rc_req;
// Validate the arguments
if (responseBuffer == NULL ||
senseBuffer == NULL ||
responseSize == NULL ||
scsiStatus == NULL) {
throw BadArgumentException();
}
senseBuffer, *senseSize);
scsi_rc_req.g1_reladdr = 0;
scsi_rc_req.g1_addr3 = 0;
scsi_rc_req.g1_count0 = 0;
}
// Validate the arguments
if (pRspBuffer == NULL ||
RspBufferSize == NULL) {
throw BadArgumentException();
}
// NodeIdDataFormat must be within the range of 0x00 and 0xff
if (nodeIdDataFormat > 0xff) {
"NodeIdDataFormat must be within the range of 0x00 "
"and 0xFF");
throw BadArgumentException();
}
remoteportfound = 0;
if (destfcid != 0) {
try {
tmp);
send = 1;
remoteportfound = 1;
} else {
send = 0;
remoteportfound = 1;
}
} catch (HBAException &e) {
/*
* Send RNID if destination port not
* present in the discovered ports table
*/
}
if (remoteportfound == 0) {
send = 1;
}
} else {
send = 1;
}
if (!send) {
// Can we log something so we can figure out why?
throw BadArgumentException();
}
throw InternalError();
}
}
}
// Copy the HBA_MGMTINFO into fc_rnid_t struct
sizeof (rnid.num_attached));
sizeof (rnid.topo_flags));
}
try {
int times = 0;
sleep(1);
if (times++ > 10) {
break;
}
}
if (fcio->fcio_errno) {
throw IOError("IOCTL transport failure");
}
} catch (...) {
switch (fcio->fcio_errno) {
case FC_BADWWN:
throw IllegalWWNException();
case FC_BADPORT:
throw IllegalWWNException();
case FC_OUTOFBOUNDS:
throw IllegalIndexException();
case FC_PBUSY:
case FC_FBUSY:
case FC_TRAN_BUSY:
case FC_STATEC_BUSY:
case FC_DEVICE_BUSY:
throw BusyException();
case FC_SUCCESS:
default:
throw;
}
}
}
}
// We use the same error handling as fp, so just re-use
}