fct.c revision 2a8164df8a5f42c8a00f10c67d7bc84f80ae9c41
/*
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/byteorder.h>
#include <stmf.h>
#include <stmf_ioctl.h>
#include <portif.h>
#include <fct.h>
#include <fctio.h>
#include <fct_impl.h>
#include <discovery.h>
void **result);
static dev_info_t *fct_dip;
static struct cb_ops fct_cb_ops = {
fct_open, /* open */
fct_close, /* close */
nodev, /* strategy */
nodev, /* print */
nodev, /* dump */
nodev, /* read */
nodev, /* write */
fct_ioctl, /* ioctl */
nodev, /* devmap */
nodev, /* mmap */
nodev, /* segmap */
nochpoll, /* chpoll */
ddi_prop_op, /* cb_prop_op */
0, /* streamtab */
CB_REV, /* rev */
nodev, /* aread */
nodev /* awrite */
};
0,
nulldev, /* identify */
nulldev, /* probe */
nodev, /* reset */
NULL, /* bus_ops */
NULL /* power */
};
#define FCT_NAME "COMSTAR FCT"
extern struct mod_ops mod_driverops;
};
static struct modlinkage modlinkage = {
&modldrv,
};
static int max_cached_ncmds = FCT_MAX_CACHED_CMDS;
static kmutex_t fct_global_mutex;
int
_init(void)
{
int ret;
if (ret)
return (ret);
/* XXX */
return (ret);
}
int
_fini(void)
{
int ret;
if (ret)
return (ret);
/* XXX */
return (ret);
}
int
{
}
/* ARGSUSED */
static int
{
switch (cmd) {
case DDI_INFO_DEVT2DEVINFO:
break;
case DDI_INFO_DEVT2INSTANCE:
break;
default:
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
static int
{
switch (cmd) {
case DDI_ATTACH:
DDI_NT_STMF_PP, 0) != DDI_SUCCESS) {
break;
}
return (DDI_SUCCESS);
}
return (DDI_FAILURE);
}
static int
{
switch (cmd) {
case DDI_DETACH:
ddi_remove_minor_node(dip, 0);
return (DDI_SUCCESS);
}
return (DDI_FAILURE);
}
/* ARGSUSED */
static int
{
return (EINVAL);
return (0);
}
/* ARGSUSED */
static int
{
return (0);
}
/* ARGSUSED */
static int
{
int ret = 0;
return (ENOTTY);
}
return (EPERM);
}
switch (cmd) {
case FCTIO_CMD:
break;
default:
break;
}
return (ret);
}
int
{
int ret = 0;
goto copyin_iocdata_done;
}
if ((*fctio)->fctio_ilen) {
goto copyin_iocdata_done;
}
}
if ((*fctio)->fctio_alen) {
goto copyin_iocdata_done;
}
}
if ((*fctio)->fctio_olen)
if (ret == 0)
return (0);
if (*obuf) {
}
if (*abuf) {
}
if (*ibuf) {
}
return (ret);
}
int
{
int ret = 0;
if (fctio->fctio_olen) {
mode);
if (ret) {
return (EFAULT);
}
}
if (ret) {
return (EFAULT);
}
return (0);
}
int
{
int i = 0, maxPorts = 0;
if (i < count)
maxPorts ++;
i++;
}
return (maxPorts);
}
/* invoked with fct_global_mutex locked */
{
return (iport);
}
return (NULL);
}
int
{
if (!iport) {
return (ENXIO);
}
KM_SLEEP);
sizeof (hba_attr->Manufacturer));
sizeof (hba_attr->SerialNumber));
sizeof (hba_attr->ModelDescription));
else
sizeof (hba_attr->HardwareVersion));
sizeof (hba_attr->OptionROMVersion));
sizeof (hba_attr->FirmwareVersion));
sizeof (hba_attr->DriverName));
sizeof (hba_attr->DriverVersion));
/* hba_attr->NumberOfPorts = fct_count_fru_ports(iport); */
return (0);
}
int
{
int i = 0;
if (!ilport) {
if (!iport) {
return (ENXIO);
}
}
KM_SLEEP);
switch (iport->iport_state) {
case FCT_STATE_ONLINE:
break;
case FCT_STATE_OFFLINE:
break;
default:
break;
}
case PORT_TOPOLOGY_PT_TO_PT:
break;
break;
break;
break;
default:
break;
}
port_attr->PortSupportedFc4Types[0] = 0;
else
port_attr->PortSymbolicName[0] = 0;
/* the definition is different so need to translate */
case PORT_SPEED_1G:
break;
case PORT_SPEED_2G:
break;
case PORT_SPEED_4G:
break;
case PORT_SPEED_8G:
break;
case PORT_SPEED_10G:
break;
default:
break;
}
}
}
return (0);
}
int
{
int count = 0, i = 0;
if (!remote_port) {
if (!iport) {
return (ENXIO);
}
return (EINVAL);
}
count ++;
break;
}
}
return (EINVAL);
}
} else {
iport = (fct_i_local_port_t *)
}
else
sizeof (irp->irp_fc4types));
sizeof (irp->irp_fc4types));
else
port_attr->PortMaxFrameSize = 0;
if (!remote_port) {
}
return (0);
}
int
{
int i, ret;
if (iport) {
}
/* else */
for (i = 0; i < rportid_table_size; i++) {
while (irp) {
port_wwn, 8) == 0 &&
return (ret);
}
}
}
}
return (ENXIO);
}
/* ARGSUSED */
int
{
if (!iport)
return (ENXIO);
/*
* port_stats->SecondsSinceLastReset = ;
* port_stats->TxFrames = ;
* port_stats->TxWords = ;
* port_stats->RxFrames = ;
* port_stats->RxWords = ;
* port_stats->LIPCount = ;
* port_stats->NOSCount = ;
* port_stats->ErrorFrames = ;
* port_stats->DumpedFrames = ;
* port_stats->LinkFailureCount = ;
* port_stats->LossOfSyncCount = ;
* port_stats->LossOfSignalCount = ;
* port_stats->PrimitiveSeqProtocol = ;
* port_stats->InvalidTxWordCount = ;
* port_stats->InvalidCRCCount = ;
*/
return (0);
}
static int
{
int ret = 0;
if (ret) {
return (ret);
}
case FCTIO_ADAPTER_LIST: {
int count;
break;
}
if (count < 0) {
break;
}
}
break;
}
case FCTIO_GET_ADAPTER_ATTRIBUTES: {
attr_length = sizeof (fc_tgt_hba_adapter_attributes_t);
break;
}
&fctio->fctio_errno);
break;
}
attr_length = sizeof (fc_tgt_hba_port_attributes_t);
break;
}
&fctio->fctio_errno);
break;
}
attr_length = sizeof (fc_tgt_hba_port_attributes_t);
break;
}
break;
}
case FCTIO_GET_PORT_ATTRIBUTES: {
attr_length = sizeof (fc_tgt_hba_port_attributes_t);
break;
}
&fctio->fctio_errno);
break;
}
case FCTIO_GET_ADAPTER_PORT_STATS: {
&fctio->fctio_errno);
break;
}
default:
break;
}
if (ret == 0) {
} else if (fctio->fctio_errno) {
}
if (obuf) {
}
if (abuf) {
}
if (ibuf) {
}
return (ret);
}
typedef struct {
void *bp; /* back pointer from internal struct to main struct */
int alloc_size;
} __ifct_t;
typedef struct {
void *cp; /* Caller private */
void *ss; /* struct specific */
} __fct_t;
static struct {
int shared;
int fw_private;
int struct_specific;
} fct_sizes[] = { { 0, 0, 0 },
GET_STRUCT_SIZE(fct_i_cmd_t), 0 },
GET_STRUCT_SIZE(__ifct_t), 0 }
};
void *
{
int fct_size;
int kmem_flag;
return (NULL);
} else {
}
if (struct_id == FCT_STRUCT_LOCAL_PORT) {
if (lport) {
} else {
return (NULL);
}
} else if (struct_id == FCT_STRUCT_DBUF_STORE) {
if (ds) {
} else {
return (NULL);
}
} else {
}
return (NULL);
if (struct_id == FCT_STRUCT_CMD_FCP_XCHG) {
} else if (struct_id == FCT_STRUCT_CMD_RCVD_ELS) {
} else if (struct_id == FCT_STRUCT_CMD_SOL_ELS) {
} else if (struct_id == FCT_STRUCT_CMD_RCVD_ABTS) {
} else if (struct_id == FCT_STRUCT_CMD_SOL_CT) {
}
return (sh);
}
void
{
if (struct_id == FCT_STRUCT_CMD_SOL_CT) {
if (ct->ct_req_alloc_size) {
}
if (ct->ct_resp_alloc_size) {
}
} else if ((struct_id == FCT_STRUCT_CMD_RCVD_ELS) ||
(struct_id == FCT_STRUCT_CMD_SOL_ELS)) {
if (els->els_req_alloc_size)
if (els->els_resp_alloc_size)
}
if (struct_id == FCT_STRUCT_LOCAL_PORT) {
} else if (struct_id == FCT_STRUCT_DBUF_STORE) {
} else {
}
}
{
}
void
{
}
static uint32_t taskq_cntr = 0;
{
int i;
char taskq_name[24];
if (port->port_default_alias) {
if (l < 16) {
} else {
iport->iport_alias =
}
} else {
}
taskq_name[23] = 0;
return (FCT_FAILURE);
}
/* Remote port mgmt */
sizeof (fct_i_remote_port_t *), KM_SLEEP);
/* fct_cmds for SCSI traffic */
iport->iport_cached_ncmds = 0;
/* Initialize cmd slots */
iport->iport_next_free_slot = 0;
for (i = 0; i < port->port_max_xchges; ) {
}
/* Start worker thread */
/* Wait for taskq to start */
delay(1);
}
goto fct_regport_fail1;
}
if (iport->iport_next)
return (FCT_SUCCESS);
/* Stop the taskq 1st */
delay(1);
}
}
if (iport->iport_rp_tb) {
sizeof (fct_i_remote_port_t *));
}
return (FCT_FAILURE);
}
{
int ndx;
return (FCT_FAILURE);
}
/* Stop the taskq 1st */
== 0) {
break;
}
}
if (ndx == 100) {
return (FCT_WORKER_STUCK);
}
}
goto fct_deregport_fail1;
}
if (iport->iport_next)
if (iport->iport_prev)
else
/*
* At this time, there should be no outstanding and pending
*/
}
sizeof (fct_cmd_slot_t));
sizeof (fct_i_remote_port_t *));
if (iport->iport_rp_tb) {
sizeof (fct_i_remote_port_t *));
}
return (FCT_SUCCESS);
/* Restart the worker */
/* Wait for taskq to start */
delay(1);
}
return (FCT_FAILURE);
}
/* ARGSUSED */
void
{
char info[80];
fct_i_event_t *e;
if (e == NULL) {
/*
* XXX Throw HBA fatal error event
*/
"fct_handle_event: iport-%p, allocation "
"of fct_i_event failed", (void *)iport);
info[79] = 0;
return;
}
/* Just queue the event */
e->event_type = event_id;
} else {
iport->iport_event_tail = e;
}
if (IS_WORKER_SLEEPING(iport))
}
/*
* Called with iport_lock held as reader.
*/
{
return (irp);
}
return (NULL);
}
/*
* Called with irp_lock held as writer.
*/
void
{
int hash_key =
iport->iport_nrps++;
}
/*
* Called with irp_lock and iport_lock held as writer.
*/
void
{
int hash_key =
break;
}
}
if (irp_next) {
} else {
}
iport->iport_nrps--;
}
}
int
{
int logging_out = 0;
logging_out = 0;
goto ilo_done;
}
logging_out = 0;
} else {
logging_out = 1;
}
goto ilo_done;
}
if (irp->irp_els_list) {
/* Last session affecting ELS should be a LOGO */
if (op == ELS_OP_LOGO) {
if (force_implicit) {
logging_out = 1;
else
logging_out = 0;
} else {
logging_out = 1;
}
} else if ((op == ELS_OP_PLOGI) ||
(op == ELS_OP_PRLI) ||
logging_out = 0;
}
}
}
ilo_done:;
return (logging_out);
}
/*
* The force_implicit flag enforces the implicit semantics which may be
* needed if a received logout got stuck e.g. a response to a received
* LOGO never came back from the FCA.
*/
int
{
int i = 0;
int nports = 0;
if (!iport->iport_nrps) {
return (nports);
}
for (i = 0; i < rportid_table_size; i++) {
while (irp) {
continue;
}
"fct_implictly_logo_all: cmd null");
return (nports);
}
nports++;
}
}
return (nports);
}
void
{
int i;
sizeof (fct_i_remote_port_t *), KM_SLEEP);
/* reconstruct the hash table */
iport->iport_nrps = 0;
for (i = 0; i < rportid_table_size; i++) {
irp = iport_rp_tb_tmp[i];
while (irp) {
}
}
sizeof (fct_i_remote_port_t *));
}
{
int i;
if (iport->iport_nrps_login)
return (0);
/* loop all rps to check if the cmd have already been drained */
for (i = 0; i < rportid_table_size; i++) {
while (irp) {
if (irp->irp_fcp_xchg_count ||
return (0);
}
}
return (1);
}
{
" was offline");
return (NULL);
}
if (rp_handle == FCT_HANDLE_NONE) {
"non existent port %x", rportid);
return (NULL);
}
} else {
"invalid port handle %x", rp_handle);
return (NULL);
}
}
return (NULL);
}
} else {
}
port->port_fca_fcp_cmd_size, 0);
"memory, port=%p", port);
return (NULL);
}
}
/*
* The accuracy of iport_max_active_ncmds is not important
*/
}
/* Lets get a slot */
if (cmd_slot == FCT_SLOT_EOL) {
cmd->cmd_handle = 0;
return (NULL);
}
return (cmd);
}
return (NULL);
}
void
{
}
void
{
irp_task >= 4) ||
irp_task >= 1) ||
}
return;
}
/* We dont need dbuf for other cmds */
if (dbuf) {
}
return;
}
return;
}
ASSERT(0);
}
/*
* This function bypasses fct_handle_els()
*/
void
{
/*
* An implicit LOGO can also be posted to a irp where a PLOGI might
* be in process. That PLOGI will reset this flag and decrement the
* iport_nrps_login counter.
*/
}
}
/*
* called with iport_lock held, return the slot number
*/
{
do {
if (cmd_slot == FCT_SLOT_EOL)
return (cmd_slot);
/*
* We use high order 16 bits as a counter which keeps on
* incrementing to avoid ABA issues with atomic lists.
*/
<< 24);
return (cmd_slot);
}
/*
* If icmd is not NULL, irp_lock must be held
*/
void
{
fct_i_cmd_t **p;
if (icmd) {
p = &((*p)->icmd_next));
*p = icmd;
}
/*
* CAUTION: do not grab local_port/remote_port locks after
* grabbing the worker lock.
*/
if (iport->iport_rpwe_tail) {
} else {
}
}
/*
* We need always signal the port worker irrespective of the fact that
* irp is already in discovery queue or not.
*/
if (IS_WORKER_SLEEPING(iport)) {
}
}
{
}
void
{
if (ioflags & FCT_IOF_FCA_DONE) {
do {
if (old & ICMD_BEING_ABORTED) {
return;
}
new &= ~ICMD_KNOWN_TO_FCA;
}
return;
}
{
}
void
{
if ((ioflags & FCT_IOF_FCA_DONE) == 0) {
/* Until we support confirmed completions, this is an error */
return;
}
do {
if (old & ICMD_BEING_ABORTED) {
return;
}
new &= ~ICMD_KNOWN_TO_FCA;
cmd->cmd_comp_status = s;
return;
}
return;
/* Tell the caller that we are done */
} else {
ASSERT(0);
}
}
void
{
char info[80];
int do_abts_acc = 0;
/* Give the slot back */
/*
* If anything went wrong, grab the lock as writer. This is
* probably unnecessary.
*/
} else {
}
do_abts_acc = 1;
}
/* XXX Validate slot before freeing */
slot->slot_uniq_cntr++;
do {
cmd->cmd_handle = 0;
irp = (fct_i_remote_port_t *)
else
}
/* for implicit cmd, no cmd slot is used */
irp = (fct_i_remote_port_t *)
else
}
}
if (do_abts_acc) {
/*
* XXX Throw HBA fatal error event
* Later shutdown svc will terminate the ABTS in the end
*/
"fct_cmd_free: iport-%p, ABTS_ACC"
" port_send_cmd_response failed", (void *)iport);
info[79] = 0;
return;
} else {
}
}
/* Free the cmd */
icmd->icmd_flags = 0;
} else {
}
} else {
}
}
/* ARGSUSED */
{
do {
if ((old & ICMD_KNOWN_TO_FCA) == 0)
return (STMF_NOT_FOUND);
}
return (ret);
}
void
{
(cmd == STMF_ACK_LPORT_ONLINE_COMPLETE) ||
(cmd == STMF_CMD_LPORT_OFFLINE) ||
(cmd == STMF_ACK_LPORT_OFFLINE_COMPLETE) ||
(cmd == FCT_CMD_PORT_ONLINE_COMPLETE) ||
(cmd == FCT_CMD_PORT_OFFLINE_COMPLETE));
/*
* We are mostly a passthrough, except during offline.
*/
switch (cmd) {
case STMF_CMD_LPORT_ONLINE:
&st);
break;
}
break;
iport->iport_state_not_acked = 0;
} else {
}
break;
iport->iport_state_not_acked = 0;
break;
case STMF_CMD_LPORT_OFFLINE:
&st);
break;
}
break;
iport->iport_state_not_acked = 0;
pst);
break;
}
/*
* If FCA's offline was successful, we dont tell stmf yet.
* Becasue now we have to do the cleanup before we go upto
* stmf. That cleanup is done by the worker thread.
*/
/* FCA is offline, post a link down, its harmless anyway */
/* Trigger port offline processing by the worker */
break;
iport->iport_state_not_acked = 0;
break;
}
}
/* ARGSUSED */
{
return (STMF_NOT_SUPPORTED);
}
/*
* implicit: if it's true, it means it will only be used in fct module, or else
* it will be sent to the link.
*/
{
if (!cmd) {
return (NULL);
}
if (rp) {
"fct_create_solels: Must PLOGI to %x first", wkdid);
return (NULL);
}
cmd->cmd_handle = 0;
if (irp) {
} else {
}
if (implicit) {
/*
* Since we will not send it to FCA, so we only allocate space
*/
if (elsop == ELS_OP_LOGO) {
/*
* Handling implicit LOGO should dependent on as less
* as resources. So a trick here.
*/
} else {
}
} else {
/*
* Allocate space for its request and response
* Fill the request payload according to spec.
*/
switch (elsop) {
case ELS_OP_LOGO:
break;
case ELS_OP_RSCN:
break;
case ELS_OP_PLOGI:
/*
* Common service parameters
*/
p[0x04] = 0x09; /* high version */
p[0x05] = 0x08; /* low version */
p[0x06] = 0x00; /* BB credit: 0x0065 */
p[0x07] = 0x65;
/* CI0: Continuously Increasing Offset - 1 */
/* RRO: Randomly Relative Offset - 0 */
/* VVV: Vendor Version Level - 0 */
/* N-F: N or F Port Payload Sender - 0 (N) */
/* BBM: BB Credit Management - 0 (Normal) */
p[0x08] = 0x80;
p[0x09] = 0x00;
/* Max RX size */
p[0x0A] = 0x08;
p[0x0B] = 0x00;
/* NPTCS: N Port Total Concurrent Sequences - 0x0000 */
p[0x0C] = 0x00;
p[0x0D] = 0x00;
/* ROIC: Relative Offset By Info - 0xFFFF */
p[0x0E] = 0xFF;
p[0x0F] = 0xFF;
/* EDTOV: Error Detect Timeout - 0x000007D0 */
p[0x10] = 0x00;
p[0x11] = 0x00;
p[0x12] = 0x07;
p[0x13] = 0xD0;
/*
* Class-3 Parameters
*/
/* C3-VAL: Class 3 Value - 1 */
/* C3-XID: X_ID Reassignment - 0 */
/* C3-IPA: Initial Process Assignment */
/* C3-AI-DCC: Data compression capable */
/* C3-AI-DC-HB: Data compression history buffer size */
/* C3-AI-DCE: Data encrytion capable */
/* C3-AI-CSC: Clock synchronization capable */
/* C3-ErrPol: Error pliciy */
/* C3-CatSeq: Information Cat. Per Sequence */
/* C3-AR-DCC: */
/* C3-AR-DC-HB: */
/* C3-AR-DCE: */
/* C3-AR-CSC */
p[0x44] = 0x80;
p[0x45] = 0x00;
p[0x46] = 0x00;
p[0x47] = 0x00;
p[0x48] = 0x00;
p[0x49] = 0x00;
/* C3-RxSize: Class 3 receive data size */
p[0x4A] = 0x08;
p[0x4B] = 0x00;
/* C3-ConSeq: Class 3 Concourrent sequences */
p[0x4C] = 0x00;
p[0x4D] = 0xFF;
/* C3-OSPE: Class 3 open sequence per exchange */
p[0x50] = 0x00;
p[0x51] = 0x01;
break;
case ELS_OP_SCR:
p[7] = FC_SCR_FULL_REGISTRATION;
break;
default:
ASSERT(0);
}
}
return (cmd);
}
{
int namelen = 0;
/*
* Allocate space
*/
if (!cmd) {
return (NULL);
}
/*
* We should have PLOGIed to the name server (0xFFFFFC)
* Caution: this irp is not query_rp->rp_fct_private.
*/
"fct_create_solct: Must PLOGI name server first");
return (NULL);
}
cmd->cmd_handle = 0;
switch (ctop) {
case NS_GSNN_NN:
/*
* Allocate max space for its sybolic name
*/
KM_SLEEP);
KM_SLEEP);
break;
case NS_RNN_ID:
KM_SLEEP);
KM_SLEEP);
/*
* Port Identifier
*/
/*
* Node Name
*/
break;
case NS_RCS_ID:
KM_SLEEP);
KM_SLEEP);
/*
* Port Identifier
*/
/*
* Class of Service
*/
*(p + 23) = FC_NS_CLASS3;
break;
case NS_RFT_ID:
KM_SLEEP);
KM_SLEEP);
/*
* Port Identifier
*/
/*
* FC-4 Protocol Types
*/
*(p + 22) = 0x1; /* 0x100 */
break;
case NS_RSPN_ID:
/*
* If we get here, port->port_sym_port_name is always not NULL.
*/
KM_SLEEP);
KM_SLEEP);
/*
* Port Identifier
*/
/*
* String length
*/
p[20] = namelen;
/*
* Symbolic port name
*/
break;
case NS_RSNN_NN:
KM_SLEEP);
KM_SLEEP);
/*
* Node name
*/
/*
* String length
*/
p[24] = namelen;
/*
* Symbolic node name
*/
break;
case NS_GSPN_ID:
KM_SLEEP);
KM_SLEEP);
/*
* Port Identifier
*/
break;
case NS_GCS_ID:
KM_SLEEP);
KM_SLEEP);
/*
* Port Identifier
*/
break;
case NS_GFT_ID:
KM_SLEEP);
KM_SLEEP);
/*
* Port Identifier
*/
break;
case NS_GID_PN:
KM_SLEEP);
KM_SLEEP);
break;
default:
/* CONSTCOND */
ASSERT(0);
}
return (cmd);
}
/*
* queue eventually too.
* We queue solicited cmds here to track solicited cmds and to take full use
* of single thread mechanism.
* But in current implmentation, we don't use this mechanism on SOL_CT, PLOGI.
* To avoid to interrupt current flow, ICMD_IN_SOLCMD_QUEUE is used here.
*/
void
{
if (IS_WORKER_SLEEPING(iport)) {
}
}
/* ARGSUSED */
void
{
switch (eventid) {
break;
default:
"Unknown event received, %d", eventid);
}
}
void
{
/* XXX For now just call send_resp_done() */
}
void
{
char info[160];
unsigned long long st;
st = s; /* To make gcc happy */
if ((((s != FCT_ABORT_SUCCESS) && (s != FCT_NOT_FOUND))) ||
((ioflags & FCT_IOF_FCA_DONE) == 0)) {
info[159] = 0;
return;
}
/* For non FCP Rest of the work is done by the terminator */
/* For FCP stuff just call stmf */
s, STMF_IOF_LPORT_DONE);
}
}
/*
* FCA drivers will use it, when they want to abort some FC transactions
* due to lack of resource.
*/
{
return (0xFFFF);
} else {
}
}
{
if (!CMD_HANDLE_VALID(fct_handle))
return (NULL);
return (NULL);
ndx];
return (NULL);
}
void
{
do {
return;
s, NULL);
}
void
{
uint8_t *p;
p = abts->abts_resp_payload;
bzero(p, 12);
p[10] = p[11] = 0xff;
}
void
{
char info[80];
int found = 0;
int i;
/* Make sure local port is sane */
return;
}
else
/* XXX Throw a logout to the initiator */
return;
}
/*
* No need to allocate an xchg resource. ABTSes use the same
* xchg resource as the cmd they are aborting.
*/
/* Lets find the command first */
for (i = 0; i < port->port_max_xchges; i++) {
continue;
continue;
if (!CMD_HANDLE_VALID(c->cmd_handle))
continue;
continue;
/* Found the command */
found = 1;
break;
}
if (!found) {
/* Dont even bother queueing it. Just respond */
/*
* XXX Throw HBA fatal error event
* Later shutdown svc will terminate the ABTS in the end
*/
"fct_handle_rcvd_abts: iport-%p, "
"ABTS_ACC port_send_cmd_response failed",
(void *)iport);
info[79] = 0;
} else {
}
return;
}
/* Check if this an abts retry */
/* Kill this abts. */
if (IS_WORKER_SLEEPING(iport))
return;
}
}
void
{
return;
}
if (IS_WORKER_SLEEPING(iport))
}
/*
* This function will not be called for SCSI CMDS
*/
void
fct_status_t s)
{
do {
if (old & ICMD_BEING_ABORTED)
return;
}
/*
* For those cmds, for which we called fca_abort but it has not yet completed,
* reset the FCA_ABORT_CALLED flag, so that abort can be called again.
* This is done after a FCA offline. The reason is that after offline, the
* firmware is not running so abort will never complete. But if we call it
* again, the FCA will detect that it is not offline and it will
* not call the firmware at all. Most likely it will abort in a synchronous
* manner i.e. return FCT_ABORT_SUCCESS or FCT_NOT_FOUND.
*/
void
{
int i, do_clear;
continue;
do {
if ((old & (ICMD_KNOWN_TO_FCA |
new &= ~ICMD_FCA_ABORT_CALLED;
do_clear = 1;
} else {
do_clear = 0;
break;
}
if (do_clear &&
}
}
}
/*
* Modify the irp_deregister_timer such that the ports start deregistering
* quickly.
*/
void
{
int i;
if (!iport->iport_nrps)
return;
for (i = 0; i < rportid_table_size; i++) {
while (irp) {
}
}
}
{
/* fct_ctl has already submitted a link offline event */
return (DISC_ACTION_DELAY_RESCAN);
}
return (DISC_ACTION_DELAY_RESCAN);
/*
* the port deregister process.
*/
return (DISC_ACTION_RESCAN);
}
if (iport->iport_solcmd_queue) {
return (DISC_ACTION_DELAY_RESCAN);
}
if (iport->iport_nrps) {
/*
* A port logout may have gone when implicit logo all
* was retried. So do the port speedup again here.
*/
return (DISC_ACTION_DELAY_RESCAN);
}
return (DISC_ACTION_DELAY_RESCAN);
}
return (DISC_ACTION_DELAY_RESCAN);
}
/* NOTREACHED */
return (0);
}
/*
* See stmf.h for information on rflags. Additional info is just a text
* description of the reason for this call. Additional_info can be NULL.
* Also the caller can declare additional info on the stack. stmf_ctl
* makes a copy of it before returning.
*/
char *additional_info)
{
}
char *additional_info)
{
}
/*
* Called by worker thread. The aim is to terminate the command
* using whatever means it takes.
* Called with worker lock held.
*/
{
char info[80];
int flags;
unsigned long long st;
/* Lets Limit each run to 20ms max. */
/* Start from where we left off last time */
if (iport->iport_ppicmd_term) {
} else {
}
/*
* Once a command gets on discovery queue, this is the only thread
* which can access it. So no need for the lock here.
*/
/* Always remember that cmd->cmd_rp can be NULL */
flags = 0;
else
if ((abort_ret != FCT_SUCCESS) &&
(abort_ret != FCT_ABORT_SUCCESS) &&
(abort_ret != FCT_NOT_FOUND)) {
if (flags & FCT_IOF_FORCE_FCA_DONE) {
/*
* XXX trigger port fatal,
* Abort the termination, and shutdown
* svc will trigger fct_cmd_termination
* again.
*/
"fct_cmd_terminator:"
" iport-%p, port_abort_cmd with "
"FORCE_FCA_DONE failed",
(void *)iport);
info[79] = 0;
(void) fct_port_shutdown(
return (DISC_ACTION_DELAY_RESCAN);
}
} else if ((flags & FCT_IOF_FORCE_FCA_DONE) ||
(abort_ret == FCT_ABORT_SUCCESS) ||
(abort_ret == FCT_NOT_FOUND)) {
}
cmd_implicit = 1;
}
fca_done = 1;
else
fca_done = 0;
fct_done = 1;
else
fct_done = 0;
/* Free the cmd */
if (IS_LOGO_ELS(icmd)) {
/* IMPLICIT LOGO is special */
}
}
/* Tell the caller that we are done */
if (fct_netbuf_to_value(
if (irp) {
}
}
} else {
ASSERT(0);
}
} else {
if (port->port_fca_abort_timeout)
else
/* 10 seconds by default */
if ((ddi_get_lbolt() >
/* timeout, reset the port */
char cmd_type[10];
sizeof (cmd_type), "%x.%x",
els->els_req_payload[0]);
sizeof (cmd_type), "%x.%02x%02x",
} else {
cmd_type[0] = 0;
}
" iport-%p, cmd_type(0x%s),"
st);
info[79] = 0;
(void) fct_port_shutdown(port,
info);
}
}
if (ddi_get_lbolt() > endtime) {
return (DISC_ACTION_DELAY_RESCAN);
}
}
if (iport->iport_abort_queue)
return (DISC_ACTION_DELAY_RESCAN);
if (ret == DISC_ACTION_NO_WORK)
return (DISC_ACTION_RESCAN);
return (ret);
}
/*
* Send a syslog event for adapter port level events.
*/
void
{
int port_instance;
if (!fct_dip)
return;
KM_SLEEP) != DDI_SUCCESS) {
goto alloc_failed;
}
!= DDI_SUCCESS) {
goto error;
}
goto error;
}
return;
"Unable to send %s event", subclass);
}
void
{
int port_instance;
if (!fct_dip)
return;
KM_SLEEP) != DDI_SUCCESS) {
goto alloc_failed;
}
!= DDI_SUCCESS) {
goto error;
}
goto error;
}
goto error;
}
rp_id) != DDI_SUCCESS) {
goto error;
}
return;
"Unable to send %s event", subclass);
}
{
do {
return (ret);
}
void
{
}
}