ISP 10x0 driver from Matthew Jacob of NASA Ames Research Center.

(March 12, 1997 version).
This commit is contained in:
cgd 1997-03-12 20:44:50 +00:00
parent 5c9a92362a
commit 099e30a322
8 changed files with 5139 additions and 0 deletions

View File

@ -0,0 +1,310 @@
/* $NetBSD: isp_sbus.c,v 1.1.1.1 1997/03/12 20:44:50 cgd Exp $ */
/*
* SBus specific probe and attach routines for Qlogic ISP SCSI adapters.
*
* Copyright (c) 1997 by Matthew Jacob
* NASA AMES Research Center
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice immediately at the beginning of the file, without modification,
* this list of conditions, and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/queue.h>
#include <sys/device.h>
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
#include <machine/autoconf.h>
#include <sparc/cpu.h>
#include <sparc/sparc/cpuvar.h>
#include <sparc/dev/sbusvar.h>
#include <dev/ic/ispreg.h>
#include <dev/ic/ispvar.h>
#include <dev/microcode/isp/asm_sbus.h>
#include <machine/param.h>
#include <machine/vmparam.h>
static u_int16_t isp_sbus_rd_reg __P((struct ispsoftc *, int));
static void isp_sbus_wr_reg __P((struct ispsoftc *, int, u_int16_t));
static vm_offset_t
isp_sbus_mbxdma __P((struct ispsoftc *, vm_offset_t, u_int32_t));
static int
isp_sbus_dmasetup __P((struct ispsoftc *, struct scsi_xfer *, ispreq_t *,
u_int8_t *, u_int8_t));
static void
isp_sbus_dmateardown __P((struct ispsoftc *, struct scsi_xfer *, u_int32_t));
static struct ispmdvec mdvec = {
isp_sbus_rd_reg,
isp_sbus_wr_reg,
isp_sbus_mbxdma,
isp_sbus_dmasetup,
isp_sbus_dmateardown,
NULL,
NULL,
(u_int16_t *) ISP_RISC_CODE,
ISP_CODE_LENGTH,
ISP_CODE_ORG,
0
};
struct isp_sbussoftc {
struct ispsoftc sbus_isp;
struct intrhand sbus_ih;
volatile u_char *sbus_reg;
int sbus_node;
int sbus_pri;
vm_offset_t sbus_kdma_allocs[RQUEST_QUEUE_LEN];
};
static int isp_match __P((struct device *, struct cfdata *, void *));
static void isp_sbus_attach __P((struct device *, struct device *, void *));
struct cfattach isp_sbus_ca = {
sizeof (struct isp_sbussoftc), isp_match, isp_sbus_attach
};
static int
isp_match(parent, cf, aux)
struct device *parent;
struct cfdata *cf;
void *aux;
{
struct confargs *ca = aux;
register struct romaux *ra = &ca->ca_ra;
if (strcmp(cf->cf_driver->cd_name, ra->ra_name) &&
strcmp("SUNW,isp", ra->ra_name) &&
strcmp("QLGC,isp", ra->ra_name)) {
return (0);
}
if (ca->ca_bustype == BUS_SBUS)
return (1);
ra->ra_len = NBPG;
return (probeget(ra->ra_vaddr, 1) != -1);
}
static void
isp_sbus_attach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct confargs *ca = aux;
struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) self;
if (ca->ca_ra.ra_nintr != 1) {
printf(": expected 1 interrupt, got %d\n", ca->ca_ra.ra_nintr);
return;
}
sbc->sbus_pri = ca->ca_ra.ra_intr[0].int_pri;
printf(" pri %d\n", sbc->sbus_pri);
if (ca->ca_ra.ra_vaddr) {
sbc->sbus_reg = (volatile u_char *) ca->ca_ra.ra_vaddr;
} else {
sbc->sbus_reg = (volatile u_char *)
mapiodev(ca->ca_ra.ra_reg, 0, ca->ca_ra.ra_len,
ca->ca_bustype);
}
sbc->sbus_node = ca->ca_ra.ra_node;
sbc->sbus_isp.isp_mdvec = &mdvec;
isp_reset(&sbc->sbus_isp);
if (sbc->sbus_isp.isp_state != ISP_RESETSTATE) {
return;
}
isp_init(&sbc->sbus_isp);
if (sbc->sbus_isp.isp_state != ISP_INITSTATE) {
isp_uninit(&sbc->sbus_isp);
return;
}
sbc->sbus_ih.ih_fun = (void *) isp_intr;
sbc->sbus_ih.ih_arg = sbc;
intr_establish(sbc->sbus_pri, &sbc->sbus_ih);
/*
* Do Generic attach now.
*/
isp_attach(&sbc->sbus_isp);
if (sbc->sbus_isp.isp_state != ISP_RUNSTATE) {
isp_uninit(&sbc->sbus_isp);
}
}
#define SBUS_BIU_REGS_OFF 0x00
#define SBUS_MBOX_REGS_OFF 0x80
#define SBUS_SXP_REGS_OFF 0x200
#define SBUS_RISC_REGS_OFF 0x400
static u_int16_t
isp_sbus_rd_reg(isp, regoff)
struct ispsoftc *isp;
int regoff;
{
struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
int offset;
if ((regoff & BIU_BLOCK) != 0) {
offset = SBUS_BIU_REGS_OFF;
} else if ((regoff & MBOX_BLOCK) != 0) {
offset = SBUS_MBOX_REGS_OFF;
} else if ((regoff & SXP_BLOCK) != 0) {
offset = SBUS_SXP_REGS_OFF;
} else {
offset = SBUS_RISC_REGS_OFF;
}
regoff &= 0xff;
offset += regoff;
return (*((u_int16_t *) &sbc->sbus_reg[offset]));
}
static void
isp_sbus_wr_reg (isp, regoff, val)
struct ispsoftc *isp;
int regoff;
u_int16_t val;
{
struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
int offset;
if ((regoff & BIU_BLOCK) != 0) {
offset = SBUS_BIU_REGS_OFF;
} else if ((regoff & MBOX_BLOCK) != 0) {
offset = SBUS_MBOX_REGS_OFF;
} else if ((regoff & SXP_BLOCK) != 0) {
offset = SBUS_SXP_REGS_OFF;
} else {
offset = SBUS_RISC_REGS_OFF;
}
regoff &= 0xff;
offset += regoff;
*((u_int16_t *) &sbc->sbus_reg[offset]) = val;
}
static vm_offset_t
isp_sbus_mbxdma(isp, kva, len)
struct ispsoftc *isp;
vm_offset_t kva;
u_int32_t len;
{
/*
* Since most Sun machines aren't I/O coherent,
* map the mailboxes through kdvma space to
* force them to be uncached.
*/
return ((vm_offset_t) kdvma_mapin((caddr_t)kva, len, 0));
}
/*
* TODO: If kdvma_mapin fails, try using multiple smaller chunks..
*/
static int
isp_sbus_dmasetup(isp, xs, rq, iptrp, optr)
struct ispsoftc *isp;
struct scsi_xfer *xs;
ispreq_t *rq;
u_int8_t *iptrp;
u_int8_t optr;
{
struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
vm_offset_t kdvma;
int dosleep = (xs->flags & SCSI_NOSLEEP) != 0;
if (xs->datalen == 0) {
rq->req_seg_count = 1;
rq->req_flags |= REQFLAG_DATA_IN;
return (0);
}
if (rq->req_handle >= RQUEST_QUEUE_LEN) {
panic("%s: bad handle (%d) in isp_sbus_dmasetup\n",
isp->isp_name, rq->req_handle);
/* NOTREACHED */
}
if (CPU_ISSUN4M) {
kdvma = (vm_offset_t)
kdvma_mapin((caddr_t)xs->data, xs->datalen, dosleep);
if (kdvma == (vm_offset_t) 0) {
return (1);
}
} else {
kdvma = (vm_offset_t) xs->data;
}
if (sbc->sbus_kdma_allocs[rq->req_handle] != (vm_offset_t) 0) {
panic("%s: kdma handle already allocated\n", isp->isp_name);
/* NOTREACHED */
}
sbc->sbus_kdma_allocs[rq->req_handle] = kdvma;
if (xs->flags & SCSI_DATA_IN) {
rq->req_flags |= REQFLAG_DATA_IN;
} else {
rq->req_flags |= REQFLAG_DATA_OUT;
}
rq->req_dataseg[0].ds_count = xs->datalen;
rq->req_dataseg[0].ds_base = (u_int32_t) kdvma;
rq->req_seg_count = 1;
return (0);
}
static void
isp_sbus_dmateardown(isp, xs, handle)
struct ispsoftc *isp;
struct scsi_xfer *xs;
u_int32_t handle;
{
struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
vm_offset_t kdvma;
if (xs->flags & SCSI_DATA_IN) {
cpuinfo.cache_flush(xs->data, xs->datalen - xs->resid);
}
if (handle >= RQUEST_QUEUE_LEN) {
panic("%s: bad handle (%d) in isp_sbus_dmateardown\n",
isp->isp_name, handle);
/* NOTREACHED */
}
if (sbc->sbus_kdma_allocs[handle] == (vm_offset_t) 0) {
panic("%s: kdma handle not already allocated\n", isp->isp_name);
/* NOTREACHED */
}
kdvma = sbc->sbus_kdma_allocs[handle];
sbc->sbus_kdma_allocs[handle] = (vm_offset_t) 0;
if (CPU_ISSUN4M) {
dvma_mapout(kdvma, (vm_offset_t) xs->data, xs->datalen);
}
}

998
sys/dev/ic/isp.c Normal file
View File

