ql_api.c revision c1fad183c9a0deeb49586645ec9baa8f3c1bc8be
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Copyright 2010 QLogic Corporation */
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "Copyright 2010 QLogic Corporation; ql_api.c"
/*
* ISP2xxx Solaris Fibre Channel Adapter (FCA) driver source file.
*
* ***********************************************************************
* * **
* * NOTICE **
* * COPYRIGHT (C) 1996-2010 QLOGIC CORPORATION **
* * ALL RIGHTS RESERVED **
* * **
* ***********************************************************************
*
*/
#include <ql_apps.h>
#include <ql_api.h>
#include <ql_debug.h>
#include <ql_init.h>
#include <ql_iocb.h>
#include <ql_ioctl.h>
#include <ql_isr.h>
#include <ql_mbx.h>
#include <ql_xioctl.h>
/*
* Solaris external defines.
*/
extern pri_t minclsyspri;
extern pri_t maxclsyspri;
/*
* dev_ops functions prototypes
*/
static int ql_power(dev_info_t *, int, int);
static int ql_quiesce(dev_info_t *);
/*
* FCA functions prototypes exported by means of the transport table
*/
static void ql_unbind_port(opaque_t);
static int ql_get_cap(opaque_t, char *, void *);
static int ql_set_cap(opaque_t, char *, void *);
/*
* FCA Driver Support Function Prototypes.
*/
ql_srb_t *);
static void ql_task_daemon(void *);
static void ql_task_thread(ql_adapter_state_t *);
static void ql_unsol_callback(ql_srb_t *);
static void ql_free_unsolicited_buffer(ql_adapter_state_t *,
fc_unsol_buf_t *);
static void ql_timer(void *);
static void ql_halt(ql_adapter_state_t *, int);
ql_srb_t *);
static int ql_kstat_update(kstat_t *, int);
static void ql_rst_aen(ql_adapter_state_t *);
static void ql_restart_queues(ql_adapter_state_t *);
static void ql_abort_queues(ql_adapter_state_t *);
static void ql_idle_check(ql_adapter_state_t *);
static int ql_loop_resync(ql_adapter_state_t *);
static int ql_save_config_regs(dev_info_t *);
static int ql_restore_config_regs(dev_info_t *);
static int ql_handle_rscn_update(ql_adapter_state_t *);
static int ql_dump_firmware(ql_adapter_state_t *);
void *);
uint8_t);
static int ql_suspend_adapter(ql_adapter_state_t *);
static int ql_setup_interrupts(ql_adapter_state_t *);
static int ql_setup_msi(ql_adapter_state_t *);
static int ql_setup_msix(ql_adapter_state_t *);
static int ql_setup_fixed(ql_adapter_state_t *);
static void ql_release_intr(ql_adapter_state_t *);
static void ql_disable_intr(ql_adapter_state_t *);
static int ql_legacy_intr(ql_adapter_state_t *);
static int ql_init_mutex(ql_adapter_state_t *);
static void ql_destroy_mutex(ql_adapter_state_t *);
static void ql_iidma(ql_adapter_state_t *);
static int ql_n_port_plogi(ql_adapter_state_t *);
els_descriptor_t *);
static void ql_isp_els_request_ctor(els_descriptor_t *,
/*
* Global data
*/
static int ql_flash_sbus_fpga = 0;
uint32_t ql_disable_aif = 0;
uint32_t ql_disable_msi = 0;
uint32_t ql_disable_msix = 0;
/* Timer routine variables. */
static clock_t ql_timer_ticks;
/* Soft state head pointer. */
/* Head adapter link. */
NULL,
};
/* Global hba index */
/*
* Some IP defines and globals
*/
/* Device AL_PA to Device Head Queue index array. */
uint8_t ql_alpa_to_index[] = {
0x7e, 0x7d, 0x7c, 0x00, 0x7b, 0x01, 0x02, 0x03, 0x7a, 0x04,
0x05, 0x06, 0x07, 0x08, 0x09, 0x79, 0x78, 0x0a, 0x0b, 0x0c,
0x0d, 0x0e, 0x0f, 0x77, 0x76, 0x10, 0x11, 0x75, 0x12, 0x74,
0x73, 0x72, 0x13, 0x14, 0x15, 0x71, 0x16, 0x70, 0x6f, 0x6e,
0x17, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0x18, 0x19, 0x67,
0x66, 0x65, 0x64, 0x63, 0x62, 0x20, 0x21, 0x61, 0x60, 0x23,
0x5f, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x5e, 0x2a, 0x5d,
0x5c, 0x5b, 0x2b, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55, 0x2c,
0x2d, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x2e, 0x2f, 0x4e,
0x4d, 0x30, 0x4c, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x4b,
0x37, 0x4a, 0x49, 0x48, 0x38, 0x47, 0x46, 0x45, 0x44, 0x43,
0x42, 0x39, 0x3a, 0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b,
0x3c, 0x3b, 0x3a, 0x3d, 0x39, 0x3e, 0x3f, 0x40, 0x38, 0x37,
0x36, 0x41, 0x35, 0x42, 0x43, 0x44, 0x34, 0x45, 0x46, 0x47,
0x48, 0x49, 0x4a, 0x33, 0x32, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x31, 0x30, 0x51, 0x52, 0x2f, 0x53, 0x2e, 0x2d, 0x2c,
0x54, 0x55, 0x56, 0x2b, 0x57, 0x2a, 0x29, 0x28, 0x58, 0x27,
0x26, 0x25, 0x24, 0x23, 0x22, 0x59, 0x5a, 0x21, 0x20, 0x1f,
0x1e, 0x1d, 0x1c, 0x5b, 0x5c, 0x1b, 0x1a, 0x5d, 0x19, 0x5e,
0x5f, 0x60, 0x61, 0x62, 0x63, 0x18, 0x64, 0x17, 0x16, 0x15,
0x65, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x66, 0x67, 0x0e,
0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x68, 0x69, 0x08, 0x07, 0x6a,
0x06, 0x6b, 0x6c, 0x6d, 0x05, 0x04, 0x03, 0x6e, 0x02, 0x6f,
0x70, 0x71, 0x01, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x00,
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7f, 0x80, 0x00, 0x01,
0x02, 0x03, 0x80, 0x7f, 0x7e, 0x04
};
/* Device loop_id to ALPA array. */
static uint8_t ql_index_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
};
/* 2200 register offsets */
static reg_off_t reg_off_2200 = {
0x00, 0x02, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
0x18, 0x18, 0x1A, 0x1A, /* req in, out, resp in, out */
0x00, 0x00, /* intr info lo, hi */
24, /* Number of mailboxes */
/* Mailbox register offsets */
0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee,
0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,
/* 2200 does not have mailbox 24-31 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x96, 0xa4, 0xb0, 0xb8, 0xc0, 0xcc, 0xce,
/* host to host sema */
0x00,
/* 2200 does not have pri_req_in, pri_req_out, */
/* atio_req_in, atio_req_out, io_base_addr */
0xff, 0xff, 0xff, 0xff, 0xff
};
/* 2300 register offsets */
static reg_off_t reg_off_2300 = {
0x00, 0x02, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
0x10, 0x12, 0x14, 0x16, /* req in, out, resp in, out */
0x18, 0x1A, /* intr info lo, hi */
32, /* Number of mailboxes */
/* Mailbox register offsets */
0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e,
0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e,
0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,
0x96, 0xa4, 0xb0, 0x80, 0xc0, 0xcc, 0xce,
/* host to host sema */
0x1c,
/* 2300 does not have pri_req_in, pri_req_out, */
/* atio_req_in, atio_req_out, io_base_addr */
0xff, 0xff, 0xff, 0xff, 0xff
};
/* 2400/2500 register offsets */
0x00, 0x04, /* flash_address, flash_data */
0x08, 0x0c, 0x10, /* ctrl_status, ictrl, istatus */
/* 2400 does not have semaphore, nvram */
0x14, 0x18,
0x1c, 0x20, 0x24, 0x28, /* req_in, req_out, resp_in, resp_out */
0x44, 0x46, /* intr info lo, hi */
32, /* Number of mailboxes */
/* Mailbox register offsets */
0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e,
0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae,
0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
/* 2400 does not have fpm_diag_config, pcr, mctr, fb_cmd */
0xff, 0xff, 0xff, 0xff,
0x48, 0x4c, 0x50, /* hccr, gpiod, gpioe */
0xff, /* host to host sema */
0x2c, 0x30, /* pri_req_in, pri_req_out */
0x3c, 0x40, /* atio_req_in, atio_req_out */
0x54 /* io_base_addr */
};
/* mutex for protecting variables shared by all instances of the driver */
/* DMA access attribute structure. */
static ddi_device_acc_attr_t ql_dev_acc_attr = {
};
/* I/O DMA attributes structures. */
static ddi_dma_attr_t ql_64bit_io_dma_attr = {
DMA_ATTR_V0, /* dma_attr_version */
QL_DMA_LOW_ADDRESS, /* low DMA address range */
QL_DMA_HIGH_64BIT_ADDRESS, /* high DMA address range */
QL_DMA_XFER_COUNTER, /* DMA counter register */
QL_DMA_ADDRESS_ALIGNMENT, /* DMA address alignment */
QL_DMA_BURSTSIZES, /* DMA burstsizes */
QL_DMA_MIN_XFER_SIZE, /* min effective DMA size */
QL_DMA_MAX_XFER_SIZE, /* max DMA xfer size */
QL_DMA_SEGMENT_BOUNDARY, /* segment boundary */
QL_DMA_SG_LIST_LENGTH, /* s/g list length */
QL_DMA_GRANULARITY, /* granularity of device */
QL_DMA_XFER_FLAGS /* DMA transfer flags */
};
static ddi_dma_attr_t ql_32bit_io_dma_attr = {
DMA_ATTR_V0, /* dma_attr_version */
QL_DMA_LOW_ADDRESS, /* low DMA address range */
QL_DMA_HIGH_32BIT_ADDRESS, /* high DMA address range */
QL_DMA_XFER_COUNTER, /* DMA counter register */
QL_DMA_ADDRESS_ALIGNMENT, /* DMA address alignment */
QL_DMA_BURSTSIZES, /* DMA burstsizes */
QL_DMA_MIN_XFER_SIZE, /* min effective DMA size */
QL_DMA_MAX_XFER_SIZE, /* max DMA xfer size */
QL_DMA_SEGMENT_BOUNDARY, /* segment boundary */
QL_DMA_SG_LIST_LENGTH, /* s/g list length */
QL_DMA_GRANULARITY, /* granularity of device */
QL_DMA_XFER_FLAGS /* DMA transfer flags */
};
/* Load the default dma attributes */
static ddi_dma_attr_t ql_32fcsm_cmd_dma_attr;
static ddi_dma_attr_t ql_64fcsm_cmd_dma_attr;
static ddi_dma_attr_t ql_32fcsm_rsp_dma_attr;
static ddi_dma_attr_t ql_64fcsm_rsp_dma_attr;
static ddi_dma_attr_t ql_32fcip_cmd_dma_attr;
static ddi_dma_attr_t ql_64fcip_cmd_dma_attr;
static ddi_dma_attr_t ql_32fcip_rsp_dma_attr;
static ddi_dma_attr_t ql_64fcip_rsp_dma_attr;
static ddi_dma_attr_t ql_32fcp_cmd_dma_attr;
static ddi_dma_attr_t ql_64fcp_cmd_dma_attr;
static ddi_dma_attr_t ql_32fcp_rsp_dma_attr;
static ddi_dma_attr_t ql_64fcp_rsp_dma_attr;
static ddi_dma_attr_t ql_32fcp_data_dma_attr;
static ddi_dma_attr_t ql_64fcp_data_dma_attr;
/* Static declarations of cb_ops entry point functions... */
ql_open, /* b/c open */
ql_close, /* b/c close */
nodev, /* b strategy */
nodev, /* b print */
nodev, /* b dump */
nodev, /* c read */
nodev, /* c write */
ql_ioctl, /* c ioctl */
nodev, /* c devmap */
nodev, /* c mmap */
nodev, /* c segmap */
nochpoll, /* c poll */
nodev, /* cb_prop_op */
NULL, /* streamtab */
CB_REV, /* cb_ops revision */
nodev, /* c aread */
nodev /* c awrite */
};
/* Static declarations of dev_ops entry point functions... */
DEVO_REV, /* devo_rev */
0, /* refcnt */
ql_getinfo, /* getinfo */
nulldev, /* identify */
nulldev, /* probe */
ql_attach, /* attach */
ql_detach, /* detach */
nodev, /* reset */
NULL, /* bus operations */
ql_power, /* power management */
ql_quiesce /* quiesce device */
};
/* ELS command code to text converter */
/* Mailbox command code to text converter */
char qlc_driver_version[] = QL_VERSION;
/*
* Loadable Driver Interface Structures.
* Declare and initialize the module configuration section...
*/
&mod_driverops, /* type of module: driver */
&ql_devops /* driver dev_ops */
};
static struct modlinkage modlinkage = {
&modldrv,
};
/* ************************************************************************ */
/* Loadable Module Routines. */
/* ************************************************************************ */
/*
* _init
* Initializes a loadable module. It is called before any other
* routine in a loadable module.
*
* Returns:
* 0 = success
*
* Context:
* Kernel context.
*/
int
_init(void)
{
int rval = 0;
/* Get OS major release level. */
w16++;
break;
}
}
&ql_os_release_level, 0);
} else {
ql_os_release_level = 0;
}
if (ql_os_release_level < 6) {
}
if (ql_os_release_level == 6) {
}
if (rval == 0) {
sizeof (ql_adapter_state_t), 0);
}
if (rval == 0) {
/* allow the FC Transport to tweak the dev_ops */
if (rval != 0) {
} else {
/*EMPTY*/
}
}
if (rval != 0) {
QL_NAME);
}
return (rval);
}
/*
* _fini
* Prepares a module for unloading. It is called when the system
* wants to unload a module. If the module determines that it can
* be unloaded, then _fini() returns the value returned by
* mod_remove(). Upon successful return from _fini() no other
* routine in the module will be called before _init() is called.
*
* Returns:
* 0 = success
*
* Context:
* Kernel context.
*/
int
_fini(void)
{
int rval;
if (rval == 0) {
}
return (rval);
}
/*
* _info
* Returns information about loadable module.
*
* Input:
* modinfo = pointer to module information structure.
*
* Returns:
* Value returned by mod_info().
*
* Context:
* Kernel context.
*/
int
{
}
/* ************************************************************************ */
/* dev_ops functions */
/* ************************************************************************ */
/*
* ql_getinfo
* Returns the pointer associated with arg when cmd is
* set to DDI_INFO_DEVT2DEVINFO, or it should return the
* instance number associated with arg when cmd is set
* to DDI_INFO_DEV2INSTANCE.
*
* Input:
* dip = Do not use.
* cmd = command argument.
* arg = command specific argument.
* resultp = pointer to where request information is stored.
*
* Returns:
* DDI_SUCCESS or DDI_FAILURE.
*
* Context:
* Kernel context.
*/
/* ARGSUSED */
static int
{
int minor;
int rval = DDI_FAILURE;
return (rval);
}
switch (cmd) {
case DDI_INFO_DEVT2DEVINFO:
rval = DDI_SUCCESS;
break;
case DDI_INFO_DEVT2INSTANCE:
rval = DDI_SUCCESS;
break;
default:
rval = DDI_FAILURE;
break;
}
return (rval);
}
/*
* ql_attach
* Configure and attach an instance of the driver
* for a port.
*
* Input:
* dip = pointer to device information structure.
* cmd = attach type.
*
* Returns:
* DDI_SUCCESS or DDI_FAILURE.
*
* Context:
* Kernel context.
*/
static int
{
int rval;
int instance;
char *buf;
static char *pmcomps[] = {
NULL,
PM_LEVEL_D3_STR, /* Device OFF */
PM_LEVEL_D0_STR, /* Device ON */
};
switch (cmd) {
case DDI_ATTACH:
/* first get the instance */
/* Correct OS version? */
if (ql_os_release_level != 11) {
goto attach_failed;
}
/* Hardware is installed in a DMA-capable slot? */
instance);
goto attach_failed;
}
/* No support for high-level interrupts */
if (ddi_intr_hilevel(dip, 0) != 0) {
goto attach_failed;
}
/* Allocate our per-device-instance structure */
instance) != DDI_SUCCESS) {
goto attach_failed;
}
goto attach_failed;
}
goto attach_failed;
}
/* Get extended logging and dump flags. */
"sbus") == 0) {
}
KM_SLEEP);
KM_SLEEP);
} else {
}
/*
* For cards where PCI is mapped to sbus e.g. Ivory.
*
* 0x00 : 0x000 - 0x0FF PCI Config Space for 2200
* : 0x100 - 0x3FF PCI IO space for 2200
* 0x01 : 0x000 - 0x0FF PCI Config Space for fpga
* : 0x100 - 0x3FF PCI IO Space for fpga
*/
!= DDI_SUCCESS) {
goto attach_failed;
}
!= DDI_SUCCESS) {
/* We should not fail attach here */
}
} else {
/*
* Setup the ISP2200 registers address mapping to be
* accessed by this particular driver.
* 0x0 Configuration Space
* 0x1 I/O Space
* 0x2 32-bit Memory Space address
* 0x3 64-bit Memory Space address
*/
0, 0x100, &ql_dev_acc_attr,
goto attach_failed;
}
/*
* We need I/O space mappings for 23xx HBAs for
* loading flash (FCode). The chip has a bug due to
* which loading flash fails through mem space
* mappings in PCI-X mode.
*/
goto attach_failed;
}
}
/*
* We should map config space before adding interrupt
* So that the chip type (2200 or 2300) can be determined
* before the interrupt routine gets a chance to execute.
*/
if (ddi_regs_map_setup(dip, 0,
DDI_SUCCESS) {
goto attach_failed;
}
} else {
DDI_SUCCESS) {
goto attach_failed;
}
}
case 0x2300:
case 0x2312:
#if !defined(__sparc) || defined(QL_DEBUG_ROUTINES)
/*
* per marketing, fibre-lite HBA's are not supported
* on sparc platforms
*/
case 0x6312:
case 0x6322:
#endif /* !defined(__sparc) || defined(QL_DEBUG_ROUTINES) */
}
} else {
}
goto attach_failed;
}
} else {
}
break;
case 0x2200:
goto attach_failed;
}
} else {
}
break;
case 0x2422:
case 0x2432:
case 0x5422:
case 0x5432:
case 0x8432:
#ifdef __sparc
/*
* also use the 2422 & 2432) are only for the
* x86 platform (SMB market).
*/
"%s(%d): Unsupported HBA ssid: %x",
goto attach_failed;
}
#endif /* __sparc */
}
} else {
}
goto attach_failed;
}
break;
case 0x2522:
case 0x2532:
}
goto attach_failed;
}
break;
case 0x8001:
}
goto attach_failed;
}
break;
default:
goto attach_failed;
}
/* Setup hba buffer. */
QL_DMA_RING_ALIGN) != QL_SUCCESS) {
goto attach_failed;
}
/* Setup buffer pointers. */
/* Allocate resource for QLogic IOCTL */
(void) ql_alloc_xioctl_resource(ha);
/* Setup interrupts */
goto attach_failed;
}
goto attach_failed;
}
/*
* Allocate an N Port information structure
* for use when in P2P topology.
*/
goto attach_failed;
}
/*
* Determine support for Power Management
*/
while (caps_ptr != PCI_CAP_NEXT_PTR_NULL) {
if (cap == PCI_CAP_ID_PM) {
break;
}
}
if (ha->pm_capable) {
/*
* Enable PM for 2200 based HBAs only.
*/
ha->pm_capable = 0;
}
}
if (ha->pm_capable) {
}
if (ha->pm_capable) {
/*
* Initialize power management bookkeeping;
* components are created idle.
*/
/*LINTED [Solaris DDI_DEV_T_NONE Lint warning]*/
" pm-components property", QL_NAME,
instance);
/* Initialize adapter. */
" initialize adapter", QL_NAME,
instance);
goto attach_failed;
}
} else {
PM_LEVEL_D0) != DDI_SUCCESS) {
" raise power or initialize"
}
}
} else {
/* Initialize adapter. */
}
}
ha->fw_subminor_version == 0) {
} else {
int rval;
char ver_fmt[256];
", MPI fw version %d.%d.%d",
", PHY fw version %d.%d.%d",
}
}
}
"controller", KSTAT_TYPE_RAW,
goto attach_failed;
}
goto attach_failed;
}
/* Allocate a transport structure for this instance */
goto attach_failed;
}
/* fill in the structure */
}
/* Specify the amount of space needed in each packet */
/* command limits are usually dictated by hardware */
/* dmaattr are static, set elsewhere. */
} else {
}
/* the remaining values are simply function vectors */
/* give it to the FC transport */
instance);
goto attach_failed;
}
/* Stash the structure so it can be freed at detach */
/* Acquire global state lock. */
/* Add adapter structure to link list. */
/* Start one second driver timer. */
if (ql_timer_timeout_id == NULL) {
}
/* Release global state lock. */
/* Determine and populate HBA fru info */
/* Setup task_daemon thread. */
/* Disable link reset in panic path */
rval = DDI_SUCCESS;
break;
if (progress & QL_FCA_ATTACH_DONE) {
(void) fc_fca_detach(dip);
}
if (progress & QL_FCA_TRAN_ALLOCED) {
}
if (progress & QL_MINOR_NODE_CREATED) {
}
if (progress & QL_KSTAT_CREATED) {
progress &= ~QL_KSTAT_CREATED;
}
if (progress & QL_N_PORT_INFO_CREATED) {
}
if (progress & QL_TASK_DAEMON_STARTED) {
/* Release task daemon lock. */
/* Wait for for task daemon to stop running. */
}
}
if (progress & QL_IOMAP_IOBASE_MAPPED) {
}
if (progress & QL_CONFIG_SPACE_SETUP) {
} else {
}
}
if (progress & QL_INTR_ADDED) {
progress &= ~QL_INTR_ADDED;
}
if (progress & QL_MUTEX_CV_INITED) {
}
if (progress & QL_HBA_BUFFER_SETUP) {
}
if (progress & QL_REGS_MAPPED) {
}
progress &= ~QL_REGS_MAPPED;
}
if (progress & QL_SOFT_STATE_ALLOCED) {
sizeof (*ha->adapter_stats));
sizeof (*ha->outstanding_cmds) *
}
}
}
}
rval = DDI_FAILURE;
break;
case DDI_RESUME:
rval = DDI_FAILURE;
break;
}
if (ha->pm_capable) {
/*
* Get ql_power to do power on initialization
*/
PM_LEVEL_D0) != DDI_SUCCESS) {
}
}
/*
* There is a bug in DR that prevents PM framework
* from calling ql_power.
*/
}
/* Wake up task_daemon. */
0);
}
/* Acquire global state lock. */
/* Restart driver timer. */
if (ql_timer_timeout_id == NULL) {
}
/* Release global state lock. */
/* Wake up command start routine. */
/*
* Transport doesn't make FC discovery in polled
* mode; So we need the daemon thread's services
* right here.
*/
rval = DDI_SUCCESS;
/* Restart IP if it was running. */
(void) ql_initialize_ip(ha);
}
break;
default:
rval = DDI_FAILURE;
break;
}
if (rval != DDI_SUCCESS) {
/*EMPTY*/
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_detach
* Used to remove all the states associated with a given
* instances of a device node prior to the removal of that
* instance from the system.
*
* Input:
* dip = pointer to device information structure.
* cmd = type of detach.
*
* Returns:
* DDI_SUCCESS or DDI_FAILURE.
*
* Context:
* Kernel context.
*/
static int
{
int delay_cnt;
char *buf;
return (DDI_FAILURE);
}
switch (cmd) {
case DDI_DETACH:
(void) ql_wait_for_td_stop(ha);
}
}
/* Disable driver timer if no adapters. */
}
if (timer_id) {
}
if (ha->pm_capable) {
PM_LEVEL_D3) != DDI_SUCCESS) {
}
}
/*
* If pm_lower_power shutdown the adapter, there
* isn't much else to do
*/
}
/* Remove virtual ports. */
}
/* Free target queues. */
}
}
/*
* Free unsolicited buffers.
* If we are here then there are no ULPs still
* alive that wish to talk to ql so free up
* any SRB_IP_UB_UNUSED buffers that are
* lingering around
*/
QL_UB_LOCK(ha);
SRB_UB_ACQUIRED))) {
QL_UB_LOCK(ha);
}
QL_UB_LOCK(ha);
}
}
/* Free any saved RISC code. */
ha->risc_code_size = 0;
}
}
/* Free resources. */
(void) fc_fca_detach(dip);
}
} else {
}
}
}
}
}
}
break;
case DDI_SUSPEND:
delay_cnt = 0;
}
rval = DDI_FAILURE;
break;
}
(void) ql_shutdown_ip(ha);
}
/* Restart IP if it was running. */
(void) ql_initialize_ip(ha);
}
rval = DDI_FAILURE;
break;
}
/* Acquire global state lock. */
/* Disable driver timer if last adapter. */
}
if (timer_id) {
}
break;
default:
rval = DDI_FAILURE;
break;
}
if (rval != DDI_SUCCESS) {
} else {
/*EMPTY*/
}
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_power
* Power a device attached to the system.
*
* Input:
* dip = pointer to device information structure.
* component = device.
* level = power level.
*
* Returns:
* DDI_SUCCESS or DDI_FAILURE.
*
* Context:
* Kernel context.
*/
/* ARGSUSED */
static int
{
int rval = DDI_FAILURE;
char *buf;
char *path;
return (rval);
}
level != PM_LEVEL_D3)) {
return (rval);
}
switch (level) {
case PM_LEVEL_D0: /* power up to D0 state - fully on */
QL_PM_LOCK(ha);
rval = DDI_SUCCESS;
break;
}
/*
* Enable interrupts now
*/
/*
* Delay after reset, for chip to recover.
* Otherwise causes system PANIC
*/
drv_usecwait(200000);
if (ha->config_saved) {
ha->config_saved = 0;
QL_PM_LOCK(ha);
"config regs", buf);
break;
}
}
buf);
}
/* Wake up task_daemon. */
/* Restart IP if it was running. */
(void) ql_initialize_ip(ha);
}
rval = DDI_SUCCESS;
break;
case PM_LEVEL_D3: /* power down to D3 state - off */
QL_PM_LOCK(ha);
TASK_DAEMON_SLEEPING_FLG) == 0)) {
break;
}
rval = DDI_SUCCESS;
break;
}
break;
}
/*
* Don't enable interrupts. Running mailbox commands with
* interrupts enabled could cause hangs since pm_run_scan()
* runs out of a callout thread and on single cpu systems
* cv_timedwait(), called from ql_mailbox_command(), would
* not get to run.
*/
/*
* Setup ql_intr to ignore interrupts from here on.
*/
QL_PM_LOCK(ha);
/*
* Wait for ISR to complete.
*/
rval = DDI_SUCCESS;
break;
}
return (rval);
}
/*
* ql_quiesce
* quiesce a device attached to the system.
*
* Input:
* dip = pointer to device information structure.
*
* Returns:
* DDI_SUCCESS
*
* Context:
* Kernel context.
*/
static int
{
/* Oh well.... */
return (DDI_SUCCESS);
}
break;
}
}
drv_usecwait(100);
}
/* Reset the chip. */
drv_usecwait(100);
} else {
/* Disable ISP interrupts. */
/* Select RISC module registers. */
/* Reset ISP semaphore. */
/* Reset RISC module. */
/* Release RISC module. */
}
return (DDI_SUCCESS);
}
/* ************************************************************************ */
/* Fibre Channel Adapter (FCA) Transport Functions. */
/* ************************************************************************ */
/*
* ql_bind_port
* Handling port binding. The FC Transport attempts to bind an FCA port
* when it is ready to start transactions on the port. The FC Transport
* will call the fca_bind_port() function specified in the fca_transport
* structure it receives. The FCA must fill in the port_info structure
* passed in the call and also stash the information for future calls.
*
* Input:
* dip = pointer to FCA information structure.
* port_info = pointer to port information structure.
* bind_info = pointer to bind information structure.
*
* Returns:
* NULL = failure
*
* Context:
* Kernel context.
*/
static opaque_t
{
/* get state info based on the dip */
return (NULL);
}
/* Verify port number is supported. */
if (port_npiv != 0) {
return (NULL);
}
return (NULL);
}
return (NULL);
}
return (NULL);
}
return (NULL);
}
/* Locate port context. */
break;
}
}
/* If virtual port does not exist. */
}
/* make sure this port isn't already bound */
} else {
}
return (NULL);
}
"WWPN=%02x%02x%02x%02x%02x%02x%02x%02x : "
"WWNN=%02x%02x%02x%02x%02x%02x%02x%02x\n",
}
/* stash the bind_info supplied by the FC Transport */
/* Set port's source ID. */
/* copy out the default login parameters */
(void *)&port_info->pi_login_params,
sizeof (la_els_logi_t));
/* Set port's hard address if enabled. */
firmware_options_1[0] & BIT_0) {
hard_address[0]];
}
BIT_0) {
}
/* Set the node id data */
if (ql_get_rnid_params(ha,
QL_SUCCESS) {
} else {
}
/* Populate T11 FC-HBA details */
KM_SLEEP);
sizeof (fca_port_attrs_t));
}
} else {
sizeof (fca_port_attrs_t));
}
}
/* Generate handle for this FCA. */
/* Set port's current state. */
}
return (fca_handle);
}
/*
* ql_unbind_port
* To unbind a Fibre Channel Adapter from an FC Port driver.
*
* Input:
* fca_handle = handle setup by ql_bind_port().
*
* Context:
* Kernel context.
*/
static void
{
/*EMPTY*/
(void *)fca_handle);
} else {
/*EMPTY*/
} else {
FL_PORT_24XX_HDL)) != NULL) {
}
} else {
}
}
}
}
/*
* ql_init_pkt
* Initialize FCA portion of packet.
*
* Input:
* fca_handle = handle setup by ql_bind_port().
* pkt = pointer to fc_packet.
*
* Returns:
* FC_SUCCESS - the packet has successfully been initialized.
* FC_UNBOUND - the fca_handle specified is not bound.
* FC_NOMEM - the FCA failed initialization due to an allocation error.
* FC_FAILURE - the FCA failed initialization for undisclosed reasons
*
* Context:
* Kernel context.
*/
/* ARGSUSED */
static int
{
(void *)fca_handle);
return (FC_UNBOUND);
}
/* init cmd links */
/* init watchdog links */
return (FC_SUCCESS);
}
/*
* ql_un_init_pkt
* Release all local resources bound to packet.
*
* Input:
* fca_handle = handle setup by ql_bind_port().
* pkt = pointer to fc_packet.
*
* Returns:
* FC_SUCCESS - the packet has successfully been invalidated.
* FC_UNBOUND - the fca_handle specified is not bound.
* FC_BADPACKET - the packet has not been initialized or has
* already been freed by this FCA.
*
* Context:
* Kernel context.
*/
static int
{
int rval;
(void *)fca_handle);
return (FC_UNBOUND);
}
rval = FC_BADPACKET;
} else {
rval = FC_SUCCESS;
}
return (rval);
}
/*
* ql_els_send
* Issue a extended link service request.
*
* Input:
* fca_handle = handle setup by ql_bind_port().
* pkt = pointer to fc_packet.
*
* Returns:
* FC_SUCCESS - the command was successful.
* FC_ELS_FREJECT - the command was rejected by a Fabric.
* FC_ELS_PREJECT - the command was rejected by an N-port.
* FC_TRANSPORT_ERROR - a transport error occurred.
* FC_UNBOUND - the fca_handle specified is not bound.
* FC_ELS_BAD - the FCA can not issue the requested ELS.
*
* Context:
* Kernel context.
*/
static int
{
int rval;
/* Verify proper command. */
rval, fca_handle);
return (FC_INVALID_REQUEST);
}
/* Wait for suspension to end. */
/* 30 seconds from now */
/*
* The timeout time 'timer' was
* reached without the condition
* being signaled.
*/
/* Release task daemon lock. */
return (FC_TRAN_BUSY);
}
}
/* Release task daemon lock. */
/* Setup response header. */
sizeof (fc_frame_hdr_t));
if (pkt->pkt_rsplen) {
}
/* map the type of ELS to a function */
#if 0
sizeof (fc_frame_hdr_t) / 4);
#endif
case LA_ELS_RJT:
case LA_ELS_ACC:
rval = FC_SUCCESS;
break;
case LA_ELS_PLOGI:
case LA_ELS_PDISC:
break;
case LA_ELS_FLOGI:
case LA_ELS_FDISC:
break;
case LA_ELS_LOGO:
break;
case LA_ELS_PRLI:
break;
case LA_ELS_PRLO:
break;
case LA_ELS_ADISC:
break;
case LA_ELS_LINIT:
break;
case LA_ELS_LPC:
break;
case LA_ELS_LSTS:
break;
case LA_ELS_SCR:
break;
case LA_ELS_RSCN:
break;
case LA_ELS_FARP_REQ:
break;
case LA_ELS_FARP_REPLY:
break;
case LA_ELS_RLS:
break;
case LA_ELS_RNID:
break;
default:
/* Build RJT. */
rval = FC_SUCCESS;
break;
}
#if 0
sizeof (fc_frame_hdr_t) / 4);
#endif
/*
* Return success if the srb was consumed by an iocb. The packet
* completion callback will be invoked by the response handler.
*/
if (rval == QL_CONSUMED) {
rval = FC_SUCCESS;
} else if (rval == FC_SUCCESS &&
/* Do command callback only if no error */
}
if (rval != FC_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_get_cap
* Export FCA hardware and software capabilities.
*
* Input:
* fca_handle = handle setup by ql_bind_port().
* cap = pointer to the capabilities string.
* ptr = buffer pointer for return capability.
*
* Returns:
* FC_CAP_ERROR - no such capability
* FC_CAP_FOUND - the capability was returned and cannot be set
* FC_CAP_SETTABLE - the capability was returned and can be set
* FC_UNBOUND - the fca_handle specified is not bound.
*
* Context:
* Kernel context.
*/
static int
{
int rval;
(void *)fca_handle);
return (FC_UNBOUND);
}
ptr, 8);
rval = FC_CAP_FOUND;
sizeof (la_els_logi_t));
rval = FC_CAP_FOUND;
rval = FC_CAP_FOUND;
#ifdef __sparc
/*
* Disable streaming for certain 2 chip adapters
* below Psycho to handle Psycho byte hole issue.
*/
"pcipsy") == 0) {
break;
}
}
}
#endif /* __sparc */
if (psydip) {
} else {
}
rval = FC_CAP_FOUND;
} else {
}
rval = FC_CAP_FOUND;
rval = FC_CAP_FOUND;
*rptr = FC_NO_DVMA_SPACE;
rval = FC_CAP_FOUND;
} else {
rval = FC_CAP_ERROR;
}
return (rval);
}
/*
* ql_set_cap
* Allow the FC Transport to set FCA capabilities if possible.
*
* Input:
* fca_handle = handle setup by ql_bind_port().
* cap = pointer to the capabilities string.
* ptr = buffer pointer for capability.
*
* Returns:
* FC_CAP_ERROR - no such capability
* FC_CAP_FOUND - the capability cannot be set by the FC Transport.
* FC_CAP_SETTABLE - the capability was successfully set.
* FC_UNBOUND - the fca_handle specified is not bound.
*
* Context:
* Kernel context.
*/
/* ARGSUSED */
static int
{
int rval;
(void *)fca_handle);
return (FC_UNBOUND);
}
rval = FC_CAP_FOUND;
rval = FC_CAP_FOUND;
rval = FC_CAP_FOUND;
rval = FC_CAP_FOUND;
rval = FC_CAP_FOUND;
} else {
rval = FC_CAP_ERROR;
}
return (rval);
}
/*
* ql_getmap
* Request of Arbitrated Loop (AL-PA) map.
*
* Input:
* fca_handle = handle setup by ql_bind_port().
* mapbuf= buffer pointer for map.
*
* Returns:
* FC_OLDPORT - the specified port is not operating in loop mode.
* FC_OFFLINE - the specified port is not online.
* FC_NOMAP - there is no loop map available for this port.
* FC_UNBOUND - the fca_handle specified is not bound.
* FC_SUCCESS - a valid map has been placed in mapbuf.
*
* Context:
* Kernel context.
*/
static int
{
int rval = FC_SUCCESS;
(void *)fca_handle);
return (FC_UNBOUND);
}
/* Wait for suspension to end. */
/* 30 seconds from now */
/*
* The timeout time 'timer' was
* reached without the condition
* being signaled.
*/
/* Release task daemon lock. */
return (FC_TRAN_BUSY);
}
}
/* Release task daemon lock. */
/*
* Now, since transport drivers cosider this as an
* offline condition, let's wait for few seconds
* for any loop transitions before we reset the.
* chip and restart all over again.
*/
} else {
/*EMPTY*/
}
#if 0
#endif
return (rval);
}
/*
* ql_transport
* Issue an I/O request. Handles all regular requests.
*
* Input:
* fca_handle = handle setup by ql_bind_port().
* pkt = pointer to fc_packet.
*
* Returns:
* FC_SUCCESS - the packet was accepted for transport.
* FC_TRANSPORT_ERROR - a transport error occurred.
* FC_BADPACKET - the packet to be transported had not been
* initialized by this FCA.
* FC_UNBOUND - the fca_handle specified is not bound.
*
* Context:
* Kernel context.
*/
static int
{
int rval = FC_TRANSPORT_ERROR;
/* Verify proper command. */
rval, fca_handle);
return (rval);
}
#if 0
sizeof (fc_frame_hdr_t) / 4);
#endif
/* Reset SRB flags. */
case R_CTL_COMMAND:
}
break;
default:
/* Setup response header and buffer. */
if (pkt->pkt_rsplen) {
}
case R_CTL_UNSOL_DATA:
}
break;
case R_CTL_UNSOL_CONTROL:
}
break;
case R_CTL_SOLICITED_DATA:
case R_CTL_STATUS:
default:
break;
}
}
if (rval != FC_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_ub_alloc
* Allocate buffers for unsolicited exchanges.
*
* Input:
* fca_handle = handle setup by ql_bind_port().
* tokens = token array for each buffer.
* size = size of each buffer.
* count = pointer to number of buffers.
* type = the FC-4 type the buffers are reserved for.
*
* Returns:
* FC_FAILURE - buffers could not be allocated.
* FC_TOOMANY - the FCA could not allocate the requested
* number of buffers.
* FC_SUCCESS - unsolicited buffers were allocated.
* FC_UNBOUND - the fca_handle specified is not bound.
*
* Context:
* Kernel context.
*/
static int
{
uint32_t ub_array_index = 0;
int rval = FC_SUCCESS;
int ub_updated = FALSE;
/* Check handle. */
(void *)fca_handle);
return (FC_UNBOUND);
}
QL_PM_LOCK(ha);
return (FC_FAILURE);
}
/* Acquire adapter state lock. */
/* Check the count. */
*count = 0;
rval = FC_TOOMANY;
}
/*
* reset ub_array_index
*/
ub_array_index = 0;
/*
* Now proceed to allocate any buffers required
*/
/* Allocate all memory needed. */
KM_SLEEP);
rval = FC_FAILURE;
} else {
rval = FC_FAILURE;
} else {
if (type == FC_TYPE_IS8802_SNAP) {
#ifdef __sparc
if (ql_get_dma_mem(ha,
QL_DMA_DATA_ALIGN) != QL_SUCCESS) {
rval = FC_FAILURE;
sizeof (fc_unsol_buf_t));
sizeof (ql_srb_t));
} else {
}
#else
if (ql_get_dma_mem(ha,
QL_DMA_DATA_ALIGN) != QL_SUCCESS) {
rval = FC_FAILURE;
sizeof (fc_unsol_buf_t));
sizeof (ql_srb_t));
} else {
}
#endif
} else {
rval = FC_FAILURE;
sizeof (fc_unsol_buf_t));
sizeof (ql_srb_t));
} else {
}
}
}
}
if (rval == FC_SUCCESS) {
/* Find next available slot. */
QL_UB_LOCK(ha);
}
/* init cmd links */
/* init wdg links */
/* Save the token. */
/* Setup FCA private information. */
ha->ub_allocated++;
ub_updated = TRUE;
}
}
/* Release adapter state lock. */
/* IP buffer. */
if (ub_updated) {
if ((type == FC_TYPE_IS8802_SNAP) &&
cnt = CHAR_TO_SHORT(
}
} else {
cnt = CHAR_TO_SHORT(
}
}
(void) ql_initialize_ip(ha);
}
}
}
if (rval != FC_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_ub_free
* Free unsolicited buffers.
*
* Input:
* fca_handle = handle setup by ql_bind_port().
* count = number of buffers.
* tokens = token array for each buffer.
*
* Returns:
* FC_SUCCESS - the requested buffers have been freed.
* FC_UNBOUND - the fca_handle specified is not bound.
* FC_UB_BADTOKEN - an invalid token was encountered.
* No buffers have been released.
*
* Context:
* Kernel context.
*/
static int
{
int rval = FC_SUCCESS;
/* Check handle. */
(void *)fca_handle);
return (FC_UNBOUND);
}
/* Acquire adapter state lock. */
/* Check all returned tokens. */
/* Check the token range. */
break;
}
/* Check the unsolicited buffer array. */
QL_UB_LOCK(ha);
break;
}
/* Check the state of the unsolicited buffer. */
QL_UB_LOCK(ha);
}
}
if (rval == FC_SUCCESS) {
/*
* Signal any pending hardware reset when there are
* no more unsolicited buffers in use.
*/
if (ha->ub_allocated == 0) {
}
}
/* Release adapter state lock. */
if (rval != FC_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_ub_release
* Release unsolicited buffers from FC Transport
* to FCA for future use.
*
* Input:
* fca_handle = handle setup by ql_bind_port().
* count = number of buffers.
* tokens = token array for each buffer.
*
* Returns:
* FC_SUCCESS - the requested buffers have been released.
* FC_UNBOUND - the fca_handle specified is not bound.
* FC_UB_BADTOKEN - an invalid token was encountered.
* No buffers have been released.
*
* Context:
* Kernel context.
*/
static int
{
int rval = FC_SUCCESS;
int ub_ip_updated = FALSE;
/* Check handle. */
(void *)fca_handle);
return (FC_UNBOUND);
}
/* Acquire adapter state lock. */
QL_UB_LOCK(ha);
/* Check all returned tokens. */
/* Check the token range. */
break;
}
/* Check the unsolicited buffer array. */
break;
}
/* Check the state of the unsolicited buffer. */
break;
}
}
/* If all tokens checkout, release the buffers. */
if (rval == FC_SUCCESS) {
/* Check all returned tokens. */
ubp->ub_resp_flags = 0;
/* IP buffer. */
}
}
}
/* Release adapter state lock. */
/*
* XXX: We should call ql_isp_rcvbuf() to return a
* buffer to ISP only if the number of buffers fall below
* the low water mark.
*/
if (ub_ip_updated) {
}
if (rval != FC_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_abort
* Abort a packet.
*
* Input:
* fca_handle = handle setup by ql_bind_port().
* pkt = pointer to fc_packet.
* flags = KM_SLEEP flag.
*
* Returns:
* FC_SUCCESS - the packet has successfully aborted.
* FC_ABORTED - the packet has successfully aborted.
* FC_ABORTING - the packet is being aborted.
* FC_ABORT_FAILED - the packet could not be aborted.
* FC_TRANSPORT_ERROR - a transport error occurred while attempting
* to abort the packet.
* FC_BADEXCHANGE - no packet found.
* FC_UNBOUND - the fca_handle specified is not bound.
*
* Context:
* Kernel context.
*/
static int
{
int rval = FC_ABORTED;
(void *)fca_handle);
return (FC_UNBOUND);
}
/* Get target queue pointer. */
} else {
rval = FC_OFFLINE;
}
return (rval);
}
/* Set poll flag if sleep wanted. */
}
/* Acquire target queue lock. */
/* If command not already started. */
/* Check pending queue for command. */
/* Remove srb from q. */
break;
} else {
}
}
/* Check for cmd on device queue. */
/* Remove srb from q. */
break;
} else {
}
}
}
/* Release device lock */
/* If command on target queue. */
/* Set return status */
rval = FC_ABORTED;
} else {
}
/* Release device queue lock. */
rval = FC_FAILURE;
/*
* with an error, we need not do any thing. If FW
* decides not to terminate those IOs and simply keep
* quite then we need to initiate cleanup here by
* calling ql_done.
*/
rval = FC_ABORTED;
} else {
break;
}
ep++;
}
}
/* Release device queue lock. */
rval = FC_ABORTED;
}
return (rval);
}
/*
* ql_reset
* Reset link or hardware.
*
* Input:
* fca_handle = handle setup by ql_bind_port().
* cmd = reset type command.
*
* Returns:
* FC_SUCCESS - reset has successfully finished.
* FC_UNBOUND - the fca_handle specified is not bound.
* FC_FAILURE - reset failed.
*
* Context:
* Kernel context.
*/
static int
{
(void *)fca_handle);
return (FC_UNBOUND);
}
switch (cmd) {
case FC_FCA_CORE:
/* dump firmware core if specified. */
rval = FC_FAILURE;
}
}
break;
case FC_FCA_LINK_RESET:
rval = FC_FAILURE;
}
}
break;
case FC_FCA_RESET_CORE:
case FC_FCA_RESET:
/* if dump firmware core if specified. */
if (cmd == FC_FCA_RESET_CORE) {
} else {
}
if (rval2 != QL_SUCCESS) {
rval = FC_FAILURE;
}
}
/* Free up all unsolicited buffers. */
if (ha->ub_allocated != 0) {
/* Inform to release buffers. */
}
}
/* All buffers freed */
if (ha->ub_allocated == 0) {
/* Hardware reset. */
if (cmd == FC_FCA_RESET) {
(void) ql_abort_isp(ha);
LOOP_DOWN)) {
(void) ql_loop_reset(ha);
}
}
/* Inform that the hardware has been reset */
} else {
/*
* the port driver expects an online if
* buffers are not freed.
*/
} else {
}
}
break;
default:
break;
}
if (rval != FC_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_port_manage
* Perform port management or diagnostics.
*
* Input:
* fca_handle = handle setup by ql_bind_port().
* cmd = pointer to command structure.
*
* Returns:
* FC_SUCCESS - the request completed successfully.
* FC_FAILURE - the request did not complete successfully.
* FC_UNBOUND - the fca_handle specified is not bound.
*
* Context:
* Kernel context.
*/
static int
{
char buf[80];
int i0;
(void *)fca_handle);
return (FC_UNBOUND);
}
cmd->pm_cmd_code);
/*
* Wait for all outstanding commands to complete
*/
if (index != MAX_OUTSTANDING_COMMANDS) {
return (FC_TRAN_BUSY);
}
switch (cmd->pm_cmd_code) {
case FC_PORT_BYPASS:
rval = FC_FAILURE;
}
break;
case FC_PORT_UNBYPASS:
rval = FC_FAILURE;
}
break;
case FC_PORT_GET_FW_REV:
rval = FC_FAILURE;
} else {
}
break;
case FC_PORT_GET_FCODE_REV: {
i0 = 0;
/*LINTED [Solaris DDI_DEV_T_ANY Lint warning]*/
if (rval2 != DDI_PROP_SUCCESS) {
length = 20;
if (fcode_ver_buf != NULL) {
(void) sprintf(fcode_ver_buf,
"NO FCODE FOUND");
}
}
rval = FC_FAILURE;
} else if (fcode_ver_buf != NULL) {
length);
}
if (fcode_ver_buf != NULL) {
}
break;
}
case FC_PORT_GET_DUMP:
rval = FC_FAILURE;
rval = FC_TRAN_BUSY;
} else {
rval = FC_FAILURE;
}
break;
case FC_PORT_FORCE_DUMP:
rval = FC_FAILURE;
}
break;
case FC_PORT_DOWNLOAD_FW:
rval = FC_FAILURE;
}
} else {
/* Save copy of the firmware. */
pha->risc_code_size = 0;
}
KM_SLEEP);
cmd->pm_data_len);
/* Do abort to force reload. */
pha->risc_code_size = 0;
(void) ql_abort_isp(ha);
" FC_FAILURE\n");
rval = FC_FAILURE;
}
}
}
break;
case FC_PORT_GET_DUMP_SIZE:
break;
case FC_PORT_DIAG:
/*
* Prevents concurrent diags
*/
/* Wait for suspension to end. */
}
rval = FC_TRAN_BUSY;
break;
}
switch (cmd->pm_cmd_flags) {
case QL_DIAG_EXEFMW:
rval = FC_FAILURE;
}
break;
case QL_DIAG_CHKCMDQUE:
i0++) {
}
if (cnt != 0) {
"FC_FAILURE\n");
rval = FC_FAILURE;
}
break;
case QL_DIAG_FMWCHKSUM:
"FC_FAILURE\n");
rval = FC_FAILURE;
}
break;
case QL_DIAG_SLFTST:
rval = FC_FAILURE;
}
break;
case QL_DIAG_REVLVL:
if (cmd->pm_stat_len <
sizeof (ql_adapter_revlvl_t)) {
"slen=%lxh, rlvllen=%lxh\n",
sizeof (ql_adapter_revlvl_t));
} else {
cmd->pm_stat_len =
sizeof (ql_adapter_revlvl_t);
}
break;
case QL_DIAG_LPBMBX:
"FC_INVALID_REQUEST, pmlen=%lxh, "
sizeof (struct app_mbx_cmd));
break;
}
/*
* Don't do the wrap test on a 2200 when the
* firmware is running.
*/
sizeof (uint16_t) * 8);
"FC_FAILURE\n");
rval = FC_FAILURE;
break;
} else {
"QL_DIAG_LPBMBX "
"FC_FAILURE-2\n");
rval = FC_FAILURE;
break;
}
}
}
if (rval == FC_FAILURE) {
(void) ql_flash_errlog(ha,
}
}
break;
case QL_DIAG_LPBDTA:
/*
* For loopback data, we receive the
* data back in pm_stat_buf. This provides
* the user an opportunity to compare the
* transmitted and received data.
*
* NB: lb->options are:
* 0 --> Ten bit loopback
* 1 --> One bit loopback
* 2 --> External loopback
*/
rval = FC_TOOMANY;
break;
}
QL_DMA_DATA_ALIGN) != QL_SUCCESS) {
break;
}
QL_DMA_DATA_ALIGN) != QL_SUCCESS) {
break;
}
/* 22xx's adapter must be in loop mode for test. */
(void) ql_abort_isp(ha);
}
}
/* Shutdown IP. */
(void) ql_shutdown_ip(pha);
}
lb->transfer_count =
lb->transfer_segment_count = 0;
lb->receive_segment_count = 0;
(QL_LOOP_TRANSITION | LOOP_DOWN)) {
/* Loop must be up for external */
rval = FC_TRAN_BUSY;
cmd->pm_stat_len);
} else {
rval = FC_FAILURE;
}
/* Needed to recover the f/w */
/* Restart IP if it was shutdown. */
(void) ql_initialize_ip(pha);
}
break;
case QL_DIAG_ECHO: {
/*
* issue an echo command with a user supplied
* data pattern and destination address
*/
/* Setup echo cmd & adjust for platform */
/*
* due to limitations in the ql
* firmaware the echo data field is
* limited to 220
*/
"cmdl1=%lxh, statl2=%lxh\n",
rval = FC_TOOMANY;
break;
}
/*
* the input data buffer has the user
* supplied data pattern. The "echoed"
* data will be DMAed into the output
* data buffer. Therefore the length
* of the output buffer must be equal
* to or greater then the input buffer
* length
*/
" cmdl1=%lxh, statl2=%lxh\n",
rval = FC_TOOMANY;
break;
}
/* add four bytes for the opcode */
/*
* are we 32 or 64 bit addressed???
* We need to get the appropriate
* DMA and set the command options;
* 64 bit (bit 6) or 32 bit
* (no bit 6) addressing.
* while we are at it lets ask for
* real echo (bit 15)
*/
}
/*
* Set up the DMA mappings for the
* output and input data buffers.
* First the output buffer
*/
QL_DMA_DATA_ALIGN) != QL_SUCCESS) {
break;
}
/* Next the input buffer */
QL_DMA_DATA_ALIGN) != QL_SUCCESS) {
/*
* since we could not allocate
* DMA space for the input
* buffer we need to clean up
* by freeing the DMA space
* we allocated for the output
* buffer
*/
break;
}
/*
* copy the 4 byte ECHO op code to the
* allocated DMA space
*/
/*
* copy the user supplied data to the
* allocated DMA space
*/
/* Shutdown IP. */
(void) ql_shutdown_ip(pha);
}
/* send the echo */
} else {
rval = FC_FAILURE;
}
/* Restart IP if it was shutdown. */
(void) ql_initialize_ip(pha);
}
/* free up our DMA buffers */
break;
}
default:
break;
}
break;
case FC_PORT_LINK_STATE:
/* Check for name equal to null. */
index++) {
break;
}
}
/* If name not null. */
/* Locate device queue. */
break;
} else {
}
}
}
} else {
}
} else {
}
break;
case FC_PORT_INITIALIZE:
if (!VALID_DEVICE_ID(ha,
}
break;
} else {
}
}
}
"FC_FAILURE\n");
rval = FC_FAILURE;
}
} else {
rval = FC_FAILURE;
}
break;
case FC_PORT_RLS:
(sizeof (fc_rls_acc_t)));
rval = FC_FAILURE;
} else if (LOOP_NOT_READY(pha)) {
rval = FC_FAILURE;
#ifdef _BIG_ENDIAN
} else {
#endif /* _BIG_ENDIAN */
}
break;
case FC_PORT_GET_NODE_ID:
rval = FC_FAILURE;
}
break;
case FC_PORT_SET_NODE_ID:
rval = FC_FAILURE;
}
break;
case FC_PORT_DOWNLOAD_FCODE:
} else {
} else {
}
}
if (rval != QL_SUCCESS) {
rval = FC_FAILURE;
} else {
rval = FC_SUCCESS;
}
break;
default:
break;
}
/* Wait for suspension to end. */
timer = 0;
while (timer++ < 3000 &&
}
if (rval != FC_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
static opaque_t
{
(void *)fca_handle);
return (NULL);
}
} else {
/*EMPTY*/
}
return (tq);
}
/* ************************************************************************ */
/* FCA Driver Local Support Functions. */
/* ************************************************************************ */
/*
* ql_cmd_setup
* Verifies proper command.
*
* Input:
* fca_handle = handle setup by ql_bind_port().
* pkt = pointer to fc_packet.
* rval = pointer for return value.
*
* Returns:
* Adapter state pointer, NULL = failure.
*
* Context:
* Kernel context.
*/
static ql_adapter_state_t *
{
pkt->pkt_resp_resid = 0;
pkt->pkt_data_resid = 0;
/* check that the handle is assigned by this FCA */
*rval = FC_UNBOUND;
(void *)fca_handle);
return (NULL);
}
return (ha);
}
return (NULL);
}
/* Exit on loop down. */
*rval = FC_OFFLINE;
return (NULL);
}
}
*rval = FC_DEVICE_BUSY;
return (NULL);
}
}
}
/*
* Check DMA pointers.
*/
*rval = DDI_SUCCESS;
if (*rval == DDI_SUCCESS) {
}
}
pkt->pkt_rsplen != 0) {
if (*rval == DDI_SUCCESS) {
}
}
/*
* Minimum branch conditional; Change it with care.
*/
(pkt->pkt_datalen != 0)) != 0) {
if (*rval == DDI_SUCCESS) {
}
}
if (*rval != DDI_SUCCESS) {
/* Do command callback. */
}
*rval = FC_BADPACKET;
return (NULL);
}
*rval = FC_BADPACKET;
return (NULL);
}
*rval = FC_SUCCESS;
return (ha);
}
/*
* ql_els_plogi
* Issue a extended link service port login request.
*
* Input:
* ha = adapter state pointer.
* pkt = pointer to fc_packet.
*
* Returns:
* FC_SUCCESS - the packet was accepted for transport.
* FC_TRANSPORT_ERROR - a transport error occurred.
*
* Context:
* Kernel context.
*/
static int
{
int ret;
int rval = FC_SUCCESS;
return (FC_OFFLINE);
}
ret = QL_SUCCESS;
/*
* In p2p topology he sends a PLOGI after determining
* he has the N_Port login initiative.
*/
}
if (ret == QL_CONSUMED) {
return (ret);
}
case QL_SUCCESS:
break;
case QL_LOOP_ID_USED:
}
break;
default:
break;
}
if (ret != QL_SUCCESS) {
/*
* Invalidate this entry so as to seek a fresh loop ID
* in case firmware reassigns it to something else
*/
}
} else if (tq) {
}
/* Build ACC. */
rval = FC_TRAN_BUSY;
} else {
tq->logout_sent = 0;
}
}
}
} else {
/* Build RJT. */
switch (ret) {
case QL_FUNCTION_TIMEOUT:
break;
case QL_MEMORY_ALLOC_FAILED:
rval = FC_TRAN_BUSY;
break;
rval = FC_TRAN_BUSY;
break;
default:
break;
}
}
if (rval == FC_TRAN_BUSY) {
}
}
}
if (rval != FC_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_p2p_plogi
* Start an extended link service port login request using
* an ELS Passthru iocb.
*
* Input:
* ha = adapter state pointer.
* pkt = pointer to fc_packet.
*
* Returns:
* QL_CONSUMMED - the iocb was queued for transport.
*
* Context:
* Kernel context.
*/
static int
{
int rval;
/*
* Verify that the port database hasn't moved beneath our feet by
* switching to the appropriate n_port_handle if necessary. This is
* less unplesant than the error recovery if the wrong one is used.
*/
/* check all the ones not logged in for possible use */
if (rval == QL_NOT_LOGGED_IN) {
break;
}
/*
* Use a 'port unavailable' entry only
* if we used it before.
*/
/* if the port_id matches, reuse it */
"master state=%xh\n",
break;
// avoid a lint error
val++;
val++;
}
tq->master_state);
}
}
if (rval == QL_SUCCESS) {
break;
}
tq->master_state);
}
}
return (QL_CONSUMED);
}
/*
* ql_els_flogi
* Issue a extended link service fabric login request.
*
* Input:
* ha = adapter state pointer.
* pkt = pointer to fc_packet.
*
* Returns:
* FC_SUCCESS - the packet was accepted for transport.
* FC_TRANSPORT_ERROR - a transport error occurred.
*
* Context:
* Kernel context.
*/
static int
{
int rval = FC_SUCCESS;
int accept = 0;
/*
* d_id of zero in a FLOGI accept response in a point to point
* topology triggers evaluation of N Port login initiative.
*/
/*
* An N_Port already logged in with the firmware
* will have the only database entry.
*/
}
/*
* If the target port has initiative send
* up a PLOGI about the new device.
*/
} else {
ha->send_plogi_timer = 0;
}
} else {
/*
* An N_Port not logged in with the firmware will not
* have a database entry. We accept anyway and rely
* on a PLOGI from the upper layers to set the d_id
* and s_id.
*/
accept = 1;
}
} else {
}
/* Build ACC. */
/* clear F_Port indicator */
} else {
}
if (accept) {
/* Use the saved N_Port WWNN and WWPN */
/* mark service options invalid */
} else {
/* Build RJT. */
}
} else {
}
} else {
/* Build RJT. */
}
if (rval != FC_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_els_logo
* Issue a extended link service logout request.
*
* Input:
* ha = adapter state pointer.
* pkt = pointer to fc_packet.
*
* Returns:
* FC_SUCCESS - the packet was accepted for transport.
* FC_TRANSPORT_ERROR - a transport error occurred.
*
* Context:
* Kernel context.
*/
static int
{
int rval = FC_SUCCESS;
if (tq) {
return (FC_SUCCESS);
}
do {
/*
* Wait for commands to drain in F/W (doesn't
* take more than a few milliseconds)
*/
}
/* Build ACC. */
} else {
/* Build RJT. */
}
if (rval != FC_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_els_prli
* Issue a extended link service process login request.
*
* Input:
* ha = adapter state pointer.
* pkt = pointer to fc_packet.
*
* Returns:
* FC_SUCCESS - the packet was accepted for transport.
* FC_TRANSPORT_ERROR - a transport error occurred.
*
* Context:
* Kernel context.
*/
static int
{
int rval = FC_SUCCESS;
rval = QL_CONSUMED;
} else {
/* Build ACC. */
}
} else {
/* Build RJT. */
}
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_els_prlo
* Issue a extended link service process logout request.
*
* Input:
* ha = adapter state pointer.
* pkt = pointer to fc_packet.
*
* Returns:
* FC_SUCCESS - the packet was accepted for transport.
* FC_TRANSPORT_ERROR - a transport error occurred.
*
* Context:
* Kernel context.
*/
/* ARGSUSED */
static int
{
int rval = FC_SUCCESS;
/* Build ACC. */
if (rval != FC_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_els_adisc
* Issue a extended link service address discovery request.
*
* Input:
* ha = adapter state pointer.
* pkt = pointer to fc_packet.
*
* Returns:
* FC_SUCCESS - the packet was accepted for transport.
* FC_TRANSPORT_ERROR - a transport error occurred.
*
* Context:
* Kernel context.
*/
static int
{
int rval = FC_SUCCESS;
/*
* MBC_GET_PORT_DATABASE causes ADISC to go out to
* the device from the firmware
*/
break;
} else {
}
}
QL_SUCCESS) {
break;
}
}
} else {
}
}
}
}
/* Build ACC. */
}
}
}
} else {
/* Build RJT. */
}
if (rval != FC_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_els_linit
* Issue a extended link service loop initialize request.
*
* Input:
* ha = adapter state pointer.
* pkt = pointer to fc_packet.
*
* Returns:
* FC_SUCCESS - the packet was accepted for transport.
* FC_TRANSPORT_ERROR - a transport error occurred.
*
* Context:
* Kernel context.
*/
static int
{
conv_num_t n;
int rval = FC_SUCCESS;
/* Setup LFA mailbox command data. */
LITTLE_ENDIAN_64(&n.size64);
} else {
LITTLE_ENDIAN_32(&n.size32[0]);
}
/* Set buffer address. */
}
LITTLE_ENDIAN_32(&n.size32[0]);
} else {
}
} else {
/* Build RJT. */
}
if (rval != FC_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_els_lpc
* Issue a extended link service loop control request.
*
* Input:
* ha = adapter state pointer.
* pkt = pointer to fc_packet.
*
* Returns:
* FC_SUCCESS - the packet was accepted for transport.
* FC_TRANSPORT_ERROR - a transport error occurred.
*
* Context:
* Kernel context.
*/
static int
{
conv_num_t n;
int rval = FC_SUCCESS;
/* Setup LFA mailbox command data. */
LITTLE_ENDIAN_64(&n.size64);
} else {
LITTLE_ENDIAN_32(&n.size32[0]);
n.size32[1] = 0;
}
/* Set buffer address. */
}
LITTLE_ENDIAN_32(&n.size32[0]);
} else {
}
} else {
/* Build RJT. */
}
if (rval != FC_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_els_lsts
* Issue a extended link service loop status request.
*
* Input:
* ha = adapter state pointer.
* pkt = pointer to fc_packet.
*
* Returns:
* FC_SUCCESS - the packet was accepted for transport.
* FC_TRANSPORT_ERROR - a transport error occurred.
*
* Context:
* Kernel context.
*/
static int
{
conv_num_t n;
int rval = FC_SUCCESS;
/* Setup LFA mailbox command data. */
LITTLE_ENDIAN_64(&n.size64);
} else {
LITTLE_ENDIAN_32(&n.size32[0]);
n.size32[1] = 0;
}
/* Set buffer address. */
}
LITTLE_ENDIAN_32(&n.size32[0]);
} else {
}
} else {
/* Build RJT. */
}
if (rval != FC_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_els_scr
* Issue a extended link service state change registration request.
*
* Input:
* ha = adapter state pointer.
* pkt = pointer to fc_packet.
*
* Returns:
* FC_SUCCESS - the packet was accepted for transport.
* FC_TRANSPORT_ERROR - a transport error occurred.
*
* Context:
* Kernel context.
*/
static int
{
int rval = FC_SUCCESS;
QL_SUCCESS) {
/* Build ACC. */
} else {
/* Build RJT. */
}
} else {
/* Build RJT. */
}
if (rval != FC_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_els_rscn
* Issue a extended link service register state
* change notification request.
*
* Input:
* ha = adapter state pointer.
* pkt = pointer to fc_packet.
*
* Returns:
* FC_SUCCESS - the packet was accepted for transport.
* FC_TRANSPORT_ERROR - a transport error occurred.
*
* Context:
* Kernel context.
*/
static int
{
int rval = FC_SUCCESS;
/* Build ACC. */
} else {
/* Build RJT. */
}
if (rval != FC_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_els_farp_req
* Issue FC Address Resolution Protocol (FARP)
* extended link service request.
*
* Note: not supported.
*
* Input:
* ha = adapter state pointer.
* pkt = pointer to fc_packet.
*
* Returns:
* FC_SUCCESS - the packet was accepted for transport.
* FC_TRANSPORT_ERROR - a transport error occurred.
*
* Context:
* Kernel context.
*/
static int
{
int rval = FC_SUCCESS;
/* Build ACC. */
if (rval != FC_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_els_farp_reply
* Issue FC Address Resolution Protocol (FARP)
* extended link service reply.
*
* Note: not supported.
*
* Input:
* ha = adapter state pointer.
* pkt = pointer to fc_packet.
*
* Returns:
* FC_SUCCESS - the packet was accepted for transport.
* FC_TRANSPORT_ERROR - a transport error occurred.
*
* Context:
* Kernel context.
*/
/* ARGSUSED */
static int
{
int rval = FC_SUCCESS;
/* Build ACC. */
return (rval);
}
static int
{
break;
} else {
}
}
/* Allocate memory for rnid status block */
return (FC_FAILURE);
}
return (FC_SUCCESS);
}
static int
{
break;
} else {
}
}
/* Allocate memory for link error status block */
return (FC_FAILURE);
}
return (FC_SUCCESS);
}
static int
{
int rval = FC_SUCCESS;
int cnt = 5;
/*
* we need to ensure that q->outcnt == 0, otherwise
* any cmd completed with PKT_PORT_OFFLINE after PLOGI
* will confuse ulps.
*/
do {
/*
* wait for the cmds to get drained. If they
* don't get drained then the transport will
* retry PLOGI after few secs.
*/
rval = FC_TRAN_BUSY;
cnt--;
if (!cnt) {
" for %xh outcount %xh", QL_NAME,
}
} else {
rval = FC_SUCCESS;
break;
}
} while (cnt > 0);
/*
* return, if busy or if the plogi was asynchronous.
*/
if ((rval != FC_SUCCESS) ||
return (rval);
}
/*
* Let us give daemon sufficient time and hopefully
* when transport retries PLOGI, it would have flushed
* callback queue.
*/
} else {
}
rval = FC_TRAN_BUSY;
break;
}
}
return (rval);
}
/*
* ql_login_port
* Logs in a device if not already logged in.
*
* Input:
* ha = adapter state pointer.
* d_id = 24 bit port ID.
* DEVICE_QUEUE_LOCK must be released.
*
* Returns:
* QL local function return status code.
*
* Context:
* Kernel context.
*/
static int
{
int rval = QL_SUCCESS;
/* Get head queue index. */
/* Check for device already has a queue. */
break;
} else {
}
}
/* Let's stop issuing any IO and unsolicited logo */
}
}
/* Special case for Nameserver */
return (QL_FUNCTION_FAILED);
}
}
if (rval == QL_SUCCESS) {
}
/* Check for device already logged in. */
if (rval == QL_PORT_ID_USED) {
rval = QL_SUCCESS;
}
} else if (LOCAL_LOOP_ID(loop_id)) {
if (rval == QL_SUCCESS) {
}
}
/* Locate unused loop ID. */
first_loop_id = 0;
first_loop_id = 0;
} else {
}
/* Acquire adapter state lock. */
return (QL_FUNCTION_FAILED);
}
index--) {
if (loop_id < first_loop_id ||
loop_id > last_loop_id) {
(loop_id + 1);
}
/* Bypass if loop ID used. */
break;
}
}
continue;
}
/*
* If PORT_ID_USED is returned
* the login_fabric_port() updates
* with the correct loop ID
*/
switch (rval) {
case QL_PORT_ID_USED:
/*
* use f/w handle and try to
* login again.
*/
break;
case QL_SUCCESS:
(void) ql_get_port_database(ha,
index = 1;
break;
case QL_LOOP_ID_USED:
break;
case QL_ALL_IDS_IN_USE:
index = 1;
break;
default:
index = 1;
break;
}
}
} else {
}
if (rval != QL_SUCCESS) {
} else {
}
return (rval);
}
/*
* ql_login_fabric_port
* Issue login fabric port mailbox command.
*
* Input:
* ha: adapter state pointer.
* tq: target queue pointer.
* loop_id: FC Loop ID.
*
* Returns:
* ql local function return status code.
*
* Context:
* Kernel context.
*/
static int
{
int rval;
int index;
int retry = 0;
/*
* QL_PARAMETER_ERROR also means the firmware is
* not able to allocate PCB entry due to resource
* issues, or collision.
*/
do {
if ((rval == QL_PARAMETER_ERROR) ||
retry++;
} else {
break;
}
} while (retry < 5);
switch (rval) {
case QL_SUCCESS:
break;
case QL_PORT_ID_USED:
/*
* This Loop ID should NOT be in use in drivers
*/
}
break;
case QL_LOOP_ID_USED:
/*
* This should NEVER ever happen; but this
* code is needed to bail out when the worst
* case happens - or as used to happen before
*/
"reassigned; old pairs: [%xh, %xh] and [%xh, %xh];"
"new pairs: [%xh, unknown] and [%xh, %xh]\n",
}
}
/*
* Invalidate the loop ID for the
* us to obtain a new one.
*/
break;
case QL_ALL_IDS_IN_USE:
break;
default:
if (rval == QL_COMMAND_ERROR) {
case 2:
case 3:
break;
case 4:
break;
case 7:
break;
default:
break;
}
} else {
" D_ID=%xh, rval=%xh, mb1=%xh", QL_NAME,
}
break;
}
rval != QL_LOOP_ID_USED) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_logout_port
* Logs out a device if possible.
*
* Input:
* ha: adapter state pointer.
* d_id: 24 bit port ID.
*
* Returns:
* QL local function return status code.
*
* Context:
* Kernel context.
*/
static int
{
/* Get head queue index. */
/* Get device queue. */
break;
} else {
}
}
}
return (QL_SUCCESS);
}
/*
* ql_dev_init
* Initialize/allocate device queue.
*
* Input:
* ha: adapter state pointer.
* d_id: device destination ID
* loop_id: device loop ID
* ADAPTER_STATE_LOCK must be already obtained.
*
* Returns:
* NULL = failure
*
* Context:
* Kernel context.
*/
ql_tgt_t *
{
/* If device queue exists, set proper loop ID. */
/* Reset port down retry count. */
break;
} else {
}
}
/* If device does not have queue. */
/*
* mutex to protect the device queue,
* does not block interrupts.
*/
/* Reset port down retry count. */
/* Add device to device queue. */
}
}
} else {
/*EMPTY*/
}
return (tq);
}
/*
* ql_dev_free
* Remove queue from device list and frees resources used by queue.
*
* Input:
* ha: adapter state pointer.
* tq: target queue pointer.
* ADAPTER_STATE_LOCK must be already obtained.
*
* Context:
* Kernel context.
*/
void
{
return;
}
}
/* Get head queue index. */
}
break;
}
}
}
}
/*
* ql_lun_queue
* Allocate LUN queue if does not exists.
*
* Input:
* ha: adapter state pointer.
* tq: target queue.
* lun: LUN number.
*
* Returns:
* NULL = failure
*
* Context:
* Kernel context.
*/
static ql_lun_t *
{
/* Fast path. */
return (tq->last_lun_queue);
}
return (NULL);
}
/* If device queue exists, set proper loop ID. */
return (lq);
}
}
/* If queue does exist. */
/* Initialize LUN queue. */
}
return (lq);
}
/*
* ql_fcp_scsi_cmd
* Process fibre channel (FCP) SCSI protocol commands.
*
* Input:
* ha = adapter state pointer.
* pkt = pointer to fc_packet.
* sp = srb pointer.
*
* Returns:
* FC_SUCCESS - the packet was accepted for transport.
* FC_TRANSPORT_ERROR - a transport error occurred.
*
* Context:
* Kernel context.
*/
static int
{
}
/*
* zero out FCP response; 24 Bytes
*/
/* Handle task management function. */
} else {
/*
* Setup for commands with data transfer
*/
/*
* FCP data is bound to pkt_data_dma
*/
0, 0, DDI_DMA_SYNC_FORDEV);
}
/* Setup IOCB count. */
} else {
}
} else {
}
} else {
}
}
} else {
}
return (FC_SUCCESS);
}
/*
* ql_task_mgmt
* Task management function processor.
*
* Input:
* ha: adapter state pointer.
* tq: target queue pointer.
* pkt: pointer to fc_packet.
* sp: SRB pointer.
*
* Context:
* Kernel context.
*/
static void
{
struct fcp_rsp_info *rsp;
}
}
QL_SUCCESS) {
}
}
}
} else {
}
/* Do command callback. */
}
}
/*
* ql_fcp_ip_cmd
* Process fibre channel (FCP) Internet (IP) protocols commands.
*
* Input:
* ha: adapter state pointer.
* pkt: pointer to fc_packet.
* sp: SRB pointer.
*
* Returns:
* FC_SUCCESS - the packet was accepted for transport.
* FC_TRANSPORT_ERROR - a transport error occurred.
*
* Context:
* Kernel context.
*/
static int
{
}
/*
* IP data is bound to pkt_cmd_dma
*/
0, 0, DDI_DMA_SYNC_FORDEV);
/* Setup IOCB count. */
} else {
}
} else {
}
} else {
}
return (FC_SUCCESS);
}
/*
* ql_fc_services
* Process fibre channel services (name server).
*
* Input:
* ha: adapter state pointer.
* pkt: pointer to fc_packet.
*
* Returns:
* FC_SUCCESS - the packet was accepted for transport.
* FC_TRANSPORT_ERROR - a transport error occurred.
*
* Context:
* Kernel context.
*/
static int
{
int rval;
/* Do some sanity checks */
sizeof (fc_ct_header_t));
pkt->pkt_rsplen);
return (FC_ELS_MALFORMED);
}
switch (hdr.ct_fcstype) {
case FCSTYPE_DIRECTORY:
case FCSTYPE_MGMTSERVICE:
/* An FCA must make sure that the header is in big endian */
rval = QL_SUCCESS;
break;
}
/*
* Services data is bound to pkt_cmd_dma
*/
/* Setup IOCB count. */
if (cnt % CONT_TYPE_1_DATA_SEGMENTS) {
} else {
}
} else {
}
return (rval);
default:
break;
}
if (rval != QL_SUCCESS) {
/* Build RJT. */
}
/* Do command callback. */
0, 0);
}
return (FC_SUCCESS);
}
/*
* ql_cthdr_endian
* Change endianess of ct passthrough header and payload.
*
* Input:
* acc_handle: DMA buffer access handle.
* ct_hdr: Pointer to header.
* restore: Restore first flag.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
void
{
if (restore) {
hdrp++;
}
}
case NS_GA_NXT:
case NS_GPN_ID:
case NS_GNN_ID:
case NS_GCS_ID:
case NS_GFT_ID:
case NS_GSPN_ID:
case NS_GPT_ID:
case NS_GID_FT:
case NS_GID_PT:
case NS_RPN_ID:
case NS_RNN_ID:
case NS_RSPN_ID:
case NS_DA_ID:
break;
case NS_RFT_ID:
case NS_RCS_ID:
case NS_RPT_ID:
bp += 4;
break;
case NS_GNN_IP:
case NS_GIPA_IP:
break;
case NS_RIP_NN:
bp += 8;
break;
case NS_RIPA_NN:
bp += 8;
break;
default:
break;
}
}
hdrp++;
}
}
}
/*
* ql_start_cmd
* Finishes starting fibre channel protocol (FCP) command.
*
* Input:
* ha: adapter state pointer.
* tq: target queue pointer.
* pkt: pointer to fc_packet.
* sp: SRB pointer.
*
* Context:
* Kernel context.
*/
static int
{
int rval = FC_SUCCESS;
/* Set poll for finish. */
if (pkt->pkt_timeout == 0) {
}
}
/* Acquire device queue lock. */
/*
* If we need authentication, report device busy to
* upper layers to retry later
*/
return (FC_DEVICE_BUSY);
}
/* Insert command onto watchdog queue. */
} else {
/*
* Run dump requests in polled mode as kernel threads
* and interrupts may have been disabled.
*/
sp->init_wdg_q_time = 0;
sp->isp_timeout = 0;
}
/* If a polling command setup wait time. */
} else {
}
}
/* Set ending status. */
/* Call done routine to handle completions. */
} else {
int do_lip = 0;
}
if (!do_lip) {
/*
* That Qlogic F/W performs PLOGI, PRLI, etc
* is helpful here. If a PLOGI fails for some
* reason, you would get CS_PORT_LOGGED_OUT
* or some such error; and we should get a
* careful polled mode login kicked off inside
* of this driver itself. You don't have FC
* transport's services as all threads are
* suspended, interrupts disabled, and so
* on. Right now we do re-login if the packet
* state isn't FC_PKT_SUCCESS.
*/
(void) ql_abort_isp(ha);
}
} else {
/* Add the command to the device queue */
} else {
}
/* Check whether next message can be processed */
}
}
/* If polling, wait for finish. */
if (poll_wait) {
int res;
}
}
}
if (ddi_in_panic()) {
/*
* successful LOGIN implies by design
* that PRLI also succeeded for disks
* Note also that there is no special
* mailbox command to send PRLI.
*/
}
}
/*
* This should only happen during CPR dumping
*/
}
}
return (rval);
}
/*
* ql_poll_cmd
* Polls commands for completion.
*
* Input:
* ha = adapter state pointer.
* sp = SRB command pointer.
* poll_wait = poll wait time in seconds.
*
* Returns:
* QL local function return status code.
*
* Context:
* Kernel context.
*/
static int
{
int rval = QL_SUCCESS;
/* If waiting for restart, do it now. */
if (ha->port_retry_timer != 0) {
ha->port_retry_timer = 0;
}
}
/*
* Call task thread function in case the
* daemon is not running.
*/
QL_TASK_PENDING(ha)) {
}
}
if (msecs_left < 10) {
break;
}
/*
* Polling interval is 10 milli seconds; Increasing
* the polling interval to seconds since disk IO
* timeout values are ~60 seconds is tempting enough,
* but CPR dump time increases, and so will the crash
* dump time; Don't toy with the settings without due
* consideration for all the scenarios that will be
* impacted.
*/
msecs_left -= 10;
}
return (rval);
}
/*
* ql_next
* Retrieve and process next job in the device queue.
*
* Input:
* ha: adapter state pointer.
* lq: LUN queue pointer.
* DEVICE_QUEUE_LOCK must be already obtained.
*
* Output:
* Releases DEVICE_QUEUE_LOCK upon exit.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
void
{
if (ddi_in_panic()) {
return;
}
/* Exit if can not start commands. */
if (DRIVER_SUSPENDED(ha) ||
break;
}
/*
* Find out the LUN number for untagged command use.
* If there is an untagged command pending for the LUN,
* we would not submit another untagged command
* or if reached LUN execution throttle.
*/
break;
}
/*
* Set the untagged-flag for the LUN
* so that no more untagged commands
* can be submitted for this LUN.
*/
}
/* Count command as sent. */
lq->lun_outcnt++;
}
/* Remove srb from device queue. */
}
/* Release device queue lock. */
}
/*
* ql_done
* Process completed commands.
*
* Input:
* link: first command link in chain.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
void
{
QL_UB_LOCK(ha);
}
QL_UB_LOCK(ha);
}
} else {
/* Free outstanding command slot. */
}
/* Acquire device queue lock. */
/* Decrement outstanding commands on device. */
}
/*
* Clear the flag for this LUN so that
* untagged commands can be submitted
* for it.
*/
}
if (lq->lun_outcnt != 0) {
lq->lun_outcnt--;
}
}
/* Reset port down retry count on good completion. */
}
/* Alter aborted status for fast timeout feature */
}
/* Place request back on top of target command queue */
/* Reset watchdog timer */
/* Issue marker command on reset status. */
}
} else {
/* Remove command from watchdog queue. */
}
} else {
/* Release LU queue specific lock. */
NULL) {
}
}
/* Sync buffers if required. */
(void) ddi_dma_sync(
0, 0, DDI_DMA_SYNC_FORCPU);
}
/* Map ISP completion codes. */
case CS_COMPLETE:
break;
case CS_RESET:
/* Issue marker command. */
if (!(ha->task_daemon_flags &
LOOP_DOWN)) {
}
break;
case CS_RESOUCE_UNAVAILABLE:
break;
case CS_TIMEOUT:
break;
case CS_DATA_OVERRUN:
break;
case CS_PORT_UNAVAILABLE:
case CS_PORT_LOGGED_OUT:
break;
case CS_PORT_CONFIG_CHG:
break;
case CS_QUEUE_FULL:
break;
case CS_ABORTED:
} else {
}
break;
case CS_TRANSPORT:
break;
case CS_DATA_UNDERRUN:
break;
case CS_DMA_ERROR:
case CS_BAD_PAYLOAD:
case CS_UNKNOWN:
case CS_CMD_FAILED:
default:
break;
}
/* Now call the pkt completion callback */
} else {
0, 0);
}
}
}
}
}
}
/*
* ql_awaken_task_daemon
* awakens task daemon thread.
*
* Input:
* ha: adapter state pointer.
* sp: srb pointer.
* set_flags: task daemon flags to set.
* reset_flags: task daemon flags to reset.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
void
{
/* Acquire task daemon lock. */
if (set_flags & ISP_ABORT_NEEDED) {
}
}
if (QL_DAEMON_SUSPENDED(ha)) {
/* Do callback. */
} else {
}
} else {
}
}
} else {
}
}
}
}
/*
* ql_task_daemon
* Thread that is awaken by the driver when a
* background needs to be done.
*
* Input:
* arg = adapter state pointer.
*
* Context:
* Kernel context.
*/
static void
ql_task_daemon(void *arg)
{
"ql_task_daemon");
/* Acquire task daemon lock. */
/*
* Before we wait on the conditional variable, we
* need to check if STOP_FLG is set for us to terminate
*/
break;
}
/*LINTED [Solaris CALLB_CPR_SAFE_BEGIN Lint error]*/
/* If killed, stop task daemon */
&ha->task_daemon_mutex) == 0) {
}
/*LINTED [Solaris CALLB_CPR_SAFE_END Lint error]*/
}
/*LINTED [Solaris CALLB_CPR_EXIT Lint error]*/
thread_exit();
}
/*
* ql_task_thread
* Thread run by daemon.
*
* Input:
* ha = adapter state pointer.
* TASK_DAEMON_LOCK must be acquired prior to call.
*
* Context:
* Kernel context.
*/
static void
{
int loop_again, rval;
do {
loop_again = FALSE;
QL_PM_LOCK(ha);
break;
}
/* IDC acknowledge needed. */
case IDC_OPC_DRV_START:
if (ha->idc_restart_mpi != 0) {
ha->idc_restart_mpi--;
if (ha->idc_restart_mpi == 0) {
ha->restart_mpi_timer = 0;
ha->task_daemon_flags &=
}
}
if (ha->idc_flash_acc != 0) {
ha->idc_flash_acc--;
if (ha->idc_flash_acc == 0) {
ha->flash_acc_timer = 0;
}
}
break;
case IDC_OPC_FLASH_ACC:
if (ha->idc_flash_acc == 0) {
}
ha->idc_flash_acc++;
break;
case IDC_OPC_RESTART_MPI:
ha->idc_restart_mpi++;
ha->task_daemon_flags |=
break;
default:
break;
}
if (rval != QL_SUCCESS) {
}
loop_again = TRUE;
}
}
DRIVER_STALL) ||
break;
}
loop_again = TRUE;
}
/* Idle Check. */
loop_again = TRUE;
}
}
/* Crystal+ port#0 bypass transition */
(void) ql_initiate_lip(ha);
loop_again = TRUE;
}
/* Abort queues needed. */
}
/* Not suspended, awaken waiting routines. */
loop_again = TRUE;
}
/* Handle RSCN changes. */
(void) ql_handle_rscn_update(vha);
loop_again = TRUE;
}
}
/* Handle state changes. */
!(ha->task_daemon_flags &
/* Report state change. */
if (vha->task_daemon_flags &
vha->task_daemon_flags &=
if (!(ha->task_daemon_flags &
ha->task_daemon_flags |=
ha->task_daemon_flags &=
}
}
if (vha->task_daemon_flags &
STATE_ONLINE) {
msg = "Loop OFFLINE";
} else {
msg = "Link OFFLINE";
}
}
vha->task_daemon_flags &=
if (!(vha->task_daemon_flags &
STATE_ONLINE)) {
msg = "Loop ONLINE";
}
if (!(vha->task_daemon_flags &
STATE_ONLINE)) {
msg = "Link ONLINE";
}
} else {
msg = "Unknown Link state";
}
}
}
loop_again = TRUE;
}
}
}
}
loop_again = TRUE;
}
FIRMWARE_UP)) {
/*
* The firmware needs more unsolicited
* buffers. We cannot allocate any new
* buffers unless the ULP module requests
* for new buffers. All we can do here is
* to give received buffers from the pool
* that is already allocated
*/
loop_again = TRUE;
}
(void) ql_abort_isp(ha);
loop_again = TRUE;
}
COMMAND_WAIT_NEEDED))) {
}
loop_again = TRUE;
}
}
if (!(ha->task_daemon_flags &
ha->task_daemon_flags |=
(void) ql_loop_resync(ha);
loop_again = TRUE;
}
}
}
/* Port retry needed. */
ha->port_retry_timer = 0;
loop_again = B_TRUE;
}
/* iiDMA setting needed? */
loop_again = B_TRUE;
}
(void) ql_n_port_plogi(ha);
}
/* Dequeue command. */
/* Release task daemon lock. */
/* Do callback. */
} else {
}
/* Acquire task daemon lock. */
loop_again = TRUE;
}
} while (loop_again);
}
/*
* ql_idle_check
* Test for adapter is alive and well.
*
* Input:
* ha: adapter state pointer.
*
* Context:
* Kernel context.
*/
static void
{
int rval;
/* Firmware Ready Test. */
if (state == DDI_DEVSTATE_UP) {
/*EMPTY*/
DDI_DEVICE_FAULT, "Firmware Ready Test failed");
}
}
}
}
/*
* ql_unsol_callback
* Handle unsolicited buffer callbacks.
*
* Input:
* ha = adapter state pointer.
* sp = srb pointer.
*
* Context:
* Kernel context.
*/
static void
{
} else {
}
QL_UB_LOCK(ha);
return;
}
/* Process RSCN */
int sendup = 1;
/*
* Defer RSCN posting until commands return
*/
/* Abort outstanding commands */
if (sendup == 0) {
/*
* Wait for commands to drain in F/W (doesn't take
* more than a few milliseconds)
*/
return;
}
QL_UB_LOCK(ha);
}
/* Process UNSOL LOGO */
return;
}
QL_UB_LOCK(ha);
}
}
}
/*
* ql_send_logo
*
* Input:
* ha: adapter state pointer.
* tq: target queue pointer.
* done_q: done queue pointer.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
void
{
return;
}
/* Locate a buffer to use. */
return;
}
tq->logout_sent++;
/* Set header. */
/* set payload. */
/* Make sure ls_code in payload is always big endian */
QL_UB_LOCK(ha);
} else {
}
if (done_q) {
} else {
}
}
}
static int
{
int sendup = 1;
sendup = 0;
} else {
continue;
}
sendup = 0;
break;
}
}
}
return (sendup);
}
static int
{
LOOP_DOWN)) {
return (QL_FUNCTION_FAILED);
}
/* Locate a buffer to use. */
return (QL_FUNCTION_FAILED);
}
/* Set header. */
/* set payload. */
QL_UB_LOCK(ha);
if (done_q) {
} else {
}
return (QL_SUCCESS);
}
/*
* Abort outstanding commands in the Firmware, clear internally
* queued commands in the driver, Synchronize the target with
* the Firmware
*/
int
{
int rval = QL_SUCCESS;
/*
* First clear, internally queued commands
*/
continue;
}
/* Remove srb from device command queue. */
/* Set ending status. */
/* Call done routine to handle completions. */
}
}
}
}
if (rval != QL_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_rcv_rscn_els
* Processes received RSCN extended link service.
*
* Input:
* ha: adapter state pointer.
* mb: array containing input mailbox registers.
* done_q: done queue pointer.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
void
{
/* Locate a buffer to use. */
/* Set header. */
/* set payload. */
QL_UB_LOCK(ha);
}
} else {
/*EMPTY*/
}
}
/*
* ql_update_rscn
* Update devices from received RSCN.
*
* Input:
* ha: adapter state pointer.
* af: pointer to RSCN data.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
static void
{
if (tq) {
}
return;
}
switch (af->aff_format) {
case FC_RSCN_FABRIC_ADDRESS:
}
break;
case FC_RSCN_AREA_ADDRESS:
}
break;
case FC_RSCN_DOMAIN_ADDRESS:
}
break;
default:
break;
}
}
}
}
/*
* ql_process_rscn
*
* Input:
* ha: adapter state pointer.
* af: RSCN payload pointer.
*
* Context:
* Kernel context.
*/
static int
{
int sendit;
int sendup = 1;
if (tq) {
}
return (sendup);
}
continue;
}
switch (af->aff_format) {
case FC_RSCN_FABRIC_ADDRESS:
if (sendup) {
}
}
break;
case FC_RSCN_AREA_ADDRESS:
if (sendup) {
}
}
break;
case FC_RSCN_DOMAIN_ADDRESS:
if (sendup) {
}
}
break;
default:
break;
}
}
}
return (sendup);
}
/*
* ql_process_rscn_for_device
*
* Input:
* ha: adapter state pointer.
* tq: target queue pointer.
*
* Context:
* Kernel context.
*/
static int
{
int sendup = 1;
/*
* with their low level recoveries.
*/
/*
* Cause ADISC to go out
*/
}
sendup = 0;
} else {
}
} else {
}
if (sendup) {
}
}
return (sendup);
}
static int
{
int rval;
return (rval);
}
/*
* Get data from RISC code d_id list to init each device queue.
*/
if (rval != QL_SUCCESS) {
return (rval);
}
/* Acquire adapter state lock. */
/* Check for new devices */
continue;
}
/* Test for fabric device. */
}
QL_SUCCESS) {
}
/*
* Send up a PLOGI about the new device
*/
}
}
}
/* Release adapter state lock. */
}
if (rval != QL_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_free_unsolicited_buffer
* Frees allocated buffer.
*
* Input:
* ha = adapter state pointer.
* index = buffer array index.
* ADAPTER_STATE_LOCK must be already obtained.
*
* Context:
* Kernel context.
*/
static void
{
int status;
/* Disconnect IP from system buffers. */
if (status != QL_SUCCESS) {
"!Qlogic %s(%d): Failed to shutdown IP",
return;
}
}
} else {
}
if (ha->ub_allocated != 0) {
ha->ub_allocated--;
}
}
/*
* ql_get_unsolicited_buffer
* Locates a free unsolicited buffer.
*
* Input:
* ha = adapter state pointer.
* type = buffer type.
*
* Returns:
* Unsolicited buffer pointer.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
{
/* Locate a buffer to use. */
QL_UB_LOCK(ha);
SRB_UB_FREE_REQUESTED | SRB_UB_ACQUIRED)))) {
ubp->ub_resp_flags = 0;
break;
}
}
}
if (ubp) {
}
return (ubp);
}
/*
* ql_ub_frame_hdr
* Processes received unsolicited buffers from ISP.
*
* Input:
* ha: adapter state pointer.
* tq: target queue pointer.
* index: unsolicited buffer array index.
* done_q: done queue pointer.
*
* Returns:
* ql local function return status code.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
int
{
int rval = QL_FUNCTION_FAILED;
QL_UB_LOCK(ha);
return (rval);
}
return (rval);
}
/* set broadcast D_ID */
} else {
}
} else {
}
tq->ub_seq_cnt++;
} else {
}
tq->ub_total_seg_cnt = 0;
}
rval = QL_SUCCESS;
} else {
}
index);
}
index);
}
index);
}
}
return (rval);
}
/*
* ql_timer
* One second timer function.
*
* Input:
* ql_hba.first = first link in adapter list.
*
* Context:
* Interrupt context, no mailbox commands allowed.
*/
static void
{
/* Acquire global state lock. */
if (ql_timer_timeout_id == NULL) {
/* Release global state lock. */
return;
}
/* Skip adapter if suspended of stalled. */
continue;
}
QL_PM_LOCK(ha);
continue;
}
set_flags = 0;
reset_flags = 0;
/* Port retry timer handler. */
if (LOOP_READY(ha)) {
if (ha->port_retry_timer != 0) {
ha->port_retry_timer--;
if (ha->port_retry_timer == 0) {
}
}
}
/* Loop down timer handler. */
if (LOOP_RECONFIGURE(ha) == 0) {
ha->loop_down_timer--;
/*
* give the firmware loop down dump flag
* a chance to work.
*/
(void) ql_binary_fw_dump(ha,
TRUE);
}
"isp_abort_needed\n");
}
}
/* Command abort time handler. */
if (ha->loop_down_timer ==
"abort_queues_needed\n");
}
/* Watchdog timer handler. */
if (ha->watchdog_timer == 0) {
} else if (LOOP_READY(ha)) {
ha->watchdog_timer--;
if (ha->watchdog_timer == 0) {
&reset_flags);
}
ha->watchdog_timer =
}
}
}
}
/* Idle timer handler. */
if (!DRIVER_SUSPENDED(ha)) {
#if defined(QL_DEBUG_LEVEL_6) || !defined(QL_DEBUG_LEVEL_3)
#endif
ha->idle_timer = 0;
}
ha->send_plogi_timer--;
set_flags |= SEND_PLOGI;
}
}
}
if (ha->restart_mpi_timer != 0) {
ha->restart_mpi_timer--;
if (ha->restart_mpi_timer == 0 &&
ha->idc_restart_mpi != 0) {
ha->idc_restart_mpi = 0;
}
}
if (ha->flash_acc_timer != 0) {
ha->flash_acc_timer--;
if (ha->flash_acc_timer == 0 &&
ha->idc_flash_acc != 0) {
}
}
if (set_flags != 0 || reset_flags != 0) {
}
}
/* Update the IO stats */
}
}
QL_PM_LOCK(ha);
}
/* Restart timer, if not being stopped. */
if (ql_timer_timeout_id != NULL) {
}
/* Release global state lock. */
}
/*
* ql_timeout_insert
* Function used to insert a command block onto the
* watchdog timer queue.
*
* Note: Must insure that pkt_time is not zero
* before calling ql_timeout_insert.
*
* Input:
* ha: adapter state pointer.
* tq: target queue pointer.
* sp: SRB pointer.
* DEVICE_QUEUE_LOCK must be already obtained.
*
* Context:
* Kernel context.
*/
/* ARGSUSED */
static void
{
/*
* The WATCHDOG_TIME must be rounded up + 1. As an example,
* consider a 1 second timeout. If the WATCHDOG_TIME is 1, it
* will expire in the next watchdog call, which could be in
* 1 microsecond.
*
*/
/*
* Added an additional 10 to account for the
* firmware timer drift which can occur with
* very long timeout values.
*/
/*
* Add 6 more to insure watchdog does not timeout at the same
* time as ISP RISC code timeout.
*/
/* Save initial time for resetting watchdog time. */
/* Insert command onto watchdog queue. */
} else {
sp->isp_timeout = 0;
sp->wdg_q_time = 0;
sp->init_wdg_q_time = 0;
}
}
/*
* ql_watchdog
* Timeout handler that runs in interrupt context. The
* ql_adapter_state_t * argument is the parameter set up when the
* timeout was initialized (state structure pointer).
* Function used to update timeout values and if timeout
* has occurred command will be aborted.
*
* Input:
* ha: adapter state pointer.
* set_flags: task daemon flags to set.
* reset_flags: task daemon flags to reset.
*
* Context:
* Interrupt context, no mailbox commands allowed.
*/
static void
{
int q_sane;
/* Loop through all targets. */
link = next_device) {
/* Try to acquire device queue lock. */
if (TRY_DEVICE_QUEUE_LOCK(tq) == 0) {
next_device = NULL;
continue;
}
(tq->port_down_retry_count == 0)) {
/* Release device queue lock. */
continue;
}
/* Find out if this device is in a sane state. */
q_sane = 0;
} else {
q_sane = 1;
}
/* Loop through commands on watchdog queue. */
/*
* For SCSI commands, if everything seems to
* be going fine and this packet is stuck
* because of throttling at LUN or target
* level then do not decrement the
* sp->wdg_q_time
*/
continue;
}
if (sp->wdg_q_time != 0) {
sp->wdg_q_time--;
/* Timeout? */
if (sp->wdg_q_time != 0) {
continue;
}
next_device = NULL;
} else {
}
}
}
/* Release device queue lock. */
}
}
}
}
/*
* ql_cmd_timeout
* Command timeout handler.
*
* Input:
* ha: adapter state pointer.
* tq: target queue pointer.
* sp: SRB pointer.
* set_flags: task daemon flags to set.
* reset_flags: task daemon flags to reset.
*
* Context:
* Interrupt context, no mailbox commands allowed.
*/
/* ARGSUSED */
static void
{
/* if it's on a queue */
/*
* The pending_cmds que needs to be
* protected by the ring lock
*/
}
/* Release device queue lock. */
/* Set timeout status */
/* Ensure no retry */
/* Call done routine to handle completion. */
} else {
"isp_abort_needed\n", (void *)sp,
/* Release device queue lock. */
/* Set ISP needs to be reset */
}
}
}
/*
* ql_rst_aen
* Processes asynchronous reset.
*
* Input:
* ha = adapter state pointer.
*
* Context:
* Kernel context.
*/
static void
{
/* Issue marker command. */
}
/*
* ql_cmd_wait
* Stall driver until all outstanding commands are returned.
*
* Input:
* ha = adapter state pointer.
*
* Context:
* Kernel context.
*/
void
{
/* Wait for all outstanding commands to be returned. */
(void) ql_wait_outstanding(ha);
/*
* clear out internally queued commands
*/
if (tq &&
(!(tq->prli_svc_param_word_3 &
PRLI_W3_RETRY))) {
}
}
}
}
}
/*
* ql_wait_outstanding
* Wait for all outstanding commands to complete.
*
* Input:
* ha = adapter state pointer.
*
* Returns:
* index - the index for ql_srb into outstanding_cmds.
*
* Context:
* Kernel context.
*/
static uint16_t
{
count = 3000;
index = 1;
}
if (count-- != 0) {
index = 0;
} else {
break;
}
}
}
return (index);
}
/*
* ql_restart_queues
* Restart device queues.
*
* Input:
* ha = adapter state pointer.
* DEVICE_QUEUE_LOCK must be released.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
static void
{
/* Acquire device queue lock. */
}
}
/* Release device queue lock. */
}
}
}
}
/*
* ql_iidma
* Setup iiDMA parameters to firmware
*
* Input:
* ha = adapter state pointer.
* DEVICE_QUEUE_LOCK must be released.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
static void
{
char buf[256];
return;
}
/* Acquire device queue lock. */
continue;
}
continue;
}
/* Get the iiDMA persistent data */
"iidma-rate-%02x%02x%02x%02x%02x"
0xffffffff) {
} else {
switch (data) {
case IIDMA_RATE_1GB:
case IIDMA_RATE_2GB:
case IIDMA_RATE_4GB:
case IIDMA_RATE_10GB:
break;
case IIDMA_RATE_8GB:
CFG_CTRL_25XX)) {
} else {
tq->iidma_rate =
}
break;
default:
"parameter: %s: %xh\n",
tq->iidma_rate =
break;
}
}
}
/* Set the firmware's iiDMA rate */
if (data != QL_SUCCESS) {
}
}
/* Release device queue lock. */
}
}
}
/*
* ql_abort_queues
* Abort all commands on device queues.
*
* Input:
* ha = adapter state pointer.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
static void
{
/* Return all commands in outstanding command list. */
/* Place all commands in outstanding cmd list on device queue. */
/* Delay for system */
index = 1;
}
/* skip devices capable of FCP2 retrys */
/* Set ending status. */
/* Call done routine to handle completions. */
}
}
/* skip devices capable of FCP2 retrys */
if (!(tq->prli_svc_param_word_3 &
PRLI_W3_RETRY)) {
/*
* Set port unavailable status and
* return all commands on a devices
* queues.
*/
}
}
}
}
}
/*
* ql_abort_device_queues
* Abort all commands on device queues.
*
* Input:
* ha = adapter state pointer.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
static void
{
continue;
}
/* Remove srb from device cmd queue. */
/* Set ending status. */
/* Call done routine to handle completion. */
/* Delay for system */
}
}
}
/*
* ql_loop_resync
* Resync with fibre channel devices.
*
* Input:
* ha = adapter state pointer.
* DEVICE_QUEUE_LOCK must be released.
*
* Returns:
* ql local function return status code.
*
* Context:
* Kernel context.
*/
static int
{
int rval;
(void) ql_shutdown_ip(ha);
}
/* Set loop online, if it really is. */
if (rval == QL_SUCCESS) {
} else {
}
return (rval);
}
/*
* ql_loop_online
* Set loop online status if it really is online.
*
* Input:
* ha = adapter state pointer.
* DEVICE_QUEUE_LOCK must be released.
*
* Context:
* Kernel context.
*/
void
{
/* Inform the FC Transport that the hardware is online. */
if (!(vha->task_daemon_flags &
(LOOP_RESYNC_NEEDED | LOOP_DOWN))) {
/* Restart IP if it was shutdown. */
(void) ql_initialize_ip(vha);
}
} else {
}
}
}
}
/* Restart device queues that may have been stopped. */
}
/*
* ql_fca_handle_to_state
* Verifies handle to be correct.
*
* Input:
* fca_handle = pointer to state structure.
*
* Returns:
* NULL = failure
*
* Context:
* Kernel context.
*/
static ql_adapter_state_t *
{
#ifdef QL_DEBUG_ROUTINES
break;
}
}
break;
} else {
}
}
/*EMPTY*/
}
#endif /* QL_DEBUG_ROUTINES */
return ((ql_adapter_state_t *)fca_handle);
}
/*
* ql_d_id_to_queue
* Locate device queue that matches destination ID.
*
* Input:
* ha = adapter state pointer.
* d_id = destination ID
*
* Returns:
* NULL = failure
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
ql_tgt_t *
{
/* Get head queue index. */
return (tq);
}
}
return (NULL);
}
/*
* ql_loop_id_to_queue
* Locate device queue that matches loop ID.
*
* Input:
* ha: adapter state pointer.
* loop_id: destination ID
*
* Returns:
* NULL = failure
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
ql_tgt_t *
{
return (tq);
}
}
}
return (NULL);
}
/*
* ql_kstat_update
* Updates kernel statistics.
*
* Input:
* ksp - driver kernel statistics structure pointer.
* rw - function to perform
*
* Returns:
* 0 or EACCES
*
* Context:
* Kernel context.
*/
/* ARGSUSED */
static int
{
int rval;
if (rw == KSTAT_WRITE) {
} else {
rval = 0;
}
if (rval != 0) {
/*EMPTY*/
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_load_flash
* Loads flash.
*
* Input:
* ha: adapter state pointer.
* dp: data pointer.
* size: data length.
*
* Returns:
* ql local function return status code.
*
* Context:
* Kernel context.
*/
int
{
int rval;
int erase_all;
}
size_to_compare = 0x20000;
size_to_offset = 0;
erase_all = 0;
if (size == 0x80000) {
/* Request to flash the entire chip. */
size_to_compare = 0x80000;
erase_all = 1;
} else {
size_to_compare = 0x40000;
if (ql_flash_sbus_fpga) {
size_to_offset = 0x40000;
}
}
}
if (size > size_to_compare) {
return (rval);
}
/* Erase flash prior to write. */
if (rval == QL_SUCCESS) {
/* Write data to flash. */
/* Allow other system activity. */
if (cnt % 0x1000 == 0) {
}
if (rval != QL_SUCCESS) {
break;
}
}
}
if (rval != QL_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_program_flash_address
* Program flash address.
*
* Input:
* ha = adapter state pointer.
* addr = flash byte address.
* data = data to be written to flash.
*
* Returns:
* ql local function return status code.
*
* Context:
* Kernel context.
*/
static int
{
int rval;
} else {
/* Write Program Command Sequence */
}
/* Wait for write to complete. */
if (rval != QL_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_erase_flash
* Erases entire flash.
*
* Input:
* ha = adapter state pointer.
*
* Returns:
* ql local function return status code.
*
* Context:
* Kernel context.
*/
int
{
int rval;
if (ql_flash_sbus_fpga == 1) {
} else {
}
erase_delay = 20000000;
/* Save the section of flash we're not updating to buffer */
/* Allow other system activity. */
if (cnt % 0x1000 == 0) {
}
}
}
/* Chip Erase Command Sequence */
/* Wait for erase to complete. */
if (rval != QL_SUCCESS) {
}
return (rval);
}
/* restore the section we saved in the buffer */
/* Restore the section we saved off */
/* Allow other system activity. */
if (cnt % 0x1000 == 0) {
}
if (rval != QL_SUCCESS) {
break;
}
}
}
if (rval != QL_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_poll_flash
* Polls flash for completion.
*
* Input:
* ha = adapter state pointer.
* addr = flash byte address.
* data = data to be polled.
*
* Returns:
* ql local function return status code.
*
* Context:
* Kernel context.
*/
int
{
int rval = QL_FUNCTION_FAILED;
/* Wait for 30 seconds for command to finish. */
rval = QL_SUCCESS;
break;
}
cnt = 2;
}
drv_usecwait(1);
}
if (rval != QL_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_flash_enable
*
* Input:
* ha = adapter state pointer.
*
* Context:
* Kernel context.
*/
void
{
/* Read reset command sequence */
} else {
}
(void) ql_read_flash_byte(ha, 0);
}
/*
* ql_flash_disable
* Disable flash and allow RISC to run.
*
* Input:
* ha = adapter state pointer.
*
* Context:
* Kernel context.
*/
void
{
/*
* Lock the flash back up.
*/
} else {
}
}
/*
* ql_write_flash_byte
* Write byte to flash.
*
* Input:
* ha = adapter state pointer.
* addr = flash byte address.
* data = data to be written.
*
* Context:
* Kernel context.
*/
void
{
} else {
/* Setup bit 16 of flash address. */
} else {
}
}
} else {
}
}
}
/*
* ql_read_flash_byte
* Reads byte from flash, but must read a word from chip.
*
* Input:
* ha = adapter state pointer.
* addr = flash byte address.
*
* Returns:
* byte from flash.
*
* Context:
* Kernel context.
*/
{
} else {
/* Setup bit 16 of flash address. */
} else {
!(bank_select & ISP_FLASH_64K_BANK)) {
}
}
} else {
}
}
return (data);
}
/*
* ql_24xx_flash_id
* Get flash IDs.
*
* Input:
* ha: adapter state pointer.
*
* Returns:
* ql local function return status code.
*
* Context:
* Kernel context.
*/
int
{
int rval;
fdata = 0;
}
if (rval != QL_SUCCESS) {
} else if (fdata != 0) {
} else {
}
return (rval);
}
/*
* ql_24xx_load_flash
* Loads flash.
*
* Input:
* ha = adapter state pointer.
* dp = data pointer.
* size = data length in bytes.
* faddr = 32bit word flash byte address.
*
* Returns:
* ql local function return status code.
*
* Context:
* Kernel context.
*/
int
{
int rval;
/* start address must be 32 bit word aligned */
if ((faddr & 0x3) != 0) {
return (QL_FUNCTION_PARAMETER_ERROR);
}
/* Allocate DMA buffer */
QL_SUCCESS) {
return (rval);
}
}
/* Enable flash write */
return (rval);
}
/* setup mask of address range within a sector */
/*
* Write data to flash.
*/
cnt = 0;
/* Beginning of a sector? */
rest_addr, 0);
if (rval != QL_SUCCESS) {
"%xh, start=%xh, end=%xh"
break;
}
} else {
if (rest_addr == 0x1fff) {
/* 32kb sector block erase */
FLASH_CONF_ADDR | 0x0352,
fdata);
} else {
/* 64kb sector block erase */
FLASH_CONF_ADDR | 0x03d8,
fdata);
}
if (rval != QL_SUCCESS) {
": address=%xh\n", faddr);
break;
}
}
}
/* Write data */
((faddr & 0x3f) == 0)) {
/*
* Limit write up to sector boundary.
*/
}
if (rval != QL_SUCCESS) {
break;
}
} else {
if (rval != QL_SUCCESS) {
"address=%xh data=%xh\n", faddr,
*dp);
break;
}
cnt++;
faddr++;
/* Allow other system activity. */
if (cnt % 0x1000 == 0) {
}
}
}
if (rval != QL_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_24xx_read_flash
*
* Input:
* ha: adapter state pointer.
* bp: data pointer.
*
* Returns:
* ql local function return status code.
*
* Context:
* Kernel context.
*/
int
{
int rval = QL_SUCCESS;
/* Clear access error flag */
/* Wait for READ cycle to complete. */
break;
}
drv_usecwait(10);
}
if (timer == 0) {
}
return (rval);
}
/*
* ql_24xx_write_flash
*
* Input:
* ha: adapter state pointer.
* value: data.
*
* Returns:
* ql local function return status code.
*
* Context:
* Kernel context.
*/
int
{
int rval = QL_SUCCESS;
/* Clear access error flag */
/* Wait for Write cycle to complete. */
/* Check flash write in progress. */
(void) ql_24xx_read_flash(ha,
break;
}
} else {
break;
}
}
drv_usecwait(10);
}
if (timer == 0) {
}
return (rval);
}
/*
* ql_24xx_unprotect_flash
* Enable writes
*
* Input:
* ha: adapter state pointer.
*
* Returns:
* ql local function return status code.
*
* Context:
* Kernel context.
*/
int
{
int rval;
0)) != QL_SUCCESS) {
}
return (rval);
}
} else {
/* Enable flash write. */
}
/*
* Remove block write protection (SST and ST) and
* Unprotect sectors.
*/
}
}
return (QL_SUCCESS);
}
/*
* ql_24xx_protect_flash
* Disable writes
*
* Input:
* ha: adapter state pointer.
*
* Context:
* Kernel context.
*/
void
{
int rval;
0)) != QL_SUCCESS) {
}
return;
}
} else {
/* Enable flash write. */
}
/*
* Protect sectors.
* Set block write protection (SST and ST) and
*/
}
/* TODO: ??? */
(void) ql_24xx_write_flash(ha,
} else {
(void) ql_24xx_write_flash(ha,
}
/* Disable flash write. */
}
}
/*
* ql_dump_firmware
* Save RISC code state information.
*
* Input:
* ha = adapter state pointer.
*
* Returns:
* QL local function return status code.
*
* Context:
* Kernel context.
*/
static int
{
int rval;
return (QL_SUCCESS);
}
/*
* Wait for all outstanding commands to complete
*/
(void) ql_wait_outstanding(ha);
/* Dump firmware. */
/* Do abort to force restart. */
/* Acquire task daemon lock. */
/* Wait for suspension to end. */
/* 30 seconds from now */
/*
* The timeout time 'timer' was
* reached without the condition
* being signaled.
*/
break;
}
}
/* Release task daemon lock. */
/*EMPTY*/
} else {
}
return (rval);
}
/*
* ql_binary_fw_dump
* Dumps binary data from firmware.
*
* Input:
* ha = adapter state pointer.
* lock_needed = mailbox lock needed.
*
* Returns:
* ql local function return status code.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
int
{
int rval = QL_SUCCESS;
return (QL_DATA_EXISTS);
}
/* Insert Time Stamp */
if (rval != QL_SUCCESS) {
"time stamp failed: %xh\n", rval);
}
}
if (lock_needed == TRUE) {
/* Acquire mailbox register lock. */
/* Check for mailbox available, if not wait for signal. */
/* 30 seconds from now */
/*
* The timeout time 'timer' was
* reached without the condition
* being signaled.
*/
/* Release mailbox register lock. */
return (QL_FUNCTION_TIMEOUT);
}
}
/* Set busy flag. */
/* Release mailbox register lock. */
}
/* Free previous dump buffer. */
}
} else {
}
NULL) {
} else {
} else {
}
}
/* Reset ISP chip. */
if (rval != QL_SUCCESS) {
}
} else {
}
return (rval);
}
/*
* ql_ascii_fw_dump
* Converts firmware binary dump to ascii.
*
* Input:
* ha = adapter state pointer.
* bptr = buffer pointer.
*
* Returns:
* Amount of data buffer used.
*
* Context:
* Kernel context.
*/
{
int mbox_cnt;
}
} else {
}
if (cnt % 8 == 0) {
*bp++ = '\n';
}
}
"registers:");
if (cnt % 8 == 0) {
*bp++ = '\n';
}
}
}
if (cnt % 8 == 0) {
*bp++ = '\n';
}
}
if (cnt % 8 == 0) {
*bp++ = '\n';
}
}
}
if (cnt % 8 == 0) {
*bp++ = '\n';
}
}
if (cnt % 8 == 0) {
*bp++ = '\n';
}
}
if (cnt % 8 == 0) {
*bp++ = '\n';
}
}
if (cnt % 8 == 0) {
*bp++ = '\n';
}
}
if (cnt % 8 == 0) {
*bp++ = '\n';
}
}
if (cnt % 8 == 0) {
*bp++ = '\n';
}
}
if (cnt % 8 == 0) {
*bp++ = '\n';
}
}
if (cnt % 8 == 0) {
*bp++ = '\n';
}
}
if (cnt % 8 == 0) {
*bp++ = '\n';
}
}
if (cnt % 8 == 0) {
*bp++ = '\n';
}
}
CFG_CTRL_6322)) == 0))) {
break;
}
if (cnt % 8 == 0) {
*bp++ = '\n';
}
}
if (cnt % 8 == 0) {
*bp++ = '\n';
}
}
if (cnt % 8 == 0) {
*bp++ = '\n';
}
}
if (cnt % 8 == 0) {
}
}
if (cnt % 8 == 0) {
}
}
if (cnt % 8 == 0) {
}
}
} else {
if (cnt % 8 == 0) {
}
}
}
if (cnt % 8 == 0) {
}
}
if (cnt % 8 == 0) {
}
}
}
/*
* ql_24xx_ascii_fw_dump
* Converts ISP24xx firmware binary dump to ascii.
*
* Input:
* ha = adapter state pointer.
* bptr = buffer pointer.
*
* Returns:
* Amount of data buffer used.
*
* Context:
* Kernel context.
*/
static size_t
{
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 16 == 0) {
}
bp += 5;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
bp += 11;
}
bp += 9;
}
if (cnt % 8 == 0) {
bp += 11;
}
bp += 9;
}
if (cnt % 8 == 0) {
}
}
if (cnt % 8 == 0) {
}
}
/* show data address as a byte address, data as long words */
if (cnt_b % 32 == 0) {
bp += 11;
}
bp += 9;
}
}
/* show data address as a byte address, data as long words */
if (cnt_b % 32 == 0) {
bp += 11;
}
bp += 9;
}
}
return (cnt);
}
/*
* ql_2581_ascii_fw_dump
* Converts ISP25xx or ISP81xx firmware binary dump to ascii.
*
* Input:
* ha = adapter state pointer.
* bptr = buffer pointer.
*
* Returns:
* Amount of data buffer used.
*
* Context:
* Kernel context.
*/
static size_t
{
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 16 == 0) {
}
bp += 5;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
}
bp += 9;
}
if (cnt % 8 == 0) {
bp += 11;
}
bp += 9;
}
if (cnt % 8 == 0) {
bp += 11;
}
bp += 9;
}
if (cnt % 8 == 0) {
}
}
if (cnt % 8 == 0) {
}
}
/* show data address as a byte address, data as long words */
if (cnt_b % 32 == 0) {
bp += 11;
}
bp += 9;
}
}
/* show data address as a byte address, data as long words */
if (cnt_b % 32 == 0) {
bp += 11;
}
bp += 9;
}
}
return (cnt);
}
/*
* ql_2200_binary_fw_dump
*
* Input:
* ha: adapter state pointer.
* fw: firmware dump context pointer.
*
* Returns:
* ql local function return status code.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
static int
{
int rval = QL_SUCCESS;
/* Disable ISP interrupts. */
/* Release mailbox registers. */
/* Pause RISC. */
timer = 30000;
if (timer-- != 0) {
} else {
break;
}
}
if (rval == QL_SUCCESS) {
/* In 2200 we only read 8 mailboxes */
8, 16);
/* 2200 has only 16 registers */
/* Select FPM registers. */
/* FPM Soft Reset. */
/* Select frame buffer registers. */
/* Reset frame buffer FIFOs. */
/* Select RISC module registers. */
/* Reset RISC module. */
/* Reset ISP semaphore. */
/* Release RISC module. */
/* Wait for RISC to recover from reset. */
timer = 30000;
if (timer-- != 0) {
} else {
break;
}
}
/* Disable RISC pause on FPM parity error. */
}
if (rval == QL_SUCCESS) {
/* Pause RISC. */
timer = 30000;
if (timer-- != 0) {
} else {
break;
}
}
}
if (rval == QL_SUCCESS) {
/* Set memory configuration and timing. */
/* Release RISC. */
/* Get RISC SRAM. */
risc_address = 0x1000;
/* Check for pending interrupts. */
BIT_0) {
mailbox[0]);
mailbox[2]);
semaphore, 0);
break;
}
}
drv_usecwait(5);
}
if (timer == 0) {
} else {
}
if (rval != QL_SUCCESS) {
break;
}
}
}
return (rval);
}
/*
* ql_2300_binary_fw_dump
*
* Input:
* ha: adapter state pointer.
* fw: firmware dump context pointer.
*
* Returns:
* ql local function return status code.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
static int
{
int rval = QL_SUCCESS;
/* Disable ISP interrupts. */
/* Release mailbox registers. */
/* Pause RISC. */
timer = 30000;
if (timer-- != 0) {
} else {
break;
}
}
if (rval == QL_SUCCESS) {
/* Select FPM registers. */
/* FPM Soft Reset. */
/* Select frame buffer registers. */
/* Reset frame buffer FIFOs. */
/* Select RISC module registers. */
/* Reset RISC module. */
/* Reset ISP semaphore. */
/* Release RISC module. */
/* Wait for RISC to recover from reset. */
timer = 30000;
if (timer-- != 0) {
} else {
break;
}
}
/* Disable RISC pause on FPM parity error. */
}
/* Get RISC SRAM. */
if (rval == QL_SUCCESS) {
}
/* Get STACK SRAM. */
if (rval == QL_SUCCESS) {
}
/* Get DATA SRAM. */
if (rval == QL_SUCCESS) {
}
return (rval);
}
/*
* ql_24xx_binary_fw_dump
*
* Input:
* ha: adapter state pointer.
* fw: firmware dump context pointer.
*
* Returns:
* ql local function return status code.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
static int
{
void *bp;
int rval = QL_SUCCESS;
/* Pause RISC. */
/* Disable ISP interrupts. */
for (timer = 30000;
if (timer) {
drv_usecwait(100);
} else {
}
}
}
if (rval == QL_SUCCESS) {
/* Host interface registers. */
/* Disable ISP interrupts. */
/* Shadow registers. */
/* Mailbox registers. */
/* Transfer sequence registers. */
/* XSEQ GP */
16, 32);
/* XSEQ-0 */
/* XSEQ-1 */
/* Receive sequence registers. */
/* RSEQ GP */
16, 32);
/* RSEQ-0 */
/* RSEQ-1 */
/* RSEQ-2 */
/* Command DMA registers. */
/* Queues. */
/* RequestQ0 */
8, 32);
/* ResponseQ0 */
8, 32);
/* RequestQ1 */
8, 32);
/* Transmit DMA registers. */
/* XMT0 */
16, 32);
/* XMT1 */
16, 32);
/* XMT2 */
16, 32);
/* XMT3 */
16, 32);
/* XMT4 */
16, 32);
/* XMT Common */
/* Receive DMA registers. */
/* RCVThread0 */
/* RCVThread1 */
/* RISC registers. */
/* RISC GP */
16, 32);
/* Local memory controller registers. */
/* LMC */
16, 32);
/* Fibre Protocol Module registers. */
/* FPM hardware */
16, 32);
/* Frame Buffer registers. */
/* FB hardware */
16, 32);
}
/* Get the request queue */
if (rval == QL_SUCCESS) {
/* Sync DMA buffer. */
}
}
/* Get the response queue */
if (rval == QL_SUCCESS) {
/* Sync DMA buffer. */
}
}
/* Reset RISC. */
/* Memory. */
if (rval == QL_SUCCESS) {
/* Code RAM. */
}
if (rval == QL_SUCCESS) {
/* External Memory. */
}
/* Get the extended trace buffer */
if (rval == QL_SUCCESS) {
/* Sync DMA buffer. */
}
}
}
/* Get the FC event trace buffer */
if (rval == QL_SUCCESS) {
/* Sync DMA buffer. */
}
}
}
if (rval != QL_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_25xx_binary_fw_dump
*
* Input:
* ha: adapter state pointer.
* fw: firmware dump context pointer.
*
* Returns:
* ql local function return status code.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
static int
{
void *bp;
int rval = QL_SUCCESS;
/* Pause RISC. */
/* Disable ISP interrupts. */
for (timer = 30000;
if (timer) {
drv_usecwait(100);
if (timer % 10000 == 0) {
}
} else {
}
}
}
if (rval == QL_SUCCESS) {
/* Host Interface registers */
/* HostRisc registers. */
16, 32);
/* PCIe registers. */
3, 32);
/* Host interface registers. */
/* Disable ISP interrupts. */
/* Shadow registers. */
/* RISC I/O register. */
1, 32);
/* Mailbox registers. */
/* Transfer sequence registers. */
/* XSEQ GP */
16, 32);
/* XSEQ-0 */
16, 32);
/* XSEQ-1 */
16, 32);
/* Receive sequence registers. */
/* RSEQ GP */
16, 32);
/* RSEQ-0 */
16, 32);
/* RSEQ-1 */
/* RSEQ-2 */
/* Auxiliary sequencer registers. */
/* ASEQ GP */
16, 32);
/* ASEQ-0 */
16, 32);
/* ASEQ-1 */
16, 32);
/* ASEQ-2 */
16, 32);
/* Command DMA registers. */
/* Queues. */
/* RequestQ0 */
8, 32);
/* ResponseQ0 */
8, 32);
/* RequestQ1 */
8, 32);
/* Transmit DMA registers. */
/* XMT0 */
16, 32);
/* XMT1 */
16, 32);
/* XMT2 */
16, 32);
/* XMT3 */
16, 32);
/* XMT4 */
16, 32);
/* XMT Common */
/* Receive DMA registers. */
/* RCVThread0 */
/* RCVThread1 */
/* RISC registers. */
/* RISC GP */
16, 32);
/* Local memory controller (LMC) registers. */
/* LMC */
16, 32);
/* Fibre Protocol Module registers. */
/* FPM hardware */
16, 32);
/* Frame Buffer registers. */
/* FB hardware */
16, 32);
}
/* Get the request queue */
if (rval == QL_SUCCESS) {
/* Sync DMA buffer. */
}
}
/* Get the respons queue */
if (rval == QL_SUCCESS) {
/* Sync DMA buffer. */
}
}
/* Reset RISC. */
/* Memory. */
if (rval == QL_SUCCESS) {
/* Code RAM. */
}
if (rval == QL_SUCCESS) {
/* External Memory. */
}
/* Get the FC event trace buffer */
if (rval == QL_SUCCESS) {
/* Sync DMA buffer. */
}
}
}
/* Get the extended trace buffer */
if (rval == QL_SUCCESS) {
/* Sync DMA buffer. */
}
}
}
if (rval != QL_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_81xx_binary_fw_dump
*
* Input:
* ha: adapter state pointer.
* fw: firmware dump context pointer.
*
* Returns:
* ql local function return status code.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
static int
{
void *bp;
int rval = QL_SUCCESS;
/* Pause RISC. */
/* Disable ISP interrupts. */
for (timer = 30000;
if (timer) {
drv_usecwait(100);
if (timer % 10000 == 0) {
}
} else {
}
}
}
if (rval == QL_SUCCESS) {
/* Host Interface registers */
/* HostRisc registers. */
16, 32);
/* PCIe registers. */
3, 32);
/* Host interface registers. */
/* Disable ISP interrupts. */
/* Shadow registers. */
/* RISC I/O register. */
1, 32);
/* Mailbox registers. */
/* Transfer sequence registers. */
/* XSEQ GP */
16, 32);
/* XSEQ-0 */
16, 32);
/* XSEQ-1 */
16, 32);
/* Receive sequence registers. */
/* RSEQ GP */
16, 32);
/* RSEQ-0 */
16, 32);
/* RSEQ-1 */
/* RSEQ-2 */
/* Auxiliary sequencer registers. */
/* ASEQ GP */
16, 32);
/* ASEQ-0 */
16, 32);
/* ASEQ-1 */
16, 32);
/* ASEQ-2 */
16, 32);
/* Command DMA registers. */
/* Queues. */
/* RequestQ0 */
8, 32);
/* ResponseQ0 */
8, 32);
/* RequestQ1 */
8, 32);
/* Transmit DMA registers. */
/* XMT0 */
16, 32);
/* XMT1 */
16, 32);
/* XMT2 */
16, 32);
/* XMT3 */
16, 32);
/* XMT4 */
16, 32);
/* XMT Common */
/* Receive DMA registers. */
/* RCVThread0 */
/* RCVThread1 */
/* RISC registers. */
/* RISC GP */
16, 32);
/* Local memory controller (LMC) registers. */
/* LMC */
16, 32);
/* Fibre Protocol Module registers. */
/* FPM hardware */
16, 32);
/* Frame Buffer registers. */
/* FB hardware */
16, 32);
}
/* Get the request queue */
if (rval == QL_SUCCESS) {
/* Sync DMA buffer. */
}
}
/* Get the respons queue */
if (rval == QL_SUCCESS) {
/* Sync DMA buffer. */
}
}
/* Reset RISC. */
/* Memory. */
if (rval == QL_SUCCESS) {
/* Code RAM. */
}
if (rval == QL_SUCCESS) {
/* External Memory. */
}
/* Get the FC event trace buffer */
if (rval == QL_SUCCESS) {
/* Sync DMA buffer. */
}
}
}
/* Get the extended trace buffer */
if (rval == QL_SUCCESS) {
/* Sync DMA buffer. */
}
}
}
if (rval != QL_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_read_risc_ram
* Reads RISC RAM one word at a time.
* Risc interrupts must be disabled when this routine is called.
*
* Input:
* ha: adapter state pointer.
* risc_address: RISC code start address.
* len: Number of words.
* buf: buffer pointer.
*
* Returns:
* ql local function return status code.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
static int
void *buf)
{
int rval = QL_SUCCESS;
mailbox[2]),
mailbox[3]));
} else {
}
break;
break;
}
} else {
}
}
drv_usecwait(5);
}
} else {
}
if (timer == 0) {
}
}
return (rval);
}
/*
* ql_read_regs
* Reads adapter registers to buffer.
*
* Input:
* ha: adapter state pointer.
* buf: buffer pointer.
* reg: start address.
* count: number of registers.
* wds: register size.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
static void *
{
switch (wds) {
case 32:
while (count--) {
}
return (bp32);
case 16:
while (count--) {
}
return (bp16);
case 8:
while (count--) {
}
return (bp8);
default:
return (buf);
}
}
static int
{
int ret;
return (DDI_FAILURE);
}
/*LINTED [Solaris DDI_DEV_T_ANY Lint warning]*/
1) {
return (DDI_SUCCESS);
}
}
}
/*LINTED [Solaris DDI_DEV_T_NONE Lint warning]*/
if (ret != DDI_PROP_SUCCESS) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
static int
{
return (DDI_FAILURE);
}
/*LINTED [Solaris DDI_DEV_T_ANY Lint warning]*/
return (DDI_FAILURE);
}
}
}
/*LINTED [Solaris DDI_DEV_T_NONE Lint warning]*/
}
return (DDI_SUCCESS);
}
{
}
#ifdef KERNEL_32
#else
#endif
}
{
}
#ifdef KERNEL_32
#else
#endif
}
{
}
#ifdef KERNEL_32
#else
#endif
}
void
{
} else {
#ifdef KERNEL_32
#else
#endif
}
}
void
{
} else {
#ifdef KERNEL_32
#else
#endif
}
}
void
{
} else {
#ifdef KERNEL_32
#else
#endif
}
}
/*
* ql_halt
* Waits for commands that are running to finish and
* if they do not, commands are aborted.
* Finally the adapter is reset.
*
* Input:
* ha: adapter state pointer.
* pwr: power state.
*
* Context:
* Kernel context.
*/
static void
{
/* Wait for all commands running to finish. */
/* Wait for 30 seconds for commands to finish. */
/* Acquire device queue lock. */
/* Release device queue lock. */
break;
} else {
/* Release device queue lock. */
}
}
/* Finish any commands waiting for more status. */
}
/* Abort commands that did not finish. */
if (cnt == 0) {
cnt++) {
cnt = 1;
}
tq) {
}
}
}
}
}
/* Shutdown IP. */
(void) ql_shutdown_ip(ha);
}
/* Stop all timers. */
ha->port_retry_timer = 0;
ha->watchdog_timer = 0;
if (pwr == PM_LEVEL_D3) {
/* Reset ISP chip. */
}
}
/*
* ql_get_dma_mem
* Function used to allocate dma memory.
*
* Input:
* ha: adapter state pointer.
* mem: pointer to dma memory object.
* size: size of the request in bytes
*
* Returns:
* qn local function return status code.
*
* Context:
* Kernel context.
*/
int
{
int rval;
switch (alignment) {
case QL_DMA_DATA_ALIGN:
break;
case QL_DMA_RING_ALIGN:
break;
default:
break;
}
}
return (rval);
}
/*
* ql_alloc_phys
* Function used to allocate memory and zero it.
* Memory is below 4 GB.
*
* Input:
* ha: adapter state pointer.
* mem: pointer to dma memory object.
* sleep: KM_SLEEP/KM_NOSLEEP flag.
* mem->cookie_count number of segments allowed.
* mem->type memory allocation type.
* mem->size memory size.
* mem->alignment memory alignment.
*
* Returns:
* qn local function return status code.
*
* Context:
* Kernel context.
*/
int
{
/*
* Workaround for SUN XMITS buffer must end and start on 8 byte
* boundary. Else, hardware will overrun the buffer. Simple fix is
* to make sure buffer has enough room for overrun.
*/
}
/*
* Allocate DMA memory for command.
*/
DDI_SUCCESS) {
return (QL_MEMORY_ALLOC_FAILED);
}
case KERNEL_MEM:
break;
case BIG_ENDIAN_DMA:
case LITTLE_ENDIAN_DMA:
case NO_SWAP_DMA:
}
/* ensure we got what we asked for (32bit) */
"returned 64 bit DMA address\n");
return (QL_MEMORY_ALLOC_FAILED);
}
}
} else {
}
break;
default:
break;
}
return (QL_MEMORY_ALLOC_FAILED);
}
return (QL_MEMORY_ALLOC_FAILED);
}
return (QL_SUCCESS);
}
/*
* ql_free_phys
* Function used to free physical memory.
*
* Input:
* ha: adapter state pointer.
* mem: pointer to dma memory object.
*
* Context:
* Kernel context.
*/
void
{
case KERNEL_MEM:
}
break;
case LITTLE_ENDIAN_DMA:
case BIG_ENDIAN_DMA:
case NO_SWAP_DMA:
}
break;
default:
break;
}
}
}
/*
* ql_alloc_dma_resouce.
* Allocates DMA resource for buffer.
*
* Input:
* ha: adapter state pointer.
* mem: pointer to dma memory object.
* sleep: KM_SLEEP/KM_NOSLEEP flag.
* mem->cookie_count number of segments allowed.
* mem->type memory allocation type.
* mem->size memory size.
* mem->bp pointer to memory or struct buf
*
* Returns:
* qn local function return status code.
*
* Context:
* Kernel context.
*/
int
{
/*
* Allocate DMA handle for command.
*/
DDI_SUCCESS) {
return (QL_MEMORY_ALLOC_FAILED);
}
return (QL_MEMORY_ALLOC_FAILED);
}
return (QL_SUCCESS);
}
/*
* ql_free_dma_resource
* Frees DMA resources.
*
* Input:
* ha: adapter state pointer.
* mem: pointer to dma memory object.
* mem->dma_handle DMA memory handle.
*
* Context:
* Kernel context.
*/
void
{
}
/*
* ql_bind_dma_buffer
* Binds DMA buffer.
*
* Input:
* ha: adapter state pointer.
* mem: pointer to dma memory object.
* sleep: KM_SLEEP or KM_NOSLEEP.
* mem->dma_handle DMA memory handle.
* mem->cookie_count number of segments allowed.
* mem->type memory allocation type.
* mem->size memory size.
* mem->bp pointer to memory or struct buf
*
* Returns:
* mem->cookies pointer to list of cookies.
* mem->cookie_count number of cookies.
* status success = DDI_DMA_MAPPED
* DDI_DMA_PARTIAL_MAP, DDI_DMA_INUSE,
* DDI_DMA_NORESOURCES, DDI_DMA_NOMAPPING or
* DDI_DMA_TOOBIG
*
* Context:
* Kernel context.
*/
static int
{
int rval;
} else {
&mem->cookie_count);
}
if (rval == DDI_DMA_MAPPED) {
} else {
sizeof (ddi_dma_cookie_t) *
cnt++) {
++cookiep);
}
} else {
(void) ddi_dma_unbind_handle(
mem->dma_handle);
}
} else {
/*
* It has been reported that dmac_size at times
* may be incorrect on sparc machines so for
* sparc machines that only have one segment
* use the buffer size instead.
*/
}
}
}
if (rval != DDI_DMA_MAPPED) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_unbind_dma_buffer
* Unbinds DMA buffer.
*
* Input:
* ha: adapter state pointer.
* mem: pointer to dma memory object.
* mem->dma_handle DMA memory handle.
* mem->cookies pointer to cookie list.
* mem->cookie_count number of cookies.
*
* Context:
* Kernel context.
*/
/* ARGSUSED */
static void
{
mem->cookie_count);
}
mem->cookie_count = 0;
}
static int
{
/*
* First we will claim mbox ownership so that no
* thread using mbox hangs when we disable the
* interrupt in the middle of it.
*/
/* Check for mailbox available, if not wait for signal. */
/* 30 seconds from now */
/* Release mailbox register lock. */
return (QL_FUNCTION_TIMEOUT);
}
}
/* Set busy flag. */
(void) ql_wait_outstanding(ha);
/*
* here we are sure that there will not be any mbox interrupt.
* So, let's make sure that we return back all the outstanding
* cmds as well as internally queued commands.
*/
/* Disable ISP interrupts. */
}
/* Reset busy status. */
/* If thread is waiting for mailbox go signal it to start. */
}
/* Release mailbox register lock. */
return (QL_SUCCESS);
}
/*
* ql_add_link_b
* Add link to the end of the chain.
*
* Input:
* head = Head of link list.
* link = link to be added.
* LOCK must be already obtained.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
void
{
/* at the end there isn't a next */
} else {
}
}
/*
* ql_add_link_t
* Add link to the beginning of the chain.
*
* Input:
* head = Head of link list.
* link = link to be added.
* LOCK must be already obtained.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
void
{
} else {
}
}
/*
* ql_remove_link
* Remove a link from the chain.
*
* Input:
* head = Head of link list.
* link = link to be removed.
* LOCK must be already obtained.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
void
{
} else {
}
} else {
}
/* not on a queue any more */
}
/*
* ql_chg_endian
* Change endianess of byte array.
*
* Input:
* buf = array pointer.
* size = size of array in bytes.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
void
{
cnt1--;
}
}
/*
* ql_bstr_to_dec
* Convert decimal byte string to number.
*
* Input:
* s: byte string pointer.
* ans: interger pointer for number.
* size: number of ascii bytes.
*
* Returns:
* success = number of ascii bytes processed.
*
* Context:
*/
static int
{
char *str;
/* Calculate size of number. */
if (size == 0) {
size++;
}
}
*ans = 0;
if (*s >= '0' && *s <= '9') {
num = *s++ - '0';
} else {
break;
}
mul *= 10;
}
}
return (cnt);
}
/*
* ql_delay
* Calls delay routine if threads are not suspended, otherwise, busy waits
* Minimum = 1 tick = 10ms
*
* Input:
* dly = delay time in microseconds.
*
* Context:
* Kernel or Interrupt context, no mailbox commands allowed.
*/
void
{
} else {
}
}
/*
* ql_stall_drv
* Stalls one or all driver instances, waits for 30 seconds.
*
* Input:
* ha: adapter state pointer or NULL for all.
* options: BIT_0 --> leave driver stalled on exit if
* failed.
*
* Returns:
* ql local function return status code.
*
* Context:
* Kernel context.
*/
int
{
/* Wait for 30 seconds for daemons unstall. */
timer = 3000;
continue;
}
timer--;
}
"unstalled"));
}
return (QL_FUNCTION_TIMEOUT);
}
return (QL_SUCCESS);
}
/*
* ql_restart_driver
* Restarts one or all driver instances.
*
* Input:
* ha: adapter state pointer or NULL for all.
*
* Context:
* Kernel context.
*/
void
{
/* Tell all daemons to unstall. */
}
/* Wait for 30 seconds for all daemons unstall. */
timer = 3000;
continue;
}
timer--;
}
}
/*
* ql_setup_interrupts
* Sets up interrupts based on the HBA's and platform's
* capabilities (e.g., legacy / MSI / FIXED).
*
* Input:
* ha = adapter state pointer.
*
* Returns:
* DDI_SUCCESS or DDI_FAILURE.
*
* Context:
* Kernel context.
*/
static int
{
int32_t i;
/*
* The Solaris Advanced Interrupt Functions (aif) are only
* supported on s10U1 or greater.
*/
"disabled, using legacy\n");
return (ql_legacy_intr(ha));
} else if (ql_os_release_level == 10) {
/*
* See if the advanced interrupt functions (aif) are
* in the kernel
*/
void *fptr = (void *)&ddi_intr_get_supported_types;
"interrupts (rev)\n");
return (ql_legacy_intr(ha));
}
}
/* See what types of interrupts this HBA and platform support */
DDI_SUCCESS) {
"assuming FIXED\n", i);
}
if ((itypes & DDI_INTR_TYPE_MSIX) &&
} else if ((itypes & DDI_INTR_TYPE_MSI) &&
} else {
}
if (rval != DDI_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_setup_msi
* Set up aif MSI interrupts
*
* Input:
* ha = adapter state pointer.
*
* Returns:
* DDI_SUCCESS or DDI_FAILURE.
*
* Context:
* Kernel context.
*/
static int
{
if (ql_disable_msi != 0) {
return (DDI_FAILURE);
}
/* MSI support is only suported on 24xx HBA's. */
return (DDI_FAILURE);
}
/* Get number of MSI interrupts the system supports */
DDI_SUCCESS) || count == 0) {
return (DDI_FAILURE);
}
/* Get number of available MSI interrupts */
DDI_SUCCESS) || avail == 0) {
return (DDI_FAILURE);
}
/* MSI requires only 1. */
count = 1;
/* Allocate space for interrupt handles */
/* Allocate the interrupts */
return (DDI_FAILURE);
}
/* Get interrupt priority */
DDI_SUCCESS) {
return (ret);
}
/* Add the interrupt handler */
return (ret);
}
/* Setup mutexes */
return (ret);
}
/* Get the capabilities */
/* Enable interrupts */
DDI_SUCCESS) {
return (ret);
}
} else {
return (ret);
}
}
return (DDI_SUCCESS);
}
/*
* ql_setup_msix
* Set up aif MSI-X interrupts
*
* Input:
* ha = adapter state pointer.
*
* Returns:
* DDI_SUCCESS or DDI_FAILURE.
*
* Context:
* Kernel context.
*/
static int
{
uint32_t i;
if (ql_disable_msix != 0) {
return (DDI_FAILURE);
}
/*
* MSI-X support is only available on 24xx HBA's that have
* rev A2 parts (revid = 3) or greater.
*/
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
/* Per HP, these HP branded HBA's are not supported with MSI-X */
return (DDI_FAILURE);
}
/* Get the number of 24xx/25xx MSI-X h/w vectors */
if (hwvect < QL_MSIX_MAXAIF) {
return (DDI_FAILURE);
}
/* Get number of MSI-X interrupts the platform h/w supports */
DDI_SUCCESS) || count == 0) {
return (DDI_FAILURE);
}
/* Get number of available system interrupts */
DDI_SUCCESS) || avail == 0) {
return (DDI_FAILURE);
}
/* Fill out the intr table */
/* Allocate space for interrupt handles */
return (DDI_FAILURE);
}
/* Allocate the interrupts */
actual < QL_MSIX_MAXAIF) {
return (DDI_FAILURE);
}
/* Get interrupt priority */
DDI_SUCCESS) {
return (ret);
}
/* Add the interrupt handlers */
for (i = 0; i < actual; i++) {
return (ret);
}
}
/*
* duplicate the rest of the intr's
* ddi_intr_dup_handler() isn't working on x86 just yet...
*/
#ifdef __sparc
return (ret);
}
}
#endif
/* Setup mutexes */
return (ret);
}
/* Get the capabilities */
/* Enable interrupts */
DDI_SUCCESS) {
return (ret);
}
} else {
DDI_SUCCESS) {
return (ret);
}
}
}
return (DDI_SUCCESS);
}
/*
* ql_setup_fixed
* Sets up aif FIXED interrupts
*
* Input:
* ha = adapter state pointer.
*
* Returns:
* DDI_SUCCESS or DDI_FAILURE.
*
* Context:
* Kernel context.
*/
static int
{
uint32_t i;
/* Get number of fixed interrupts the system supports */
return (DDI_FAILURE);
}
/* Allocate space for interrupt handles */
/* Allocate the interrupts */
return (DDI_FAILURE);
}
/* Get interrupt priority */
DDI_SUCCESS) {
return (ret);
}
/* Add the interrupt handlers */
return (ret);
}
}
/* Setup mutexes */
return (ret);
}
/* Enable interrupts */
return (ret);
}
}
return (DDI_SUCCESS);
}
/*
* ql_disable_intr
* Disables interrupts
*
* Input:
* ha = adapter state pointer.
*
* Returns:
*
* Context:
* Kernel context.
*/
static void
{
/* Disable legacy interrupts */
/* Remove AIF block interrupts (MSI) */
!= DDI_SUCCESS) {
}
} else {
/* Remove AIF non-block interrupts (fixed). */
DDI_SUCCESS) {
"rval=%xh\n", i, rval);
}
}
}
}
/*
* ql_release_intr
* Releases aif legacy interrupt resources
*
* Input:
* ha = adapter state pointer.
*
* Returns:
*
* Context:
* Kernel context.
*/
static void
{
int32_t i;
return;
}
while (i-- > 0) {
continue;
}
}
}
}
}
/*
* ql_legacy_intr
* Sets up legacy interrupts.
*
* NB: Only to be used if AIF (Advanced Interupt Framework)
* if NOT in the kernel.
*
* Input:
* ha = adapter state pointer.
*
* Returns:
* DDI_SUCCESS or DDI_FAILURE.
*
* Context:
* Kernel context.
*/
static int
{
int rval = DDI_SUCCESS;
/* Setup mutexes */
return (DDI_FAILURE);
}
rval = DDI_FAILURE;
}
if (rval == DDI_SUCCESS) {
}
return (rval);
}
/*
* ql_init_mutex
* Initializes mutex's
*
* Input:
* ha = adapter state pointer.
*
* Returns:
* DDI_SUCCESS or DDI_FAILURE.
*
* Context:
* Kernel context.
*/
static int
{
int ret;
void *intr;
} else {
/* Get iblock cookies to initialize mutexes */
return (DDI_FAILURE);
}
}
/* mutexes to protect the adapter state structure. */
/* mutex to protect the ISP response ring. */
/* mutex to protect the mailbox registers. */
/* power management protection */
/* Mailbox wait and interrupt conditional variable. */
/* mutex to protect the ISP request ring. */
/* Unsolicited buffer conditional variable. */
/* Suspended conditional variable. */
/* mutex to protect task daemon context. */
/* Task_daemon thread conditional variable. */
/* mutex to protect diag port manage interface */
/* mutex to protect per instance f/w dump flags and buffer */
return (DDI_SUCCESS);
}
/*
* ql_destroy_mutex
* Destroys mutex's
*
* Input:
* ha = adapter state pointer.
*
* Returns:
*
* Context:
* Kernel context.
*/
static void
{
}
/*
* ql_fwmodule_resolve
* Loads and resolves external firmware module and symbols
*
* Input:
* ha: adapter state pointer.
*
* Returns:
* ql local function return status code:
* QL_SUCCESS - external f/w module module and symbols resolved
* QL_FW_NOT_SUPPORTED - Driver does not support ISP type
* QL_FWMODLOAD_FAILED - Could not load f/w module (ddi failed)
* QL_FWSYM_NOT_FOUND - Unable to resolve internal f/w symbol
* Context:
* Kernel context.
*
* NOTE: We currently ddi_modopen/ddi_modclose at attach/detach time. We
* could switch to a tighter scope around acutal download (and add an extra
* ddi_modopen for module opens that occur before root is mounted).
*
*/
{
return (rval);
}
/* make sure the fw_class is in the fw_table of supported classes */
break; /* match */
}
return (QL_FW_NOT_SUPPORTED);
}
/*
* open the module related to the fw_class
*/
return (QL_FWMODLOAD_FAILED);
}
/*
* resolve the fw module symbols, data types depend on fw_class
*/
case 0x2200:
case 0x2300:
case 0x6322:
}
if (rval == QL_SUCCESS) {
}
break;
case 0x2400:
case 0x2500:
case 0x8100:
}
}
if (rval == QL_SUCCESS) {
}
break;
default:
}
if (rval != QL_SUCCESS) {
}
} else {
/*
* check for firmware version mismatch between module and
* compiled in fw_table version.
*/
/*
* If f/w / driver version mismatches then
* return a successful status -- however warn
* the user that this is NOT recommended.
*/
"mismatch for %x: driver-%s module-%s", QL_NAME,
} else {
}
}
return (rval);
}
/*
* ql_port_state
* Set the state on all adapter ports.
*
* Input:
* ha: parent adapter state pointer.
* state: port state.
* flags: task daemon flags to set.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
void
{
}
}
}
/*
* ql_el_trace_desc_ctor - Construct an extended logging trace descriptor.
*
* Input: Pointer to the adapter state structure.
* Returns: Success or Failure.
* Context: Kernel context.
*/
int
{
int rval = DDI_SUCCESS;
ha->el_trace_desc =
rval = DDI_FAILURE;
} else {
rval = DDI_FAILURE;
} else {
MUTEX_DRIVER, NULL);
}
}
return (rval);
}
/*
* ql_el_trace_desc_dtor - Destroy an extended logging trace descriptor.
*
* Input: Pointer to the adapter state structure.
* Returns: Success or Failure.
* Context: Kernel context.
*/
int
{
int rval = DDI_SUCCESS;
rval = DDI_FAILURE;
} else {
}
}
return (rval);
}
/*
* els_cmd_text - Return a pointer to a string describing the command
*
* Input: els_cmd = the els command opcode.
* Returns: pointer to a string.
* Context: Kernel context.
*/
char *
els_cmd_text(int els_cmd)
{
}
/*
* mbx_cmd_text - Return a pointer to a string describing the command
*
* Input: mbx_cmd = the mailbox command opcode.
* Returns: pointer to a string.
* Context: Kernel context.
*/
char *
mbx_cmd_text(int mbx_cmd)
{
}
/*
* cmd_text Return a pointer to a string describing the command
*
* Input: entry = the command table
* cmd = the command.
* Returns: pointer to a string.
* Context: Kernel context.
*/
char *
{
break;
}
}
}
/*
* ql_els_24xx_mbox_cmd_iocb - els request indication.
*
* Input: ha = adapter state pointer.
* srb = scsi request block pointer.
* arg = els passthru entry iocb pointer.
* Returns:
* Context: Kernel context.
*/
void
{
/* Extract the ELS information */
/* Construct the passthru entry */
/* Ensure correct endianness */
}
/*
* ql_fca_isp_els_request - Extract into an els descriptor the info required
* to build an els_passthru iocb from an fc packet.
*
* Input: ha = adapter state pointer.
* pkt = fc packet pointer
* els_desc = els descriptor pointer
* Returns:
* Context: Kernel context.
*/
static void
{
/* if n_port_handle is not < 0x7d use 0 */
} else {
els_desc->n_port_handle = 0;
}
els_desc->control_flags = 0;
/*
* Transmit DSD. This field defines the Fibre Channel Frame payload
* (without the frame header) in system memory.
*/
/*
* Receive DSD. This field defines the ELS response payload buffer
* for the ISP24xx firmware transferring the received ELS
* response frame to a location in host memory.
*/
}
/*
* ql_isp_els_request_ctor - Construct an els_passthru_entry iocb
* using the els descriptor.
*
* Input: ha = adapter state pointer.
* els_desc = els descriptor pointer.
* els_entry = els passthru entry iocb pointer.
* Returns:
* Context: Kernel context.
*/
static void
{
/*
* Construct command packet.
*/
(uint32_t)0);
/* Load transmit data segments and count. */
}
/*
* ql_isp_els_handle_cmd_endian - els requests must be in big endian
* in host memory.
*
* Input: ha = adapter state pointer.
* srb = scsi request block
* Returns:
* Context: Kernel context.
*/
void
{
}
/*
* ql_isp_els_handle_rsp_endian - els responses must be in big endian
* in host memory.
* Input: ha = adapter state pointer.
* srb = scsi request block
* Returns:
* Context: Kernel context.
*/
void
{
BIG_ENDIAN_32(&els);
}
/*
* in host memory.
* Input: ha = adapter state pointer.
* ls_code = els command code.
* Returns:
* Context: Kernel context.
*/
void
{
switch (ls_code) {
case LA_ELS_PLOGI: {
ptr += 4;
ptr += 2;
ptr += 2;
ptr += 2;
ptr += 2;
ptr += 2;
ptr += 2;
ptr += 2;
ptr += 2;
ptr += 2;
ptr += 2;
ptr += 2;
ptr += 2;
break;
}
case LA_ELS_PRLI: {
ptr += 2;
ptr += 2;
ptr += 4;
ptr += 4;
break;
}
default:
break;
}
}
/*
* ql_n_port_plogi
* In N port 2 N port topology where an N Port has logged in with the
* firmware because it has the N_Port login initiative, we send up
* a plogi by proxy which stimulates the login procedure to continue.
*
* Input:
* ha = adapter state pointer.
* Returns:
*
* Context:
* Kernel context.
*/
static int
{
int rval;
rval = QL_SUCCESS;
/* if we're doing this the n_port_handle must be good */
} else {
}
} else {
}
}
}
return (rval);
}
/*
* Compare two WWNs. The NAA is omitted for comparison.
*
* Note particularly that the indentation used in this
* function isn't according to Sun recommendations. It
* is indented to make reading a bit easy.
*
* Return Values:
* if first == second return 0
* if first > second return 1
* if first < second return -1
*/
int
{
int rval;
/*
* Fibre Channel protocol is big endian, so compare
* as big endian values
*/
rval = 0;
rval = 1;
} else {
rval = -1;
}
} else {
rval = 1;
} else {
rval = -1;
}
}
return (rval);
}
/*
* ql_wait_for_td_stop
* Wait for task daemon to stop running. Internal command timeout
* is approximately 30 seconds, so it may help in some corner
* cases to wait that long
*
* Input:
* ha = adapter state pointer.
*
* Returns:
* DDI_SUCCESS or DDI_FAILURE.
*
* Context:
* Kernel context.
*/
static int
{
int rval = DDI_FAILURE;
/* The task daemon clears the stop flag on exit. */
ddi_in_panic()) {
drv_usecwait(10000);
} else {
}
} else {
rval = DDI_SUCCESS;
break;
}
}
return (rval);
}
/*
* ql_nvram_cache_desc_ctor - Construct an nvram cache descriptor.
*
* Input: Pointer to the adapter state structure.
* Returns: Success or Failure.
* Context: Kernel context.
*/
int
{
int rval = DDI_SUCCESS;
ha->nvram_cache =
KM_SLEEP);
rval = DDI_FAILURE;
} else {
} else {
}
sizeof (nvram_cache_desc_t));
ha->nvram_cache = 0;
rval = DDI_FAILURE;
} else {
MUTEX_DRIVER, NULL);
}
}
return (rval);
}
/*
* ql_nvram_cache_desc_dtor - Destroy an nvram cache descriptor.
*
* Input: Pointer to the adapter state structure.
* Returns: Success or Failure.
* Context: Kernel context.
*/
int
{
int rval = DDI_SUCCESS;
rval = DDI_FAILURE;
} else {
}
}
return (rval);
}