ISP 10x0 driver from Matthew Jacob of NASA Ames Research Center.
(March 12, 1997 version).
This commit is contained in:
parent
5c9a92362a
commit
099e30a322
310
sys/arch/sparc/dev/isp_sbus.c
Normal file
310
sys/arch/sparc/dev/isp_sbus.c
Normal 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
998
sys/dev/ic/isp.c
Normal 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
285
sys/dev/ic/ispmbox.h
Normal 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
519
sys/dev/ic/ispreg.h
Normal 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
218
sys/dev/ic/ispvar.h
Normal 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 */
|
1300
sys/dev/microcode/isp/asm_pci.h
Normal file
1300
sys/dev/microcode/isp/asm_pci.h
Normal file
File diff suppressed because it is too large
Load Diff
1136
sys/dev/microcode/isp/asm_sbus.h
Normal file
1136
sys/dev/microcode/isp/asm_sbus.h
Normal file
File diff suppressed because it is too large
Load Diff
373
sys/dev/pci/isp_pci.c
Normal file
373
sys/dev/pci/isp_pci.c
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user