@ -0,0 +1,998 @@
/* $NetBSD: isp.c,v 1.1.1.1 1997/03/12 20:44:51 cgd Exp $ */
/*
* Machine Independent (well, as best as possible)
* code for the Qlogic ISP SCSI adapters.
*
* Specific probe attach and support routines for Qlogic ISP SCSI adapters.
*
* Copyright (c) 1997 by Matthew Jacob
* NASA AMES Research Center.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice immediately at the beginning of the file, without modification,
* this list of conditions, and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/*
* Inspiration and ideas about this driver are from Erik Moe's Linux driver
* (qlogicisp.c) and Dave Miller's SBus version of same (qlogicisp.c)
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/buf.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
#include <scsi/scsi_message.h>
#include <scsi/scsi_debug.h>
#include <scsi/scsiconf.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/pmap.h>
#include <dev/ic/ispreg.h>
#include <dev/ic/ispvar.h>
#include <dev/ic/ispmbox.h>
#define MBOX_DELAY_COUNT 1000000 / 100
struct cfdriver isp_cd = {
NULL, "isp", DV_DULL
};
static void ispminphys __P((struct buf *));
static int32_t ispscsicmd __P((struct scsi_xfer *xs));
static int isp_mboxcmd __P((struct ispsoftc *, mbreg_t *));
static struct scsi_adapter isp_switch = {
ispscsicmd, ispminphys, 0, 0
};
static struct scsi_device isp_dev = { NULL, NULL, NULL, NULL };
static int isp_poll __P((struct ispsoftc *, int));
static int isp_parse_status __P((struct ispsoftc *, ispstatusreq_t *));
/*
* Reset Hardware.
*
* Only looks at sc_dev.dv_xname, sc_iot and sc_ioh fields.
*/
void
isp_reset(isp)
struct ispsoftc *isp;
{
mbreg_t mbs;
int loops, i;
isp->isp_state = ISP_NILSTATE;
/*
* Do MD specific pre initialization
*/
ISP_RESET0(isp);
/*
* Hit the chip over the head with hammer.
*/
ISP_WRITE(isp, BIU_ICR, BIU_ICR_SOFT_RESET);
/*
* Give the ISP a chance to recover...
*/
delay(100);
/*
* Clear data && control DMA engines.
*/
ISP_WRITE(isp, CDMA_CONTROL,
DMA_CNTRL_CLEAR_CHAN | DMA_CNTRL_RESET_INT);
ISP_WRITE(isp, DDMA_CONTROL,
DMA_CNTRL_CLEAR_CHAN | DMA_CNTRL_RESET_INT);
/*
* Wait for ISP to be ready to go...
*/
loops = MBOX_DELAY_COUNT;
while ((ISP_READ(isp, BIU_ICR) & BIU_ICR_SOFT_RESET) != 0) {
delay(100);
if (--loops < 0) {
printf("%s: chip reset timed out\n", isp->isp_name);
return;
}
}
/*
* More initialization
*/
ISP_WRITE(isp, BIU_CONF1, 0);
ISP_WRITE(isp, HCCR, HCCR_CMD_RESET);
delay(100);
if (isp->isp_mdvec->dv_conf1) {
ISP_SETBITS(isp, BIU_CONF1, isp->isp_mdvec->dv_conf1);
if (isp->isp_mdvec->dv_conf1 & BIU_BURST_ENABLE) {
ISP_SETBITS(isp, CDMA_CONF, DMA_ENABLE_BURST);
ISP_SETBITS(isp, DDMA_CONF, DMA_ENABLE_BURST);
}
} else {
ISP_WRITE(isp, BIU_CONF1, 0);
}
#if 0
ISP_WRITE(isp, RISC_MTR, 0x1212); /* FM */
#endif
ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); /* release paused processor */
/*
* Do MD specific post initialization
*/
ISP_RESET1(isp);
/*
* Enable interrupts
*/
ISP_WRITE(isp, BIU_ICR,
BIU_ICR_ENABLE_RISC_INT | BIU_ICR_ENABLE_ALL_INTS);
/*
* Do some sanity checking.
*/
mbs.param[0] = MBOX_NO_OP;
(void) isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
printf("%s: NOP test failed\n", isp->isp_name);
return;
}
mbs.param[0] = MBOX_MAILBOX_REG_TEST;
mbs.param[1] = 0xdead;
mbs.param[2] = 0xbeef;
mbs.param[3] = 0xffff;
mbs.param[4] = 0x1111;
mbs.param[5] = 0xa5a5;
(void) isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
printf("%s: Mailbox Register test didn't complete\n",
isp->isp_name);
return;
}
i = 0;
if (mbs.param[1] != 0xdead) {
printf("%s: Register Test Failed @reg %d (got %x)\n",
isp->isp_name, 1, mbs.param[1]);
i++;
}
if (mbs.param[2] != 0xbeef) {
printf("%s: Register Test Failed @reg %d (got %x)\n",
isp->isp_name, 2, mbs.param[2]);
i++;
}
if (mbs.param[3] != 0xffff) {
printf("%s: Register Test Failed @reg %d (got %x)\n",
isp->isp_name, 3, mbs.param[3]);
i++;
}
if (mbs.param[4] != 0x1111) {
printf("%s: Register Test Failed @reg %d (got %x)\n",
isp->isp_name, 4, mbs.param[4]);
i++;
}
if (mbs.param[5] != 0xa5a5) {
printf("%s: Register Test Failed @reg %d (got %x)\n",
isp->isp_name, 5, mbs.param[5]);
i++;
}
if (i) {
return;
}
/*
* Download new Firmware
*/
for (i = 0; i < isp->isp_mdvec->dv_fwlen; i++) {
mbs.param[0] = MBOX_WRITE_RAM_WORD;
mbs.param[1] = isp->isp_mdvec->dv_codeorg + i;
mbs.param[2] = isp->isp_mdvec->dv_ispfw[i];
(void) isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
printf("%s: f/w download failed\n", isp->isp_name);
return;
}
}
/*
* Verify that it downloaded correctly.
*/
mbs.param[0] = MBOX_VERIFY_CHECKSUM;
mbs.param[1] = isp->isp_mdvec->dv_codeorg;
(void) isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
printf("%s: ram checksum failure\n", isp->isp_name);
return;
}
/*
* Now start it rolling...
*/
mbs.param[0] = MBOX_EXEC_FIRMWARE;
mbs.param[1] = isp->isp_mdvec->dv_codeorg;
(void) isp_mboxcmd(isp, &mbs);
mbs.param[0] = MBOX_ABOUT_FIRMWARE;
(void) isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
printf("%s: ABOUT FIRMWARE command failed\n", isp->isp_name);
return;
}
printf("%s: F/W Revision %d.%d\n", isp->isp_name,
mbs.param[1], mbs.param[2]);
isp->isp_state = ISP_RESETSTATE;
}
/*
* Initialize Hardware to known state
*/
void
isp_init(isp)
struct ispsoftc *isp;
{
vm_offset_t queue_addr;
mbreg_t mbs;
int s, i, l;
/*
* Set Default Host Adapter Parameters
* XXX: Should try and get them out of NVRAM
*/
isp->isp_adapter_enabled = 1;
isp->isp_req_ack_active_neg = 1;
isp->isp_data_line_active_neg = 1;
isp->isp_cmd_dma_burst_enable = 1;
isp->isp_data_dma_burst_enabl = 1;
isp->isp_fifo_threshold = 2;
isp->isp_initiator_id = 7;
isp->isp_async_data_setup = 6;
isp->isp_selection_timeout = 250;
isp->isp_max_queue_depth = 256;
isp->isp_tag_aging = 8;
isp->isp_bus_reset_delay = 3;
isp->isp_retry_count = 0;
isp->isp_retry_delay = 1;
for (i = 0; i < MAX_TARGETS; i++) {
isp->isp_devparam[i].dev_flags = DPARM_DEFAULT;
isp->isp_devparam[i].exc_throttle = 16;
isp->isp_devparam[i].sync_period = 25;
isp->isp_devparam[i].sync_offset = 12;
isp->isp_devparam[i].dev_enable = 1;
}
s = splbio();
mbs.param[0] = MBOX_SET_INIT_SCSI_ID;
mbs.param[1] = isp->isp_initiator_id;
(void) isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
(void) splx(s);
printf("%s: failed to set initiator id\n", isp->isp_name);
return;
}
mbs.param[0] = MBOX_SET_RETRY_COUNT;
mbs.param[1] = isp->isp_retry_count;
mbs.param[2] = isp->isp_retry_delay;
(void) isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
(void) splx(s);
printf("%s: failed to set retry count and delay\n",
isp->isp_name);
return;
}
mbs.param[0] = MBOX_SET_ASYNC_DATA_SETUP_TIME;
mbs.param[1] = isp->isp_async_data_setup;
(void) isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
(void) splx(s);
printf("%s: failed to set async data setup time\n",
isp->isp_name);
return;
}
mbs.param[0] = MBOX_SET_ACTIVE_NEG_STATE;
mbs.param[1] =
(isp->isp_req_ack_active_neg << 4) |
(isp->isp_data_line_active_neg << 5);
(void) isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
(void) splx(s);
printf("%s: failed to set active negation state\n",
isp->isp_name);
return;
}
mbs.param[0] = MBOX_SET_TAG_AGE_LIMIT;
mbs.param[1] = isp->isp_tag_aging;
(void) isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
(void) splx(s);
printf("%s: failed to set tag age limit\n", isp->isp_name);
return;
}
mbs.param[0] = MBOX_SET_SELECT_TIMEOUT;
mbs.param[1] = isp->isp_selection_timeout;
(void) isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
(void) splx(s);
printf("%s: failed to set selection timeout\n", isp->isp_name);
return;
}
for (i = 0; i < MAX_TARGETS; i++) {
if (isp->isp_devparam[i].dev_enable == 0)
continue;
mbs.param[0] = MBOX_SET_TARGET_PARAMS;
mbs.param[1] = i << 8;
mbs.param[2] = isp->isp_devparam[i].dev_flags << 8;
mbs.param[3] =
(isp->isp_devparam[i].sync_offset << 8) |
(isp->isp_devparam[i].sync_period);
(void) isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
(void) splx(s);
printf("%s: failed to set target parameters\n",
isp->isp_name);
return;
}
for (l = 0; l < MAX_LUNS; l++) {
mbs.param[0] = MBOX_SET_DEV_QUEUE_PARAMS;
mbs.param[1] = (i << 8) | l;
mbs.param[2] = isp->isp_max_queue_depth;
mbs.param[3] = isp->isp_devparam[i].exc_throttle;
(void) isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
(void) splx(s);
printf("%s: failed to set device queue "
"parameters\n", isp->isp_name);
return;
}
}
}
queue_addr =
ISP_MBOXDMASETUP(isp, isp->isp_result, sizeof (isp->isp_result));
if (queue_addr == 0) {
(void) splx(s);
return;
}
mbs.param[0] = MBOX_INIT_RES_QUEUE;
mbs.param[1] = RESULT_QUEUE_LEN;
mbs.param[2] = (u_int16_t) (queue_addr >> 16);
mbs.param[3] = (u_int16_t) (queue_addr & 0xffff);
mbs.param[4] = 0;
(void) isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
(void) splx(s);
printf("%s: set of response queue failed\n", isp->isp_name);
return;
}
isp->isp_residx = 0;
queue_addr =
ISP_MBOXDMASETUP(isp, isp->isp_rquest, sizeof (isp->isp_rquest));
if (queue_addr == 0) {
(void) splx(s);
return;
}
mbs.param[0] = MBOX_INIT_REQ_QUEUE;
mbs.param[1] = RQUEST_QUEUE_LEN;
mbs.param[2] = (u_int16_t) (queue_addr >> 16);
mbs.param[3] = (u_int16_t) (queue_addr & 0xffff);
mbs.param[4] = 0;
(void) isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
(void) splx(s);
printf("%s: set of request queue failed\n", isp->isp_name);
return;
}
isp->isp_reqidx = 0;
/*
* Unfortunately, this is the only way right now for
* forcing a sync renegotiation. If we boot off of
* an Alpha, it's put the chip in SYNC mode, but we
* haven't necessarily set up the parameters the
* same, so we'll have to yank the reset line to
* get everyone to renegotiate.
*/
mbs.param[0] = MBOX_BUS_RESET;
mbs.param[1] = 2;
(void) isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
(void) splx(s);
printf("%s: SCSI bus reset failed\n", isp->isp_name);
}
isp->isp_sendmarker = 1;
(void) splx(s);
isp->isp_state = ISP_INITSTATE;
}
/*
* Complete attachment of Hardware, include subdevices.
*/
void
isp_attach(isp)
struct ispsoftc *isp;
{
isp->isp_state = ISP_RUNSTATE;
isp->isp_link.channel = SCSI_CHANNEL_ONLY_ONE;
isp->isp_link.adapter_softc = isp;
isp->isp_link.adapter_target = isp->isp_initiator_id;
isp->isp_link.adapter = &isp_switch;
isp->isp_link.device = &isp_dev;
isp->isp_link.openings = RESULT_QUEUE_LEN / (MAX_TARGETS - 1);
isp->isp_link.max_target = MAX_TARGETS-1;
config_found((void *)isp, &isp->isp_link, scsiprint);
}
/*
* Free any associated resources prior to decommissioning.
*/
void
isp_uninit(isp)
struct ispsoftc *isp;
{
}
/*
* minphys our xfers
*/
static void
ispminphys(bp)
struct buf *bp;
{
/*
* XX: Only the 1020 has a 24 bit limit.
*/
if (bp->b_bcount >= (1 << 24)) {
bp->b_bcount = (1 << 24) - 1;
}
minphys(bp);
}
/*
* start an xfer
*/
static int32_t
ispscsicmd(xs)
struct scsi_xfer *xs;
{
struct ispsoftc *isp;
u_int8_t iptr, optr;
ispreq_t *req;
int s, i;
isp = xs->sc_link->adapter_softc;
optr = ISP_READ(isp, OUTMAILBOX4);
iptr = isp->isp_reqidx;
req = (ispreq_t *) &isp->isp_rquest[iptr][0];
iptr = (iptr + 1) & (RQUEST_QUEUE_LEN - 1);
if (iptr == optr) {
printf("%s: Request Queue Overflow\n", isp->isp_name);
xs->error = XS_DRIVER_STUFFUP;
return (TRY_AGAIN_LATER);
}
s = splbio();
if (isp->isp_sendmarker) {
ipsmarkreq_t *marker = (ipsmarkreq_t *) req;
bzero((void *) marker, sizeof (*marker));
marker->req_header.rqs_entry_count = 1;
marker->req_header.rqs_entry_type = RQSTYPE_MARKER;
marker->req_modifier = SYNC_ALL;
isp->isp_sendmarker = 0;
if (((iptr + 1) & (RQUEST_QUEUE_LEN - 1)) == optr) {
ISP_WRITE(isp, INMAILBOX4, iptr);
isp->isp_reqidx = iptr;
(void) splx(s);
printf("%s: Request Queue Overflow+\n", isp->isp_name);
xs->error = XS_DRIVER_STUFFUP;
return (TRY_AGAIN_LATER);
}
req = (ispreq_t *) &isp->isp_rquest[iptr][0];
iptr = (iptr + 1) & (RQUEST_QUEUE_LEN - 1);
}
bzero((void *) req, sizeof (*req));
req->req_header.rqs_entry_count = 1;
req->req_header.rqs_entry_type = RQSTYPE_REQUEST;
req->req_header.rqs_flags = 0;
req->req_header.rqs_seqno = isp->isp_seqno++;
for (i = 0; i < RQUEST_QUEUE_LEN; i++) {
if (isp->isp_xflist[i] == NULL)
break;
}
if (i == RQUEST_QUEUE_LEN) {
panic("%s: ran out of xflist pointers\n", isp->isp_name);
/* NOTREACHED */
} else {
isp->isp_xflist[i] = xs;
req->req_handle = i;
}
req->req_flags = 0;
req->req_lun_trn = xs->sc_link->lun;
req->req_target = xs->sc_link->target;
req->req_cdblen = xs->cmdlen;
bcopy((void *)xs->cmd, req->req_cdb, xs->cmdlen);
#if 0
printf("%s(%d.%d): START%d cmd 0x%x datalen %d\n", isp->isp_name,
xs->sc_link->target, xs->sc_link->lun,
req->req_header.rqs_seqno, *(u_char *) xs->cmd, xs->datalen);
#endif
req->req_time = xs->timeout / 1000;
req->req_seg_count = 0;
if (ISP_DMASETUP(isp, xs, req, &iptr, optr)) {
(void) splx(s);
xs->error = XS_DRIVER_STUFFUP;
return (COMPLETE);
}
xs->error = 0;
ISP_WRITE(isp, INMAILBOX4, iptr);
isp->isp_reqidx = iptr;
(void) splx(s);
if ((xs->flags & SCSI_POLL) == 0) {
return (SUCCESSFULLY_QUEUED);
}
do {
if (isp_poll(isp, xs->timeout)) {
break;
}
} while ((xs->flags & ITSDONE) == 0);
return (COMPLETE);
}
/*
* Interrupt Service Routine(s)
*/
int
isp_poll(isp, mswait)
struct ispsoftc *isp;
int mswait;
{
while (--mswait > 0) {
if (isp_intr((void *)isp)) {
break;
}
delay(1000);
}
if (mswait <= 0)
return (1);
else
return (0);
}
int
isp_intr(arg)
void *arg;
{
struct scsi_xfer *xs;
struct ispsoftc *isp = arg;
u_int16_t iptr, optr, isr;
isr = ISP_READ(isp, BIU_ISR);
if (isr == 0 || (isr & BIU_ISR_RISC_INT) == 0) {
#if 0
if (isr) {
printf("%s: isp_intr isr=%x\n", isp->isp_name, isr);
}
#endif
return (0);
}
optr = isp->isp_residx;
iptr = ISP_READ(isp, OUTMAILBOX5);
ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT);
ISP_WRITE(isp, BIU_ICR,
BIU_ICR_ENABLE_RISC_INT | BIU_ICR_ENABLE_ALL_INTS);
if (ISP_READ(isp, BIU_SEMA) & 1) {
u_int16_t mbox0 = ISP_READ(isp, OUTMAILBOX0);
switch (mbox0) {
case ASYNC_BUS_RESET:
case ASYNC_TIMEOUT_RESET:
printf("%s: bus or timeout reset\n", isp->isp_name);
isp->isp_sendmarker = 1;
break;
default:
printf("%s: async %x\n", isp->isp_name, mbox0);
break;
}
ISP_WRITE(isp, BIU_SEMA, 0);
#if 0
} else {
if (optr == iptr) {
printf("why'd we interrupt? isr %x iptr %x optr %x\n",
isr, optr, iptr);
}
#endif
}
while (optr != iptr) {
ispstatusreq_t *sp;
int buddaboom = 0;
sp = (ispstatusreq_t *) &isp->isp_result[optr][0];
optr = (optr + 1) & (RESULT_QUEUE_LEN-1);
if (sp->req_header.rqs_entry_type != RQSTYPE_RESPONSE) {
printf("%s: not RESPONSE in RESPONSE Queue (0x%x)\n",
isp->isp_name, sp->req_header.rqs_entry_type);
if (sp->req_header.rqs_entry_type != RQSTYPE_REQUEST) {
ISP_WRITE(isp, INMAILBOX5, optr);
continue;
}
buddaboom = 1;
}
if (sp->req_header.rqs_flags & 0xf) {
if (sp->req_header.rqs_flags & RQSFLAG_CONTINUATION) {
ISP_WRITE(isp, INMAILBOX5, optr);
continue;
}
printf("%s: rqs_flags=%x\n", isp->isp_name,
sp->req_header.rqs_flags & 0xf);
}
if (sp->req_handle >= RQUEST_QUEUE_LEN) {
printf("%s: bad request handle %d\n", isp->isp_name,
sp->req_handle);
ISP_WRITE(isp, INMAILBOX5, optr);
continue;
}
xs = (struct scsi_xfer *) isp->isp_xflist[sp->req_handle];
if (xs == NULL) {
printf("%s: NULL xs in xflist\n", isp->isp_name);
ISP_WRITE(isp, INMAILBOX5, optr);
continue;
}
isp->isp_xflist[sp->req_handle] = NULL;
if (sp->req_status_flags & RQSTF_BUS_RESET) {
isp->isp_sendmarker = 1;
}
if (buddaboom) {
xs->error = XS_DRIVER_STUFFUP;
}
if (sp->req_state_flags & RQSF_GOT_SENSE) {
bcopy(sp->req_sense_data, &xs->sense,
sizeof (xs->sense));
xs->error = XS_SENSE;
}
xs->status = sp->req_scsi_status;
if (xs->error == 0 && xs->status == SCSI_BUSY)
xs->error = XS_BUSY;
if (sp->req_header.rqs_entry_type == RQSTYPE_RESPONSE) {
if (xs->error == 0)
xs->error = isp_parse_status(isp, sp);
} else {
printf("%s: unknown return %x\n", isp->isp_name,
sp->req_header.rqs_entry_type);
if (xs->error == 0)
xs->error = XS_DRIVER_STUFFUP;
}
xs->resid = sp->req_resid;
xs->flags |= ITSDONE;
if (xs->datalen) {
ISP_DMAFREE(isp, xs, sp->req_handle);
}
#if 0
printf("%s(%d.%d): FINISH%d cmd 0x%x resid %d STS %x",
isp->isp_name, xs->sc_link->target, xs->sc_link->lun,
sp->req_header.rqs_seqno, *(u_char *) xs->cmd,
xs->resid, xs->status);
if (sp->req_state_flags & RQSF_GOT_SENSE) {
printf(" Skey: %x", xs->sense.flags);
if (xs->error != XS_SENSE) {
printf(" BUT NOT SET");
}
}
printf(" xs->error %d\n", xs->error);
#endif
ISP_WRITE(isp, INMAILBOX5, optr);
scsi_done(xs);
}
isp->isp_residx = optr;
return (1);
}
/*
* Support routines.
*/
static int
isp_parse_status(isp, sp)
struct ispsoftc *isp;
ispstatusreq_t *sp;
{
switch (sp->req_completion_status) {
case RQCS_COMPLETE:
return (XS_NOERROR);
break;
case RQCS_INCOMPLETE:
if ((sp->req_state_flags & RQSF_GOT_TARGET) == 0) {
return (XS_SELTIMEOUT);
}
printf("%s: incomplete, state %x\n",
isp->isp_name, sp->req_state_flags);
break;
case RQCS_DATA_UNDERRUN:
return (XS_NOERROR);
case RQCS_TIMEOUT:
return (XS_TIMEOUT);
case RQCS_RESET_OCCURRED:
printf("%s: reset occurred\n", isp->isp_name);
isp->isp_sendmarker = 1;
break;
case RQCS_ABORTED:
printf("%s: command aborted\n", isp->isp_name);
isp->isp_sendmarker = 1;
break;
default:
printf("%s: comp status %x\n", isp->isp_name,
sp->req_completion_status);
break;
}
return (XS_DRIVER_STUFFUP);
}
#define HINIB(x) ((x) >> 0x4)
#define LONIB(x) ((x) & 0xf)
#define MAKNIB(a, b) (((a) << 4) | (b))
static u_int8_t mbpcnt[] = {
MAKNIB(1, 1), /* MBOX_NO_OP */
MAKNIB(5, 5), /* MBOX_LOAD_RAM */
MAKNIB(2, 0), /* MBOX_EXEC_FIRMWARE */
MAKNIB(5, 5), /* MBOX_DUMP_RAM */
MAKNIB(3, 3), /* MBOX_WRITE_RAM_WORD */
MAKNIB(2, 3), /* MBOX_READ_RAM_WORD */
MAKNIB(6, 6), /* MBOX_MAILBOX_REG_TEST */
MAKNIB(2, 3), /* MBOX_VERIFY_CHECKSUM */
MAKNIB(1, 3), /* MBOX_ABOUT_FIRMWARE */
MAKNIB(0, 0), /* 0x0009 */
MAKNIB(0, 0), /* 0x000a */
MAKNIB(0, 0), /* 0x000b */
MAKNIB(0, 0), /* 0x000c */
MAKNIB(0, 0), /* 0x000d */
MAKNIB(1, 2), /* MBOX_CHECK_FIRMWARE */
MAKNIB(0, 0), /* 0x000f */
MAKNIB(5, 5), /* MBOX_INIT_REQ_QUEUE */
MAKNIB(6, 6), /* MBOX_INIT_RES_QUEUE */
MAKNIB(4, 4), /* MBOX_EXECUTE_IOCB */
MAKNIB(2, 2), /* MBOX_WAKE_UP */
MAKNIB(1, 6), /* MBOX_STOP_FIRMWARE */
MAKNIB(4, 4), /* MBOX_ABORT */
MAKNIB(2, 2), /* MBOX_ABORT_DEVICE */
MAKNIB(3, 3), /* MBOX_ABORT_TARGET */
MAKNIB(2, 2), /* MBOX_BUS_RESET */
MAKNIB(2, 3), /* MBOX_STOP_QUEUE */
MAKNIB(2, 3), /* MBOX_START_QUEUE */
MAKNIB(2, 3), /* MBOX_SINGLE_STEP_QUEUE */
MAKNIB(2, 3), /* MBOX_ABORT_QUEUE */
MAKNIB(2, 4), /* MBOX_GET_DEV_QUEUE_STATUS */
MAKNIB(0, 0), /* 0x001e */
MAKNIB(1, 3), /* MBOX_GET_FIRMWARE_STATUS */
MAKNIB(1, 2), /* MBOX_GET_INIT_SCSI_ID */
MAKNIB(1, 2), /* MBOX_GET_SELECT_TIMEOUT */
MAKNIB(1, 3), /* MBOX_GET_RETRY_COUNT */
MAKNIB(1, 2), /* MBOX_GET_TAG_AGE_LIMIT */
MAKNIB(1, 2), /* MBOX_GET_CLOCK_RATE */
MAKNIB(1, 2), /* MBOX_GET_ACT_NEG_STATE */
MAKNIB(1, 2), /* MBOX_GET_ASYNC_DATA_SETUP_TIME */
MAKNIB(1, 3), /* MBOX_GET_PCI_PARAMS */
MAKNIB(2, 4), /* MBOX_GET_TARGET_PARAMS */
MAKNIB(2, 4), /* MBOX_GET_DEV_QUEUE_PARAMS */
MAKNIB(0, 0), /* 0x002a */
MAKNIB(0, 0), /* 0x002b */
MAKNIB(0, 0), /* 0x002c */
MAKNIB(0, 0), /* 0x002d */
MAKNIB(0, 0), /* 0x002e */
MAKNIB(0, 0), /* 0x002f */
MAKNIB(2, 2), /* MBOX_SET_INIT_SCSI_ID */
MAKNIB(2, 2), /* MBOX_SET_SELECT_TIMEOUT */
MAKNIB(3, 3), /* MBOX_SET_RETRY_COUNT */
MAKNIB(2, 2), /* MBOX_SET_TAG_AGE_LIMIT */
MAKNIB(2, 2), /* MBOX_SET_CLOCK_RATE */
MAKNIB(2, 2), /* MBOX_SET_ACTIVE_NEG_STATE */
MAKNIB(2, 2), /* MBOX_SET_ASYNC_DATA_SETUP_TIME */
MAKNIB(3, 3), /* MBOX_SET_PCI_CONTROL_PARAMS */
MAKNIB(4, 4), /* MBOX_SET_TARGET_PARAMS */
MAKNIB(4, 4), /* MBOX_SET_DEV_QUEUE_PARAMS */
MAKNIB(0, 0), /* 0x003a */
MAKNIB(0, 0), /* 0x003b */
MAKNIB(0, 0), /* 0x003c */
MAKNIB(0, 0), /* 0x003d */
MAKNIB(0, 0), /* 0x003e */
MAKNIB(0, 0), /* 0x003f */
MAKNIB(1, 2), /* MBOX_RETURN_BIOS_BLOCK_ADDR */
MAKNIB(6, 1), /* MBOX_WRITE_FOUR_RAM_WORDS */
MAKNIB(2, 3) /* MBOX_EXEC_BIOS_IOCB */
};
#define NMBCOM (sizeof (mbpcnt) / sizeof (mbpcnt[0]))
static int
isp_mboxcmd(isp, mbp)
struct ispsoftc *isp;
mbreg_t *mbp;
{
int outparam, inparam;
int loops;
if (mbp->param[0] > NMBCOM) {
printf("%s: bad command %x\n", isp->isp_name, mbp->param[0]);
return (-1);
}
inparam = HINIB(mbpcnt[mbp->param[0]]);
outparam = LONIB(mbpcnt[mbp->param[0]]);
if (inparam == 0 && outparam == 0) {
printf("%s: no parameters for %x\n", isp->isp_name,
mbp->param[0]);
return (-1);
}
/*
* Make sure we can send some words..
*/
loops = MBOX_DELAY_COUNT;
while ((ISP_READ(isp, HCCR) & HCCR_HOST_INT) != 0) {
delay(100);
if (--loops < 0) {
printf("%s: isp_mboxcmd timeout #1\n", isp->isp_name);
return (-1);
}
}
/*
* Write input parameters
*/
switch (inparam) {
case 6: ISP_WRITE(isp, INMAILBOX5, mbp->param[5]); mbp->param[5] = 0;
case 5: ISP_WRITE(isp, INMAILBOX4, mbp->param[4]); mbp->param[4] = 0;
case 4: ISP_WRITE(isp, INMAILBOX3, mbp->param[3]); mbp->param[3] = 0;
case 3: ISP_WRITE(isp, INMAILBOX2, mbp->param[2]); mbp->param[2] = 0;
case 2: ISP_WRITE(isp, INMAILBOX1, mbp->param[1]); mbp->param[1] = 0;
case 1: ISP_WRITE(isp, INMAILBOX0, mbp->param[0]); mbp->param[0] = 0;
}
/*
* Clear semaphore on mailbox registers
*/
ISP_WRITE(isp, BIU_SEMA, 0);
/*
* Clear RISC int condition.
*/
ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT);
/*
* Set Host Interrupt condition so that RISC will pick up mailbox regs.
*/
ISP_WRITE(isp, HCCR, HCCR_CMD_SET_HOST_INT);
/*
* Wait until RISC int is set
*/
loops = MBOX_DELAY_COUNT;
while ((ISP_READ(isp, BIU_ISR) & BIU_ISR_RISC_INT) != 0) {
delay(100);
if (--loops < 0) {
printf("%s: isp_mboxcmd timeout #2\n", isp->isp_name);
return (-1);
}
}
/*
* Check to make sure that the semaphore has been set.
*/
loops = MBOX_DELAY_COUNT;
while ((ISP_READ(isp, BIU_SEMA) & 1) == 0) {
delay(100);
if (--loops < 0) {
printf("%s: isp_mboxcmd timeout #3\n", isp->isp_name);
return (-1);
}
}
/*
* Make sure that the MBOX_BUSY has gone away
*/
loops = MBOX_DELAY_COUNT;
while (ISP_READ(isp, OUTMAILBOX0) == MBOX_BUSY) {
delay(100);
if (--loops < 0) {
printf("%s: isp_mboxcmd timeout #4\n", isp->isp_name);
return (-1);
}
}
/*
* Pick up output parameters.
*/
switch (outparam) {
case 6: mbp->param[5] = ISP_READ(isp, OUTMAILBOX5);
case 5: mbp->param[4] = ISP_READ(isp, OUTMAILBOX4);
case 4: mbp->param[3] = ISP_READ(isp, OUTMAILBOX3);
case 3: mbp->param[2] = ISP_READ(isp, OUTMAILBOX2);
case 2: mbp->param[1] = ISP_READ(isp, OUTMAILBOX1);
case 1: mbp->param[0] = ISP_READ(isp, OUTMAILBOX0);
}
/*
* Clear RISC int.
*/
ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT);
/*
* Release semaphore on mailbox registers
*/
ISP_WRITE(isp, BIU_SEMA, 0);
return (0);
}

