NEWS5000 internal SCSI driver.
This commit is contained in:
parent
4c2d830e97
commit
c6c547497d
227
sys/arch/newsmips/apbus/dmac3.c
Normal file
227
sys/arch/newsmips/apbus/dmac3.c
Normal file
@ -0,0 +1,227 @@
|
||||
/* $NetBSD: dmac3.c,v 1.1 2000/10/30 10:07:35 tsubai Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2000 Tsubai Masanari. 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, 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 ``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 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/device.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <uvm/uvm_extern.h>
|
||||
|
||||
#include <machine/locore.h>
|
||||
|
||||
#include <newsmips/apbus/apbusvar.h>
|
||||
#include <newsmips/apbus/dmac3reg.h>
|
||||
|
||||
#define DMA_BURST
|
||||
#define DMA_APAD_OFF
|
||||
|
||||
#ifdef DMA_APAD_OFF
|
||||
# define APAD_MODE 0
|
||||
#else
|
||||
# define APAD_MODE DMAC3_CSR_APAD
|
||||
#endif
|
||||
|
||||
#ifdef DMA_BURST
|
||||
# define BURST_MODE (DMAC3_CSR_DBURST | DMAC3_CSR_MBURST)
|
||||
#else
|
||||
# define BURST_MODE 0
|
||||
#endif
|
||||
|
||||
struct dmac3_softc {
|
||||
struct device sc_dev;
|
||||
struct dmac3reg *sc_reg;
|
||||
vaddr_t sc_dmaaddr;
|
||||
int *sc_dmamap;
|
||||
int sc_conf;
|
||||
int sc_ctlnum;
|
||||
};
|
||||
|
||||
int dmac3_match __P((struct device *, struct cfdata *, void *));
|
||||
void dmac3_attach __P((struct device *, struct device *, void *));
|
||||
|
||||
paddr_t kvtophys __P((vaddr_t));
|
||||
|
||||
struct cfattach dmac_ca = {
|
||||
sizeof(struct dmac3_softc), dmac3_match, dmac3_attach
|
||||
};
|
||||
|
||||
int
|
||||
dmac3_match(parent, cf, aux)
|
||||
struct device *parent;
|
||||
struct cfdata *cf;
|
||||
void *aux;
|
||||
{
|
||||
struct apbus_attach_args *apa = aux;
|
||||
|
||||
if (strcmp(apa->apa_name, "dmac3") == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
dmac3_attach(parent, self, aux)
|
||||
struct device *parent, *self;
|
||||
void *aux;
|
||||
{
|
||||
struct dmac3_softc *sc = (void *)self;
|
||||
struct apbus_attach_args *apa = aux;
|
||||
struct dmac3reg *reg;
|
||||
|
||||
static paddr_t dmamap = DMAC3_PAGEMAP;
|
||||
static vaddr_t dmaaddr = 0;
|
||||
|
||||
reg = (void *)apa->apa_hwbase;
|
||||
sc->sc_reg = reg;
|
||||
sc->sc_ctlnum = apa->apa_ctlnum;
|
||||
sc->sc_dmamap = (int *)dmamap;
|
||||
sc->sc_dmaaddr = dmaaddr;
|
||||
dmamap += 0x1000;
|
||||
dmaaddr += 0x200000;
|
||||
|
||||
sc->sc_conf = DMAC3_CONF_PCEN | DMAC3_CONF_DCEN | DMAC3_CONF_FASTACCESS;
|
||||
|
||||
dmac3_reset(sc);
|
||||
|
||||
printf(" slot%d addr 0x%lx", apa->apa_slotno, apa->apa_hwbase);
|
||||
printf(": ctlnum = %d, map = %p, va = %lx",
|
||||
apa->apa_ctlnum, sc->sc_dmamap, sc->sc_dmaaddr);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void *
|
||||
dmac3_link(ctlnum)
|
||||
int ctlnum;
|
||||
{
|
||||
struct dmac3_softc *sc;
|
||||
struct device *dv;
|
||||
|
||||
for (dv = alldevs.tqh_first; dv; dv = dv->dv_list.tqe_next) {
|
||||
if (strncmp(dv->dv_xname, "dmac", 4) == 0) {
|
||||
sc = (void *)dv;
|
||||
if (sc->sc_ctlnum == ctlnum)
|
||||
return sc;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
dmac3_reset(sc)
|
||||
struct dmac3_softc *sc;
|
||||
{
|
||||
struct dmac3reg *reg = sc->sc_reg;
|
||||
|
||||
reg->csr = DMAC3_CSR_RESET;
|
||||
reg->csr = 0;
|
||||
reg->intr = DMAC3_INTR_EOPIE | DMAC3_INTR_INTEN;
|
||||
reg->conf = sc->sc_conf;
|
||||
}
|
||||
|
||||
void
|
||||
dmac3_start(sc, addr, len, direction)
|
||||
struct dmac3_softc *sc;
|
||||
vaddr_t addr;
|
||||
int len, direction;
|
||||
{
|
||||
struct dmac3reg *reg = sc->sc_reg;
|
||||
paddr_t pa;
|
||||
vaddr_t start, end, v;
|
||||
u_int *p;
|
||||
|
||||
if (reg->csr & DMAC3_CSR_ENABLE)
|
||||
dmac3_reset(sc);
|
||||
|
||||
start = mips_trunc_page(addr);
|
||||
end = mips_round_page(addr + len);
|
||||
p = sc->sc_dmamap;
|
||||
for (v = start; v < end; v += NBPG) {
|
||||
pa = kvtophys(v);
|
||||
MachFlushDCache(MIPS_PHYS_TO_KSEG0(pa), NBPG);
|
||||
*p++ = 0;
|
||||
*p++ = (pa >> PGSHIFT) | 0xc0000000;
|
||||
}
|
||||
*p++ = 0;
|
||||
*p++ = 0x003fffff;
|
||||
|
||||
addr &= PGOFSET;
|
||||
addr += sc->sc_dmaaddr;
|
||||
|
||||
reg->len = len;
|
||||
reg->addr = addr;
|
||||
reg->intr = DMAC3_INTR_EOPIE | DMAC3_INTR_INTEN;
|
||||
reg->csr = DMAC3_CSR_ENABLE | direction | BURST_MODE | APAD_MODE;
|
||||
}
|
||||
|
||||
int
|
||||
dmac3_intr(v)
|
||||
void *v;
|
||||
{
|
||||
struct dmac3_softc *sc = v;
|
||||
struct dmac3reg *reg = sc->sc_reg;
|
||||
int intr, conf, rv = 1;
|
||||
|
||||
intr = reg->intr;
|
||||
if ((intr & DMAC3_INTR_INT) == 0)
|
||||
return 0;
|
||||
|
||||
/* clear interrupt */
|
||||
conf = reg->conf;
|
||||
reg->conf = conf;
|
||||
reg->intr = intr;
|
||||
|
||||
if (intr & DMAC3_INTR_PERR) {
|
||||
printf("%s: intr = 0x%x\n", sc->sc_dev.dv_xname, intr);
|
||||
rv = -1;
|
||||
}
|
||||
|
||||
if (conf & (DMAC3_CONF_IPER | DMAC3_CONF_MPER | DMAC3_CONF_DERR)) {
|
||||
printf("%s: conf = 0x%x\n", sc->sc_dev.dv_xname, conf);
|
||||
if (conf & DMAC3_CONF_DERR) {
|
||||
printf("DMA address = 0x%x\n", reg->addr);
|
||||
printf("resetting DMA...\n");
|
||||
dmac3_reset(sc);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
dmac3_misc(sc, cmd)
|
||||
struct dmac3_softc *sc;
|
||||
int cmd;
|
||||
{
|
||||
struct dmac3reg *reg = sc->sc_reg;
|
||||
int conf;
|
||||
|
||||
conf = DMAC3_CONF_PCEN | DMAC3_CONF_DCEN | cmd;
|
||||
sc->sc_conf = conf;
|
||||
reg->conf = conf;
|
||||
}
|
84
sys/arch/newsmips/apbus/dmac3reg.h
Normal file
84
sys/arch/newsmips/apbus/dmac3reg.h
Normal file
@ -0,0 +1,84 @@
|
||||
/* $NetBSD: dmac3reg.h,v 1.1 2000/10/30 10:07:35 tsubai Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2000 Tsubai Masanari. 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, 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 ``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 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.
|
||||
*/
|
||||
|
||||
struct dmac3reg {
|
||||
volatile u_int csr;
|
||||
volatile u_int intr;
|
||||
volatile u_int len;
|
||||
volatile u_int addr;
|
||||
volatile u_int conf;
|
||||
};
|
||||
|
||||
#define DMAC3_CSR_DBURST 0x0020
|
||||
#define DMAC3_CSR_MBURST 0x0010
|
||||
#define DMAC3_CSR_APAD 0x0008
|
||||
#define DMAC3_CSR_RESET 0x0004
|
||||
#define DMAC3_CSR_RECV 0x0002
|
||||
#define DMAC3_CSR_SEND 0x0000
|
||||
#define DMAC3_CSR_ENABLE 0x0001
|
||||
|
||||
#define DMAC3_INTR_PERR 0x8000
|
||||
#define DMAC3_INTR_DRQI 0x4000
|
||||
#define DMAC3_INTR_DRQIE 0x2000
|
||||
#define DMAC3_INTR_DREQ 0x1000
|
||||
#define DMAC3_INTR_EOPI 0x0400
|
||||
#define DMAC3_INTR_EOPIE 0x0200
|
||||
#define DMAC3_INTR_EOP 0x0100
|
||||
#define DMAC3_INTR_TCI 0x0040
|
||||
#define DMAC3_INTR_TCIE 0x0020
|
||||
#define DMAC3_INTR_INTEN 0x0002
|
||||
#define DMAC3_INTR_INT 0x0001
|
||||
|
||||
#define DMAC3_CONF_IPER 0x8000
|
||||
#define DMAC3_CONF_MPER 0x4000
|
||||
#define DMAC3_CONF_PCEN 0x2000
|
||||
#define DMAC3_CONF_DERR 0x1000
|
||||
#define DMAC3_CONF_DCEN 0x0800
|
||||
#define DMAC3_CONF_ODDP 0x0200
|
||||
#define DMAC3_CONF_WIDTH 0x00ff
|
||||
#define DMAC3_CONF_SLOWACCESS 0x0020
|
||||
#define DMAC3_CONF_FASTACCESS 0x0001
|
||||
|
||||
|
||||
#define DMAC3_PAGEMAP 0xb4c20000
|
||||
#define DMAC3_MAPSIZE 0x20000
|
||||
|
||||
struct dma_pte {
|
||||
u_int pad1;
|
||||
u_int valid:1,
|
||||
coherent:1, /* ? */
|
||||
pad2:10, /* ? */
|
||||
pfnum:20;
|
||||
};
|
||||
|
||||
struct dmac3_softc;
|
||||
void *dmac3_link(int);
|
||||
void dmac3_reset(struct dmac3_softc *);
|
||||
void dmac3_start(struct dmac3_softc *, vaddr_t, int, int);
|
||||
int dmac3_intr(void *);
|
||||
void dmac3_misc(struct dmac3_softc *, int);
|
845
sys/arch/newsmips/apbus/spifi.c
Normal file
845
sys/arch/newsmips/apbus/spifi.c
Normal file
@ -0,0 +1,845 @@
|
||||
/* $NetBSD: spifi.c,v 1.1 2000/10/30 10:07:35 tsubai Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2000 Tsubai Masanari. 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, 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 ``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 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/buf.h>
|
||||
#include <sys/device.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <uvm/uvm_extern.h>
|
||||
|
||||
#include <dev/scsipi/scsi_all.h>
|
||||
#include <dev/scsipi/scsi_message.h>
|
||||
#include <dev/scsipi/scsipi_all.h>
|
||||
#include <dev/scsipi/scsiconf.h>
|
||||
|
||||
#include <newsmips/apbus/apbusvar.h>
|
||||
#include <newsmips/apbus/spifireg.h>
|
||||
#include <newsmips/apbus/dmac3reg.h>
|
||||
|
||||
#include <machine/adrsmap.h>
|
||||
|
||||
/* #define SPIFI_DEBUG */
|
||||
|
||||
#ifdef SPIFI_DEBUG
|
||||
# define DPRINTF printf
|
||||
#else
|
||||
# define DPRINTF while (0) printf
|
||||
#endif
|
||||
|
||||
struct spifi_scb {
|
||||
TAILQ_ENTRY(spifi_scb) chain;
|
||||
int flags;
|
||||
struct scsipi_xfer *xs;
|
||||
struct scsi_generic cmd;
|
||||
int cmdlen;
|
||||
int resid;
|
||||
vaddr_t daddr;
|
||||
u_char target;
|
||||
u_char lun;
|
||||
u_char lun_targ;
|
||||
u_char status;
|
||||
};
|
||||
/* scb flags */
|
||||
#define SPIFI_READ 0x80
|
||||
#define SPIFI_DMA 0x01
|
||||
|
||||
struct spifi_softc {
|
||||
struct device sc_dev;
|
||||
struct scsipi_link sc_link;
|
||||
|
||||
struct spifi_reg *sc_reg;
|
||||
struct spifi_scb *sc_nexus;
|
||||
void *sc_dma; /* attached DMA softc */
|
||||
int sc_id; /* my SCSI ID */
|
||||
int sc_msgout;
|
||||
u_char sc_omsg[16];
|
||||
struct spifi_scb sc_scb[16];
|
||||
TAILQ_HEAD(, spifi_scb) free_scb;
|
||||
TAILQ_HEAD(, spifi_scb) ready_scb;
|
||||
};
|
||||
|
||||
#define SPIFI_SYNC_OFFSET_MAX 7
|
||||
|
||||
#define SEND_REJECT 1
|
||||
#define SEND_IDENTIFY 2
|
||||
#define SEND_SDTR 4
|
||||
|
||||
#define SPIFI_DATAOUT 0
|
||||
#define SPIFI_DATAIN PRS_IO
|
||||
#define SPIFI_COMMAND PRS_CD
|
||||
#define SPIFI_STATUS (PRS_CD | PRS_IO)
|
||||
#define SPIFI_MSGOUT (PRS_MSG | PRS_CD)
|
||||
#define SPIFI_MSGIN (PRS_MSG | PRS_CD | PRS_IO)
|
||||
|
||||
int spifi_match(struct device *, struct cfdata *, void *);
|
||||
void spifi_attach(struct device *, struct device *, void *);
|
||||
|
||||
int spifi_scsi_cmd(struct scsipi_xfer *);
|
||||
struct spifi_scb *spifi_get_scb(struct spifi_softc *);
|
||||
void spifi_free_scb(struct spifi_softc *, struct spifi_scb *);
|
||||
int spifi_poll(struct spifi_softc *);
|
||||
void spifi_minphys(struct buf *);
|
||||
|
||||
void spifi_sched(struct spifi_softc *);
|
||||
int spifi_intr(void *);
|
||||
void spifi_pmatch(struct spifi_softc *);
|
||||
|
||||
void spifi_select(struct spifi_softc *);
|
||||
void spifi_sendmsg(struct spifi_softc *, int);
|
||||
void spifi_command(struct spifi_softc *);
|
||||
void spifi_data_io(struct spifi_softc *);
|
||||
void spifi_status(struct spifi_softc *);
|
||||
int spifi_done(struct spifi_softc *);
|
||||
void spifi_fifo_drain(struct spifi_softc *);
|
||||
void spifi_reset(struct spifi_softc *);
|
||||
void spifi_bus_reset(struct spifi_softc *);
|
||||
|
||||
static int spifi_read_count(struct spifi_reg *);
|
||||
static void spifi_write_count(struct spifi_reg *, int);
|
||||
|
||||
#define DMAC3_FASTACCESS(sc) dmac3_misc((sc)->sc_dma, DMAC3_CONF_FASTACCESS)
|
||||
#define DMAC3_SLOWACCESS(sc) dmac3_misc((sc)->sc_dma, DMAC3_CONF_SLOWACCESS)
|
||||
|
||||
struct scsipi_device spifi_dev = {
|
||||
NULL, /* Use default error handler */
|
||||
NULL, /* have a queue, served by this */
|
||||
NULL, /* have no async handler */
|
||||
NULL, /* Use default 'done' routine */
|
||||
};
|
||||
|
||||
struct scsipi_adapter spifi_adapter = {
|
||||
0,
|
||||
spifi_scsi_cmd,
|
||||
spifi_minphys,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
struct cfattach spifi_ca = {
|
||||
sizeof(struct spifi_softc), spifi_match, spifi_attach
|
||||
};
|
||||
|
||||
int
|
||||
spifi_match(parent, cf, aux)
|
||||
struct device *parent;
|
||||
struct cfdata *cf;
|
||||
void *aux;
|
||||
{
|
||||
struct apbus_attach_args *apa = aux;
|
||||
|
||||
if (strcmp(apa->apa_name, "spifi") == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
spifi_attach(parent, self, aux)
|
||||
struct device *parent, *self;
|
||||
void *aux;
|
||||
{
|
||||
struct spifi_softc *sc = (void *)self;
|
||||
struct apbus_attach_args *apa = aux;
|
||||
struct device *dma;
|
||||
int intr, i;
|
||||
|
||||
/* Initialize scbs. */
|
||||
TAILQ_INIT(&sc->free_scb);
|
||||
TAILQ_INIT(&sc->ready_scb);
|
||||
for (i = 0; i < sizeof(sc->sc_scb)/sizeof(sc->sc_scb[0]); i++)
|
||||
TAILQ_INSERT_TAIL(&sc->free_scb, &sc->sc_scb[i], chain);
|
||||
|
||||
sc->sc_reg = (struct spifi_reg *)apa->apa_hwbase;
|
||||
sc->sc_id = 7; /* XXX */
|
||||
|
||||
/* Find my dmac3. */
|
||||
dma = dmac3_link(apa->apa_ctlnum);
|
||||
if (dma == NULL) {
|
||||
printf(": cannot find slave dmac\n");
|
||||
return;
|
||||
}
|
||||
sc->sc_dma = dma;
|
||||
|
||||
printf(" slot%d addr 0x%lx", apa->apa_slotno, apa->apa_hwbase);
|
||||
printf(": SCSI ID = %d, using %s\n", sc->sc_id, dma->dv_xname);
|
||||
|
||||
dmac3_reset(sc->sc_dma);
|
||||
|
||||
DMAC3_SLOWACCESS(sc);
|
||||
spifi_reset(sc);
|
||||
DMAC3_FASTACCESS(sc);
|
||||
|
||||
sc->sc_link.scsipi_scsi.adapter_target = sc->sc_id;
|
||||
sc->sc_link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
|
||||
sc->sc_link.scsipi_scsi.max_target = 7;
|
||||
sc->sc_link.scsipi_scsi.max_lun = 7;
|
||||
sc->sc_link.adapter_softc = sc;
|
||||
sc->sc_link.adapter = &spifi_adapter;
|
||||
sc->sc_link.device = &spifi_dev;
|
||||
sc->sc_link.openings = 2;
|
||||
sc->sc_link.type = BUS_SCSI;
|
||||
|
||||
if (apa->apa_slotno == 0)
|
||||
intr = NEWS5000_INT0_DMAC;
|
||||
else
|
||||
intr = SLOTTOMASK(apa->apa_slotno);
|
||||
apbus_intr_establish(0, intr, 0, spifi_intr, sc, apa->apa_name,
|
||||
apa->apa_ctlnum);
|
||||
|
||||
config_found(&sc->sc_dev, &sc->sc_link, scsiprint);
|
||||
}
|
||||
|
||||
int
|
||||
spifi_scsi_cmd(xs)
|
||||
struct scsipi_xfer *xs;
|
||||
{
|
||||
struct scsipi_link *sc_link = xs->sc_link;
|
||||
struct spifi_softc *sc = sc_link->adapter_softc;
|
||||
struct spifi_scb *scb;
|
||||
u_int flags;
|
||||
int s;
|
||||
|
||||
DPRINTF("spifi_scsi_cmd\n");
|
||||
|
||||
flags = xs->xs_control;
|
||||
|
||||
scb = spifi_get_scb(sc);
|
||||
if (scb == NULL) {
|
||||
DPRINTF("no scb\n");
|
||||
return TRY_AGAIN_LATER;
|
||||
}
|
||||
|
||||
scb->xs = xs;
|
||||
scb->flags = 0;
|
||||
scb->status = 0;
|
||||
scb->daddr = (vaddr_t)xs->data;
|
||||
scb->resid = xs->datalen;
|
||||
bcopy(xs->cmd, &scb->cmd, xs->cmdlen);
|
||||
scb->cmdlen = xs->cmdlen;
|
||||
|
||||
scb->target = sc_link->scsipi_scsi.target;
|
||||
scb->lun = sc_link->scsipi_scsi.lun;
|
||||
scb->lun_targ = scb->target | (scb->lun << 3);
|
||||
|
||||
if (flags & XS_CTL_DATA_IN)
|
||||
scb->flags |= SPIFI_READ;
|
||||
|
||||
s = splbio();
|
||||
|
||||
TAILQ_INSERT_TAIL(&sc->ready_scb, scb, chain);
|
||||
|
||||
if (sc->sc_nexus == NULL) /* IDLE */
|
||||
spifi_sched(sc);
|
||||
|
||||
splx(s);
|
||||
|
||||
if ((flags & XS_CTL_POLL) == 0)
|
||||
return SUCCESSFULLY_QUEUED;
|
||||
|
||||
if (spifi_poll(sc)) {
|
||||
printf("spifi: timeout\n");
|
||||
if (spifi_poll(sc))
|
||||
printf("spifi: timeout again\n");
|
||||
}
|
||||
return COMPLETE;
|
||||
}
|
||||
|
||||
struct spifi_scb *
|
||||
spifi_get_scb(sc)
|
||||
struct spifi_softc *sc;
|
||||
{
|
||||
struct spifi_scb *scb;
|
||||
int s;
|
||||
|
||||
s = splbio();
|
||||
scb = sc->free_scb.tqh_first;
|
||||
if (scb)
|
||||
TAILQ_REMOVE(&sc->free_scb, scb, chain);
|
||||
splx(s);
|
||||
|
||||
return scb;
|
||||
}
|
||||
|
||||
void
|
||||
spifi_free_scb(sc, scb)
|
||||
struct spifi_softc *sc;
|
||||
struct spifi_scb *scb;
|
||||
{
|
||||
int s;
|
||||
|
||||
s = splbio();
|
||||
TAILQ_INSERT_HEAD(&sc->free_scb, scb, chain);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
int
|
||||
spifi_poll(sc)
|
||||
struct spifi_softc *sc;
|
||||
{
|
||||
struct spifi_scb *scb = sc->sc_nexus;
|
||||
struct scsipi_xfer *xs;
|
||||
int count;
|
||||
|
||||
printf("spifi_poll: not implemented yet\n");
|
||||
delay(10000);
|
||||
return 0;
|
||||
|
||||
if (xs == NULL)
|
||||
return 0;
|
||||
|
||||
xs = scb->xs;
|
||||
count = xs->timeout;
|
||||
|
||||
while (count > 0) {
|
||||
if (dmac3_intr(sc->sc_dma) != 0)
|
||||
spifi_intr(sc);
|
||||
|
||||
if (xs->xs_status & XS_STS_DONE)
|
||||
return 0;
|
||||
DELAY(1000);
|
||||
count--;
|
||||
};
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
spifi_minphys(bp)
|
||||
struct buf *bp;
|
||||
{
|
||||
if (bp->b_bcount > 64*1024)
|
||||
bp->b_bcount = 64*1024;
|
||||
|
||||
minphys(bp);
|
||||
}
|
||||
|
||||
void
|
||||
spifi_sched(sc)
|
||||
struct spifi_softc *sc;
|
||||
{
|
||||
struct spifi_scb *scb;
|
||||
|
||||
scb = sc->ready_scb.tqh_first;
|
||||
start:
|
||||
if (scb == NULL || sc->sc_nexus != NULL)
|
||||
return;
|
||||
/*
|
||||
if (sc->sc_targets[scb->target] & (1 << scb->lun))
|
||||
goto next;
|
||||
*/
|
||||
TAILQ_REMOVE(&sc->ready_scb, scb, chain);
|
||||
|
||||
#ifdef SPIFI_DEBUG
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("spifi_sched: ID:LUN = %d:%d, ", scb->target, scb->lun);
|
||||
printf("cmd = 0x%x", scb->cmd.opcode);
|
||||
for (i = 0; i < 5; i++)
|
||||
printf(" 0x%x", scb->cmd.bytes[i]);
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
DMAC3_SLOWACCESS(sc);
|
||||
sc->sc_nexus = scb;
|
||||
spifi_select(sc);
|
||||
DMAC3_FASTACCESS(sc);
|
||||
|
||||
scb = scb->chain.tqe_next;
|
||||
goto start;
|
||||
}
|
||||
|
||||
static inline int
|
||||
spifi_read_count(reg)
|
||||
struct spifi_reg *reg;
|
||||
{
|
||||
int count;
|
||||
|
||||
count = (reg->count_hi & 0xff) |
|
||||
(reg->count_mid & 0xff) |
|
||||
(reg->count_low & 0xff);
|
||||
return count;
|
||||
}
|
||||
|
||||
static inline void
|
||||
spifi_write_count(reg, count)
|
||||
struct spifi_reg *reg;
|
||||
int count;
|
||||
{
|
||||
reg->count_hi = count >> 16;
|
||||
reg->count_mid = count >> 8;
|
||||
reg->count_low = count;
|
||||
}
|
||||
|
||||
|
||||
#ifdef SPIFI_DEBUG
|
||||
static char scsi_phase_name[][8] = {
|
||||
"DATAOUT", "DATAIN", "COMMAND", "STATUS",
|
||||
"", "", "MSGOUT", "MSGIN"
|
||||
};
|
||||
#endif
|
||||
|
||||
int
|
||||
spifi_intr(v)
|
||||
void *v;
|
||||
{
|
||||
struct spifi_softc *sc = v;
|
||||
struct spifi_reg *reg = sc->sc_reg;
|
||||
int intr, state, icond;
|
||||
struct spifi_scb *scb;
|
||||
struct scsipi_xfer *xs;
|
||||
#ifdef SPIFI_DEBUG
|
||||
char bitmask[64];
|
||||
#endif
|
||||
|
||||
switch (dmac3_intr(sc->sc_dma)) {
|
||||
case 0:
|
||||
DPRINTF("sprious dma intr\n");
|
||||
return 0;
|
||||
case -1:
|
||||
printf("DMAC parity error, data PAD\n");
|
||||
|
||||
DMAC3_SLOWACCESS(sc);
|
||||
reg->prcmd = PRC_TRPAD;
|
||||
DMAC3_FASTACCESS(sc);
|
||||
return 1;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
DMAC3_SLOWACCESS(sc);
|
||||
|
||||
intr = reg->intr & 0xff;
|
||||
if (intr == 0) {
|
||||
DMAC3_FASTACCESS(sc);
|
||||
DPRINTF("sprious intr (not me)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
scb = sc->sc_nexus;
|
||||
xs = scb->xs;
|
||||
state = reg->spstat;
|
||||
icond = reg->icond;
|
||||
|
||||
/* clear interrupt */
|
||||
reg->intr = ~intr;
|
||||
|
||||
#ifdef SPIFI_DEBUG
|
||||
bitmask_snprintf(intr, INTR_BITMASK, bitmask, sizeof bitmask);
|
||||
printf("spifi_intr intr = 0x%s (%s), ", bitmask,
|
||||
scsi_phase_name[(reg->prstat >> 3) & 7]);
|
||||
printf("state = 0x%x, icond = 0x%x\n", state, icond);
|
||||
#endif
|
||||
|
||||
if (intr & INTR_FCOMP) {
|
||||
spifi_fifo_drain(sc);
|
||||
scb->status = reg->cmbuf[scb->target].status;
|
||||
scb->resid = spifi_read_count(reg);
|
||||
|
||||
DPRINTF("datalen = %d, resid = %d, status = 0x%x\n",
|
||||
xs->datalen, scb->resid, scb->status);
|
||||
DPRINTF("msg = 0x%x\n", reg->cmbuf[sc->sc_id].cdb[0]);
|
||||
|
||||
DMAC3_FASTACCESS(sc);
|
||||
spifi_done(sc);
|
||||
return 1;
|
||||
}
|
||||
if (intr & INTR_DISCON)
|
||||
panic("disconnect");
|
||||
|
||||
if (intr & INTR_TIMEO) {
|
||||
xs->error = XS_SELTIMEOUT;
|
||||
DMAC3_FASTACCESS(sc);
|
||||
spifi_done(sc);
|
||||
return 1;
|
||||
}
|
||||
if (intr & INTR_BSRQ) {
|
||||
if (scb == NULL)
|
||||
panic("reconnect?");
|
||||
|
||||
if (intr & INTR_PERR) {
|
||||
printf("%s: %d:%d parity error\n", sc->sc_dev.dv_xname,
|
||||
scb->target, scb->lun);
|
||||
|
||||
/* XXX reset */
|
||||
xs->error = XS_DRIVER_STUFFUP;
|
||||
spifi_done(sc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (state >> 4 == SPS_MSGIN && icond == ICOND_NXTREQ)
|
||||
panic("spifi_intr: NXTREQ");
|
||||
if (reg->fifoctrl & FIFOC_RQOVRN)
|
||||
panic("spifi_intr RQOVRN");
|
||||
if (icond == ICOND_UXPHASEZ)
|
||||
panic("ICOND_UXPHASEZ");
|
||||
|
||||
if ((icond & 0x0f) == ICOND_ADATAOFF) {
|
||||
spifi_data_io(sc);
|
||||
goto done;
|
||||
}
|
||||
if ((icond & 0xf0) == ICOND_UBF) {
|
||||
reg->exstat = reg->exstat & ~EXS_UBF;
|
||||
spifi_pmatch(sc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX Work around the SPIFI bug that interrupts during
|
||||
* XXX dataout phase.
|
||||
*/
|
||||
if (state == ((SPS_DATAOUT << 4) | SPS_INTR) &&
|
||||
(reg->prstat & PRS_PHASE) == SPIFI_DATAOUT) {
|
||||
reg->prcmd = PRC_DATAOUT;
|
||||
goto done;
|
||||
}
|
||||
if ((reg->prstat & PRS_Z) == 0) {
|
||||
spifi_pmatch(sc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
panic("spifi_intr: unknown intr state");
|
||||
}
|
||||
|
||||
done:
|
||||
DMAC3_FASTACCESS(sc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
spifi_pmatch(sc)
|
||||
struct spifi_softc *sc;
|
||||
{
|
||||
struct spifi_reg *reg = sc->sc_reg;
|
||||
int phase;
|
||||
|
||||
phase = (reg->prstat & PRS_PHASE);
|
||||
|
||||
#ifdef SPIFI_DEBUG
|
||||
printf("spifi_pmatch (%s)\n", scsi_phase_name[phase >> 3]);
|
||||
#endif
|
||||
|
||||
switch (phase) {
|
||||
|
||||
case SPIFI_COMMAND:
|
||||
spifi_command(sc);
|
||||
break;
|
||||
case SPIFI_DATAIN:
|
||||
case SPIFI_DATAOUT:
|
||||
spifi_data_io(sc);
|
||||
break;
|
||||
case SPIFI_STATUS:
|
||||
spifi_status(sc);
|
||||
break;
|
||||
|
||||
case SPIFI_MSGIN: /* XXX */
|
||||
case SPIFI_MSGOUT: /* XXX */
|
||||
default:
|
||||
printf("spifi: unknown phase %d\n", phase);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
spifi_select(sc)
|
||||
struct spifi_softc *sc;
|
||||
{
|
||||
struct spifi_reg *reg = sc->sc_reg;
|
||||
struct spifi_scb *scb = sc->sc_nexus;
|
||||
int sel;
|
||||
|
||||
#if 0
|
||||
if (reg->loopdata || reg->intr)
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (scb == NULL) {
|
||||
printf("%s: spifi_select: NULL nexus\n", sc->sc_dev.dv_xname);
|
||||
return;
|
||||
}
|
||||
|
||||
reg->exctrl = EXC_IPLOCK;
|
||||
|
||||
dmac3_reset(sc->sc_dma);
|
||||
sel = scb->target << 4 | SEL_ISTART | SEL_IRESELEN | SEL_WATN;
|
||||
spifi_sendmsg(sc, SEND_IDENTIFY);
|
||||
reg->select = sel;
|
||||
}
|
||||
|
||||
void
|
||||
spifi_sendmsg(sc, msg)
|
||||
struct spifi_softc *sc;
|
||||
int msg;
|
||||
{
|
||||
struct spifi_scb *scb = sc->sc_nexus;
|
||||
/* struct mesh_tinfo *ti; */
|
||||
int lun, len, i;
|
||||
|
||||
int id = sc->sc_id;
|
||||
struct spifi_reg *reg = sc->sc_reg;
|
||||
|
||||
DPRINTF("spifi_sendmsg: sending");
|
||||
sc->sc_msgout = msg;
|
||||
len = 0;
|
||||
|
||||
if (msg & SEND_REJECT) {
|
||||
DPRINTF(" REJECT");
|
||||
sc->sc_omsg[len++] = MSG_MESSAGE_REJECT;
|
||||
}
|
||||
if (msg & SEND_IDENTIFY) {
|
||||
DPRINTF(" IDENTIFY");
|
||||
lun = scb->xs->sc_link->scsipi_scsi.lun;
|
||||
sc->sc_omsg[len++] = MSG_IDENTIFY(lun, 0);
|
||||
}
|
||||
if (msg & SEND_SDTR) {
|
||||
DPRINTF(" SDTR");
|
||||
#if 0
|
||||
ti = &sc->sc_tinfo[scb->target];
|
||||
sc->sc_omsg[len++] = MSG_EXTENDED;
|
||||
sc->sc_omsg[len++] = 3;
|
||||
sc->sc_omsg[len++] = MSG_EXT_SDTR;
|
||||
sc->sc_omsg[len++] = ti->period;
|
||||
sc->sc_omsg[len++] = ti->offset;
|
||||
#endif
|
||||
}
|
||||
DPRINTF("\n");
|
||||
|
||||
reg->cmlen = CML_AMSG_EN | len;
|
||||
for (i = 0; i < len; i++)
|
||||
reg->cmbuf[id].cdb[i] = sc->sc_omsg[i];
|
||||
}
|
||||
void
|
||||
spifi_command(struct spifi_softc *sc)
|
||||
{
|
||||
struct spifi_scb *scb = sc->sc_nexus;
|
||||
struct spifi_reg *reg = sc->sc_reg;
|
||||
int len = scb->cmdlen;
|
||||
u_char *cmdp = (char *)&scb->cmd;
|
||||
int i;
|
||||
|
||||
DPRINTF("spifi_command\n");
|
||||
|
||||
reg->cmdpage = scb->lun_targ;
|
||||
|
||||
if (reg->init_status & IST_ACK) {
|
||||
/* Negate ACK. */
|
||||
reg->prcmd = PRC_NJMP | PRC_CLRACK | PRC_COMMAND;
|
||||
reg->prcmd = PRC_NJMP | PRC_COMMAND;
|
||||
}
|
||||
|
||||
reg->cmlen = CML_AMSG_EN | len;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
reg->cmbuf[sc->sc_id].cdb[i] = *cmdp++;
|
||||
|
||||
reg->prcmd = PRC_COMMAND;
|
||||
}
|
||||
|
||||
void
|
||||
spifi_data_io(struct spifi_softc *sc)
|
||||
{
|
||||
struct spifi_scb *scb = sc->sc_nexus;
|
||||
struct spifi_reg *reg = sc->sc_reg;
|
||||
int phase;
|
||||
|
||||
DPRINTF("spifi_data_io\n");
|
||||
|
||||
phase = reg->prstat & PRS_PHASE;
|
||||
dmac3_reset(sc->sc_dma);
|
||||
|
||||
spifi_write_count(reg, scb->resid);
|
||||
reg->cmlen = CML_AMSG_EN | 1;
|
||||
reg->data_xfer = 0;
|
||||
|
||||
scb->flags |= SPIFI_DMA;
|
||||
if (phase == SPIFI_DATAIN) {
|
||||
if (reg->fifoctrl & FIFOC_SSTKACT) {
|
||||
/*
|
||||
* Clear FIFO and load the contents of synchronous
|
||||
* stack into the FIFO.
|
||||
*/
|
||||
reg->fifoctrl = FIFOC_CLREVEN;
|
||||
reg->fifoctrl = FIFOC_LOAD;
|
||||
}
|
||||
reg->autodata = ADATA_IN | scb->lun_targ;
|
||||
dmac3_start(sc->sc_dma, scb->daddr, scb->resid, DMAC3_CSR_RECV);
|
||||
reg->prcmd = PRC_DATAIN;
|
||||
} else {
|
||||
reg->fifoctrl = FIFOC_CLREVEN;
|
||||
reg->autodata = scb->lun_targ;
|
||||
dmac3_start(sc->sc_dma, scb->daddr, scb->resid, DMAC3_CSR_SEND);
|
||||
reg->prcmd = PRC_DATAOUT;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
spifi_status(struct spifi_softc *sc)
|
||||
{
|
||||
struct spifi_reg *reg = sc->sc_reg;
|
||||
|
||||
DPRINTF("spifi_status\n");
|
||||
spifi_fifo_drain(sc);
|
||||
reg->cmlen = CML_AMSG_EN | 1;
|
||||
reg->prcmd = PRC_STATUS;
|
||||
}
|
||||
|
||||
int
|
||||
spifi_done(sc)
|
||||
struct spifi_softc *sc;
|
||||
{
|
||||
struct spifi_scb *scb = sc->sc_nexus;
|
||||
struct scsipi_xfer *xs = scb->xs;
|
||||
|
||||
DPRINTF("spifi_done\n");
|
||||
|
||||
/* XXX sense */
|
||||
|
||||
if (scb->status == SCSI_CHECK)
|
||||
DPRINTF("spifi_done: CHECK CONDITION\n");
|
||||
|
||||
xs->xs_status |= XS_STS_DONE;
|
||||
xs->resid = scb->resid;
|
||||
|
||||
scsipi_done(xs);
|
||||
spifi_free_scb(sc, scb);
|
||||
|
||||
sc->sc_nexus = NULL;
|
||||
spifi_sched(sc);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
spifi_fifo_drain(sc)
|
||||
struct spifi_softc *sc;
|
||||
{
|
||||
struct spifi_scb *scb = sc->sc_nexus;
|
||||
struct spifi_reg *reg = sc->sc_reg;
|
||||
int fifoctrl, fifo_count;
|
||||
|
||||
DPRINTF("spifi_fifo_drain\n");
|
||||
|
||||
if ((scb->flags & SPIFI_READ) == 0)
|
||||
return;
|
||||
|
||||
fifoctrl = reg->fifoctrl;
|
||||
if (fifoctrl & FIFOC_SSTKACT)
|
||||
return;
|
||||
|
||||
fifo_count = 8 - (fifoctrl & FIFOC_FSLOT);
|
||||
if (fifo_count > 0 && (scb->flags & SPIFI_DMA)) {
|
||||
/* Flush data still in FIFO. */
|
||||
reg->fifoctrl = FIFOC_FLUSH;
|
||||
return;
|
||||
}
|
||||
|
||||
reg->fifoctrl = FIFOC_CLREVEN;
|
||||
}
|
||||
|
||||
void
|
||||
spifi_reset(sc)
|
||||
struct spifi_softc *sc;
|
||||
{
|
||||
struct spifi_reg *reg = sc->sc_reg;
|
||||
int id = sc->sc_id;
|
||||
|
||||
DPRINTF("spifi_reset\n");
|
||||
|
||||
reg->auxctrl = AUXCTRL_SRST;
|
||||
reg->auxctrl = AUXCTRL_CRST;
|
||||
|
||||
dmac3_reset(sc->sc_dma);
|
||||
|
||||
reg->auxctrl = AUXCTRL_SRST;
|
||||
reg->auxctrl = AUXCTRL_CRST;
|
||||
reg->auxctrl = AUXCTRL_DMAEDGE;
|
||||
|
||||
/* Mask (only) target mode interrupts. */
|
||||
reg->imask = INTR_TGSEL | INTR_COMRECV;
|
||||
|
||||
reg->config = CONFIG_DMABURST | CONFIG_PCHKEN | CONFIG_PGENEN | id;
|
||||
reg->fastwide = FAST_FASTEN;
|
||||
reg->prctrl = 0;
|
||||
reg->loopctrl = 0;
|
||||
|
||||
/* Enable automatic status input except the initiator. */
|
||||
reg->autostat = ~(1 << id);
|
||||
|
||||
reg->fifoctrl = FIFOC_CLREVEN;
|
||||
spifi_write_count(reg, 0);
|
||||
|
||||
/* Flush write buffer. */
|
||||
(void)reg->spstat;
|
||||
}
|
||||
|
||||
void
|
||||
spifi_bus_reset(sc)
|
||||
struct spifi_softc *sc;
|
||||
{
|
||||
struct spifi_reg *reg = sc->sc_reg;
|
||||
|
||||
printf("%s: bus reset\n", sc->sc_dev.dv_xname);
|
||||
|
||||
sc->sc_nexus = NULL;
|
||||
|
||||
reg->auxctrl = AUXCTRL_SETRST;
|
||||
delay(100);
|
||||
reg->auxctrl = 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static u_char spifi_sync_period[] = {
|
||||
/* 0 1 2 3 4 5 6 7 8 9 10 11 */
|
||||
137, 125, 112, 100, 87, 75, 62, 50, 43, 37, 31, 25
|
||||
};
|
||||
|
||||
void
|
||||
spifi_setsync(sc, ti)
|
||||
struct spifi_softc *sc;
|
||||
struct spifi_tinfo *ti;
|
||||
{
|
||||
if ((ti->flags & T_SYNCMODE) == 0)
|
||||
reg->data_xfer = 0;
|
||||
else {
|
||||
int period = ti->period;
|
||||
int offset = ti->offset;
|
||||
int v;
|
||||
|
||||
for (v = sizeof(spifi_sync_period) - 1; v >= 0; v--)
|
||||
if (spifi_sync_period[v] >= period)
|
||||
break;
|
||||
if (v == -1)
|
||||
reg->data_xfer = 0; /* XXX */
|
||||
else
|
||||
reg->data_xfer = v << 4 | offset;
|
||||
}
|
||||
}
|
||||
#endif
|
195
sys/arch/newsmips/apbus/spifireg.h
Normal file
195
sys/arch/newsmips/apbus/spifireg.h
Normal file
@ -0,0 +1,195 @@
|
||||
/* $NetBSD: spifireg.h,v 1.1 2000/10/30 10:07:35 tsubai Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2000 Tsubai Masanari. 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, 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 ``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 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.
|
||||
*/
|
||||
|
||||
struct spifi_reg {
|
||||
volatile int spstat; /* RO: SPIFI state */
|
||||
volatile int cmlen; /* RW: Command/message length */
|
||||
volatile int cmdpage; /* RW: Command page */
|
||||
volatile int count_hi; /* RW: Data count (high) */
|
||||
volatile int count_mid; /* RW: (mid) */
|
||||
volatile int count_low; /* RW: (low) */
|
||||
volatile int svptr_hi; /* RO: Saved data pointer (high)*/
|
||||
volatile int svptr_mid; /* RO: (mid) */
|
||||
volatile int svptr_low; /* RO: (low) */
|
||||
volatile int intr; /* RW: Processor interrupt */
|
||||
volatile int imask; /* RW: Processor interrupt mask */
|
||||
volatile int prctrl; /* RW: Processor control */
|
||||
volatile int prstat; /* RO: Processor status */
|
||||
volatile int init_status; /* RO: Initiator status */
|
||||
volatile int fifoctrl; /* RW: FIFO control */
|
||||
volatile int fifodata; /* RW: FIFO data */
|
||||
volatile int config; /* RW: Configuration */
|
||||
volatile int data_xfer; /* RW: Data transfer */
|
||||
volatile int autocmd; /* RW: Auto command control */
|
||||
volatile int autostat; /* RW: Auto status control */
|
||||
volatile int resel; /* RW: Reselection */
|
||||
volatile int select; /* RW: Selection */
|
||||
volatile int prcmd; /* WO: Processor command */
|
||||
volatile int auxctrl; /* RW: Aux control */
|
||||
volatile int autodata; /* RW: Auto data control */
|
||||
volatile int loopctrl; /* RW: Loopback control */
|
||||
volatile int loopdata; /* RW: Loopback data */
|
||||
volatile int identify; /* WO: Identify (?) */
|
||||
volatile int complete; /* WO: Command complete (?) */
|
||||
volatile int scsi_status; /* WO: SCSI status (?) */
|
||||
volatile int data; /* RW: Data register (?) */
|
||||
volatile int icond; /* RO: Interrupt condition */
|
||||
volatile int fastwide; /* RW: Fast/wide enable */
|
||||
volatile int exctrl; /* RW: Extended control */
|
||||
volatile int exstat; /* RW: Extended status */
|
||||
volatile int test; /* RW: SPIFI test register */
|
||||
volatile int quematch; /* RW: Queue match */
|
||||
volatile int quecode; /* RW: Queue code */
|
||||
volatile int quetag; /* RW: Queue tag */
|
||||
volatile int quepage; /* RW: Queue page */
|
||||
int image[88]; /* (image of the above) */
|
||||
struct {
|
||||
volatile int cdb[12]; /* RW: Command descriptor block */
|
||||
volatile int quecode; /* RW: Queue code */
|
||||
volatile int quetag; /* RW: Queue tag */
|
||||
volatile int idmsg; /* RW: Identify message */
|
||||
volatile int status; /* RW: SCSI status */
|
||||
} cmbuf[8];
|
||||
};
|
||||
|
||||
/* spstat */
|
||||
#define SPS_IDLE 0x00
|
||||
#define SPS_SEL 0x01
|
||||
#define SPS_ARB 0x02
|
||||
#define SPS_RESEL 0x03
|
||||
#define SPS_MSGOUT 0x04
|
||||
#define SPS_COMMAND 0x05
|
||||
#define SPS_DISCON 0x06
|
||||
#define SPS_NXIN 0x07
|
||||
#define SPS_INTR 0x08
|
||||
#define SPS_NXOUT 0x09
|
||||
#define SPS_CCOMP 0x0a
|
||||
#define SPS_SVPTR 0x0b
|
||||
#define SPS_STATUS 0x0c
|
||||
#define SPS_MSGIN 0x0d
|
||||
#define SPS_DATAOUT 0x0e
|
||||
#define SPS_DATAIN 0x0f
|
||||
|
||||
/* cmlen */
|
||||
#define CML_LENMASK 0x0f
|
||||
#define CML_AMSG_EN 0x40
|
||||
#define CML_ACOM_EN 0x80
|
||||
|
||||
/* intr and imask */
|
||||
#define INTR_BSRQ 0x01
|
||||
#define INTR_COMRECV 0x02
|
||||
#define INTR_PERR 0x04
|
||||
#define INTR_TIMEO 0x08
|
||||
#define INTR_DERR 0x10
|
||||
#define INTR_TGSEL 0x20
|
||||
#define INTR_DISCON 0x40
|
||||
#define INTR_FCOMP 0x80
|
||||
|
||||
#define INTR_BITMASK \
|
||||
"\20\10FCOMP\07DISCON\06TGSEL\05DERR\04TIMEO\03PERR\02COMRECV\01BSRQ"
|
||||
|
||||
/* prstat */
|
||||
#define PRS_IO 0x08
|
||||
#define PRS_CD 0x10
|
||||
#define PRS_MSG 0x20
|
||||
#define PRS_ATN 0x40
|
||||
#define PRS_Z 0x80
|
||||
#define PRS_PHASE (PRS_MSG | PRS_CD | PRS_IO)
|
||||
|
||||
#define PRS_BITMASK "\20\10Z\07ATN\06MSG\05CD\04IO"
|
||||
|
||||
/* init_status */
|
||||
#define IST_ACK 0x40
|
||||
|
||||
/* fifoctrl */
|
||||
#define FIFOC_FSLOT 0x0f /* Free slots in FIFO */
|
||||
#define FIFOC_SSTKACT 0x10 /* Synchronous stack active (?) */
|
||||
#define FIFOC_RQOVRN 0x20
|
||||
#define FIFOC_CLREVEN 0x00
|
||||
#define FIFOC_CLRODD 0x40
|
||||
#define FIFOC_FLUSH 0x80
|
||||
#define FIFOC_LOAD 0xc0
|
||||
|
||||
/* config */
|
||||
#define CONFIG_PGENEN 0x08 /* Parity generation enable */
|
||||
#define CONFIG_PCHKEN 0x10 /* Parity checking enable */
|
||||
#define CONFIG_WORDEN 0x20
|
||||
#define CONFIG_AUTOID 0x40
|
||||
#define CONFIG_DMABURST 0x80
|
||||
|
||||
/* select */
|
||||
#define SEL_SETATN 0x02
|
||||
#define SEL_IRESELEN 0x04
|
||||
#define SEL_ISTART 0x08
|
||||
#define SEL_WATN 0x80
|
||||
|
||||
/* prcmd */
|
||||
#define PRC_DATAOUT 0
|
||||
#define PRC_DATAIN 1
|
||||
#define PRC_COMMAND 2
|
||||
#define PRC_STATUS 3
|
||||
#define PRC_TRPAD 4
|
||||
#define PRC_MSGOUT 6
|
||||
#define PRC_MSGIN 7
|
||||
#define PRC_KILLREQ 0x08
|
||||
#define PRC_CLRACK 0x10
|
||||
#define PRC_NJMP 0x80
|
||||
|
||||
/* auxctrl */
|
||||
#define AUXCTRL_DMAEDGE 0x04
|
||||
#define AUXCTRL_SETRST 0x20 /* Bus reset (?) */
|
||||
#define AUXCTRL_CRST 0x40
|
||||
#define AUXCTRL_SRST 0x80
|
||||
|
||||
/* autodata */
|
||||
#define ADATA_IN 0x40
|
||||
#define ADATA_EN 0x80
|
||||
|
||||
/* icond */
|
||||
#define ICOND_ADATAOFF 0x02
|
||||
#define ICOND_AMSGOFF 0x06
|
||||
#define ICOND_ACMDOFF 0x0a
|
||||
#define ICOND_ASTATOFF 0x0e
|
||||
#define ICOND_SVPTEXP 0x10
|
||||
#define ICOND_ADATAMIS 0x20
|
||||
#define ICOND_CNTZERO 0x40
|
||||
#define ICOND_UXPHASEZ 0x80
|
||||
#define ICOND_UXPHASENZ 0x81
|
||||
#define ICOND_NXTREQ 0xa0
|
||||
#define ICOND_UKMSGZ 0xc0
|
||||
#define ICOND_UKMSGNZ 0xc1
|
||||
#define ICOND_UBF 0xe0 /* Unexpected bus free */
|
||||
|
||||
/* fastwide */
|
||||
#define FAST_FASTEN 0x01
|
||||
|
||||
/* exctrl */
|
||||
#define EXC_IPLOCK 0x04 /* Initiator page lock */
|
||||
|
||||
/* exstat */
|
||||
#define EXS_UBF 0x08 /* Unexpected bus free */
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: files.newsmips,v 1.10 2000/10/29 12:36:35 tsutsui Exp $
|
||||
# $NetBSD: files.newsmips,v 1.11 2000/10/30 10:07:35 tsubai Exp $
|
||||
|
||||
# NEWSMIPS-specific configuration info
|
||||
|
||||
@ -120,6 +120,14 @@ attach sc at hb
|
||||
file arch/newsmips/dev/scsi_1185.c sc needs-count
|
||||
file arch/newsmips/dev/sc_wrap.c sc
|
||||
|
||||
device spifi: scsi
|
||||
attach spifi at ap
|
||||
file arch/newsmips/apbus/spifi.c spifi
|
||||
|
||||
device dmac
|
||||
attach dmac at ap
|
||||
file arch/newsmips/apbus/dmac3.c dmac
|
||||
|
||||
# network devices MII bus
|
||||
include "dev/mii/files.mii"
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user