emlxs_fct.c revision e51761e09da808a4941f77a1197220eb1d664423
/*
* 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 Emulex. All rights reserved.
* Use is subject to License terms.
*/
#include <emlxs.h>
#ifdef SFCT_SUPPORT
/* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
#ifndef PORT_SPEED_10G
#define PORT_SPEED_10G 0x10
#endif /* PORT_SPEED_10G */
struct fct_flogi_xchg *fx);
#ifdef FCT_IO_TRACE
int emlxs_iotrace_cnt = 0;
void
{
int i;
if (!iop) {
return;
}
switch (data) {
/* New entry */
case EMLXS_FCT_SEND_ELS_REQ:
case EMLXS_FCT_SEND_CT_REQ:
for (i = 0; i < iotrace_cnt; i++) {
break;
iop++;
}
if (i < iotrace_cnt) {
/* New entry already exists */
"IOTRACE: New entry already exists: fct_cmd: %p",
fct_cmd);
return;
}
for (i = 0; i < iotrace_cnt; i++) {
break;
iop++;
}
if (i >= iotrace_cnt) {
/* No new slots available */
"IOTRACE: No new slots: fct_cmd: %p data: %d",
return;
}
port->iotrace_index++;
port->iotrace_index = 0;
return;
}
for (i = 0; i < iotrace_cnt; i++) {
break;
iop++;
}
if (i >= iotrace_cnt) {
/* Cannot find existing slot for fct_cmd */
if ((data != EMLXS_FCT_REG_PENDING) &&
(data != EMLXS_FCT_REG_COMPLETE)) {
"IOTRACE: Missing slot: fct_cmd: %p data: %d",
}
return;
}
/* trc overrun for fct_cmd */
"IOTRACE: trc overrun slot: fct_cmd: %p data: %d",
return;
}
/* xri mismatch for fct_cmd */
"IOTRACE: xri mismatch %x != %x: fct_cmd: %p data: %d",
return;
}
/* IOCB ulpCommand is saved after EMLXS_FCT_IOCB_ISSUED */
else
}
else
}
#endif /* FCT_IO_TRACE */
#ifdef MODSYM_SUPPORT
extern int
{
int err;
if (emlxs_modsym.mod_fct) {
return (1);
}
/* Comstar (fct) */
err = 0;
if (!emlxs_modsym.mod_fct) {
DRIVER_NAME, err);
goto failed;
}
/* Comstar (stmf) */
err = 0;
if (!emlxs_modsym.mod_stmf) {
DRIVER_NAME, err);
goto failed;
}
err = 0;
/* Check if the fct fct_alloc is present */
"fct_alloc", &err);
"?%s: drv/fct: fct_alloc not present", DRIVER_NAME);
goto failed;
}
err = 0;
/* Check if the fct fct_free is present */
"fct_free", &err);
"?%s: drv/fct: fct_free not present", DRIVER_NAME);
goto failed;
}
err = 0;
/* Check if the fct fct_scsi_task_alloc is present */
"fct_scsi_task_alloc", &err);
goto failed;
}
err = 0;
/* Check if the fct fct_register_local_port is present */
"fct_register_local_port", &err);
goto failed;
}
err = 0;
/* Check if the fct fct_deregister_local_port is present */
"fct_deregister_local_port", &err);
goto failed;
}
err = 0;
/* Check if the fct fct_handle_event is present */
&err);
goto failed;
}
err = 0;
/* Check if the fct fct_post_rcvd_cmd is present */
&err);
goto failed;
}
err = 0;
/* Check if the fct fct_alloc is present */
"fct_ctl", &err);
"?%s: drv/fct: fct_ctl not present", DRIVER_NAME);
goto failed;
}
err = 0;
/* Check if the fct fct_queue_cmd_for_termination is present */
"fct_queue_cmd_for_termination", &err);
goto failed;
}
err = 0;
/* Check if the fct fct_send_response_done is present */
"fct_send_response_done", &err);
goto failed;
}
err = 0;
/* Check if the fct fct_send_cmd_done is present */
&err);
goto failed;
}
err = 0;
/* Check if the fct fct_scsi_xfer_data_done is present */
"fct_scsi_data_xfer_done", &err);
goto failed;
}
err = 0;
/* Check if the fct fct_port_shutdown is present */
"fct_port_shutdown", &err);
goto failed;
}
err = 0;
/* Check if the fct fct_port_initialize is present */
"fct_port_initialize", &err);
goto failed;
}
err = 0;
/* Check if the fct fct_cmd_fca_aborted is present */
"fct_cmd_fca_aborted", &err);
goto failed;
}
err = 0;
/* Check if the fct fct_handle_rcvd_flogi is present */
"fct_handle_rcvd_flogi", &err);
goto failed;
}
/* Comstar (stmf) */
err = 0;
/* Check if the stmf stmf_alloc is present */
&err);
"?%s: drv/stmf: stmf_alloc not present", DRIVER_NAME);
goto failed;
}
err = 0;
/* Check if the stmf stmf_free is present */
"stmf_free", &err);
"?%s: drv/stmf: stmf_free not present", DRIVER_NAME);
goto failed;
}
err = 0;
/* Check if the stmf stmf_deregister_port_provider is present */
"stmf_deregister_port_provider", &err);
goto failed;
}
err = 0;
/* Check if the stmf stmf_register_port_provider is present */
"stmf_register_port_provider", &err);
goto failed;
}
return (1);
return (0);
} /* emlxs_fct_modopen() */
extern void
{
if (emlxs_modsym.mod_fct) {
emlxs_modsym.mod_fct = 0;
}
if (emlxs_modsym.mod_stmf) {
emlxs_modsym.mod_stmf = 0;
}
} /* emlxs_fct_modclose() */
#endif /* MODSYM_SUPPORT */
/* This routine is called to process a FLOGI ELS command that been recieved. */
static void
{
/*
* If FCT has been notified of a Link Up event, process the
* FLOGI now. Otherwise, defer processing till the Link Up happens.
*/
/* Setup for call to emlxs_els_reply() */
status =
#ifdef FCT_API_TRACE
#endif /* FCT_API_TRACE */
if (status == FCT_SUCCESS) {
ELS_CMD_ACC, ELS_CMD_FLOGI, 0, 0);
} else { /* ELS_OP_LSRJT */
}
} else {
"FLOGI: sid=%x. fct_handle_rcvd_flogi failed. "
"Rejecting.",
}
}
return;
} /* emlxs_fct_handle_rcvd_flogi() */
extern void
{
#ifdef FCT_API_TRACE
"fct_post_rcvd_cmd:4 %p: portid x%x", fct_cmd,
#endif /* FCT_API_TRACE */
return;
}
/* Online & Link up */
#ifdef FCT_API_TRACE
"fct_post_rcvd_cmd:1 %p: portid x%x", fct_cmd,
#endif /* FCT_API_TRACE */
} else { /* Online & Link down */
/*
* Defer processing of fct_cmd till later (after link up).
* Add buffer to queue tail
*/
if (port->fct_wait_tail) {
}
if (!port->fct_wait_head) {
}
}
return;
} /* emlxs_fct_unsol_callback() */
/* This is called at port online and offline */
static void
{
return;
}
/* Return if nothing to do */
if (!port->fct_wait_head) {
return;
}
/* First, see if there is an outstanding FLOGI to process */
/* Process Deferred FLOGI now */
} else {
}
}
/*
* Next process any outstanding ELS commands. It doesn't
* matter if the Link is up or not, always post them to FCT.
*/
while (cmd_sbp) {
"Completing fct_cmd: %p", fct_cmd);
#ifdef FCT_API_TRACE
"fct_post_rcvd_cmd:2 %p: portid x%x", fct_cmd,
#endif /* FCT_API_TRACE */
} /* while() */
return;
} /* emlxs_fct_unsol_flush() */
int
{
return (1);
}
return (0);
} /* emlxs_is_digit */
/*
* Convert an ASCII decimal numeric string to integer.
* Negation character '-' is not handled.
*/
{
int i = 0;
while (string[i]) {
if (!emlxs_is_digit(string[i])) {
return (num);
}
}
return (num);
} /* emlxs_str_atoi() */
static void
{
int i;
int bck;
int nbufs;
int maxbufs;
int size;
bck = 0;
for (i = 0; i < cnt; i++) {
if (datap == 0)
break;
datap++;
datap++;
datap++;
datap++;
/* Check for a bad entry */
size = 0;
nbufs = 0;
}
while (nbufs) {
/*
* We are not going to try to allocate a chunk
* of memory > FCT_DMEM_MAX_BUF_SEGMENT
* to accomidate the buffer pool of the
* requested size.
*/
bck++;
if (bck >= FCT_MAX_BUCKETS)
break;
} else {
bck++;
nbufs = 0;
}
}
if (bck >= FCT_MAX_BUCKETS) {
"fct-bufpool entry %d %d Exceeds available buckets",
break;
}
}
}
static void
{
char **arrayp;
char buf[32];
int status;
cnt = 0;
} else {
} else {
sizeof (port->dmem_bucket));
}
}
cnt = 0;
/*
* 0 means use HBA throttle for target queue depth,
* non-0 value is the actual target queue depth,
* default is EMLXS_FCT_DFLT_QDEPTH.
*/
(DDI_PROP_DONTPASS), "fct-queue-depth",
if (cnt == DDI_PROP_NOT_FOUND) {
}
}
#ifdef FCT_IO_TRACE
port->iotrace_index = 0;
if (cnt)
KM_SLEEP);
"FCT_ABORT_SUCCESS:%lx FCT_SUCCESS:%lx", FCT_ABORT_SUCCESS,
#endif /* FCT_IO_TRACE */
return;
} /* emlxs_fct_cfg_init() */
extern void
{
uint32_t i;
return;
}
/* Check if COMSTAR is present */
"Comstar not present. Target mode disabled.");
goto failed;
}
"Comstar present. Target mode enabled.");
#ifdef NPIV_SUPPORT
"enable-npiv: Not supported in target mode. Disabling.");
/* Temporary patch to disable npiv */
}
#endif /* NPIV_SUPPORT */
#ifdef DHCHAP_SUPPORT
"enable-auth: Not supported in target mode. Disabling.");
/* Temporary patch to disable auth */
}
#endif /* DHCHAP_SUPPORT */
return;
for (i = 0; i < MAX_VPORTS; i++) {
}
return;
} /* emlxs_fct_init() */
extern void
{
return;
}
/* Bind the physical port */
/* Bind virtual ports */
continue;
}
}
}
return;
} /* emlxs_fct_attach() */
extern void
{
uint32_t i;
for (i = 0; i < MAX_VPORTS; i++) {
continue;
}
}
}
#ifdef FCT_IO_TRACE
{
}
#endif /* FCT_IO_TRACE */
return;
} /* emlxs_fct_detach() */
extern void
{
char node_name[32];
return;
}
return;
}
/* Destroy & flush all port nodes, if they exist */
if (port->node_count) {
}
hba->num_of_ports--;
#ifdef FCT_API_TRACE
#endif /* FCT_API_TRACE */
#ifdef FCT_API_TRACE
#endif /* FCT_API_TRACE */
}
#ifdef FCT_API_TRACE
#endif /* FCT_API_TRACE */
}
if (port->port_provider) {
#ifdef FCT_API_TRACE
"stmf_deregister_port_provider:1 %p",
#endif /* FCT_API_TRACE */
#ifdef FCT_API_TRACE
#endif /* FCT_API_TRACE */
}
if (port->dmem_bucket) {
}
return;
} /* emlxs_fct_unbind_port() */
extern void
{
char node_name[32];
return;
}
return;
}
/* Perform generic port initialization */
} else {
}
"emlxs_fct_bind_port: Unable to allocate fct memory.");
goto failed;
}
flag |= 0x00000001;
#ifdef FCT_API_TRACE
#endif /* FCT_API_TRACE */
"emlxs_fct_bind_port: Unable to allocate port provider.");
goto failed;
}
flag |= 0x00000002;
#ifdef FCT_API_TRACE
#endif /* FCT_API_TRACE */
/* register port provider with framework */
STMF_SUCCESS) {
"emlxs_fct_bind_port: Unable to register port provider.");
goto failed;
}
flag |= 0x00000004;
0);
#ifdef FCT_API_TRACE
#endif /* FCT_API_TRACE */
"emlxs_fct_bind_port: Unable to allocate fct port.");
goto failed;
}
flag |= 0x00000008;
0);
#ifdef FCT_API_TRACE
#endif /* FCT_API_TRACE */
"emlxs_fct_bind_port: Unable to allocate dbuf store.");
goto failed;
}
flag |= 0x00000010;
NULL, 0) == DDI_FAILURE) {
"Unable to create SFCT device node.");
goto failed;
}
flag |= 0x00000020;
/* Intialize */
if ((port->fct_queue_depth) &&
} else {
}
#ifdef FCT_API_TRACE
"fct_register_local_port %p", fct_port);
#endif /* FCT_API_TRACE */
/* register this local port with the fct module */
"emlxs_fct_bind_port: Unable to register fct port.");
goto failed;
}
/* Set the bound flag */
hba->num_of_ports++;
return;
if (flag & 0x20) {
}
if (flag & 0x10) {
#ifdef FCT_API_TRACE
#endif /* FCT_API_TRACE */
}
if (flag & 0x8) {
#ifdef FCT_API_TRACE
#endif /* FCT_API_TRACE */
}
if (flag & 0x4) {
#ifdef FCT_API_TRACE
"stmf_deregister_port_provider:2 %p",
#endif /* FCT_API_TRACE */
}
if (flag & 0x2) {
#ifdef FCT_API_TRACE
#endif /* FCT_API_TRACE */
}
if (flag & 0x1) {
}
"Target mode disabled.");
return;
} /* emlxs_fct_bind_port() */
static void
{
}
}
}
}
}
"Port attr: model_description = %s",
"Port attr: hardware_version = %s",
"Port attr: option_rom_version = %s",
"Port attr: firmware_version = %s",
"Port attr: vendor_specific_id = 0x%x",
"Port attr: supported_cos = 0x%x",
"Port attr: supported_speed = 0x%x",
"Port attr: max_frame_size = 0x%x",
return;
} /* emlxs_populate_hba_details() */
/* ARGSUSED */
static void
{
switch (cmd) {
case FCT_CMD_PORT_ONLINE:
/* If the HBA is offline, we cannot bring the tgtport online */
break;
}
"STATE: ONLINE chk");
} else {
"STATE: OFFLINE --> ONLINE");
/* Try to bring the link up */
}
"STATE: ONLINE");
}
break;
case FCT_CMD_PORT_OFFLINE:
"STATE: OFFLINE chk");
} else {
"STATE: ONLINE --> OFFLINE");
/* Take link down and flush */
/* Declare this port offline now */
/* Take link down and hold it down */
(void) emlxs_reset_link(hba, 0);
"STATE: OFFLINE");
}
break;
"STATE: OFFLINE ack");
break;
"STATE: ONLINE ack");
break;
}
return;
} /* emlxs_fct_ctl() */
extern int
{
int i = 0;
if (!fct_port) {
return (0);
}
"emlxs shutdown");
i++;
if (i > 300) { /* 30 seconds */
"fct_port_shutdown failed to ACK");
break;
}
}
return (1);
}
extern int
{
int i = 0;
if (!fct_port) {
return (0);
}
"fct_port_initialize");
"emlxs initialize");
i++;
if (i > 300) { /* 30 seconds */
"fct_port_initialize failed to ACK");
break;
}
}
return (1);
}
static fct_status_t
{
#ifdef FCT_API_TRACE
#endif /* FCT_API_TRACE */
case FCT_CMD_SOL_ELS:
return (emlxs_fct_send_els_cmd(fct_cmd));
case FCT_CMD_SOL_CT:
return (emlxs_fct_send_ct_cmd(fct_cmd));
default:
"emlxs_fct_send_cmd: Invalid cmd type found. type=%x",
return (FCT_FAILURE);
}
} /* emlxs_fct_send_cmd() */
static fct_status_t
{
#ifdef FCT_API_TRACE
#endif /* FCT_API_TRACE */
case FCT_CMD_FCP_XCHG:
if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
goto failure;
}
return (rval);
case FCT_CMD_RCVD_ELS:
if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
goto failure;
}
return (emlxs_fct_send_els_rsp(fct_cmd));
default:
if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
fct_cmd->cmd_handle = 0;
}
"emlxs_fct_send_cmd_rsp: Invalid cmd type found. type=%x",
return (FCT_FAILURE);
}
"emlxs_fct_send_cmd_rsp: "
"Unable to handle FCT_IOF_FORCE_FCA_DONE. type=%x",
return (FCT_FAILURE);
} /* emlxs_fct_send_cmd_rsp() */
static fct_status_t
{
#ifdef FCT_API_TRACE
"emlxs_flogi_xchg: Sending FLOGI: %p", fct_port);
#else
"emlxs_flogi_xchg: Sending FLOGI.");
#endif /* FCT_API_TRACE */
"emlxs_flogi_xchg: FLOGI failed. Link down.");
return (FCT_FAILURE);
}
"emlxs_flogi_xchg: FLOGI failed. Unable allocate packet.");
return (FCT_FAILURE);
}
/* Make this a polled IO */
/* Build the fc header */
/* Build the command */
/* Service paramters will be added automatically later by the driver */
"emlxs_flogi_xchg: FLOGI failed. Unable to send packet.");
return (FCT_FAILURE);
}
return (FCT_TIMEOUT);
return (FCT_NOT_FOUND);
}
"emlxs_flogi_xchg: FLOGI failed. state=%x reason=%x",
return (FCT_FAILURE);
}
} else { /* FC_PKT_SUCCESS */
}
return (FCT_SUCCESS);
} /* emlxs_flogi_xchg() */
/* This is called right after we report that link has come online */
static fct_status_t
{
"emlxs_fct_get_link_info %p", fct_port);
return (FCT_SUCCESS);
}
} else {
}
case LA_1GHZ_LINK:
break;
case LA_2GHZ_LINK:
break;
case LA_4GHZ_LINK:
break;
case LA_8GHZ_LINK:
break;
case LA_10GHZ_LINK:
break;
default:
break;
}
link->port_no_fct_flogi = 0;
link->port_fca_flogi_done = 0;
link->port_fct_flogi_done = 0;
return (FCT_SUCCESS);
} /* emlxs_fct_get_link_info() */
static fct_status_t
{
#ifdef FCT_API_TRACE
"emlxs_fct_register_remote_port %p", fct_port);
#endif /* FCT_API_TRACE */
/* mutex_enter(&cmd_sbp->fct_mtx); */
} else {
}
}
/* Check for unsolicited PLOGI */
sizeof (uint32_t));
} else { /* Solicited PLOGI */
sizeof (SERV_PARM));
/*
* Create temporary WWN's from fct_cmd address
* This simply allows us to get an RPI from the
* adapter until we get real service params.
* The PLOGI ACC reply will trigger a REG_LOGIN
* update later
*/
}
"emlxs_fct_register_remote_port: Register did=%x. (%x,%p)",
/* Create a new node */
"emlxs_fct_register_remote_port: "
"Reg login failed. did=%x",
goto done;
}
/* Wait for completion */
pkt_ret = 0;
while ((pkt_ret != -1) &&
timeout);
}
return (FCT_FAILURE);
}
}
done:
if (ndlp) {
"emlxs_fct_register_remote_port: did=%x hdl=%x",
return (FCT_SUCCESS);
} else {
"emlxs_fct_register_remote_port: failed. did=%x hdl=%x",
return (FCT_FAILURE);
}
} /* emlxs_fct_register_remote_port() */
static fct_status_t
{
#ifdef FCT_API_TRACE
"emlxs_fct_deregister_remote_port: did=%x hdl=%x",
#else
"emlxs_fct_deregister_remote_port: did=%x hdl=%x",
#endif /* FCT_API_TRACE */
return (FCT_SUCCESS);
} /* emlxs_fct_deregister_remote_port() */
/* ARGSUSED */
extern int
{
if (!ndlp) {
"FCP rcvd: Unknown RPI. rpi=%x rxid=%x. Dropping...",
goto dropped;
}
"FCP rcvd: Target unbound. rpi=%x rxid=%x. Dropping...",
goto dropped;
}
"FCP rcvd: Target offline. rpi=%x rxid=%x. Dropping...",
goto dropped;
}
/* Get lun id */
}
fct_cmd =
lun, 16, 0);
#ifdef FCT_API_TRACE
"fct_scsi_task_alloc %p: FCP rcvd: "
"cmd=%x sid=%x rxid=%x lun=%02x%02x dl=%d",
#endif /* FCT_API_TRACE */
"FCP rcvd: sid=%x xid=%x. "
"Unable to allocate scsi task. Returning QFULL.",
goto dropped;
}
/* mutex_enter(&cmd_sbp->fct_mtx); */
/* Initialize fct_cmd */
/* Initialize cmd_sbp */
/* Set task_flags */
case SIMPLE_Q:
break;
case HEAD_OF_Q:
break;
case ORDERED_Q:
break;
case ACA_Q:
break;
case UNTAGGED:
break;
}
case 0:
break;
case 1:
break;
case 2:
break;
}
fct_task->task_priority = 0;
/* task_mgmt_function */
if (tm) {
} else {
}
}
/* Parallel buffers support - future */
fct_task->task_cur_nbufs = 0;
fct_task->task_cmd_seq_no = 0;
#ifdef FCT_API_TRACE
"fct_post_rcvd_cmd:3 %p: portid x%x", fct_cmd,
#endif /* FCT_API_TRACE */
return (0);
return (1);
} /* emlxs_fct_handle_unsol_req() */
/* ARGSUSED */
static fct_status_t
{
emlxs_port_t *port =
#ifdef FCT_API_TRACE
#endif /* FCT_API_TRACE */
#ifdef FCT_API_TRACE
#endif /* FCT_API_TRACE */
/* Initialize cmd_sbp */
/*
* This check is here because task_max_nbufs is set to 1.
* This ensures we will only have 1 outstanding call
* to this routine.
*/
"Adapter Busy. Processing IO. did=0x%x", did);
return (FCT_BUSY);
}
#ifdef FCT_API_TRACE
"emlxs_fct_send_fcp_data %p: flgs=%x ioflags=%x dl=%d,%d,%d",
#endif /* FCT_API_TRACE */
return (FCT_BUSY);
}
}
}
return (FCT_SUCCESS);
} /* emlxs_fct_send_fcp_data() */
static fct_status_t
{
emlxs_port_t *port =
/* Initialize cmd_sbp */
/* &cmd_sbp->fct_mtx should be already held */
size = 24;
if (fct_task->task_sense_length) {
}
#ifdef FCT_API_TRACE
"emlxs_fct_send_fcp_status %p: stat=%d resid=%d size=%d rx=%x",
#endif /* FCT_API_TRACE */
"emlxs_fct_send_fcp_status: Unable to allocate packet.");
return (FCT_BUSY);
}
pkt->pkt_timeout =
/* Build the fc header */
/* Build the status payload */
if (fct_task->task_resid) {
}
}
if (fct_task->task_scsi_status) {
} else {
}
/* Make sure residual reported on non-SCSI_GOOD READ status */
}
}
if (fct_task->task_sense_length) {
}
"emlxs_fct_send_fcp_status: Unable to send packet.");
}
return (FCT_BUSY);
}
return (FCT_SUCCESS);
} /* emlxs_fct_send_fcp_status() */
static fct_status_t
{
size = 24;
"emlxs_fct_send_qfull_reply: Unable to allocate packet.");
return (FCT_FAILURE);
}
pkt->pkt_timeout =
/* Build the fc header */
"emlxs_fct_send_qfull_reply: Sending QFULL: x%x lun x%x: %d %d",
/* Build the status payload */
"emlxs_fct_send_qfull_reply: Unable to send packet.");
return (FCT_FAILURE);
}
return (FCT_SUCCESS);
} /* emlxs_fct_send_qfull_reply() */
/* ARGSUSED */
extern int
{
if (!sbp) {
/* completion with missing xmit command */
/* emlxs_stray_fcp_completion_msg */
"FCP event cmd=%x status=%x error=%x iotag=%x",
return (1);
}
#ifdef FCT_API_TRACE
"emlxs_fct_handle_fcp_event: %p: cmd=%x status=%x", fct_cmd,
#endif /* FCT_API_TRACE */
/* For driver generated QFULL response */
}
return (0);
}
/* Validate fct_cmd */
goto done;
}
term_io = 0;
if (status) {
term_io = 1;
}
/* mutex_exit(&cmd_sbp->fct_mtx); */
goto done;
}
if (term_io) {
/*
* The error indicates this IO should be terminated
* immediately.
*/
#ifdef FCT_API_TRACE
"fct_queue_cmd_for_termination:1 %p: x%x",
#endif /* FCT_API_TRACE */
goto done;
}
switch (iocb->ulpCommand) {
/*
* FCP Data completion
*/
case CMD_FCP_TSEND_CX:
case CMD_FCP_TSEND64_CX:
case CMD_FCP_TRECEIVE_CX:
case CMD_FCP_TRECEIVE64_CX:
if (status == 0) {
}
fct_task =
fct_task->task_scsi_status = 0;
(void) emlxs_fct_send_fcp_status(fct_cmd);
break;
}
}
#ifdef FCT_API_TRACE
#endif /* FCT_API_TRACE */
break;
/* FCP Status completion */
case CMD_FCP_TRSP_CX:
case CMD_FCP_TRSP64_CX:
/* mutex_exit(&cmd_sbp->fct_mtx); */
#ifdef FCT_API_TRACE
"fct_scsi_data_xfer_done:2 %p %p",
#endif /* FCT_API_TRACE */
} else {
/* mutex_exit(&cmd_sbp->fct_mtx); */
#ifdef FCT_API_TRACE
"fct_send_response_done:1 %p: x%x",
#endif /* FCT_API_TRACE */
}
break;
default:
if (pkt) {
}
} /* switch(iocb->ulpCommand) */
done:
if (pkt) {
}
if (status == IOSTAT_SUCCESS) {
} else {
}
return (0);
} /* emlxs_fct_handle_fcp_event() */
/* ARGSUSED */
extern int
{
if (!sbp) {
/* completion with missing xmit command */
/* emlxs_stray_fcp_completion_msg */
"ABORT event cmd=%x status=%x error=%x iotag=%x",
return (1);
}
#ifdef FCT_API_TRACE
#endif /* FCT_API_TRACE */
if (pkt) {
}
return (0);
} /* emlxs_fct_handle_abort() */
extern int
{
"%s: sid=%x. Target unbound. Rejecting...",
goto done;
}
"%s: sid=%x. Target offline. Rejecting...",
goto done;
}
/* Process the request */
switch (cmd_code) {
case ELS_CMD_FLOGI:
rval =
if (!rval) {
/* Save the FLOGI exchange information */
sizeof (fct_flogi_xchg_t));
/* Try to handle the FLOGI now */
}
goto done;
case ELS_CMD_PLOGI:
rval =
break;
default:
rval = 0;
break;
}
if (rval) {
goto done;
}
#ifdef FCT_API_TRACE
{
"fct_alloc %p: ELS rcvd: rxid=%x payload: x%x x%x",
}
#endif /* FCT_API_TRACE */
"%s: sid=%x. Out of memory. Rejecting...",
goto done;
}
/* mutex_enter(&cmd_sbp->fct_mtx); */
/* Initialize fct_cmd */
/* Initialize cmd_sbp */
sizeof (emlxs_iocb_t));
done:
return (0);
} /* emlxs_fct_handle_unsol_els() */
/* ARGSUSED */
static uint32_t
{
char buffer[64];
buffer[0] = 0;
/* Perform processing of FLOGI payload */
return (1);
}
return (0);
} /* emlxs_fct_process_unsol_flogi() */
/* ARGSUSED */
static uint32_t
{
char buffer[64];
buffer[0] = 0;
/* Perform processing of PLOGI payload */
return (1);
}
return (0);
} /* emlxs_fct_process_unsol_plogi() */
/* ARGSUSED */
static emlxs_buf_t *
{
return (sbp);
} /* emlxs_fct_pkt_init() */
/* Mutex will be acquired */
static emlxs_buf_t *
{
return (cmd_sbp);
} /* emlxs_fct_cmd_init() */
/* Mutex must be held */
static int
{
/* Flags fct_cmd is no longer used */
return (FC_FAILURE);
}
"Pkt still registered! ringo=%d iotag=%d sbp=%p",
}
}
return (FC_SUCCESS);
} /* emlxs_fct_cmd_uninit() */
static void
{
#ifdef FMA_SUPPORT
#endif /* FMA_SUPPORT */
#ifdef FMA_SUPPORT
#endif /* FMA_SUPPORT */
}
/* mutex_exit(&cmd_sbp->fct_mtx); */
goto done;
}
case FCT_CMD_FCP_XCHG:
/*
* The error indicates this IO should be terminated
* immediately.
*/
#ifdef FCT_API_TRACE
"fct_queue_cmd_for_termination:2 %p: x%x",
#endif /* FCT_API_TRACE */
goto done;
}
/* mutex_exit(&cmd_sbp->fct_mtx); */
#ifdef FCT_API_TRACE
"fct_send_response_done:2 %p: x%x",
#else
"emlxs_fct_pkt_comp: fct_send_response_done. dbuf=%p",
#endif /* FCT_API_TRACE */
break;
case FCT_CMD_RCVD_ELS:
/* mutex_exit(&cmd_sbp->fct_mtx); */
#ifdef FCT_API_TRACE
"fct_send_response_done:3 %p: x%x",
#endif /* FCT_API_TRACE */
break;
case FCT_CMD_SOL_ELS:
if (fct_els->els_resp_payload) {
}
/* mutex_exit(&cmd_sbp->fct_mtx); */
#ifdef FCT_API_TRACE
"fct_send_cmd_done:1 %p: x%x",
#endif /* FCT_API_TRACE */
break;
case FCT_CMD_SOL_CT:
if (fct_ct->ct_resp_payload) {
}
/* mutex_exit(&cmd_sbp->fct_mtx); */
#ifdef FCT_API_TRACE
"fct_send_cmd_done:2 %p: x%x",
#endif /* FCT_API_TRACE */
break;
default:
"emlxs_fct_pkt_comp: Invalid cmd type found. type=%x",
}
done:
return;
} /* emlxs_fct_pkt_comp() */
static void
{
#ifdef FCT_API_TRACE
#endif /* FCT_API_TRACE */
return;
} /* emlxs_fct_abort_pkt_comp() */
static fct_status_t
{
emlxs_port_t *port =
"emlxs_fct_send_els_cmd: Unable to allocate packet.");
return (FCT_FAILURE);
}
/* mutex_enter(&cmd_sbp->fct_mtx); */
pkt->pkt_timeout =
"emlxs_fct_send_els_cmd: pkt_timeout=%d ratov=%d",
/* Build the fc header */
/* Copy the cmd payload */
"emlxs_fct_send_els_cmd: Unable to send packet.");
}
return (FCT_FAILURE);
}
return (FCT_SUCCESS);
} /* emlxs_fct_send_els_cmd() */
static fct_status_t
{
emlxs_port_t *port =
KM_NOSLEEP))) {
"emlxs_fct_send_els_rsp: Unable to allocate packet.");
return (FCT_FAILURE);
}
pkt->pkt_timeout =
/* Build the fc header */
/* Copy the resp payload to pkt_cmd buffer */
"emlxs_fct_send_els_rsp: Unable to send packet.");
}
return (FCT_FAILURE);
}
return (FCT_SUCCESS);
} /* emlxs_fct_send_els_rsp() */
static fct_status_t
{
emlxs_port_t *port =
"emlxs_fct_send_ct_cmd: Unable to allocate packet.");
return (FCT_FAILURE);
}
/* mutex_enter(&cmd_sbp->fct_mtx); */
pkt->pkt_timeout =
/* Build the fc header */
/* Copy the cmd payload */
"emlxs_fct_send_ct_cmd: Unable to send packet.");
}
return (FCT_FAILURE);
}
return (FCT_SUCCESS);
} /* emlxs_fct_send_ct_cmd() */
{
/* Check the transmit queue */
/* The IOCB could point to a cmd_sbp (no packet) or a sbp (packet) */
if (pkt) {
goto done;
}
} else {
}
if (pkt_flags & PACKET_IN_TXQ) {
/* Find it on the queue */
found = 0;
/* Search the priority queue */
while (next) {
/* Remove it */
if (prev) {
}
(void *)iocbq) {
(void *)prev;
}
(void *)iocbq) {
}
found = 1;
break;
}
}
} else {
/* Search the normal queue */
while (next) {
/* Remove it */
if (prev) {
}
(void *)iocbq) {
(void *)prev;
}
(void *)iocbq) {
}
found = 1;
break;
}
}
}
if (!found) {
goto done;
}
/* Check if node still needs servicing */
/*
* If this is the base node, don't shift the pointers
*/
/* We want to drain the base node before moving on */
/* Shift ring queue pointers to next node */
}
} else {
/* Remove node from ring queue */
/* If this is the last node on list */
} else {
/* Remove node from head */
}
/* Clear node */
}
/* The IOCB points to a cmd_sbp (no packet) or a sbp (packet) */
}
rval = 1;
if (pkt) {
}
return (rval);
}
done:
return (rval);
}
/* FCT_NOT_FOUND & FCT_ABORT_SUCCESS indicates IO is done */
/* FCT_SUCCESS indicates abort will occur asyncronously */
static fct_status_t
{
top:
/* Sanity check */
"emlxs_fct_abort: Invalid fct_cmd=%p.", fct_cmd);
return (FCT_NOT_FOUND);
}
"emlxs_fct_abort: Invalid cmd_sbp=%p.", cmd_sbp);
return (FCT_NOT_FOUND);
}
/*
* This code path handles a race condition if
* an IO completes, in emlxs_fct_handle_fcp_event(),
* and we get an abort at the same time.
*/
goto top;
}
/* At this point, we have entered the mutex */
"emlxs_fct_abort: Invalid cmd_sbp=%p.", cmd_sbp);
return (FCT_NOT_FOUND);
}
if (flags & FCT_IOF_FORCE_FCA_DONE) {
fct_cmd->cmd_handle = 0;
}
"emlxs_fct_abort: HbaLink %d. "
"xid=%x. cmd_sbp=%p state=%d flags=%x,%x,%x",
rval = FCT_SUCCESS;
/* If Abort is already in progress */
return (rval);
}
switch (state) {
case EMLXS_FCT_CMD_POSTED:
case EMLXS_FCT_SEND_ELS_RSP:
case EMLXS_FCT_SEND_ELS_REQ:
case EMLXS_FCT_SEND_CT_REQ:
case EMLXS_FCT_RSP_PENDING:
case EMLXS_FCT_REQ_PENDING:
case EMLXS_FCT_REG_PENDING:
case EMLXS_FCT_REG_COMPLETE:
case EMLXS_FCT_OWNED:
case EMLXS_FCT_SEND_FCP_DATA:
case EMLXS_FCT_DATA_PENDING:
case EMLXS_FCT_STATUS_PENDING:
case EMLXS_FCT_IOCB_ISSUED:
case EMLXS_FCT_IOCB_COMPLETE:
case EMLXS_FCT_PKT_COMPLETE:
case EMLXS_FCT_REQ_COMPLETE:
case EMLXS_FCT_ABORT_DONE:
case EMLXS_FCT_IO_DONE:
}
/* mutex_exit(&cmd_sbp->fct_mtx); */
return (rval);
}
if ((state == EMLXS_FCT_OWNED) ||
(state == EMLXS_FCT_CMD_POSTED)) {
}
/* mutex_exit(&cmd_sbp->fct_mtx); */
return (rval);
}
return (rval);
}
"emlxs_fct_abort: Unable to allocate packet.");
return (rval);
}
pkt->pkt_timeout =
/* Build the fc header */
/* Now disassociate the sbp / pkt from the fct_cmd */
"emlxs_fct_abort: ABORT: %p xri x%x",
} else {
"emlxs_fct_abort: CLOSE: %p xri x%x",
}
/*
* If there isn't an outstanding IO, indicate the fct_cmd
* is aborted now.
*/
if ((state == EMLXS_FCT_OWNED) ||
(state == EMLXS_FCT_CMD_POSTED)) {
}
/* mutex_exit(&cmd_sbp->fct_mtx); */
}
"emlxs_fct_abort: Unable to send packet.");
return (rval);
}
break;
case EMLXS_FCT_CMD_WAITQ:
case EMLXS_FCT_SEND_ABORT:
case EMLXS_FCT_CLOSE_PENDING:
case EMLXS_FCT_ABORT_PENDING:
case EMLXS_FCT_ABORT_COMPLETE:
default:
rval = FCT_FAILURE;
break;
} /* switch */
return (rval);
} /* emlxs_fct_abort() */
extern void
{
"emlxs_fct_link_up event.");
#ifdef FCT_API_TRACE
"fct_handle_event LINK_UP");
#endif /* FCT_API_TRACE */
0, 0);
} else {
/* Take link down and hold it down */
(void) emlxs_reset_link(hba, 0);
} else {
}
}
return;
} /* emlxs_fct_link_up() */
extern void
{
"emlxs_fct_link_down event.");
#ifdef FCT_API_TRACE
"fct_handle_event LINK_DOWN");
#endif /* FCT_API_TRACE */
0, 0);
} else {
}
return;
} /* emlxs_fct_link_down() */
/* DMA FUNCTIONS */
{
int32_t j;
int32_t i;
char buf[64];
p = port->dmem_bucket;
for (i = 0; i < FCT_MAX_BUCKETS; i++, p++) {
if (!p->dmem_nbufs) {
continue;
}
sizeof (emlxs_fct_dmem_bctl_t), KM_SLEEP);
"emlxs_fct_dmem_init: Unable to allocate bctl.");
goto alloc_bctl_failed;
}
p->dmem_bctls_mem = bctl;
"emlxs_fct_dmem_init: Unable to allocate handle.");
goto alloc_handle_failed;
}
&p->dmem_acc_handle) != DDI_SUCCESS) {
"emlxs_fct_dmem_init: Unable to allocate memory.");
goto mem_alloc_failed;
}
"emlxs_fct_dmem_init: Unable to bind handle.");
goto addr_bind_handle_failed;
}
if (ncookie != 1) {
"emlxs_fct_dmem_init: DMEM init failed.");
goto dmem_init_failed;
}
p->dmem_host_addr = addr;
p->dmem_dev_addr = dev_addr;
p->dmem_bctl_free_list = bctl;
p->dmem_nbufs_free = p->dmem_nbufs;
bsize = p->dmem_buf_size;
for (j = 0; j < p->dmem_nbufs; j++) {
#ifdef FCT_API_TRACE
"stmf_alloc data_buf %p", db);
#endif /* FCT_API_TRACE */
"emlxs_fct_dmem_init: alloc failed.");
goto dmem_init_failed;
}
bctl->bctl_bucket = p;
bctl++;
}
}
return (FCT_SUCCESS);
mutex_destroy(&p->dmem_lock);
while (bc) {
#ifdef FCT_API_TRACE
#endif /* FCT_API_TRACE */
}
(void) ddi_dma_unbind_handle(p->dmem_dma_handle);
(void) ddi_dma_mem_free(&p->dmem_acc_handle);
(void) ddi_dma_free_handle(&p->dmem_dma_handle);
p->dmem_nbufs * sizeof (emlxs_fct_dmem_bctl_t));
if (--i >= 0) {
p = &port->dmem_bucket[i];
bctl = p->dmem_bctl_free_list;
goto dmem_failure_loop;
}
return (FCT_FAILURE);
} /* emlxs_fct_dmem_init() */
void
{
uint32_t i;
p = port->dmem_bucket;
for (i = 0; i < FCT_MAX_BUCKETS; i++, p++) {
if (!p->dmem_nbufs) {
continue;
}
bctl = p->dmem_bctl_free_list;
while (bctl) {
#ifdef FCT_API_TRACE
#endif /* FCT_API_TRACE */
}
bctl = p->dmem_bctl_free_list;
(void) ddi_dma_unbind_handle(p->dmem_dma_handle);
(void) ddi_dma_mem_free(&p->dmem_acc_handle);
(void) ddi_dma_free_handle(&p->dmem_dma_handle);
(p->dmem_nbufs * sizeof (emlxs_fct_dmem_bctl_t)));
mutex_destroy(&p->dmem_lock);
}
return;
} /* emlxs_fct_dmem_fini() */
/* ARGSUSED */
static stmf_data_buf_t *
{
uint32_t i;
if (size > FCT_DMEM_MAX_BUF_SIZE) {
}
p = port->dmem_bucket;
for (i = 0; i < FCT_MAX_BUCKETS; i++, p++) {
if (!p->dmem_nbufs) {
continue;
}
if (p->dmem_buf_size >= size) {
mutex_enter(&p->dmem_lock);
if (p->dmem_nbufs_free) {
if (p->dmem_buf_size < *pminsize) {
*pminsize = p->dmem_buf_size;
"emlxs_fct_dbuf_alloc: Failed(1).");
mutex_exit(&p->dmem_lock);
return (NULL);
}
bctl = p->dmem_bctl_free_list;
mutex_exit(&p->dmem_lock);
continue;
}
p->dmem_nbufs_free--;
mutex_exit(&p->dmem_lock);
#ifdef FCT_API_TRACE
"emlx_fct_buf_alloc size %p: %d",
#endif /* FCT_API_TRACE */
}
mutex_exit(&p->dmem_lock);
"emlx_fct_buf_alloc size %d Nothing free bck %d",
size, i);
}
}
*pminsize = 0;
"emlxs_fct_dbuf_alloc: Failed(2).");
return (NULL);
} /* emlxs_fct_dbuf_alloc() */
/*ARGSUSED*/
static void
{
#ifdef FCT_API_TRACE
"emlx_fct_buf_free %p", dbuf);
#endif /* FCT_API_TRACE */
mutex_enter(&p->dmem_lock);
p->dmem_bctl_free_list = bctl;
p->dmem_nbufs_free++;
mutex_exit(&p->dmem_lock);
} /* emlxs_fct_dbuf_free() */
static void
{
(void) ddi_dma_sync(p->dmem_dma_handle,
} /* emlxs_fct_dbuf_dma_sync() */
#endif /* SFCT_SUPPORT */