285
sys/dev/ic/ispmbox.h Normal file
View File

@ -0,0 +1,285 @@
/* $NetBSD: ispmbox.h,v 1.1.1.1 1997/03/12 20:44:51 cgd Exp $ */
/*
* Mailbox and Command Definitions for for Qlogic ISP SCSI adapters.
*
* Copyright (c) 1997 by Matthew Jacob (for NASA/Ames Research Center)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice immediately at the beginning of the file, without modification,
* this list of conditions, and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#ifndef _ISPMBOX_H
#define _ISPMBOX_H
/*
* Mailbox Command Opcodes
*/
#define MBOX_NO_OP 0x0000
#define MBOX_LOAD_RAM 0x0001
#define MBOX_EXEC_FIRMWARE 0x0002
#define MBOX_DUMP_RAM 0x0003
#define MBOX_WRITE_RAM_WORD 0x0004
#define MBOX_READ_RAM_WORD 0x0005
#define MBOX_MAILBOX_REG_TEST 0x0006
#define MBOX_VERIFY_CHECKSUM 0x0007
#define MBOX_ABOUT_FIRMWARE 0x0008
/* 9 */
/* a */
/* b */
/* c */
/* d */
#define MBOX_CHECK_FIRMWARE 0x000e
/* f */
#define MBOX_INIT_REQ_QUEUE 0x0010
#define MBOX_INIT_RES_QUEUE 0x0011
#define MBOX_EXECUTE_IOCB 0x0012
#define MBOX_WAKE_UP 0x0013
#define MBOX_STOP_FIRMWARE 0x0014
#define MBOX_ABORT 0x0015
#define MBOX_ABORT_DEVICE 0x0016
#define MBOX_ABORT_TARGET 0x0017
#define MBOX_BUS_RESET 0x0018
#define MBOX_STOP_QUEUE 0x0019
#define MBOX_START_QUEUE 0x001a
#define MBOX_SINGLE_STEP_QUEUE 0x001b
#define MBOX_ABORT_QUEUE 0x001c
#define MBOX_GET_DEV_QUEUE_STATUS 0x001d
/* 1e */
#define MBOX_GET_FIRMWARE_STATUS 0x001f
#define MBOX_GET_INIT_SCSI_ID 0x0020
#define MBOX_GET_SELECT_TIMEOUT 0x0021
#define MBOX_GET_RETRY_COUNT 0x0022
#define MBOX_GET_TAG_AGE_LIMIT 0x0023
#define MBOX_GET_CLOCK_RATE 0x0024
#define MBOX_GET_ACT_NEG_STATE 0x0025
#define MBOX_GET_ASYNC_DATA_SETUP_TIME 0x0026
#define MBOX_GET_SBUS_PARAMS 0x0027
#define MBOX_GET_TARGET_PARAMS 0x0028
#define MBOX_GET_DEV_QUEUE_PARAMS 0x0029
/* 2a */
/* 2b */
/* 2c */
/* 2d */
/* 2e */
/* 2f */
#define MBOX_SET_INIT_SCSI_ID 0x0030
#define MBOX_SET_SELECT_TIMEOUT 0x0031
#define MBOX_SET_RETRY_COUNT 0x0032
#define MBOX_SET_TAG_AGE_LIMIT 0x0033
#define MBOX_SET_CLOCK_RATE 0x0034
#define MBOX_SET_ACTIVE_NEG_STATE 0x0035
#define MBOX_SET_ASYNC_DATA_SETUP_TIME 0x0036
#define MBOX_SET_SBUS_CONTROL_PARAMS 0x0037
#define MBOX_SET_TARGET_PARAMS 0x0038
#define MBOX_SET_DEV_QUEUE_PARAMS 0x0039
/* 3a */
/* 3b */
/* 3c */
/* 3d */
/* 3e */
/* 3f */
#define MBOX_RETURN_BIOS_BLOCK_ADDR 0x0040
#define MBOX_WRITE_FOUR_RAM_WORDS 0x0041
#define MBOX_EXEC_BIOS_IOCB 0x0042
#define MBOX_BUSY 0x04
typedef struct {
u_int16_t param[6];
} mbreg_t;
/*
* Command Structure Definitions
*/
typedef struct {
u_int32_t ds_base;
u_int32_t ds_count;
} ispds_t;
typedef struct {
#if BYTE_ORDER == BIG_ENDIAN
u_int8_t rqs_entry_count;
u_int8_t rqs_entry_type;
u_int8_t rqs_flags;
u_int8_t rqs_seqno;
#else
u_int8_t rqs_entry_type;
u_int8_t rqs_entry_count;
u_int8_t rqs_seqno;
u_int8_t rqs_flags;
#endif
} isphdr_t;
/* RQS Flag definitions */
#define RQSFLAG_CONTINUATION 0x01
#define RQSFLAG_FULL 0x02
#define RQSFLAG_BADHEADER 0x04
#define RQSFLAG_BADPACKET 0x08
/* RQS entry_type definitions */
#define RQSTYPE_REQUEST 1
#define RQSTYPE_DATASEG 2
#define RQSTYPE_RESPONSE 3
#define RQSTYPE_MARKER 4
#define RQSTYPE_CMDONLY 5
#define ISP_RQDSEG 4
typedef struct {
isphdr_t req_header;
u_int32_t req_handle;
#if BYTE_ORDER == BIG_ENDIAN
u_int8_t req_target;
u_int8_t req_lun_trn;
#else
u_int8_t req_lun_trn;
u_int8_t req_target;
#endif
u_int16_t req_cdblen;
#define req_modifier req_cdblen /* marker packet */
u_int16_t req_flags;
u_int16_t _res1;
u_int16_t req_time;
u_int16_t req_seg_count;
u_int8_t req_cdb[12];
ispds_t req_dataseg[ISP_RQDSEG];
} ispreq_t;
/* req_flag values */
#define REQFLAG_NODISCON 0x0001
#define REQFLAG_HTAG 0x0002
#define REQFLAG_OTAG 0x0004
#define REQFLAG_STAG 0x0008
#define REQFLAG_TARGET_RTN 0x0010
#define REQFLAG_NODATA 0x0000
#define REQFLAG_DATA_IN 0x0020
#define REQFLAG_DATA_OUT 0x0040
#define REQFLAG_DATA_UNKNOWN 0x0060
#define REQFLAG_DISARQ 0x0100
typedef struct {
isphdr_t req_header;
u_int32_t req_handle;
#if BYTE_ORDER == BIG_ENDIAN
u_int8_t req_target;
u_int8_t req_lun_trn;
#else
u_int8_t req_lun_trn;
u_int8_t req_target;
#endif
u_int16_t req_cdblen;
u_int16_t req_flags;
u_int16_t _res1;
u_int16_t req_time;
u_int16_t req_seg_count;
u_int8_t req_cdb[44];
} ispextreq_t;
#define ISP_CDSEG 7
typedef struct {
isphdr_t req_header;
u_int32_t _res1;
ispds_t req_dataseg[ISP_CDSEG];
} ispcontreq_t;
typedef struct {
isphdr_t req_header;
u_int32_t _res1;
#if BYTE_ORDER == BIG_ENDIAN
u_int8_t req_target;
u_int8_t req_lun_trn;
u_int8_t _res2;
u_int8_t req_modifier;
#else
u_int8_t req_lun_trn;
u_int8_t req_target;
u_int8_t req_modifier;
u_int8_t _res2;
#endif
} ipsmarkreq_t;
#define SYNC_DEVICE 0
#define SYNC_TARGET 1
#define SYNC_ALL 2
typedef struct {
isphdr_t req_header;
u_int32_t req_handle;
u_int16_t req_scsi_status;
u_int16_t req_completion_status;
u_int16_t req_state_flags;
u_int16_t req_status_flags;
u_int16_t req_time;
u_int16_t req_sense_len;
u_int32_t req_resid;
u_int8_t _res1[8];
u_int8_t req_sense_data[32];
} ispstatusreq_t;
#define RQCS_COMPLETE 0x0000
#define RQCS_INCOMPLETE 0x0001
#define RQCS_DMA_ERROR 0x0002
#define RQCS_TRANSPORT_ERROR 0x0003
#define RQCS_RESET_OCCURRED 0x0004
#define RQCS_ABORTED 0x0005
#define RQCS_TIMEOUT 0x0006
#define RQCS_DATA_OVERRUN 0x0007
#define RQCS_COMMAND_OVERRUN 0x0008
#define RQCS_STATUS_OVERRUN 0x0009
#define RQCS_BAD_MESSAGE 0x000a
#define RQCS_NO_MESSAGE_OUT 0x000b
#define RQCS_EXT_ID_FAILED 0x000c
#define RQCS_IDE_MSG_FAILED 0x000d
#define RQCS_ABORT_MSG_FAILED 0x000e
#define RQCS_REJECT_MSG_FAILED 0x000f
#define RQCS_NOP_MSG_FAILED 0x0010
#define RQCS_PARITY_ERROR_MSG_FAILED 0x0011
#define RQCS_DEVICE_RESET_MSG_FAILED 0x0012
#define RQCS_ID_MSG_FAILED 0x0013
#define RQCS_UNEXP_BUS_FREE 0x0014
#define RQCS_DATA_UNDERRUN 0x0015
#define RQSF_GOT_BUS 0x0100
#define RQSF_GOT_TARGET 0x0200
#define RQSF_SENT_CDB 0x0400
#define RQSF_TRANFERRED_DATA 0x0800
#define RQSF_GOT_STATUS 0x1000
#define RQSF_GOT_SENSE 0x2000
#define RQSTF_DISCONNECT 0x0001
#define RQSTF_SYNCHRONOUS 0x0002
#define RQSTF_PARITY_ERROR 0x0004
#define RQSTF_BUS_RESET 0x0008
#define RQSTF_DEVICE_RESET 0x0010
#define RQSTF_ABORTED 0x0020
#define RQSTF_TIMEOUT 0x0040
#define RQSTF_NEGOTIATION 0x0080
#endif /* _ISPMBOX_H */

