socal.c revision 88b44bf4e73233af70877930178dbff7f1c2992b
/*
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
*/
/*
* socal - Serial Optical Channel Arbitrated Loop host adapter driver.
*/
#include <sys/autoconf.h>
#include <sys/ddi_impldefs.h>
#include <sys/ddidmareq.h>
#include <sys/dditypes.h>
#include <sys/ethernet.h>
#include <sys/socalreg.h>
#include <sys/socalmap.h>
#include <sys/socal_cq_defs.h>
#include <sys/socalvar.h>
/*
* Local Macros
*/
#ifdef DEBUG
#define SOCAL_DEBUG 1
#else
#define SOCAL_DEBUG 0
#endif
static int socal_core = SOCAL_TAKE_CORE;
#if SOCAL_DEBUG > 0 && !defined(lint)
static int soc_debug = SOCAL_DEBUG;
static int socal_read_stale_data = 0;
#else
#endif
/* defines for properties */
#define SOCAL_PORT_NO_PROP "socal_port"
#define SOCAL_ALT_PORT_NO_PROP "port#"
/* for socal_force_reset() */
#define RESET_PORT 1
#define DONT_RESET_PORT 0
/*
* Driver Entry points.
*/
ddi_ctl_enum_t op, void *a, void *v);
/*
* FC_AL transport functions.
*/
void (*)(), int, int, uint_t *);
void (*)(), void (*)(), void *);
static void socal_take_core(void *);
/*
* Driver internal functions.
*/
static void socal_lilp_map_done(fcal_packet_t *);
static void socal_force_lip_done(fcal_packet_t *);
static void socal_force_offline_done(fcal_packet_t *);
static void socal_abort_done(fcal_packet_t *);
static void socal_bypass_dev_done(fcal_packet_t *);
static void socal_packet_free(fcal_packet_t *);
static void socal_els_free(socal_priv_cmd_t *);
static void socal_lbf_free(socal_priv_cmd_t *);
static void socal_flush_overflowq(socal_state_t *, int, int);
static void socal_deferred_intr(void *);
/*
* SOC+ Circular Queue Management routines.
*/
fcal_sleep_t, fcal_packet_t *, int);
/*
* Utility functions
*/
/*
* Set this bit to enable 64-bit sus mode
*/
static int socal_64bitsbus = 1;
/*
* Default soc dma limits
*/
static ddi_dma_lim_t default_socallim = {
};
static struct ddi_dma_attr socal_dma_attr = {
DMA_ATTR_V0, /* version */
(unsigned long long)0, /* addr_lo */
(unsigned long long)0xffffffff, /* addr_hi */
(unsigned long long)0xffffffff, /* count max */
(unsigned long long)4, /* align */
1, /* minxfer */
(unsigned long long)0xffffffff, /* maxxfer */
(unsigned long long)0xffffffff, /* seg */
1, /* sgllen */
4, /* granularity */
0 /* flags */
};
static struct ddi_device_acc_attr socal_acc_attr = {
};
static struct fcal_transport_ops socal_transport_ops = {
};
/*
* Table used for setting the burst size in the soc+ config register
*/
static int socal_burst32_table[] = {
};
/*
* Table for setting the burst size for 64-bit sbus mode in soc+'s CR
*/
static int socal_burst64_table[] = {
(SOCAL_CR_BURST_8 << 8),
(SOCAL_CR_BURST_8 << 8),
(SOCAL_CR_BURST_8 << 8),
(SOCAL_CR_BURST_8 << 8),
(SOCAL_CR_BURST_8 << 8),
(SOCAL_CR_BURST_32 << 8),
(SOCAL_CR_BURST_64 << 8),
(SOCAL_CR_BURST_128 << 8)
};
/*
* Tables used to define the sizes of the Circular Queues
*
*/
static int socal_req_entries[] = {
SOCAL_SMALL_CQ_ENTRIES, /* Error (reset, lip) requests */
SOCAL_MAX_CQ_ENTRIES, /* Most commands */
0, /* Not currently used */
0 /* Not currently used */
};
static int socal_rsp_entries[] = {
SOCAL_MAX_CQ_ENTRIES, /* Solicited "SOC_OK" responses */
SOCAL_SMALL_CQ_ENTRIES, /* Solicited error responses */
0, /* Unsolicited responses */
0 /* Not currently used */
};
/*
* Bus ops vector
*/
static struct bus_ops socal_bus_ops = {
BUSO_REV, /* rev */
nullbusmap, /* int (*bus_map)() */
0, /* ddi_intrspec_t (*bus_get_intrspec)(); */
0, /* int (*bus_add_intrspec)(); */
0, /* void (*bus_remove_intrspec)(); */
i_ddi_map_fault, /* int (*bus_map_fault)() */
0, /* int (*bus_dma_map)() */
ddi_dma_mctl, /* int (*bus_dma_ctl)() */
socal_bus_ctl, /* int (*bus_ctl)() */
ddi_bus_prop_op, /* int (*bus_prop_op*)() */
};
static struct cb_ops socal_cb_ops = {
socal_open, /* int (*cb_open)() */
socal_close, /* int (*cb_close)() */
nodev, /* int (*cb_strategy)() */
nodev, /* int (*cb_print)() */
nodev, /* int (*cb_dump)() */
nodev, /* int (*cb_read)() */
nodev, /* int (*cb_write)() */
socal_ioctl, /* int (*cb_ioctl)() */
nodev, /* int (*cb_devmap)() */
nodev, /* int (*cb_mmap)() */
nodev, /* int (*cb_segmap)() */
nochpoll, /* int (*cb_chpoll)() */
ddi_prop_op, /* int (*cb_prop_op)() */
0, /* struct streamtab *cb_str */
CB_REV, /* rev */
nodev, /* int (*cb_aread)() */
nodev /* int (*cb_awrite)() */
};
/*
* Soc driver ops structure.
*/
DEVO_REV, /* devo_rev, */
0, /* refcnt */
socal_getinfo, /* get_dev_info */
nulldev, /* identify */
nulldev, /* probe */
socal_attach, /* attach */
socal_detach, /* detach */
nodev, /* reset */
&socal_cb_ops, /* driver operations */
&socal_bus_ops, /* bus operations */
NULL, /* power */
ddi_quiesce_not_supported, /* quiesce */
};
/*
* Driver private variables.
*/
static void *socal_soft_state_p = NULL;
static uchar_t socal_switch_to_alpa[] = {
0xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, 0xd9, 0xd6,
0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce, 0xcd, 0xcc, 0xcb, 0xca,
0xc9, 0xc7, 0xc6, 0xc5, 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5,
0xb4, 0xb3, 0xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9,
0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b, 0x98, 0x97,
0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7c, 0x7a, 0x79,
0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b,
0x6a, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56,
0x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a,
0x49, 0x47, 0x46, 0x45, 0x43, 0x3c, 0x3a, 0x39, 0x36, 0x35,
0x34, 0x33, 0x32, 0x31, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29,
0x27, 0x26, 0x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17,
0x10, 0x0f, 0x08, 0x04, 0x02, 0x01, 0x00
};
/*
* Firmware related externs
*/
extern uint32_t socal_ucode[];
extern size_t socal_ucode_size;
/*
* This is the loadable module wrapper: "module configuration section".
*/
extern struct mod_ops mod_driverops;
/*
* Module linkage information for the kernel.
*/
#define SOCAL_NAME "SOC+ FC-AL Host Adapter Driver"
static char socal_version[] = "1.62 08/19/2008";
&mod_driverops, /* Type of module. This one is a driver */
&socal_ops, /* driver ops */
};
static struct modlinkage modlinkage = {
};
/*
* This is the module initialization/completion routines
*/
#if !defined(lint)
static char socal_initmsg[] = "socal _init: socal.c\t1.62\t08/19/2008\n";
#endif
int
_init(void)
{
int stat;
/* Allocate soft state. */
sizeof (socal_state_t), SOCAL_INIT_ITEMS);
if (stat != 0)
return (stat);
/* Install the module */
if (stat != 0)
return (stat);
}
int
_fini(void)
{
int stat;
return (stat);
return (stat);
}
int
{
}
int
{
int instance;
struct ether_addr ourmacaddr;
char buf[MAXPATHLEN];
int y;
int i, j;
int burstsize;
short s;
int loop_id;
int rval;
cmd));
if (cmd == DDI_RESUME) {
return (DDI_FAILURE);
if (!socalp->socal_shutdown) {
/* our work is already done */
return (DDI_SUCCESS);
}
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
if (cmd != DDI_ATTACH) {
return (DDI_FAILURE);
}
instance);
return (DDI_FAILURE);
}
/* If we are in a slave-slot, then we can't be used. */
"socal%d attach failed: device in slave-only slot",
instance);
return (DDI_FAILURE);
}
if (ddi_intr_hilevel(dip, 0)) {
/*
* Interrupt number '0' is a high-level interrupt.
* At this point you either add a special interrupt
* handler that triggers a soft interrupt at a lower level,
* or - more simply and appropriately here - you just
* fail the attach.
*/
"socal%d attach failed: hilevel interrupt unsupported",
instance);
return (DDI_FAILURE);
}
/* Allocate soft state. */
!= DDI_SUCCESS) {
instance);
return (DDI_FAILURE);
}
instance));
/*
* Initialize the state structure.
*/
instance);
return (DDI_FAILURE);
}
/* Get the full path name for displaying error messages */
porta->sp_lilpmap_valid = 0;
portb->sp_lilpmap_valid = 0;
/*
* If an hard loop-id property is present, then the port is going
* to be used in target-mode so set the target-mode flag.
*/
"port0-loop-id", 127);
"port1-loop-id", 127);
/* Get out Node wwn and calculate port wwns */
sizeof (uint_t));
} else {
}
if (rval == DDI_SUCCESS)
for (i = 0; i < FC_WWN_SIZE; i++) {
}
sizeof (la_wwn_t));
sizeof (la_wwn_t));
for (i = 0; i < FC_WWN_SIZE; i++) {
}
"attach failed: unable to alloc xport struct");
goto fail;
}
"attach failed: unable to alloc xport struct");
goto fail;
}
instance));
/*
* Map the external ram and registers for SOC+.
* Note: Soc+ sbus host adapter provides 3 register definition
* but on-board Soc+'s may have only one register definition.
*/
/* Map XRAM */
!= DDI_SUCCESS) {
"attach failed: unable to map XRAM");
goto fail;
}
/* Map registers */
} else {
/* Map EEPROM */
DDI_SUCCESS) {
"attach failed: unable to map eeprom");
goto fail;
}
/* Map XRAM */
DDI_SUCCESS) {
"attach failed: unable to map XRAM");
goto fail;
}
/* Map registers */
DDI_SUCCESS) {
"attach failed: unable to map registers");
goto fail;
}
}
/*
* Check to see we really have a SOC+ Host Adapter card installed
*/
"attach failed: unable to access status register");
goto fail;
}
/* now that we have our registers mapped make sure soc+ reset */
/* try defacing a spot in XRAM */
0xdefaced) != DDI_SUCCESS) {
"attach failed: unable to write host adapter XRAM");
goto fail;
}
/* see if it stayed defaced */
(int32_t *)&y)
!= DDI_SUCCESS) {
"attach failed: unable to access host adapter XRAM");
goto fail;
}
#ifdef DEBUG
for (i = 0; i < 4; i++) {
}
#endif
if (y != 0xdefaced) {
goto fail;
}
/* Point to the SOC XRAM CQ Descriptor locations. */
KSTAT_FLAG_VIRTUAL)) == NULL) {
"unable to create kstats");
} else {
}
/*
* Install a dummy interrupt routine.
*/
if (ddi_add_intr(dip,
(uint_t)0,
"attach failed: unable to install interrupt handler");
goto fail;
}
/* initialize the interrupt mutex */
/* initialize the abort mutex */
"socal%d: attach: inited imr mutex, board mutex, board cv\n",
instance));
/* init the port mutexes */
instance));
/* get local copy of service params */
/*
* Initailize the FCAL transport interface.
*/
instance));
/*
* Allocate request and response queues and init their mutexs.
*/
for (i = 0; i < SOCAL_N_CQS; i++) {
goto fail;
}
}
/*
* Adjust the burst size we'll use.
*/
j = burstsize & BURSTSIZE_MASK;
for (i = 0; socal_burst32_table[i] != SOCAL_CR_BURST_64; i++)
if (!(j >>= 1)) break;
| socal_burst32_table[i];
if (socal_64bitsbus) {
DDI_SUCCESS) {
instance));
j = burstsize & BURSTSIZE_MASK;
for (i = 0; socal_burst64_table[i] !=
(SOCAL_CR_BURST_128 << 8); i++)
if (!(j >>= 1))
break;
}
}
/*
* Install the interrupt routine.
*/
if (ddi_add_intr(dip,
(uint_t)0,
"attach failed: unable to install interrupt handler");
goto fail;
}
goto fail;
goto fail;
goto fail;
return (DDI_SUCCESS);
fail:
/* Make sure soc reset */
/* let detach do the dirty work */
(void) socal_dodetach(dip);
return (DDI_FAILURE);
}
static int
{
int resp;
int i;
switch (cmd) {
case DDI_SUSPEND:
return (DDI_FAILURE);
/*
* If any of the ports are in target-mode, don't suspend
*/
for (i = 0; i < N_SOCAL_NPORTS; i++) {
return (DDI_FAILURE);
}
/* do not restart socal after reset */
return (DDI_SUCCESS);
case DDI_DETACH:
if (resp == DDI_SUCCESS)
return (resp);
default:
return (DDI_FAILURE);
}
}
static int
{
int i;
/* Get the soft state struct. */
return (DDI_FAILURE);
}
/*
* If somebody is still attached to us from above fail
* detach.
*/
if (socalp->socal_busy > 0) {
return (DDI_FAILURE);
}
/* mark socal_busy = -1 to disallow sftm attach */
/* Make sure soc+ reset */
/* remove soc+ interrupt */
"socal%d: detach: Removed SOC+ interrupt from ddi\n",
instance));
}
for (i = 0; i < N_SOCAL_NPORTS; i++) {
sizeof (fcal_transport_t));
}
}
/*
* Free request queues, if allocated
*/
for (i = 0; i < SOCAL_N_CQS; i++) {
/* Free the queues and destroy their mutexes. */
(void) ddi_dma_unbind_handle(socalp->
request[i].skc_dhandle);
}
}
(void) ddi_dma_unbind_handle(socalp->
response[i].skc_dhandle);
}
}
}
}
}
/*
* Free soc data buffer pool
*/
if (socalp->pool_dhandle) {
}
}
/* release register maps */
/* Unmap EEPROM */
}
/* Unmap XRAM */
}
/* Unmap registers */
}
return (DDI_SUCCESS);
}
int
void *a, void *v)
{
int port;
switch (op) {
case DDI_CTLOPS_REPORTDEV:
SOCAL_PORT_NO_PROP, -1);
}
/* log text identifying this driver (d) & its child (r) */
port);
break;
case DDI_CTLOPS_INITCHILD: {
char name[MAXNAMELEN];
return (DDI_FAILURE);
return (DDI_NOT_WELL_FORMED);
}
}
(PORT_CHILD_INIT | PORT_TARGET_MODE)) {
return (DDI_FAILURE);
}
socalp->socal_busy++;
break;
}
case DDI_CTLOPS_UNINITCHILD: {
return (DDI_NOT_WELL_FORMED);
}
}
socalp->socal_busy--;
break;
}
case DDI_CTLOPS_IOMIN: {
int val;
val = *((int *)v);
/*
* The 'arg' value of nonzero indicates 'streaming' mode.
* If in streaming mode, pick the largest of our burstsizes
* available and say that that is our minimum value (modulo
* what minxfer is).
*/
if ((int)(uintptr_t)a) {
} else {
}
*((int *)v) = val;
}
/*
* These ops are not available on this nexus.
*/
case DDI_CTLOPS_DMAPMAPC:
case DDI_CTLOPS_REGSIZE:
case DDI_CTLOPS_NREGS:
case DDI_CTLOPS_AFFINITY:
case DDI_CTLOPS_SIDDEV:
case DDI_CTLOPS_POKE:
case DDI_CTLOPS_PEEK:
return (DDI_FAILURE);
case DDI_CTLOPS_SLAVEONLY:
case DDI_CTLOPS_REPORTINT:
default:
/*
* Remaining requests get passed up to our parent
*/
}
return (DDI_SUCCESS);
}
/*ARGSUSED*/
/*
* int
* socal_getinfo() - Given the device number, return the devinfo
* pointer or the instance number. Note: this routine must be
* successful on DDI_INFO_DEVT2INSTANCE even before attach.
*/
int
void **result)
{
int instance;
switch (cmd) {
case DDI_INFO_DEVT2DEVINFO:
if (socalp)
else
break;
case DDI_INFO_DEVT2INSTANCE:
break;
default:
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*ARGSUSED*/
int
{
int port;
return (ENXIO);
return (0);
}
/*ARGSUSED*/
int
{
int port;
return (0);
}
/*ARGSUSED*/
int
{
int port;
int i;
uint_t r;
int offset;
int retval = FCAL_SUCCESS;
struct socal_fm_version ver;
#ifdef _MULTI_DATAMODEL
struct socal_fm_version32 {
} ver32;
#endif
return (ENXIO);
switch (cmd) {
case FCIO_FCODE_MCODE_VERSION:
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32:
dm32 = 1;
mode) == -1)
return (EFAULT);
break;
case DDI_MODEL_NONE:
mode) == -1)
return (EFAULT);
}
#else /* _MULTI_DATAMODEL */
return (EFAULT);
#endif /* _MULTI_DATAMODEL */
&i) != DDI_PROP_SUCCESS)
return (EIO);
if (i < ver.fcode_ver_len)
ver.fcode_ver_len = i;
mode) == -1) {
return (EFAULT);
}
if (socalp->socal_eeprom) {
for (i = 0; i < SOCAL_N_CQS; i++) {
}
for (i = SOCAL_N_CQS-1; i >= 0; i--) {
}
return (EFAULT);
} else {
ver.prom_ver_len = 0;
}
ver.mcode_ver_len = 0;
#ifdef _MULTI_DATAMODEL
if (dm32) {
mode) == -1)
return (EFAULT);
} else
#endif /* _MULTI_DATAMODEL */
return (EFAULT);
break;
case FCIO_LOADUCODE:
== -1)
return (EFAULT);
/* restart socal after resetting */
(void) socal_force_reset((void *)socalp, 0,
break;
case FCIO_DUMPXRAM:
for (i = 0; i < SOCAL_N_CQS; i++) {
}
for (i = 0; i < 4; i++) {
}
for (i = SOCAL_N_CQS-1; i >= 0; i--) {
}
break;
#ifdef DEBUG
case FCIO_DUMPXRAMBUF:
0x40000);
break;
#endif
case FCIO_GETMAP:
-1)
break;
case FCIO_BYPASS_DEV:
break;
case FCIO_FORCE_LIP:
break;
case FCIO_FORCE_OFFLINE:
break;
case FCIO_ADISC_ELS:
{
if ((adisc_pl =
sizeof (la_els_adisc_t),
KM_NOSLEEP)) == NULL)
return (ENOMEM);
sizeof (la_els_adisc_t)) == -1) {
sizeof (la_els_adisc_t));
return (EFAULT);
}
adisc_pl, 0);
if (retval == FCAL_SUCCESS) {
sizeof (la_els_adisc_t)) == -1) {
sizeof (la_els_adisc_t));
return (EFAULT);
}
}
break;
}
case FCIO_LINKSTATUS:
{
int dest;
if ((rls_pl =
kmem_zalloc(sizeof (la_els_rls_reply_t),
KM_NOSLEEP)) == NULL)
return (ENOMEM);
sizeof (la_els_rls_reply_t)) == -1) {
sizeof (la_els_rls_reply_t));
return (EFAULT);
}
rls_pl, 0);
if (retval == FCAL_SUCCESS) {
sizeof (la_els_rls_reply_t)) == -1) {
sizeof (la_els_rls_reply_t));
return (EFAULT);
}
}
break;
}
case FCIO_LOOPBACK_INTERNAL:
/*
* If userland doesn't provide a location for a return
* value the driver will permanently offline the port,
* ignoring any checks for devices on the loop.
*/
if (arg == 0) {
/* Already disabled */
return (EALREADY);
}
}
if (arg == 0) break;
== -1)
return (EFAULT);
break;
case FCIO_LOOPBACK_MANUAL:
return (EBUSY);
}
== -1)
return (EFAULT);
break;
case FCIO_NO_LOOPBACK:
/* Do not allow online if we're disabled */
if (arg != 0) {
/*
* It's permanently disabled -- Need to
* enable it first
*/
return (EBUSY);
}
/* This was a request to online. */
}
if (arg == 0) break;
== -1)
return (EFAULT);
break;
case FCIO_DIAG_NOP:
== -1)
return (EFAULT);
break;
case FCIO_DIAG_XRAM:
== -1)
return (EFAULT);
break;
case FCIO_DIAG_SOC:
== -1)
return (EFAULT);
break;
case FCIO_DIAG_HCB:
== -1)
return (EFAULT);
break;
case FCIO_DIAG_SOCLB:
== -1)
return (EFAULT);
break;
case FCIO_DIAG_SRDSLB:
== -1)
return (EFAULT);
break;
case FCIO_DIAG_EXTLB:
== -1)
return (EFAULT);
break;
case FCIO_DIAG_RAW:
== -1)
return (EFAULT);
(uint_t)i);
== -1)
return (EFAULT);
break;
case FCIO_LOOPBACK_FRAME:
KM_NOSLEEP)) == NULL)
return (ENOMEM);
return (EFAULT);
}
if ((flb_pl =
return (ENOMEM);
return (EFAULT);
}
flb_size, 1);
if (retval == FCAL_SUCCESS) {
return (EFAULT);
}
}
break;
default:
return (ENOTTY);
}
switch (retval) {
case FCAL_SUCCESS:
return (0);
case FCAL_ALLOC_FAILED:
return (ENOMEM);
case FCAL_STATUS_DIAG_BUSY:
return (EALREADY);
case FCAL_STATUS_DIAG_INVALID:
return (EINVAL);
default:
return (EIO);
}
}
/*
* Function name : socal_disable()
*
* Return Values : none
*
* Description : Reset the soc+
*
* Context : Can be called from different kernel process threads.
* Can be called by interrupt thread.
*
* Note: before calling this, the interface should be locked down
* so that it is guaranteed that no other threads are accessing
* the hardware.
*/
static void
{
#if !defined(lint)
int i;
#endif
/* Don't touch the hardware if the registers aren't mapped */
return;
#if !defined(lint)
#endif
}
/*
* Function name : socal_init_transport_interface()
*
* Return Values : none
*
* Description : Fill up the fcal_tranpsort struct for ULPs
*
*
* Note: Only called during attach, so no protection
*/
static void
{
int i;
for (i = 0; i < N_SOCAL_NPORTS; i++) {
xport->fcal_portno = i;
}
}
/*
* static int
* socal_cqalloc_init() - Inialize the circular queue tables.
* Also, init the locks that are associated with the tables.
*
* Returns: FCAL_SUCCESS, if able to init properly.
* FCAL_FAILURE, if unable to init properly.
*/
static int
{
/*
* Initialize the Request and Response Queue locks.
*/
/* Allocate DVMA resources for the Request Queue. */
if (cq_size) {
"!alloc of dma handle failed");
goto fail;
}
"!alloc of dma space failed");
goto fail;
}
"!alloc of dma space failed");
goto fail;
}
"!bind of dma handle failed");
goto fail;
}
req_bound = 1;
if (ccount != 1) {
"!bind of dma handle failed");
goto fail;
}
} else {
}
/* Allocate DVMA resources for the response Queue. */
if (cq_size) {
"!alloc of dma handle failed");
goto fail;
}
"!alloc of dma space failed");
goto fail;
}
"!alloc of dma space failed");
goto fail;
}
"!bind of dma handle failed");
goto fail;
}
rsp_bound = 1;
if (ccount != 1) {
"!bind of dma handle failed");
goto fail;
}
} else {
}
/*
* Initialize the queue pointers
*/
return (FCAL_SUCCESS);
fail:
if (req_bound)
(void) ddi_dma_unbind_handle(socalp->
}
if (rsp_bound)
(void) ddi_dma_unbind_handle(socalp->
}
return (FCAL_FAILURE);
}
/*
* socal_cqinit() - initializes the driver's circular queue pointers, etc.
*/
static void
{
/*
* Initialize the Request and Response Queue pointers
*/
/* Clear out memory we have allocated */
}
static int
{
uint_t r;
if (!socalp)
return (FCAL_FAILURE);
/* Make sure disabled ports stay disabled. */
(void) socal_diag_request((void *)socalp, 0, &r,
socalp->socal_shutdown = 0;
return (FCAL_FAILURE);
}
return (FCAL_FAILURE);
}
return (FCAL_SUCCESS);
}
static void
{
int i;
for (i = 0; i < SOCAL_N_CQS; i++) {
}
if (socalp->pool_dhandle) {
}
for (i = 0; i < SOCAL_N_CQS; i++)
socal_cqinit(socalp, i);
for (i = 0; i < N_SOCAL_NPORTS; i++) {
}
for (i = SOCAL_N_CQS-1; i >= 0; i--) {
}
for (i = 0; i < N_SOCAL_NPORTS; i++) {
}
for (i = 0; i < SOCAL_N_CQS; i++) {
}
for (i = 0; i < SOCAL_N_CQS; i++) {
}
for (i = SOCAL_N_CQS-1; i >= 0; i--) {
}
}
/*
* Function name : socal_download_ucode ()
*
* Return Values :
*
* Description : Copies firmware from code that has been linked into
* the socal module into the soc+'s XRAM. Prints the date
* string
*
*/
static void
{
auto char buf[256];
/* Copy the firmware image */
socal_fix_harda(socalp, 0);
/* Get the date string from the firmware image */
"!Downloading host adapter, fw date code: %s\n",
(char *)date_str);
} else {
"!Downloading host adapter fw, "
"date code: <not available>\n");
"<Not Available>");
}
}
/*
* Function name : socal_disp_err()
*
* Return Values : none
*
* Description : displays an error message on the system console
* with the full device pathname displayed
*/
static void
char *mid,
char *msg)
{
char c;
int instance;
c = *msg;
if (c == '!') /* log only */
else if (c == '?') /* boot message - log && maybe console */
else if (c == '^') /* console only */
else { /* log and console */
}
}
/*
* Function name : socal_init_cq_desc()
*
* Return Values : none
*
* Description : Initializes the request and response queue
* descriptors in the SOC+'s XRAM
*
* Context : Should only be called during initialiation when
* the SOC+ is reset.
*/
static void
{
uint32_t i;
/*
* Finish CQ table initialization and give the descriptor
* table to the soc+. Note that we don't use all of the queues
* provided by the hardware, but we make sure we initialize the
* quantities in the unused fields in the hardware to zeroes.
*/
/*
* Do request queues
*/
for (i = 0; i < SOCAL_N_CQS; i++) {
if (socal_req_entries[i]) {
que_desc[i].cq_address =
} else {
que_desc[i].cq_last_index = 0;
}
}
/* copy to XRAM */
SOCAL_N_CQS * sizeof (soc_cq_t));
/*
* Do response queues
*/
for (i = 0; i < SOCAL_N_CQS; i++) {
if (socal_rsp_entries[i]) {
que_desc[i].cq_address =
} else {
que_desc[i].cq_address = 0;
que_desc[i].cq_last_index = 0;
}
}
/* copy to XRAM */
SOCAL_N_CQS * sizeof (soc_cq_t));
}
static void
{
/* copy the node wwn to xram */
SOCAL_XRAM_NODE_WWN), sizeof (la_wwn_t));
/* copy port a's wwn to xram */
sizeof (la_wwn_t));
/* copy port b's wwn to xram */
sizeof (la_wwn_t));
/*
* need to avoid deadlock by assuring no other thread grabs both of
* these at once
*/
}
static void
{
}
/*
* static int
* socal_establish_pool() - this routine tells the SOC+ of a buffer pool
* to place LINK ctl application data as it arrives.
*
* Returns:
* FCAL_SUCCESS, upon establishing the pool.
* FCAL_FAILURE, if unable to establish the pool.
*/
static int
{
int result;
if ((prq =
KM_NOSLEEP)) == NULL)
return (FCAL_FAILURE);
/*
* Fill in the request structure.
*/
prq->spr_n_entries = 0;
/* Enque the request. */
FCAL_NOSLEEP, NULL, 0);
return (result);
}
/*
* static int
* soc_add_pool_buffer() - this routine tells the SOC+ to add one buffer
* to an established pool of buffers
*
* Returns:
* DDI_SUCCESS, upon establishing the pool.
* DDI_FAILURE, if unable to establish the pool.
*/
static int
{
int result;
int bound = 0;
if ((drq =
KM_NOSLEEP)) == NULL)
return (FCAL_FAILURE);
/* Allocate DVMA resources for the buffer pool */
goto fail;
!= DDI_SUCCESS)
goto fail;
if (real_len < SOCAL_POOL_SIZE)
goto fail;
goto fail;
bound = 1;
if (ccount != 1)
goto fail;
/*
* Fill in the request structure.
*/
/* Transport the request. */
FCAL_NOSLEEP, NULL, 0);
return (result);
fail:
"!Buffer pool DVMA alloc failed");
if (socalp->pool_dhandle) {
if (bound)
}
return (FCAL_FAILURE);
}
static uint_t
{
#endif
int port;
port = 1;
else
port = 0;
fcalpkt->fcal_cmd_state = 0;
}
/*
* Function name : socal_cq_enque()
*
* Return Values :
* FCAL_TRANSPORT_SUCCESS, if able to que the entry.
* FCAL_TRANSPORT_QFULL, if queue full & sleep not set
* FCAL_TRANSPORT_UNAVAIL if this port down
*
* Description : Enqueues an entry into the solicited request
* queue
*
* Context :
*/
/*ARGSUSED*/
static int
int mtxheld)
{
#endif
longlong_t *p, *q;
p = (longlong_t *)cqe;
/*
* Since we're only reading we don't need a mutex.
*/
if (socalp->socal_shutdown) {
return (FCAL_TRANSPORT_UNAVAIL);
}
/*
* Get a token early. That way we won't sleep
* in id32_alloc() with a mutex held.
*/
if (to_queue) {
return (FCAL_TRANSPORT_QFULL);
}
}
/*
* Grab lock for request queue.
*/
if (!mtxheld)
/*
* Determine if the queue is full
*/
do {
/*
* If soc's queue full, then we wait for an interrupt
* telling us we are not full.
*/
if (to_queue) {
if (!kcq->skc_overflowh) {
"socal%d: cq_enque: request "
"que %d is full\n",
} else
if (!mtxheld)
return (FCAL_TRANSPORT_SUCCESS);
}
if (!mtxheld)
return (FCAL_TRANSPORT_QFULL);
}
/*
* get SOC+'s copy of out to update our copy of out
*/
s_out =
"socal%d: cq_enque: &XRAM cq_in: 0x%p s_out.out 0x%x\n",
/* if soc+'s que still full set flag */
}
/* Now enque the entry. */
/* Give the entry to the SOC. */
q = (longlong_t *)sp;
*q++ = *p++;
*q++ = *p++;
*q++ = *p++;
*q++ = *p++;
*q++ = *p++;
*q++ = *p++;
*q++ = *p++;
*q = *p;
if (to_queue)
/*
* Update circular queue and ring SOC's doorbell.
*/
}
/* Let lock go for request queue. */
if (!mtxheld)
return (FCAL_TRANSPORT_SUCCESS);
}
static uint_t
{
int port;
/* make the timeout meaningful */
port = 1;
else
port = 0;
fcalpkt->fcal_cmd_state = 0;
ticker = ddi_get_lbolt();
return (retval);
} else {
t = ddi_get_lbolt();
return (FCAL_TRANSPORT_TIMEOUT);
}
}
}
return (FCAL_TRANSPORT_SUCCESS);
}
static uint_t
{
if (polled) {
} else {
CQ_REQUEST_0)) == FCAL_TRANSPORT_SUCCESS) {
lb = ddi_get_lbolt();
break;
}
}
}
}
switch (status) {
case FCAL_TRANSPORT_SUCCESS:
if (diagcode)
switch (status) {
case FCAL_STATUS_ABORT_FAILED:
if (flag == PORT_ABORT_PENDING)
break;
case FCAL_STATUS_OK:
if (flag == PORT_ABORT_PENDING)
else
break;
case FCAL_STATUS_OLD_PORT:
break;
case FCAL_STATUS_ERR_OFFLINE:
break;
case FCAL_STATUS_ABORTED:
break;
case FCAL_STATUS_BAD_XID:
break;
case FCAL_STATUS_BAD_DID:
break;
case FCAL_STATUS_DIAG_BUSY:
case FCAL_STATUS_DIAG_INVALID:
break;
default:
}
break;
case FCAL_TRANSPORT_TIMEOUT:
if (flag == PORT_LIP_PENDING ||
flag == PORT_LILP_PENDING) {
if (socal_core &&
(socal_core & SOCAL_FAILED_LIP)) {
socal_core = 0;
}
"SOCAL:Forcing SOC+ reset as LIP timed out\n");
/* restart socal after resetting */
polled, RESET_PORT);
}
else
break;
case FCAL_TRANSPORT_FAILURE:
case FCAL_BAD_PACKET:
case FCAL_TRANSPORT_UNAVAIL:
case FCAL_TRANSPORT_QFULL:
break;
default:
}
return (retval);
}
static uint_t
{
if ((fcalpkt =
== (fcal_packet_t *)NULL)
return (FCAL_ALLOC_FAILED);
if (port)
}
static uint_t
{
if (lip_req == FCAL_NO_LIP) {
return (FCAL_SUCCESS);
} else
}
if ((fcalpkt =
== (fcal_packet_t *)NULL)
return (FCAL_ALLOC_FAILED);
if (port)
}
static uint_t
{
else {
}
return (FCAL_ABORTED);
} else {
}
}
if ((fcalpkt2 =
== (fcal_packet_t *)NULL)
return (FCAL_ALLOC_FAILED);
/* Too late? */
return (FCAL_ABORTED);
/* I lied. So shoot me. */
}
/* Mark packet as being aborted and put it in the abort pending list. */
if (port)
}
/*ARGSUSED*/
static uint_t
{
return (FCAL_TRANSPORT_FAILURE);
}
static uint_t
{
if ((fcalpkt =
== (fcal_packet_t *)NULL)
return (FCAL_ALLOC_FAILED);
if (port)
}
/*ARGSUSED*/
static void
{
if (socalp->socal_shutdown) {
return;
} else {
}
if (restart) {
}
}
}
static void
void (*ulp_statec_callback)(), void (*ulp_els_callback)(),
void (*ulp_data_callback)(), void *arg)
{
return;
}
}
if ((cbentry =
return;
}
}
/*
* remove a ULP with matching type and arg
*/
static void
{
/* scan the list of unsolicited callback entries */
continue; /* this entry doesn't match */
}
/* found entry to remove */
/* remove first entry in list */
} else {
/* remove other entry in list */
if (p_cbentry)
}
break;
}
}
/*
* static unsigned int
* socal_intr() - this is the interrupt routine for the SOC. Process all
* possible incoming interrupts from the soc device.
*/
static unsigned int
{
unsigned csr;
int cause = 0;
#if !defined(lint)
#endif
int i, j, request;
char full;
"socal%d: intr: csr: 0x%x cause: 0x%x\n",
if (!cause) {
socalp->socal_on_intr = 0;
return (DDI_INTR_UNCLAIMED);
}
while (cause) {
/*
* Process the unsolicited messages first in case there are some
* high priority async events that we should act on.
*
*/
if (cause & SOCAL_CSR_RSP_QUE_1) {
}
if (cause & SOCAL_CSR_RSP_QUE_0) {
}
/*
* for use with token-only response queues in the future
* if (cause & SOCAL_CSR_RSP_QUE_0) {
* socal_intr_solicited(socalp, 0);
* }
*/
/*
* Process any request interrupts
* We only allow request interrupts when the request
* queue is full and we are waiting so we can enque
* another command.
*/
for (i = SOCAL_CSR_1ST_H_TO_S, j = 0; j < SOCAL_N_CQS;
j++, i <<= 1) {
if (request & i) {
break;
}
}
if (!kcq->skc_overflowh) {
if (full & SOCAL_SKC_SLEEP)
/* Disable this queue's intrs */
"socal%d: req que %d overflow cleared\n",
instance, j));
(socalp->socal_k_imr &= ~i);
}
}
}
}
}
}
socalp->socal_on_intr = 0;
return (DDI_INTR_CLAIMED);
}
static void
{
volatile socal_kcq_t *kcqv;
char val;
int port;
#endif
auto char buf[80];
/*
* Grab lock for request queue.
*/
/*
* Process as many response queue entries as we can.
*/
/* make sure the write completed */
}
/* Find out where the newest entry lives in the queue */
/*
* It turns out that on faster CPU's we have a problem where
* the soc interrupts us before the response has been DMA'ed
* in. This should not happen but does !!. So to workaround
* the problem for now, check the sequence # of the response.
* If it does not match with what we have, we must be
* reading stale data
*/
#endif
if (kcq->deferred_intr_timeoutid) {
return;
} else {
drv_usectohz(10000));
return;
}
}
fcalpkt = (fcal_packet_t *)
}
in, out, seqno = 0x%x, 0x%x, 0x%x\n",
"\tsoc CR: 0x%x SAE: 0x%x CSR: 0x%x IMR: 0x%x\n",
/*
* Update response queue ptrs and soc registers.
*/
}
} else {
fcalpkt));
/*
* map soc status codes to
* transport status codes
*/
== 0);
/*
* Copy the response frame header (if there is one)
* so that the upper levels can use it. Note that,
* for now, we'll copy the header only if there was
* some sort of non-OK status, to save the PIO reads
* required to get the header from the host adapter's
* xRAM.
*/
if (((status != FCAL_STATUS_OK) ||
& SOC_RESP_HEADER)) &&
1 : 0;
if ((status != FCAL_STATUS_OK) &&
(status <= FCAL_STATUS_MAX_STATUS)) {
resp_status[status]++;
} else {
}
} else if (status == FCAL_STATUS_OK) {
}
/*
* Update response queue ptrs and soc registers.
*/
}
/* For incmplt DMA offline loop by loopback */
if (fcalpkt->fcal_pkt_status ==
uint_t r;
/*
* Give up the mutex to avoid a deadlock
* with the loopback routine.
*/
if (port_statep->sp_status &
/* Already disabled */
} else {
port_statep->sp_status |=
(void) socal_diag_request(
&r, SOC_DIAG_INT_LOOP);
}
/* reacquire mutex */
}
/*
* Complete the packet *ONLY* if it not being aborted
* or the abort has already completed. Otherwise it is
* not safe to free the ID.
*/
/*
* Call the completion routine
*/
/*
* Give up the mutex to avoid a
* deadlock with the callback routine.
*/
/* callback */
/* reacquire mutex */
} else {
}
} else {
}
}
/*
* This action averts a potential PANIC scenario
* where the SUSPEND code flow grabbed the kcq->skc_mtx
* when we let it go, to call our completion routine,
* and "initialized" the response queue. We exit our
* processing loop here, thereby averting a PANIC due
* to a NULL de-reference from the response queue.
*
* Note that this is an interim measure that needs
* to be revisited when this driver is next revised
* for enhanced performance.
*/
break;
/*
* We need to re-read the input and output pointers in
* case a polling routine should process some entries
* from the response queue while we're doing a callback
* routine with the response queue mutex dropped.
*/
/*
* Mess around with the hardware if we think we've run out
* of entries in the queue, just to make sure we've read
* all entries that are available.
*/
/* Make sure the csr write has completed */
/*
* Update our idea of where the host adapter has placed
* the most recent entry in the response queue and resync
* the response queue
*/
}
/* Drop lock for request queue. */
}
/*
* Function name : socal_intr_unsolicited()
*
* Return Values : none
*
* Description : Processes entries in the unsolicited response
* queue
*
* The SOC+ will give us an unsolicited response
* whenever its status changes: OFFLINE, ONLINE,
* or in response to a packet arriving from an originator.
*
* When message requests come in they will be placed in our
* buffer queue or in the next "inline" packet by the SOC hardware.
*
* Context : Unsolicited interrupts must be masked
*/
static void
{
volatile socal_kcq_t *kcqv;
int port;
uint_t i;
int hdr_count;
int status;
auto char buf[256];
#endif
/*
* Grab lock for response queue.
*/
/* Check for continuation entries */
i = index_in;
/*
* If we think the continuation entries haven't yet
* arrived, try once more before giving up
*/
if (i < t_index) {
/* Make sure the csr write has completed */
/*
* Update our idea of where the host adapter has placed
* the most recent entry in the response queue
*/
socalreg->socal_rspp.w);
/*
* Exit if the continuation entries haven't yet
* arrived
*/
if (i < t_index)
break;
}
t_seqno++;
}
kcq->skc_last_index]);
/* A cq_hdr_count > 2 is illegal; throw away the response */
/*
* XXX - should probably throw out as many entries as the
* hdr_cout tells us there are
*/
if (hdr_count != 2) {
"!too many continuation entries");
"socal%d: soc+ unsolicited entry count = %d\n",
t_index = 0;
t_seqno++;
}
continue;
}
}
/*
* Update unsolicited response queue ptrs
*/
}
}
}
/* Make sure the csr write has completed */
}
/*
* XXX need to deal buffer pool entries here
*/
switch (flags & ~SOC_PORT_B) {
case SOC_UNSOLICITED | SOC_FC_HEADER:
case R_CTL_EXTENDED_SVC:
/*
* Extended Link Services frame received
*/
/* do callbacks to any interested ULPs */
}
}
break;
case R_CTL_BASIC_SVC:
"!unsupported Link Service command: 0x%x",
break;
case R_CTL_DEVICE_DATA:
default:
status = 1;
status = 0;
}
}
if (status == 0)
break;
"!unknown FC-4 command: 0x%x",
"link.4030", buf);
break;
}
break;
default:
break;
}
break;
case SOC_STATUS: {
/*
* Note that only the lsbyte of the status has
* interesting information...
*/
switch (status) {
case FCAL_STATUS_ONLINE:
"!port %d: Fibre Channel is ONLINE\n", port);
buf);
"socal%d intr_unsol: ONLINE intr\n",
instance));
break;
case FCAL_STATUS_LOOP_ONLINE:
"!port %d: Fibre Channel Loop is ONLINE\n",
port);
buf);
"socal%d intr_unsol: ONLINE-LOOP intr\n",
instance));
break;
case FCAL_STATUS_ERR_OFFLINE:
/*
* SOC and Responder will both flush
* all active commands.
* So I don't have to do anything
* until it comes back online.
*/
"!port %d: Fibre Channel is OFFLINE\n", port);
buf);
port_statep->sp_lilpmap_valid = 0;
"socal%d intr_unsol: OFFLINE intr\n",
instance));
break;
default:
status);
buf);
}
status);
}
}
if (status == FCAL_STATUS_ERR_OFFLINE) {
}
break;
}
default:
flags);
"\tsoc CR: 0x%x SAE: 0x%x CSR: 0x%x IMR: 0x%x\n",
}
/*
* This action averts a potential PANIC scenario
* where the SUSPEND code flow grabbed the kcq->skc_mtx
* when we let it go, to call our completion routine,
* and "initialized" the response queue. We exit our
* processing loop here, thereby averting a PANIC due
* to a NULL de-reference from the response queue.
*
* Note that this is an interim measure that needs
* to be revisited when this driver is next revised
* for enhanced performance.
*/
break;
/*
* We need to re-read the input and output pointers in
* case a polling routine should process some entries
* from the response queue while we're doing a callback
* routine with the response queue mutex dropped.
*/
/*
* Mess around with the hardware if we think we've run out
* of entries in the queue, just to make sure we've read
* all entries that are available.
*/
/* Make sure the csr write has completed */
/*
* Update our idea of where the host adapter has placed
* the most recent entry in the response queue
*/
index_in =
}
}
/* Release lock for response queue. */
}
/*
* socal_us_els() - This function handles unsolicited extended link
* service responses received from the soc.
*/
static void
{
int i;
char *bp;
auto char buf[256];
/*
* There should be a CQE continuation entry for all
* extended link services
*/
"!incomplete continuation entry");
return;
}
/* Quietly impose a maximum byte count */
if (i > SOC_CQE_PAYLOAD)
i = SOC_CQE_PAYLOAD;
i -= sizeof (union els_cmd_u);
/*
* Decode the LS_Command code
*/
case LA_ELS_DISPLAY:
/* squash newlines */
}
break;
default:
break;
}
}
/*ARGSUSED*/
static fcal_packet_t *
{
int flag;
if (sleep == FCAL_SLEEP)
else
flag = KM_NOSLEEP;
return (pkt);
}
static void
{
}
static void
{
port = 1;
else
port = 0;
}
static void
{
port = 1;
else
port = 0;
}
static void
{
port = 1;
else
port = 0;
}
static void
{
port = 1;
else
port = 0;
}
static void
{
port = 1;
else
port = 0;
}
static void
{
port = 1;
else
port = 0;
}
static void
{
soc_header_t *shp =
}
port = 1;
else
port = 0;
}
static void
{
port = 1;
else
port = 0;
}
/*ARGSUSED*/
static unsigned int
{
return (DDI_INTR_UNCLAIMED);
}
static int
{
struct fcal_lilp_map map;
/* Grabbing the state mutex is totally unnecessary.... */
!= -1) {
return (FCAL_TRANSPORT_UNAVAIL);
}
}
== (fcal_packet_t *)NULL)
return (FCAL_ALLOC_FAILED);
if (port)
SOCAL_DIAG_TIMEOUT, 0, diagcode));
}
static uint_t
{
if ((fcalpkt =
== (fcal_packet_t *)NULL)
return (FCAL_ALLOC_FAILED);
if (port)
}
static int
{
int retval;
if ((fcalpkt =
== (fcal_packet_t *)NULL)
return (FCAL_ALLOC_FAILED);
buf->hard_address = 0;
if (retval == FCAL_SUCCESS) {
}
return (retval);
}
static int
{
int retval;
return (FCAL_ALLOC_FAILED);
if (retval == FCAL_SUCCESS) {
}
return (retval);
}
static int
{
int retval;
/* load up the the struct with the local lesb */
rsp->explanation = 0;
return (FCAL_SUCCESS);
}
if ((fcalpkt =
== (fcal_packet_t *)NULL)
return (FCAL_ALLOC_FAILED);
else
if (retval == FCAL_SUCCESS) {
sizeof (la_els_rls_reply_t));
}
return (retval);
}
{
struct fcal_packet *fcalpkt;
if ((fcalpkt =
== (fcal_packet_t *)NULL)
return (NULL);
if ((privp =
goto fail;
}
goto fail;
goto fail;
goto fail;
goto fail;
!= DDI_DMA_MAPPED)
goto fail;
cmd_bound = 1;
if (ccount != 1)
goto fail;
if (rsp_size) {
goto fail;
goto fail;
goto fail;
!= DDI_DMA_MAPPED)
goto fail;
rsp_bound = 1;
if (ccount != 1)
goto fail;
}
if (port)
if (rsp_size == 0) {
} else {
}
/* this will potentially be overwritten by the calling function */
/* Fill in the Fabric Channel Header */
return (fcalpkt);
fail:
if (privp) {
if (privp->cmd_handle) {
if (cmd_bound)
}
if (privp->rsp_handle) {
if (rsp_bound)
}
}
return (NULL);
}
{
struct fcal_packet *fcalpkt;
if ((fcalpkt =
== (fcal_packet_t *)NULL)
return (NULL);
if ((privp =
goto fail;
}
goto fail;
goto fail;
goto fail;
!= DDI_DMA_MAPPED)
goto fail;
cmd_bound = 1;
if (ccount != 1)
goto fail;
if (rsp_size) {
goto fail;
goto fail;
goto fail;
!= DDI_DMA_MAPPED)
goto fail;
rsp_bound = 1;
if (ccount != 1)
goto fail;
}
if (port)
if (rsp_size == 0) {
} else {
}
/* this will potentially be overwritten by the calling function */
/* Fill in the Fabric Channel Header */
return (fcalpkt);
fail:
if (privp) {
if (privp->cmd_handle) {
if (cmd_bound)
}
if (privp->rsp_handle) {
if (rsp_bound)
}
}
return (NULL);
}
void
{
if (privp)
else
return;
if (privp->rsp_handle) {
}
}
void
{
if (privp)
else
return;
if (privp->rsp_handle) {
}
}
static int
{
if (port_statep->sp_lilpmap_valid) {
if (arg) {
return (-1);
}
return (buf->lilp_myalpa);
}
goto getmap_fail;
i = sizeof (struct fcal_lilp_map);
goto getmap_fail;
if (real_len < i)
goto getmap_fail;
goto getmap_fail;
bound = 1;
if (ccount != 1)
goto getmap_fail;
if (retval == FCAL_SUCCESS) {
if (arg) {
goto getmap_fail;
}
}
else
retval = -1;
(void) ddi_dma_unbind_handle(dhandle);
return (retval);
if (dhandle) {
if (bound)
(void) ddi_dma_unbind_handle(dhandle);
}
if (buf)
return (-1);
}
static void
{
int i;
for (i = 0; i < len/4; i++) {
}
}
static void
{
else {
}
} else {
}
}
}
}
static void
socal_deferred_intr(void *arg)
{
kcq->deferred_intr_timeoutid = 0;
return;
}
if (socalp->socal_on_intr) {
return;
}
kcq->deferred_intr_timeoutid = 0;
}
static void
socal_take_core(void *arg)
{
int i, instance;
for (i = 0; i < SOCAL_N_CQS; i++) {
}
for (i = 0; i < 4; i++) {
}
for (i = 3; i >= 0; i--) {
}
"socal take core (socal instance %d)", instance);
}
/*
* Preset AL_PA in hardware, if is told.
*/
static void
{
if (port == 0) {
accum &= 0x00FFFFFF;
} else {
accum &= 0xFF00FFFF;
}
}
/*
* Target-Mode attach function
*/
{
int hard_alpa;
char *name;
/*
* If the device is not a "socal" device, return
*/
return (NULL);
/*
* If no soft state structure, return
*/
return (NULL);
/*
* If the port is already attached, return
*/
return (NULL);
return (NULL);
/* if this instance is detaching, don't attach */
if (socalp->socal_busy < 0) {
return (NULL);
}
socalp->socal_busy++;
/*
* Since we keep the Hard Loop-id in two config files, warn the
* user if they don't match.
*/
"using Loop-id %d",
}
}
/*
* Target-Mode detach function
*/
int
{
socalp->socal_busy--;
return (0);
}