519
sys/dev/ic/ispreg.h Normal file
View File

@ -0,0 +1,519 @@
/* $NetBSD: ispreg.h,v 1.1.1.1 1997/03/12 20:44:51 cgd Exp $ */
/*
* Machine Independent (well, as best as possible) register
* definitions for Qlogic ISP SCSI adapters.
*
* Copyright (c) 1997 by Matthew Jacob (for NASA/Ames Research Center)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice immediately at the beginning of the file, without modification,
* this list of conditions, and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#ifndef _ISPREG_H
#define _ISPREG_H
/*
* Hardware definitions for the Qlogic ISP registers.
*/
/*
* This defines types of access to various registers.
*
* R: Read Only
* W: Write Only
* RW: Read/Write
*
* R*, W*, RW*: Read Only, Write Only, Read/Write, but only
* if RISC processor in ISP is paused.
*/
/*
* Offsets for various register blocks.
*
* Sad but true, different architectures have different offsets.
*/
#define BIU_REGS_OFF 0x00
#define PCI_MBOX_REGS_OFF 0x70
#define SBUS_MBOX_REGS_OFF 0x80
#define PCI_SXP_REGS_OFF 0x80
#define SBUS_SXP_REGS_OFF 0x200
#define PCI_RISC_REGS_OFF 0x80
#define SBUS_RISC_REGS_OFF 0x400
/*
* NB: The *_BLOCK definitions have no specific hardware meaning.
* They serve simply to note to the MD layer which block of
* registers offsets are being accessed.
*/
/*
* Bus Interface Block Register Offsets
*/
#define BIU_BLOCK 0x0100
#define BIU_ID_LO BIU_BLOCK+0x0 /* R : Bus ID, Low */
#define BIU_ID_HI BIU_BLOCK+0x2 /* R : Bus ID, High */
#define BIU_CONF0 BIU_BLOCK+0x4 /* R : Bus Configuration #0 */
#define BIU_CONF1 BIU_BLOCK+0x6 /* R : Bus Configuration #1 */
#define BIU_ICR BIU_BLOCK+0x8 /* RW : Bus Interface Ctrl */
#define BIU_ISR BIU_BLOCK+0xA /* R : Bus Interface Status */
#define BIU_SEMA BIU_BLOCK+0xC /* RW : Bus Semaphore */
#define BIU_NVRAM BIU_BLOCK+0xE /* RW : Bus NVRAM */
#define CDMA_CONF BIU_BLOCK+0x20 /* RW*: DMA Configuration */
#define CDMA_CONTROL BIU_BLOCK+0x22 /* RW*: DMA Control */
#define CDMA_STATUS BIU_BLOCK+0x24 /* R : DMA Status */
#define CDMA_FIFO_STS BIU_BLOCK+0x26 /* R : DMA FIFO Status */
#define CDMA_COUNT BIU_BLOCK+0x28 /* RW*: DMA Transfer Count */
#define CDMA_ADDR0 BIU_BLOCK+0x2C /* RW*: DMA Address, Word 0 */
#define CDMA_ADDR1 BIU_BLOCK+0x2E /* RW*: DMA Address, Word 1 */
/* these are for the 1040A cards */
#define CDMA_ADDR2 BIU_BLOCK+0x30 /* RW*: DMA Address, Word 2 */
#define CDMA_ADDR3 BIU_BLOCK+0x32 /* RW*: DMA Address, Word 3 */
#define DDMA_CONF BIU_BLOCK+0x40 /* RW*: DMA Configuration */
#define DDMA_CONTROL BIU_BLOCK+0x42 /* RW*: DMA Control */
#define DDMA_STATUS BIU_BLOCK+0x44 /* R : DMA Status */
#define DDMA_FIFO_STS BIU_BLOCK+0x46 /* R : DMA FIFO Status */
#define DDMA_COUNT_LO BIU_BLOCK+0x48 /* RW*: DMA Xfer Count, Low */
#define DDMA_COUNT_HI BIU_BLOCK+0x4A /* RW*: DMA Xfer Count, High */
#define DDMA_ADDR0 BIU_BLOCK+0x4C /* RW*: DMA Address, Word 0 */
#define DDMA_ADDR1 BIU_BLOCK+0x4E /* RW*: DMA Address, Word 1 */
/* these are for the 1040A cards */
#define DDMA_ADDR2 BIU_BLOCK+0x50 /* RW*: DMA Address, Word 2 */
#define DDMA_ADDR3 BIU_BLOCK+0x52 /* RW*: DMA Address, Word 3 */
#define DFIFO_COMMAND BIU_BLOCK+0x60 /* RW : Command FIFO Port */
#define DFIFO_DATA BIU_BLOCK+0x62 /* RW : Data FIFO Port */
/*
* Bus Interface Block Register Definitions
*/
/* BUS CONFIGURATION REGISTER #0 */
#define BIU_CONF0_HW_MASK 0x000F /* Hardware revision mask */
/* BUS CONFIGURATION REGISTER #1 */
#define BIU_SBUS_CONF1_PARITY 0x0100 /* Enable parity checking */
#define BIU_SBUS_CONF1_FCODE_MASK 0x00F0 /* Fcode cycle mask */
#define BIU_PCI_CONF1_FIFO_128 0x0040 /* 128 bytes FIFO threshold */
#define BIU_PCI_CONF1_FIFO_64 0x0030 /* 64 bytes FIFO threshold */
#define BIU_PCI_CONF1_FIFO_32 0x0020 /* 32 bytes FIFO threshold */
#define BIU_PCI_CONF1_FIFO_16 0x0010 /* 16 bytes FIFO threshold */
#define BIU_BURST_ENABLE 0x0004 /* Global enable Bus bursts */
#define BIU_SBUS_CONF1_FIFO_64 0x0003 /* 64 bytes FIFO threshold */
#define BIU_SBUS_CONF1_FIFO_32 0x0002 /* 32 bytes FIFO threshold */
#define BIU_SBUS_CONF1_FIFO_16 0x0001 /* 16 bytes FIFO threshold */
#define BIU_SBUS_CONF1_FIFO_8 0x0000 /* 8 bytes FIFO threshold */
#define BIU_SBUS_CONF1_BURST8 0x0008 /* Enable 8-byte bursts */
#define BIU_PCI_CONF1_SXP 0x0008 /* SXP register select */
/* BUS CONTROL REGISTER */
#define BIU_ICR_ENABLE_DMA_INT 0x0020 /* Enable DMA interrupts */
#define BIU_ICR_ENABLE_CDMA_INT 0x0010 /* Enable CDMA interrupts */
#define BIU_ICR_ENABLE_SXP_INT 0x0008 /* Enable SXP interrupts */
#define BIU_ICR_ENABLE_RISC_INT 0x0004 /* Enable Risc interrupts */
#define BIU_ICR_ENABLE_ALL_INTS 0x0002 /* Global enable all inter */
#define BIU_ICR_SOFT_RESET 0x0001 /* Soft Reset of ISP */
/* BUS STATUS REGISTER */
#define BIU_ISR_DMA_INT 0x0020 /* DMA interrupt pending */
#define BIU_ISR_CDMA_INT 0x0010 /* CDMA interrupt pending */
#define BIU_ISR_SXP_INT 0x0008 /* SXP interrupt pending */
#define BIU_ISR_RISC_INT 0x0004 /* Risc interrupt pending */
#define BIU_ISR_IPEND 0x0002 /* Global interrupt pending */
/* BUS SEMAPHORE REGISTER */
#define BIU_SEMA_STATUS 0x0002 /* Semaphore Status Bit */
#define BIU_SEMA_LOCK 0x0001 /* Semaphore Lock Bit */
/* COMNMAND && DATA DMA CONFIGURATION REGISTER */
#define DMA_ENABLE_SXP_DMA 0x0008 /* Enable SXP to DMA Data */
#define DMA_ENABLE_INTS 0x0004 /* Enable interrupts to RISC */
#define DMA_ENABLE_BURST 0x0002 /* Enable Bus burst trans */
#define DMA_DMA_DIRECTION 0x0001 /*
* Set DMA direction:
* 0 - DMA FIFO to host
* 1 - Host to DMA FIFO
*/
/* COMMAND && DATA DMA CONTROL REGISTER */
#define DMA_CNTRL_SUSPEND_CHAN 0x0010 /* Suspend DMA transfer */
#define DMA_CNTRL_CLEAR_CHAN 0x0008 /*
* Clear FIFO and DMA Channel,
* reset DMA registers
*/
#define DMA_CNTRL_CLEAR_FIFO 0x0004 /* Clear DMA FIFO */
#define DMA_CNTRL_RESET_INT 0x0002 /* Clear DMA interrupt */
#define DMA_CNTRL_STROBE 0x0001 /* Start DMA transfer */
/* DMA STATUS REGISTER */
#define DMA_SBUS_STATUS_PIPE_MASK 0x00C0 /* DMA Pipeline status mask */
#define DMA_SBUS_STATUS_CHAN_MASK 0x0030 /* Channel status mask */
#define DMA_SBUS_STATUS_BUS_PARITY 0x0008 /* Parity Error on bus */
#define DMA_SBUS_STATUS_BUS_ERR 0x0004 /* Error Detected on bus */
#define DMA_SBUS_STATUS_TERM_COUNT 0x0002 /* DMA Transfer Completed */
#define DMA_SBUS_STATUS_INTERRUPT 0x0001 /* Enable DMA channel inter */
#define DMA_PCI_STATUS_INTERRUPT 0x8000 /* Enable DMA channel inter */
#define DMA_PCI_STATUS_RETRY_STAT 0x4000 /* Retry status */
#define DMA_PCI_STATUS_CHAN_MASK 0x3000 /* Channel status mask */
#define DMA_PCI_STATUS_FIFO_OVR 0x0100 /* DMA FIFO overrun cond */
#define DMA_PCI_STATUS_FIFO_UDR 0x0080 /* DMA FIFO underrun cond */
#define DMA_PCI_STATUS_BUS_ERR 0x0040 /* Error Detected on bus */
#define DMA_PCI_STATUS_BUS_PARITY 0x0020 /* Parity Error on bus */
#define DMA_PCI_STATUS_CLR_PEND 0x0010 /* DMA clear pending */
#define DMA_PCI_STATUS_TERM_COUNT 0x0008 /* DMA Transfer Completed */
#define DMA_PCI_STATUS_DMA_SUSP 0x0004 /* DMA suspended */
#define DMA_PCI_STATUS_PIPE_MASK 0x0003 /* DMA Pipeline status mask */
/* DMA Status Register, pipeline status bits */
#define DMA_SBUS_PIPE_FULL 0x00C0 /* Both pipeline stages full */
#define DMA_SBUS_PIPE_OVERRUN 0x0080 /* Pipeline overrun */
#define DMA_SBUS_PIPE_STAGE1 0x0040 /*
* Pipeline stage 1 Loaded,
* stage 2 empty
*/
#define DMA_PCI_PIPE_FULL 0x0003 /* Both pipeline stages full */
#define DMA_PCI_PIPE_OVERRUN 0x0002 /* Pipeline overrun */
#define DMA_PCI_PIPE_STAGE1 0x0001 /*
* Pipeline stage 1 Loaded,
* stage 2 empty
*/
#define DMA_PIPE_EMPTY 0x0000 /* All pipeline stages empty */
/* DMA Status Register, channel status bits */
#define DMA_SBUS_CHAN_SUSPEND 0x0030 /* Channel error or suspended */
#define DMA_SBUS_CHAN_TRANSFER 0x0020 /* Chan transfer in progress */
#define DMA_SBUS_CHAN_ACTIVE 0x0010 /* Chan trans to host active */
#define DMA_PCI_CHAN_TRANSFER 0x3000 /* Chan transfer in progress */
#define DMA_PCI_CHAN_SUSPEND 0x2000 /* Channel error or suspended */
#define DMA_PCI_CHAN_ACTIVE 0x1000 /* Chan trans to host active */
#define ISP_DMA_CHAN_IDLE 0x0000 /* Chan idle (normal comp) */
/* DMA FIFO STATUS REGISTER */
#define DMA_FIFO_STATUS_OVERRUN 0x0200 /* FIFO Overrun Condition */
#define DMA_FIFO_STATUS_UNDERRUN 0x0100 /* FIFO Underrun Condition */
#define DMA_FIFO_SBUS_COUNT_MASK 0x007F /* FIFO Byte count mask */
#define DMA_FIFO_PCI_COUNT_MASK 0x00FF /* FIFO Byte count mask */
/*
* Mailbox Block Register Offsets
*/
#define MBOX_BLOCK 0x0200
#define INMAILBOX0 MBOX_BLOCK+0x0
#define INMAILBOX1 MBOX_BLOCK+0x2
#define INMAILBOX2 MBOX_BLOCK+0x4
#define INMAILBOX3 MBOX_BLOCK+0x6
#define INMAILBOX4 MBOX_BLOCK+0x8
#define INMAILBOX5 MBOX_BLOCK+0xA
#define OUTMAILBOX0 MBOX_BLOCK+0x0
#define OUTMAILBOX1 MBOX_BLOCK+0x2
#define OUTMAILBOX2 MBOX_BLOCK+0x4
#define OUTMAILBOX3 MBOX_BLOCK+0x6
#define OUTMAILBOX4 MBOX_BLOCK+0x8
#define OUTMAILBOX5 MBOX_BLOCK+0xA
/*
* Mailbox Command Complete Status Codes
*/
#define MBOX_COMMAND_COMPLETE 0x4000
#define MBOX_INVALID_COMMAND 0x4001
#define MBOX_HOST_INTERFACE_ERROR 0x4002
#define MBOX_TEST_FAILED 0x4003
#define MBOX_COMMAND_ERROR 0x4005
#define MBOX_COMMAND_PARAM_ERROR 0x4006
/*
* Asynchronous event status codes
*/
#define ASYNC_BUS_RESET 0x8001
#define ASYNC_SYSTEM_ERROR 0x8002
#define ASYNC_RQS_XFER_ERR 0x8003
#define ASYNC_RSP_XFER_ERR 0x8004
#define ASYNC_QWAKEUP 0x8005
#define ASYNC_TIMEOUT_RESET 0x8006
/*
* SXP Block Register Offsets
*/
#define SXP_BLOCK 0x0400
#define SXP_PART_ID SXP_BLOCK+0x0 /* R : Part ID Code */
#define SXP_CONFIG1 SXP_BLOCK+0x2 /* RW*: Configuration Reg #1 */
#define SXP_CONFIG2 SXP_BLOCK+0x4 /* RW*: Configuration Reg #2 */
#define SXP_CONFIG3 SXP_BLOCK+0x6 /* RW*: Configuration Reg #2 */
#define SXP_INSTRUCTION SXP_BLOCK+0xC /* RW*: Instruction Pointer */
#define SXP_RETURN_ADDR SXP_BLOCK+0x10 /* RW*: Return Address */
#define SXP_COMMAND SXP_BLOCK+0x14 /* RW*: Command */
#define SXP_INTERRUPT SXP_BLOCK+0x18 /* R : Interrupt */
#define SXP_SEQUENCE SXP_BLOCK+0x1C /* RW*: Sequence */
#define SXP_GROSS_ERR SXP_BLOCK+0x1E /* R : Gross Error */
#define SXP_EXCEPTION SXP_BLOCK+0x20 /* RW*: Exception Enable */
#define SXP_OVERRIDE SXP_BLOCK+0x24 /* RW*: Override */
#define SXP_LITERAL_BASE SXP_BLOCK+0x28 /* RW*: Literal Base */
#define SXP_USER_FLAGS SXP_BLOCK+0x2C /* RW*: User Flags */
#define SXP_USER_EXCEPT SXP_BLOCK+0x30 /* RW*: User Exception */
#define SXP_BREAKPOINT SXP_BLOCK+0x34 /* RW*: Breakpoint */
#define SXP_SCSI_ID SXP_BLOCK+0x40 /* RW*: SCSI ID */
#define SXP_DEV_CONFIG1 SXP_BLOCK+0x42 /* RW*: Device Config Reg #1 */
#define SXP_DEV_CONFIG2 SXP_BLOCK+0x44 /* RW*: Device Config Reg #2 */
#define SXP_PHASE_POINTER SXP_BLOCK+0x48 /* RW*: SCSI Phase Pointer */
#define SXP_BUF_POINTER SXP_BLOCK+0x4C /* RW*: SCSI Buffer Pointer */
#define SXP_BUF_COUNTER SXP_BLOCK+0x50 /* RW*: SCSI Buffer Counter */
#define SXP_BUFFER SXP_BLOCK+0x52 /* RW*: SCSI Buffer */
#define SXP_BUF_BYTE SXP_BLOCK+0x54 /* RW*: SCSI Buffer Byte */
#define SXP_BUF_WORD SXP_BLOCK+0x56 /* RW*: SCSI Buffer Word */
#define SXP_BUF_WORD_TRAN SXP_BLOCK+0x58 /* RW*: SCSI Buffer Wd xlate */
#define SXP_FIFO SXP_BLOCK+0x5A /* RW*: SCSI FIFO */
#define SXP_FIFO_STATUS SXP_BLOCK+0x5C /* RW*: SCSI FIFO Status */
#define SXP_FIFO_TOP SXP_BLOCK+0x5E /* RW*: SCSI FIFO Top Resid */
#define SXP_FIFO_BOTTOM SXP_BLOCK+0x60 /* RW*: SCSI FIFO Bot Resid */
#define SXP_TRAN_REG SXP_BLOCK+0x64 /* RW*: SCSI Transferr Reg */
#define SXP_TRAN_COUNT_LO SXP_BLOCK+0x68 /* RW*: SCSI Trans Count */
#define SXP_TRAN_COUNT_HI SXP_BLOCK+0x6A /* RW*: SCSI Trans Count */
#define SXP_TRAN_COUNTER_LO SXP_BLOCK+0x6C /* RW*: SCSI Trans Counter */
#define SXP_TRAN_COUNTER_HI SXP_BLOCK+0x6E /* RW*: SCSI Trans Counter */
#define SXP_ARB_DATA SXP_BLOCK+0x70 /* R : SCSI Arb Data */
#define SXP_PINS_CONTROL SXP_BLOCK+0x72 /* RW*: SCSI Control Pins */
#define SXP_PINS_DATA SXP_BLOCK+0x74 /* RW*: SCSI Data Pins */
#define SXP_PINS_DIFF SXP_BLOCK+0x76 /* RW*: SCSI Diff Pins */
/* SXP CONF1 REGISTER */
#define SXP_CONF1_ASYNCH_SETUP 0xF000 /* Asynchronous setup time */
#define SXP_CONF1_SELECTION_UNIT 0x0000 /* Selection time unit */
#define SXP_CONF1_SELECTION_TIMEOUT 0x0600 /* Selection timeout */
#define SXP_CONF1_CLOCK_FACTOR 0x00E0 /* Clock factor */
#define SXP_CONF1_SCSI_ID 0x000F /* SCSI id */
/* SXP CONF2 REGISTER */
#define SXP_CONF2_DISABLE_FILTER 0x0040 /* Disable SCSI rec filters */
#define SXP_CONF2_REQ_ACK_PULLUPS 0x0020 /* Enable req/ack pullups */
#define SXP_CONF2_DATA_PULLUPS 0x0010 /* Enable data pullups */
#define SXP_CONF2_CONFIG_AUTOLOAD 0x0008 /* Enable dev conf auto-load */
#define SXP_CONF2_RESELECT 0x0002 /* Enable reselection */
#define SXP_CONF2_SELECT 0x0001 /* Enable selection */
/* SXP INTERRUPT REGISTER */
#define SXP_INT_PARITY_ERR 0x8000 /* Parity error detected */
#define SXP_INT_GROSS_ERR 0x4000 /* Gross error detected */
#define SXP_INT_FUNCTION_ABORT 0x2000 /* Last cmd aborted */
#define SXP_INT_CONDITION_FAILED 0x1000 /* Last cond failed test */
#define SXP_INT_FIFO_EMPTY 0x0800 /* SCSI FIFO is empty */
#define SXP_INT_BUF_COUNTER_ZERO 0x0400 /* SCSI buf count == zero */
#define SXP_INT_XFER_ZERO 0x0200 /* SCSI trans count == zero */
#define SXP_INT_INT_PENDING 0x0080 /* SXP interrupt pending */
#define SXP_INT_CMD_RUNNING 0x0040 /* SXP is running a command */
#define SXP_INT_INT_RETURN_CODE 0x000F /* Interrupt return code */
/* SXP GROSS ERROR REGISTER */
#define SXP_GROSS_OFFSET_RESID 0x0040 /* Req/Ack offset not zero */
#define SXP_GROSS_OFFSET_UNDERFLOW 0x0020 /* Req/Ack offset underflow */
#define SXP_GROSS_OFFSET_OVERFLOW 0x0010 /* Req/Ack offset overflow */
#define SXP_GROSS_FIFO_UNDERFLOW 0x0008 /* SCSI FIFO underflow */
#define SXP_GROSS_FIFO_OVERFLOW 0x0004 /* SCSI FIFO overflow */
#define SXP_GROSS_WRITE_ERR 0x0002 /* SXP and RISC wrote to reg */
#define SXP_GROSS_ILLEGAL_INST 0x0001 /* Bad inst loaded into SXP */
/* SXP EXCEPTION REGISTER */
#define SXP_EXCEPT_USER_0 0x8000 /* Enable user exception #0 */
#define SXP_EXCEPT_USER_1 0x4000 /* Enable user exception #1 */
#define PCI_SXP_EXCEPT_SCAM 0x0400 /* SCAM Selection enable */
#define SXP_EXCEPT_BUS_FREE 0x0200 /* Enable Bus Free det */
#define SXP_EXCEPT_TARGET_ATN 0x0100 /* Enable TGT mode atten det */
#define SXP_EXCEPT_RESELECTED 0x0080 /* Enable ReSEL exc handling */
#define SXP_EXCEPT_SELECTED 0x0040 /* Enable SEL exc handling */
#define SXP_EXCEPT_ARBITRATION 0x0020 /* Enable ARB exc handling */
#define SXP_EXCEPT_GROSS_ERR 0x0010 /* Enable gross error except */
#define SXP_EXCEPT_BUS_RESET 0x0008 /* Enable Bus Reset except */
/* SXP OVERRIDE REGISTER */
#define SXP_ORIDE_EXT_TRIGGER 0x8000 /* Enable external trigger */
#define SXP_ORIDE_STEP 0x4000 /* Enable single step mode */
#define SXP_ORIDE_BREAKPOINT 0x2000 /* Enable breakpoint reg */
#define SXP_ORIDE_PIN_WRITE 0x1000 /* Enable write to SCSI pins */
#define SXP_ORIDE_FORCE_OUTPUTS 0x0800 /* Force SCSI outputs on */
#define SXP_ORIDE_LOOPBACK 0x0400 /* Enable SCSI loopback mode */
#define SXP_ORIDE_PARITY_TEST 0x0200 /* Enable parity test mode */
#define SXP_ORIDE_TRISTATE_ENA_PINS 0x0100 /* Tristate SCSI enable pins */
#define SXP_ORIDE_TRISTATE_PINS 0x0080 /* Tristate SCSI pins */
#define SXP_ORIDE_FIFO_RESET 0x0008 /* Reset SCSI FIFO */
#define SXP_ORIDE_CMD_TERMINATE 0x0004 /* Terminate cur SXP com */
#define SXP_ORIDE_RESET_REG 0x0002 /* Reset SXP registers */
#define SXP_ORIDE_RESET_MODULE 0x0001 /* Reset SXP module */
/* SXP COMMANDS */
#define SXP_RESET_BUS_CMD 0x300b
/* SXP SCSI ID REGISTER */
#define SXP_SELECTING_ID 0x0F00 /* (Re)Selecting id */
#define SXP_SELECT_ID 0x000F /* Select id */
/* SXP DEV CONFIG1 REGISTER */
#define SXP_DCONF1_SYNC_HOLD 0x7000 /* Synchronous data hold */
#define SXP_DCONF1_SYNC_SETUP 0x0F00 /* Synchronous data setup */
#define SXP_DCONF1_SYNC_OFFSET 0x000F /* Synchronous data offset */
/* SXP DEV CONFIG2 REGISTER */
#define SXP_DCONF2_FLAGS_MASK 0xF000 /* Device flags */
#define SXP_DCONF2_WIDE 0x0400 /* Enable wide SCSI */
#define SXP_DCONF2_PARITY 0x0200 /* Enable parity checking */
#define SXP_DCONF2_BLOCK_MODE 0x0100 /* Enable blk mode xfr count */
#define SXP_DCONF2_ASSERTION_MASK 0x0007 /* Assersion period mask */
/* SXP PHASE POINTER REGISTER */
#define SXP_PHASE_STATUS_PTR 0x1000 /* Status buffer offset */
#define SXP_PHASE_MSG_IN_PTR 0x0700 /* Msg in buffer offset */
#define SXP_PHASE_COM_PTR 0x00F0 /* Command buffer offset */
#define SXP_PHASE_MSG_OUT_PTR 0x0007 /* Msg out buffer offset */
/* SXP FIFO STATUS REGISTER */
#define SXP_FIFO_TOP_RESID 0x8000 /* Top residue reg full */
#define SXP_FIFO_ACK_RESID 0x4000 /* Wide transfers odd resid */
#define SXP_FIFO_COUNT_MASK 0x001C /* Words in SXP FIFO */
#define SXP_FIFO_BOTTOM_RESID 0x0001 /* Bottom residue reg full */
/* SXP CONTROL PINS REGISTER */
#define SXP_PINS_CON_PHASE 0x8000 /* Scsi phase valid */
#define SXP_PINS_CON_PARITY_HI 0x0400 /* Parity pin */
#define SXP_PINS_CON_PARITY_LO 0x0200 /* Parity pin */
#define SXP_PINS_CON_REQ 0x0100 /* SCSI bus REQUEST */
#define SXP_PINS_CON_ACK 0x0080 /* SCSI bus ACKNOWLEDGE */
#define SXP_PINS_CON_RST 0x0040 /* SCSI bus RESET */
#define SXP_PINS_CON_BSY 0x0020 /* SCSI bus BUSY */
#define SXP_PINS_CON_SEL 0x0010 /* SCSI bus SELECT */
#define SXP_PINS_CON_ATN 0x0008 /* SCSI bus ATTENTION */
#define SXP_PINS_CON_MSG 0x0004 /* SCSI bus MESSAGE */
#define SXP_PINS_CON_CD 0x0002 /* SCSI bus COMMAND */
#define SXP_PINS_CON_IO 0x0001 /* SCSI bus INPUT */
/*
* Set the hold time for the SCSI Bus Reset to be 250 ms
*/
#define SXP_SCSI_BUS_RESET_HOLD_TIME 250
/* SXP DIFF PINS REGISTER */
#define SXP_PINS_DIFF_SENSE 0x0200 /* DIFFSENS sig on SCSI bus */
#define SXP_PINS_DIFF_MODE 0x0100 /* DIFFM signal */
#define SXP_PINS_DIFF_ENABLE_OUTPUT 0x0080 /* Enable SXP SCSI data drv */
#define SXP_PINS_DIFF_PINS_MASK 0x007C /* Differential control pins */
#define SXP_PINS_DIFF_TARGET 0x0002 /* Enable SXP target mode */
#define SXP_PINS_DIFF_INITIATOR 0x0001 /* Enable SXP initiator mode */
/*
* RISC and Host Command and Control Block Register Offsets
*/
#define RISC_BLOCK 0x0800
#define RISC_ACC RISC_BLOCK+0x0 /* RW*: Accumulator */
#define RISC_R1 RISC_BLOCK+0x2 /* RW*: GP Reg R1 */
#define RISC_R2 RISC_BLOCK+0x4 /* RW*: GP Reg R2 */
#define RISC_R3 RISC_BLOCK+0x6 /* RW*: GP Reg R3 */
#define RISC_R4 RISC_BLOCK+0x8 /* RW*: GP Reg R4 */
#define RISC_R5 RISC_BLOCK+0xA /* RW*: GP Reg R5 */
#define RISC_R6 RISC_BLOCK+0xC /* RW*: GP Reg R6 */
#define RISC_R7 RISC_BLOCK+0xE /* RW*: GP Reg R7 */
#define RISC_R8 RISC_BLOCK+0x10 /* RW*: GP Reg R8 */
#define RISC_R9 RISC_BLOCK+0x12 /* RW*: GP Reg R9 */
#define RISC_R10 RISC_BLOCK+0x14 /* RW*: GP Reg R10 */
#define RISC_R11 RISC_BLOCK+0x16 /* RW*: GP Reg R11 */
#define RISC_R12 RISC_BLOCK+0x18 /* RW*: GP Reg R12 */
#define RISC_R13 RISC_BLOCK+0x1a /* RW*: GP Reg R13 */
#define RISC_R14 RISC_BLOCK+0x1c /* RW*: GP Reg R14 */
#define RISC_R15 RISC_BLOCK+0x1e /* RW*: GP Reg R15 */
#define RISC_PSR RISC_BLOCK+0x20 /* RW*: Processor Status */
#define RISC_IVR RISC_BLOCK+0x22 /* RW*: Interrupt Vector */
#define RISC_PCR RISC_BLOCK+0x24 /* RW*: Processor Ctrl */
#define RISC_RAR0 RISC_BLOCK+0x26 /* RW*: Ram Address #0 */
#define RISC_RAR1 RISC_BLOCK+0x28 /* RW*: Ram Address #1 */
#define RISC_LCR RISC_BLOCK+0x2a /* RW*: Loop Counter */
#define RISC_PC RISC_BLOCK+0x2c /* R : Program Counter */
#define RISC_MTR RISC_BLOCK+0x2e /* RW*: Memory Timing */
#define RISC_EMB RISC_BLOCK+0x30 /* RW*: Ext Mem Boundary */
#define RISC_SP RISC_BLOCK+0x32 /* RW*: Stack Pointer */
#define RISC_HRL RISC_BLOCK+0x3e /* R *: Hardware Rev Level */
#define HCCR RISC_BLOCK+0x40 /* RW : Host Command & Ctrl */
#define BP0 RISC_BLOCK+0x42 /* RW : Processor Brkpt #0 */
#define BP1 RISC_BLOCK+0x44 /* RW : Processor Brkpt #1 */
#define TCR RISC_BLOCK+0x46 /* W : Test Control */
#define TMR RISC_BLOCK+0x48 /* W : Test Mode */
/* PROCESSOR STATUS REGISTER */
#define RISC_PSR_FORCE_TRUE 0x8000
#define RISC_PSR_LOOP_COUNT_DONE 0x4000
#define RISC_PSR_RISC_INT 0x2000
#define RISC_PSR_TIMER_ROLLOVER 0x1000
#define RISC_PSR_ALU_OVERFLOW 0x0800
#define RISC_PSR_ALU_MSB 0x0400
#define RISC_PSR_ALU_CARRY 0x0200
#define RISC_PSR_ALU_ZERO 0x0100
#define RISC_PSR_DMA_INT 0x0010
#define RISC_PSR_SXP_INT 0x0008
#define RISC_PSR_HOST_INT 0x0004
#define RISC_PSR_INT_PENDING 0x0002
#define RISC_PSR_FORCE_FALSE 0x0001
/* Host Command and Control */
#define HCCR_CMD_NOP 0x0000 /* NOP */
#define HCCR_CMD_RESET 0x1000 /* Reset RISC */
#define HCCR_CMD_PAUSE 0x2000 /* Pause RISC */
#define HCCR_CMD_RELEASE 0x3000 /* Release Paused RISC */
#define HCCR_CMD_STEP 0x4000 /* Single Step RISC */
#define HCCR_CMD_SET_HOST_INT 0x5000 /* Set Host Interrupt */
#define HCCR_CMD_CLEAR_HOST_INT 0x6000 /* Clear Host Interrupt */
#define HCCR_CMD_CLEAR_RISC_INT 0x7000 /* Clear RISC interrupt */
#define HCCR_CMD_BREAKPOINT 0x8000 /* Change breakpoint enables */
#define PCI_HCCR_CMD_BIOS 0x9000 /* Write BIOS (disable) */
#define PCI_HCCR_CMD_PARITY 0xA000 /* Write parity enable */
#define PCI_HCCR_CMD_PARITY_ERR 0xE000 /* Generate parity error */
#define HCCR_CMD_TEST_MODE 0xF000 /* Set Test Mode */
#define PCI_HCCR_PARITY 0x0400 /* Parity error flag */
#define PCI_HCCR_PARITY_ENABLE_1 0x0200 /* Parity enable bank 1 */
#define PCI_HCCR_PARITY_ENABLE_0 0x0100 /* Parity enable bank 0 */
#define HCCR_HOST_INT 0x0080 /* R : Host interrupt set */
#define HCCR_RESET 0x0040 /* R : reset in progress */
#define HCCR_PAUSE 0x0020 /* R : RISC paused */
#define PCI_HCCR_BIOS 0x0001 /* W : BIOS enable */
#endif /* _ISPREG_H */

218
sys/dev/ic/ispvar.h Normal file
View File

@ -0,0 +1,218 @@
/* $NetBSD: ispvar.h,v 1.1.1.1 1997/03/12 20:44:51 cgd Exp $ */
/*
* Soft Definitions for for Qlogic ISP SCSI adapters.
*
* Copyright (c) 1997 by Matthew Jacob (for NASA/Ames Research Center)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice immediately at the beginning of the file, without modification,
* this list of conditions, and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#ifndef _ISPVAR_H
#define _ISPVAR_H
#include <dev/ic/ispmbox.h>
/*
* Vector for MD code to provide specific services.
*/
struct ispsoftc;
struct ispmdvec {
u_int16_t (*dv_rd_reg) __P((struct ispsoftc *, int));
void (*dv_wr_reg) __P((struct ispsoftc *, int, u_int16_t));
vm_offset_t (*dv_mbxdma)
__P((struct ispsoftc *, vm_offset_t, u_int32_t));
int (*dv_dmaset) __P((struct ispsoftc *,
struct scsi_xfer *, ispreq_t *, u_int8_t *, u_int8_t));
void (*dv_dmaclr)
__P((struct ispsoftc *, struct scsi_xfer *, u_int32_t));
void (*dv_reset0) __P((struct ispsoftc *));
void (*dv_reset1) __P((struct ispsoftc *));
u_int16_t * dv_ispfw; /* ptr to f/w */
u_int16_t dv_fwlen; /* length of f/w */
u_int16_t dv_codeorg; /* code ORG for f/w */
/*
* Initial values for conf1 register
*/
u_int16_t dv_conf1;
};
#define MAX_TARGETS 16
#define MAX_LUNS 8
#define RQUEST_QUEUE_LEN 256
#define RESULT_QUEUE_LEN (RQUEST_QUEUE_LEN >> 3)
#define QENTRY_LEN 64
/*
* Soft Structure per host adapter
*/
struct ispsoftc {
struct device isp_dev;
struct ispmdvec * isp_mdvec;
#define isp_name isp_dev.dv_xname
struct scsi_link isp_link;
u_int8_t isp_max_target;
u_int8_t isp_state;
/*
* Host Adapter Parameters, nominally stored in NVRAM
*/
u_int16_t isp_adapter_enabled : 1,
isp_req_ack_active_neg : 1,
isp_data_line_active_neg: 1,
isp_cmd_dma_burst_enable: 1,
isp_data_dma_burst_enabl: 1,
isp_fifo_threshold : 2,
: 1,
isp_initiator_id : 4,
isp_async_data_setup : 4;
u_int16_t isp_selection_timeout;
u_int16_t isp_max_queue_depth;
u_int8_t isp_tag_aging;
u_int8_t isp_bus_reset_delay;
u_int8_t isp_retry_count;
u_int8_t isp_retry_delay;
struct {
u_int8_t dev_flags; /* Device Flags - see below */
u_int8_t exc_throttle;
u_int8_t sync_period;
u_int8_t sync_offset : 4,
dev_enable : 1;
} isp_devparam[MAX_TARGETS];
/*
* Result and Request Queues.
*/
volatile u_int8_t isp_reqidx; /* index of next request */
volatile u_int8_t isp_residx; /* index of next result */
volatile u_int8_t isp_sendmarker;
volatile u_int8_t isp_seqno;
/*
* Sheer laziness, but it gets us around the problem
* where we don't have a clean way of remembering
* which scsi_xfer is bound to which ISP queue entry.
*
* There are other more clever ways to do this, but,
* jeez, so I blow a couple of KB per host adapter...
* and it *is* faster.
*/
volatile struct scsi_xfer *isp_xflist[RQUEST_QUEUE_LEN];
/*
* request/result queue
*/
volatile u_int8_t isp_rquest[RQUEST_QUEUE_LEN][QENTRY_LEN];
volatile u_int8_t isp_result[RESULT_QUEUE_LEN][QENTRY_LEN];
};
/*
* ISP States
*/
#define ISP_NILSTATE 0
#define ISP_RESETSTATE 1
#define ISP_INITSTATE 2
#define ISP_RUNSTATE 3
/*
* Device Flags
*/
#define DPARM_DISC 0x80
#define DPARM_PARITY 0x40
#define DPARM_WIDE 0x20
#define DPARM_SYNC 0x10
#define DPARM_TQING 0x08
#define DPARM_ARQ 0x04
#define DPARM_QFRZ 0x02
#define DPARM_RENEG 0x01
#define DPARM_DEFAULT (0xff & ~DPARM_QFRZ)
/*
* Macros to read, write ISP registers through MD code
*/
#define ISP_READ(isp, reg) \
(*(isp)->isp_mdvec->dv_rd_reg)((isp), (reg))
#define ISP_WRITE(isp, reg, val) \
(*(isp)->isp_mdvec->dv_wr_reg)((isp), (reg), (val))
#define ISP_MBOXDMASETUP(isp, kva, len) \
(*(isp)->isp_mdvec->dv_mbxdma)((isp), (vm_offset_t) (kva), (len))
#define ISP_DMASETUP(isp, xs, req, iptrp, optr) \
(*(isp)->isp_mdvec->dv_dmaset)((isp), (xs), (req), (iptrp), (optr))
#define ISP_DMAFREE(isp, xs, seqno) \
if ((isp)->isp_mdvec->dv_dmaclr) \
(*(isp)->isp_mdvec->dv_dmaclr)((isp), (xs), (seqno))
#define ISP_RESET0(isp) \
if ((isp)->isp_mdvec->dv_reset0) (*(isp)->isp_mdvec->dv_reset0)((isp))
#define ISP_RESET1(isp) \
if ((isp)->isp_mdvec->dv_reset1) (*(isp)->isp_mdvec->dv_reset1)((isp))
#define ISP_SETBITS(isp, reg, val) \
(*(isp)->isp_mdvec->dv_wr_reg)((isp), (reg), ISP_READ((isp), (reg)) | (val))
#define ISP_CLRBITS(isp, reg, val) \
(*(isp)->isp_mdvec->dv_wr_reg)((isp), (reg), ISP_READ((isp), (reg)) & ~(val))
/*
* Function Prototypes
*/
/*
* Reset Hardware.
*
* Only looks at sc_dev.dv_xname, sc_iot and sc_ioh fields.
*/
void isp_reset __P((struct ispsoftc *));
/*
* Initialize Hardware to known state
*/
void isp_init __P((struct ispsoftc *));
/*
* Complete attachment of Hardware
*/
void isp_attach __P((struct ispsoftc *));
/*
* Free any associated resources prior to decommissioning.
*/
void isp_uninit __P((struct ispsoftc *));
/*
* Interrupt Service Routine
*/
int isp_intr __P((void *));
#endif /* _ISPVAR_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

373
sys/dev/pci/isp_pci.c Normal file
View File

@ -0,0 +1,373 @@
/* $NetBSD: isp_pci.c,v 1.1.1.1 1997/03/12 20:44:52 cgd Exp $ */
/*
* PCI specific probe and attach routines for Qlogic ISP SCSI adapters.
*
* Copyright (c) 1997 by Matthew Jacob
* NASA AMES Research Center
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice immediately at the beginning of the file, without modification,
* this list of conditions, and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/queue.h>
#include <sys/device.h>
#include <machine/bus.h>
#include <machine/intr.h>
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>
#include <dev/ic/ispreg.h>
#include <dev/ic/ispvar.h>
#include <dev/ic/ispmbox.h>
#include <dev/microcode/isp/asm_pci.h>
#ifdef alpha /* XXX */
/* XXX XXX NEED REAL DMA MAPPING SUPPORT XXX XXX */
extern vm_offset_t alpha_XXX_dmamap(vm_offset_t);
#undef vtophys
#define vtophys(va) alpha_XXX_dmamap((vm_offset_t) va)
#endif
#include <sys/kernel.h>
#define KVTOPHYS(x) vtophys(x)
static u_int16_t isp_pci_rd_reg __P((struct ispsoftc *, int));
static void isp_pci_wr_reg __P((struct ispsoftc *, int, u_int16_t));
static vm_offset_t
isp_pci_mbxdma __P((struct ispsoftc *, vm_offset_t, u_int32_t));
static int
isp_pci_dmasetup __P((struct ispsoftc *, struct scsi_xfer *, ispreq_t *,
u_int8_t *, u_int8_t));
static void isp_pci_reset1 __P((struct ispsoftc *));
static struct ispmdvec mdvec = {
isp_pci_rd_reg,
isp_pci_wr_reg,
isp_pci_mbxdma,
isp_pci_dmasetup,
NULL,
NULL,
isp_pci_reset1,
(u_int16_t *) ISP_RISC_CODE,
ISP_CODE_LENGTH,
ISP_CODE_ORG,
/* BIU_PCI_CONF1_FIFO_16 | BIU_BURST_ENABLE */ 0
};
#define PCI_QLOGIC_ISP \
((PCI_PRODUCT_QLOGIC_ISP1020 << 16) | PCI_VENDOR_QLOGIC)
#define BASEADDR PCI_MAPREG_START
#ifdef __BROKEN_INDIRECT_CONFIG
static int isp_pci_probe __P((struct device *, void *, void *));
#else
static int isp_pci_probe __P((struct device *, struct cfdata *, void *));
#endif
static void isp_pci_attach __P((struct device *, struct device *, void *));
struct isp_pcisoftc {
struct ispsoftc pci_isp;
bus_space_tag_t pci_iot;
bus_space_handle_t pci_ioh;
void * pci_ih;
};
struct cfattach isp_pci_ca = {
sizeof (struct isp_pcisoftc), isp_pci_probe, isp_pci_attach
};
static int
isp_pci_probe(parent, match, aux)
struct device *parent;
#ifdef __BROKEN_INDIRECT_CONFIG
void *match, *aux;
#else
struct cfdata *match;
void *aux;
#endif
{
struct pci_attach_args *pa = aux;
if (pa->pa_id == PCI_QLOGIC_ISP) {
return (1);
} else {
return (0);
}
}
static void
isp_pci_attach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct pci_attach_args *pa = aux;
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) self;
bus_addr_t iobase;
bus_size_t iosize;
bus_space_handle_t ioh;
pci_intr_handle_t ih;
const char *intrstr;
if (pci_io_find(pa->pa_pc, pa->pa_tag, BASEADDR, &iobase, &iosize)) {
printf(" unable to find PCI base\n");
return;
}
if (bus_space_map(pa->pa_iot, iobase, iosize, 0, &ioh)) {
printf(": unable to map registers\n");
return;
}
printf("\n");
pcs->pci_iot = pa->pa_iot;
pcs->pci_ioh = ioh;
pcs->pci_isp.isp_mdvec = &mdvec;
isp_reset(&pcs->pci_isp);
if (pcs->pci_isp.isp_state != ISP_RESETSTATE) {
return;
}
isp_init(&pcs->pci_isp);
if (pcs->pci_isp.isp_state != ISP_INITSTATE) {
isp_uninit(&pcs->pci_isp);
return;
}
if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin,
pa->pa_intrline, &ih)) {
printf("%s: couldn't map interrupt\n", pcs->pci_isp.isp_name);
isp_uninit(&pcs->pci_isp);
return;
}
intrstr = pci_intr_string(pa->pa_pc, ih);
if (intrstr == NULL)
intrstr = "<I dunno>";
pcs->pci_ih =
pci_intr_establish(pa->pa_pc, ih, IPL_BIO, isp_intr, &pcs->pci_isp);
if (pcs->pci_ih == NULL) {
printf("%s: couldn't establish interrupt at %s\n",
pcs->pci_isp.isp_name, intrstr);
isp_uninit(&pcs->pci_isp);
return;
}
printf("%s: interrupting at %s\n", pcs->pci_isp.isp_name, intrstr);
/*
* Do Generic attach now.
*/
isp_attach(&pcs->pci_isp);
if (pcs->pci_isp.isp_state != ISP_RUNSTATE) {
isp_uninit(&pcs->pci_isp);
}
}
#define PCI_BIU_REGS_OFF 0x00
#define PCI_MBOX_REGS_OFF 0x70
#define PCI_SXP_REGS_OFF 0x80
#define PCI_RISC_REGS_OFF 0x80
static u_int16_t
isp_pci_rd_reg(isp, regoff)
struct ispsoftc *isp;
int regoff;
{
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
int offset;
if ((regoff & BIU_BLOCK) != 0) {
offset = PCI_BIU_REGS_OFF;
} else if ((regoff & MBOX_BLOCK) != 0) {
offset = PCI_MBOX_REGS_OFF;
} else if ((regoff & SXP_BLOCK) != 0) {
offset = PCI_SXP_REGS_OFF;
/*
* XXX
*/
panic("SXP Registers not accessible yet!");
} else {
offset = PCI_RISC_REGS_OFF;
}
regoff &= 0xff;
offset += regoff;
return bus_space_read_2(pcs->pci_iot, pcs->pci_ioh, offset);
}
static void
isp_pci_wr_reg(isp, regoff, val)
struct ispsoftc *isp;
int regoff;
u_int16_t val;
{
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
int offset;
if ((regoff & BIU_BLOCK) != 0) {
offset = PCI_BIU_REGS_OFF;
} else if ((regoff & MBOX_BLOCK) != 0) {
offset = PCI_MBOX_REGS_OFF;
} else if ((regoff & SXP_BLOCK) != 0) {
offset = PCI_SXP_REGS_OFF;
/*
* XXX
*/
panic("SXP Registers not accessible yet!");
} else {
offset = PCI_RISC_REGS_OFF;
}
regoff &= 0xff;
offset += regoff;
bus_space_write_2(pcs->pci_iot, pcs->pci_ioh, offset, val);
}
static vm_offset_t
isp_pci_mbxdma(isp, kva, len)
struct ispsoftc *isp;
vm_offset_t kva;
u_int32_t len;
{
vm_offset_t pg, start, s1;
start = KVTOPHYS(kva);
pg = kva + NBPG;
s1 = (start >> PGSHIFT) + 1;
len -= NBPG;
while ((int32_t)len > 0) {
if (s1 != (KVTOPHYS(pg) >> PGSHIFT)) {
printf("%s: mailboxes across noncontiguous pages\n",
isp->isp_name);
return ((vm_offset_t) 0);
}
len -= NBPG;
pg += NBPG;
s1++;
}
return (start);
}
/*
* TODO: reduce the number of segments by
* cchecking for adjacent physical page.
*/
static int
isp_pci_dmasetup(isp, xs, rq, iptrp, optr)
struct ispsoftc *isp;
struct scsi_xfer *xs;
ispreq_t *rq;
u_int8_t *iptrp;
u_int8_t optr;
{
ispcontreq_t *crq;
unsigned long thiskv, nextkv;
int datalen, amt;
if (xs->datalen == 0) {
rq->req_seg_count = 1;
rq->req_flags |= REQFLAG_DATA_IN;
return (0);
}
if (xs->flags & SCSI_DATA_IN) {
rq->req_flags |= REQFLAG_DATA_IN;
} else {
rq->req_flags |= REQFLAG_DATA_OUT;
}
datalen = xs->datalen;
thiskv = (unsigned long) xs->data;
while (datalen && rq->req_seg_count < ISP_RQDSEG) {
nextkv = (thiskv + NBPG) & ~(NBPG-1);
amt = nextkv - thiskv;
if (amt > datalen)
amt = datalen;
rq->req_dataseg[rq->req_seg_count].ds_count = amt;
rq->req_dataseg[rq->req_seg_count].ds_base = KVTOPHYS(thiskv);
#if 0
printf("%s: seg%d: 0x%lx..0x%lx\n", isp->isp_name,
rq->req_seg_count, thiskv,
thiskv + (unsigned long) amt);
#endif
datalen -= amt;
thiskv = nextkv;
rq->req_seg_count++;
}
if (datalen == 0) {
return (0);
}
do {
int seg;
crq = (ispcontreq_t *) &isp->isp_rquest[*iptrp][0];
*iptrp = (*iptrp + 1) & (RQUEST_QUEUE_LEN - 1);
if (*iptrp == optr) {
printf("%s: Request Queue Overflow++\n",
isp->isp_name);
return (1);
}
rq->req_header.rqs_entry_count++;
bzero((void *)crq, sizeof (*crq));
crq->req_header.rqs_entry_count = 1;
crq->req_header.rqs_entry_type = RQSTYPE_DATASEG;
seg = 0;
while (datalen && seg < ISP_CDSEG) {
nextkv = (thiskv + NBPG) & ~(NBPG-1);
amt = nextkv - thiskv;
if (amt > datalen)
amt = datalen;
crq->req_dataseg[seg].ds_count = amt;
crq->req_dataseg[seg].ds_base = KVTOPHYS(thiskv);
#if 0
printf("%s: Cont%d seg%d: 0x%lx..0x%lx\n",
isp->isp_name, rq->req_header.rqs_entry_count,
seg, thiskv, thiskv + (unsigned long) amt);
#endif
datalen -= amt;
thiskv = nextkv;
rq->req_seg_count++;
seg++;
}
} while (datalen > 0);
return (0);
}
static void
isp_pci_reset1(isp)
struct ispsoftc *isp;
{
/* Make sure the BIOS is disabled */
isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS);
}