diff options
| author | bouyer <bouyer@NetBSD.org> | 2000-04-21 17:56:58 +0000 |
|---|---|---|
| committer | bouyer <bouyer@NetBSD.org> | 2000-04-21 17:56:58 +0000 |
| commit | 19ada4a82a95cbbbfff681f4e1ead9fbd9de4365 (patch) | |
| tree | 29c1eed79a6f64471f2a3dc278ad1bba8958066f /sys/dev | |
| parent | 79f12736c0a9abec812ed1cccba1be4d3f614fab (diff) | |
Snapshot of work in progress: new driver for the NCR 53c8xx SCSI controller
(the name 'siop' is still being discussed, may change).
Only basic disconnect/reselect for now, no sync/wide negotiation.
Tested with 810A, 875 and 895 on i386 only.
The bus-independant part should also be able to handle the 53c720 and 53c770.
A new driver with enhanced script should appear for the 825/875/895 'soon'.
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/ic/siop.c | 922 | ||||
| -rw-r--r-- | sys/dev/ic/siopreg.h | 343 | ||||
| -rw-r--r-- | sys/dev/ic/siopvar.h | 83 | ||||
| -rw-r--r-- | sys/dev/microcode/siop/Makefile | 15 | ||||
| -rw-r--r-- | sys/dev/microcode/siop/siop.out | 121 | ||||
| -rw-r--r-- | sys/dev/microcode/siop/siop.ss | 153 | ||||
| -rw-r--r-- | sys/dev/pci/files.pci | 7 | ||||
| -rw-r--r-- | sys/dev/pci/siop_pci.c | 280 |
8 files changed, 1923 insertions, 1 deletions
diff --git a/sys/dev/ic/siop.c b/sys/dev/ic/siop.c new file mode 100644 index 00000000000..0060a8565b9 --- /dev/null +++ b/sys/dev/ic/siop.c @@ -0,0 +1,922 @@ +/* $NetBSD: siop.c,v 1.1 2000/04/21 17:56:58 bouyer Exp $ */ + +/* + * Copyright (c) 2000 Manuel Bouyer. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + */ + +/* SYM53c7/8xx PCI-SCSI I/O Processors driver */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/buf.h> +#include <sys/kernel.h> + +#include <machine/endian.h> +#include <machine/bus.h> + +#include <vm/vm.h> +#include <vm/vm_param.h> +#include <vm/vm_kern.h> + +#include <dev/microcode/siop/siop.out> + +#include <dev/scsipi/scsi_all.h> +#include <dev/scsipi/scsi_message.h> +#include <dev/scsipi/scsipi_all.h> + +#include <dev/scsipi/scsiconf.h> + +#include <dev/ic/siopreg.h> +#include <dev/ic/siopvar.h> + +#ifndef SIOP_DEFAULT_TARGET +#define SIOP_DEFAULT_TARGET 7 +#endif + +#define MEM_SIZE 8192 +#define SCRIPT_OFF 4096 + +/* tables used by SCRIPT */ +typedef struct scr_table { + u_int32_t count; + u_int32_t addr; +} scr_table_t ; + +/* Number of scatter/gather entries */ +#define SIOP_NSG (MAXPHYS/NBPG + 1) + +/* + * This structure interfaces the SCRIPT with the driver; it describes a full + * transfert. It lives in the same chunk of DMA-safe memory as the script. + */ +struct siop_xfer { + u_int8_t msg_out; /* 0 */ + u_int8_t msg_in; /* 1 */ + u_int8_t status; /* 2 */ + u_int8_t pad2; /* 3 */ + u_int32_t id; /* 4 */ + u_int32_t pad1; /* 8 */ + scr_table_t t_msgin; /* 12 */ + scr_table_t t_msgout; /* 20 */ + scr_table_t cmd; /* 28 */ + scr_table_t t_status; /* 36 */ + scr_table_t data[SIOP_NSG]; /* 44 */ +}; + +/* + * This decribes a command handled by the SCSI controller + * These are chained in either a free list or a active list + * We have one queue per target + (one at the adapter's target for probe) + */ +struct siop_cmd { + TAILQ_ENTRY (siop_cmd) next; + struct siop_softc *siop_sc; /* pointer to adapter */ + struct scsipi_xfer *xs; /* xfer from the upper level */ + struct siop_xfer *siop_table; /* tables dealing with this xfer */ + bus_dmamap_t dmamap_cmd; + bus_dmamap_t dmamap_data; + struct scsipi_sense rs_cmd; /* request sense command buffer */ + u_int16_t status; + u_int16_t flags; +}; + +/* status defs */ +#define CMDST_FREE 0 /* cmd slot is free */ +#define CMDST_READY 1 /* cmd slot is waiting for processing */ +#define CMDST_ACTIVE 2 /* cmd slot is being processed */ +#define CMDST_SENSE 3 /* cmd slot is being requesting sense */ +#define CMDST_SENSE_DONE 4 /* request sense done */ +#define CMDST_DONE 5 /* cmd slot has been processed */ +/* flags defs */ +#define CMDFL_TIMEOUT 0x0001 /* cmd timed out */ + +/* initial number of cmd descriptors */ +#define SIOP_NCMD 10 + +void siop_reset __P((struct siop_softc *)); +void siop_start __P((struct siop_softc *)); +void siop_timeout __P((void *)); +void siop_minphys __P((struct buf *)); +int siop_scsicmd __P((struct scsipi_xfer *)); +void siop_sdp __P((struct siop_cmd *)); +void siop_ssg __P((struct siop_cmd *)); + +struct scsipi_adapter siop_adapter = { + 0, + siop_scsicmd, + siop_minphys, + NULL, +}; + +struct scsipi_device siop_dev = { + NULL, + NULL, + NULL, + NULL, +}; + +void +siop_attach(sc) + struct siop_softc *sc; +{ + int error, i; + bus_dma_segment_t seg; + int rseg; + struct siop_cmd *cmds; + + /* + * Allocate DMA-safe memory for the script itself and internal + * variables and map it. + */ + error = bus_dmamem_alloc(sc->sc_dmat, MEM_SIZE, + NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT); + if (error) { + printf("%s: unable to allocate script DMA memory, error = %d\n", + sc->sc_dev.dv_xname, error); + return; + } + error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, MEM_SIZE, + (caddr_t *)&sc->sc_script, BUS_DMA_NOWAIT|BUS_DMA_COHERENT); + if (error) { + printf("%s: unable to map script DMA memory, error = %d\n", + sc->sc_dev.dv_xname, error); + return; + } + error = bus_dmamap_create(sc->sc_dmat, MEM_SIZE, 1, + MEM_SIZE, 0, BUS_DMA_NOWAIT, &sc->sc_scriptdma); + if (error) { + printf("%s: unable to create script DMA map, error = %d\n", + sc->sc_dev.dv_xname, error); + return; + } + error = bus_dmamap_load(sc->sc_dmat, sc->sc_scriptdma, sc->sc_script, + MEM_SIZE, NULL, BUS_DMA_NOWAIT); + if (error) { + printf("%s: unable to load script DMA map, error = %d\n", + sc->sc_dev.dv_xname, error); + return; + } + TAILQ_INIT(&sc->free_list); + for (i = 0; i < 16; i++) + TAILQ_INIT(&sc->active_list[i]); + /* allocate cmd list */ + cmds = malloc(sizeof(struct siop_cmd) * SIOP_NCMD, M_DEVBUF, M_NOWAIT); + if (cmds == NULL) { + printf("%s: can't allocate memory for command descriptors\n", + sc->sc_dev.dv_xname); + return; + } + for (i = 0; i < SIOP_NCMD; i++) { + error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, SIOP_NSG, + MAXPHYS, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, + &cmds[i].dmamap_data); + if (error) { + printf("%s: unable to create data DMA map for cbd %d\n", + sc->sc_dev.dv_xname, error); + return; + } + error = bus_dmamap_create(sc->sc_dmat, + sizeof(struct scsipi_generic), 1, + sizeof(struct scsipi_generic), 0, + BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, + &cmds[i].dmamap_cmd); + if (error) { + printf("%s: unable to create cmd DMA map for cbd %d\n", + sc->sc_dev.dv_xname, error); + return; + } + cmds[i].siop_sc = sc; + cmds[i].siop_table = &((struct siop_xfer *)sc->sc_script)[i]; + cmds[i].status = CMDST_FREE; + cmds[i].siop_table->t_msgout.count= htole32(1); + cmds[i].siop_table->t_msgout.addr = + htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + + i * sizeof(struct siop_xfer)); + cmds[i].siop_table->t_msgin.count= htole32(1); + cmds[i].siop_table->t_msgin.addr = + htole32(htole32(cmds[i].siop_table->t_msgout.addr) + 1); + cmds[i].siop_table->t_status.count= htole32(1); + cmds[i].siop_table->t_status.addr = + htole32(htole32(cmds[i].siop_table->t_msgin.addr) + 1); + TAILQ_INSERT_TAIL(&sc->free_list, &cmds[i], next); + printf("tables[%d]: out=0x%x in=0x%x status=0x%x\n", i, + cmds[i].siop_table->t_msgin.addr, + cmds[i].siop_table->t_msgout.addr, + cmds[i].siop_table->t_status.addr); + } +#ifdef DEBUG + printf("%s: script size = %d, PHY addr=0x%x, VIRT=%p\n", + sc->sc_dev.dv_xname, sizeof(siop_script), + (u_int)sc->sc_scriptdma->dm_segs[0].ds_addr, sc->sc_script); +#endif + + sc->sc_link.adapter_softc = sc; + sc->sc_link.openings = 1; + sc->sc_link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE; + sc->sc_link.scsipi_scsi.max_target = + (sc->features & SF_BUS_WIDE) ? 15 : 7; + sc->sc_link.scsipi_scsi.max_lun = 7; + sc->sc_link.scsipi_scsi.adapter_target = bus_space_read_1(sc->sc_rt, + sc->sc_rh, SIOP_SCID); + if (sc->sc_link.scsipi_scsi.adapter_target > + sc->sc_link.scsipi_scsi.max_target) + sc->sc_link.scsipi_scsi.adapter_target = SIOP_DEFAULT_TARGET; + sc->sc_link.type = BUS_SCSI; + sc->sc_link.adapter = &siop_adapter; + sc->sc_link.device = &siop_dev; + sc->sc_link.flags = 0; + + siop_reset(sc); + + config_found((struct device*)sc, &sc->sc_link, scsiprint); +} + +void +siop_reset(sc) + struct siop_softc *sc; +{ + /* reset the chip */ + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SRST); + delay(1000); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, 0); + + /* copy and patch the script */ + memcpy(&sc->sc_script[SCRIPT_OFF/4], siop_script, sizeof(siop_script)); + + /* init registers */ + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL0, + SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 0); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 0x3); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DIEN, 0xff); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN0, + 0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL)); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN1, + 0xff & ~(SIEN1_HTH | SIEN1_GEN)); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, STEST2_EXT); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, STEST3_TE); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STIME0, + (0xb << STIME0_SEL_SHIFT)); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCID, + sc->sc_link.scsipi_scsi.adapter_target | SCID_RRE); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_RESPID0, + 1 << sc->sc_link.scsipi_scsi.adapter_target); +} + +#if 0 +#define CALL_SCRIPT(ent) do {\ + printf ("start script DSA 0x%lx DSP 0x%lx\n", \ + htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + \ + (((caddr_t)siop_cmd->siop_table) - ((caddr_t)sc->sc_script))),\ + htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + SCRIPT_OFF + ent)); \ + bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSA, \ + htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + \ + (((caddr_t)siop_cmd->siop_table) - ((caddr_t)sc->sc_script)))); \ +bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + SCRIPT_OFF + ent)); \ +} while (0) +#else +#define CALL_SCRIPT(ent) do {\ + bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSA, \ + htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + \ + (((caddr_t)siop_cmd->siop_table) - ((caddr_t)sc->sc_script)))); \ +bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + SCRIPT_OFF + ent)); \ +} while (0) +#endif + +int +siop_intr(v) + void *v; +{ + struct siop_softc *sc = v; + struct siop_cmd *siop_cmd; + struct scsipi_xfer *xs; + u_int8_t istat, sist0, sist1, sstat1, dstat, scntl1; + u_int32_t irqcode; + int need_reset = 0; + int offset; + + istat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT); + if (istat & ISTAT_INTF) { + printf("INTRF\n"); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_INTF); + } + if (istat & ISTAT_DIP) { + u_int32_t *p; + dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DSTAT); + if (dstat & ~(DSTAT_SIR | DSTAT_DFE)) { + printf("DMA IRQ:"); + if (dstat & DSTAT_IID) + printf(" Illegal instruction"); + if (dstat & DSTAT_SSI) + printf(" single step"); + if (dstat & DSTAT_ABRT) + printf(" abort"); + if (dstat & DSTAT_BF) + printf(" bus fault"); + if (dstat & DSTAT_MDPE) + printf(" parity"); + if (dstat & DSTAT_DFE) + printf(" dma fifo empty"); + printf(", DSP=0x%x DSA=0x%x: ", + bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP), + bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA)); + p = &sc->sc_script[SCRIPT_OFF/4] + + (bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) - + (sc->sc_scriptdma->dm_segs[0].ds_addr + SCRIPT_OFF)-8) / 4; + printf("0x%x 0x%x 0x%x 0x%x\n", p[0], p[1], p[2], p[3]); + if ((siop_cmd = sc->active_list[sc->current_target].tqh_first)) + printf("last msg_in=0x%x status=0x%x\n", + siop_cmd->siop_table->msg_in, + siop_cmd->siop_table->status); + need_reset = 1; + } + } + if (istat & ISTAT_SIP) { + if (istat & ISTAT_DIP) + delay(1); + sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0); + delay(1); + sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1); + sstat1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1); +#if 0 + printf("scsi interrupt, sist0=0x%x sist1=0x%x sstat1=0x%x " + "DSA=0x%x DSP=0x%x\n", sist0, sist1, + bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1), + bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA), + bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP)); +#endif + siop_cmd = sc->active_list[sc->current_target].tqh_first; + if (siop_cmd) + xs = siop_cmd->xs; + if (sist0 & SIST0_RST) { + /* scsi bus reset. reset the chip and restart + * the queue. + */ + printf("%s: scsi bus reset\n", sc->sc_dev.dv_xname); + /* if we had a command running handle it */ + if (siop_cmd) { + xs = siop_cmd->xs; + if (siop_cmd->status == CMDST_ACTIVE || + siop_cmd->status == CMDST_SENSE) + xs->error = + (siop_cmd->flags & CMDFL_TIMEOUT) ? + XS_TIMEOUT : XS_RESET; + } + siop_reset(sc); + if (siop_cmd) + goto end; + siop_start(sc); + return 1; + } + if (sist0 & SIST0_SGE) { + if (siop_cmd) + scsi_print_addr(xs->sc_link); + else + printf("%s:", sc->sc_dev.dv_xname); + printf("scsi gross error\n"); + goto reset; + } + if ((sist0 & SIST0_MA) && need_reset == 0) { + if (siop_cmd) { + switch (sstat1 & SSTAT1_PHASE_MASK) { + case SSTAT1_PHASE_STATUS: + /* + * previous phase may be aborted for any reason + * ( for example, the target has less data to + * transfer than requested). Just go to status + * and the command should terminate. + */ + CALL_SCRIPT(Ent_status); + return 1; + case SSTAT1_PHASE_MSGIN: + /* + * target may be ready to disconnect + * Save data pointers just in case. + */ + siop_sdp(siop_cmd); + CALL_SCRIPT(Ent_msgin); + return 1; + } + printf("%s: unexpected phase mismatch %d\n", + sc->sc_dev.dv_xname, + sstat1 & SSTAT1_PHASE_MASK); + } else { + printf("%s: phase mismatch without command\n", + sc->sc_dev.dv_xname); + } + need_reset = 1; + } + if (sist0 & SIST0_PAR) { + /* parity error, reset */ + if (siop_cmd) + scsi_print_addr(xs->sc_link); + else + printf("%s:", sc->sc_dev.dv_xname); + printf("parity error\n"); + need_reset = 1; + } + if ((sist1 & SIST1_STO) && need_reset == 0) { + /* selection time out, assume there's no device here */ + if (siop_cmd) { + siop_cmd->status = CMDST_DONE; + xs->error = XS_SELTIMEOUT; + goto end; + } else { + printf("%s: selection timeout without " + "command\n", sc->sc_dev.dv_xname); + need_reset = 1; + } + } + if (sist0 & SIST0_UDC) { + /* + * unexpected disconnect. Usually the target signals + * a fatal condition this way. Attempt to get sense. + */ + if (siop_cmd) + goto check_sense; + printf("%s: unexpected disconnect without " + "command\n", sc->sc_dev.dv_xname); + need_reset = 1; + } + /* Else it's an unhandled exeption (for now). */ + printf("%s: unhandled scsi interrupt, sist0=0x%x sist1=0x%x " + "sstat1=0x%x DSA=0x%x DSP=0x%x\n", sc->sc_dev.dv_xname, + sist0, sist1, + bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1), + bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA), + bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP)); + if (siop_cmd) { + siop_cmd->status = CMDST_DONE; + xs->error = XS_SELTIMEOUT; + goto end; + } + need_reset = 1; + } + if (need_reset) { +reset: + /* fatal error, reset the bus */ + scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, + scntl1 | SCNTL1_RST); + /* minimum 25 us, more time won't hurt */ + delay(100); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1); + return 1; + } + + + siop_cmd = sc->active_list[sc->current_target].tqh_first; + if (siop_cmd == NULL) { + printf("Aie, no command !\n"); + return(1); + } + xs = siop_cmd->xs; + if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */ + irqcode = bus_space_read_4(sc->sc_rt, sc->sc_rh, + SIOP_DSPS); + switch(irqcode) { + case A_int_err: + printf("error\n"); + xs->error = XS_SELTIMEOUT; + goto end; + case A_int_msgin: + scsi_print_addr(xs->sc_link); + printf("unhandled message %d\n", + siop_cmd->siop_table->msg_in); + xs->error = XS_DRIVER_STUFFUP; + goto end; + case A_int_resel: /* reselected */ + if ((siop_cmd->siop_table->msg_in & 0x80) == 0) { + printf("%s: reselect without identify (%d)\n", + sc->sc_dev.dv_xname, + siop_cmd->siop_table->msg_in); + goto reset; + } + sc->current_target = bus_space_read_1(sc->sc_rt, + sc->sc_rh, SIOP_SCRATCHA); + if ((sc->current_target & 0x80) == 0) { + printf("reselect without id (%d)\n", + sc->current_target); + goto reset; + } + sc->current_target &= 0x0f; +#ifdef DEBUG_DR + printf("reselected by target %d lun %d\n", + sc->current_target, + siop_cmd->siop_table->msg_in & 0x07); +#endif + siop_cmd = + sc->active_list[sc->current_target].tqh_first; + if (siop_cmd == NULL) { + printf("%s: reselected without cmd\n", + sc->sc_dev.dv_xname); + goto reset; + } + bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSA, + htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + + (((caddr_t)siop_cmd->siop_table) - + ((caddr_t)sc->sc_script)))); + CALL_SCRIPT(Ent_reselected); + return 1; + case A_int_disc: + offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, + SIOP_SCRATCHA + 1); +#ifdef DEBUG_DR + printf("disconnect offset %d\n", offset); +#endif + if (offset > SIOP_NSG) { + printf("%s: bad offset for disconnect (%d)\n", + sc->sc_dev.dv_xname, offset); + goto reset; + } + /* + * offset == SIOP_NSG may be a valid condition if + * we get a sdp when the xfer is done. + * Don't call memmove in this case. + */ + if (offset < SIOP_NSG) { + memmove(&siop_cmd->siop_table->data[0], + &siop_cmd->siop_table->data[offset], + (SIOP_NSG - offset) * sizeof(scr_table_t)); + } + CALL_SCRIPT(Ent_reselect); + return 1; + case A_int_resfail: + printf("reselect failed\n"); + CALL_SCRIPT(Ent_reselect); + return 1; + case A_int_done: +#if 0 + printf("done, taget id 0x%x last msg in=0x%x " + "status=0x%x\n", + siop_cmd->siop_table->id, + siop_cmd->siop_table->msg_in, + siop_cmd->siop_table->status); +#endif + if (siop_cmd->status == CMDST_SENSE) + siop_cmd->status = CMDST_SENSE_DONE; + else + siop_cmd->status = CMDST_DONE; + switch(siop_cmd->siop_table->status) { + case SCSI_OK: + xs->error = (siop_cmd->status == CMDST_DONE) ? + XS_NOERROR : XS_SENSE; + break; + case SCSI_BUSY: + xs->error = XS_BUSY; + break; + case SCSI_CHECK: +check_sense: + if (siop_cmd->status == CMDST_SENSE_DONE) { + /* request sense on a request sense ? */ printf("request sense failed\n"); + xs->error = XS_DRIVER_STUFFUP; + } else { + siop_cmd->status = CMDST_SENSE; + } + break; + case 0xff: + /* + * the status byte was not updated, cmd was + * aborted + */ + xs->error = XS_SELTIMEOUT; + default: + xs->error = XS_DRIVER_STUFFUP; + } + goto end; + default: + printf("unknown irqcode %x\n", irqcode); + xs->error = XS_SELTIMEOUT; + goto end; + } + return 1; + } + siop_cmd->status = CMDST_DONE; + xs->error = XS_BUSY; + goto end; +end: + if (siop_cmd->status != CMDST_SENSE_DONE && + xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) { + bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0, + siop_cmd->dmamap_data->dm_mapsize, + (xs->xs_control & XS_CTL_DATA_IN) ? + BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data); + } + bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd); + if (siop_cmd->status == CMDST_SENSE) { + /* issue a request sense for this target */ + int error, i; + siop_cmd->rs_cmd.opcode = REQUEST_SENSE; + siop_cmd->rs_cmd.byte2 = xs->sc_link->scsipi_scsi.lun << 5; + siop_cmd->rs_cmd.unused[0] = siop_cmd->rs_cmd.unused[1] = 0; + siop_cmd->rs_cmd.length = sizeof(struct scsipi_sense_data); + siop_cmd->rs_cmd.control = 0; + siop_cmd->siop_table->status = 0xff; /* set invalid status */ + error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd, + &siop_cmd->rs_cmd, sizeof(struct scsipi_sense), + NULL, BUS_DMA_NOWAIT); + if (error) { + printf("%s: unable to load cmd DMA map: %d", + sc->sc_dev.dv_xname, error); + xs->error = XS_DRIVER_STUFFUP; + goto out; + } + siop_cmd->siop_table->cmd.count = + htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len); + siop_cmd->siop_table->cmd.addr = + htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr); + error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data, + &xs->sense.scsi_sense, sizeof(struct scsipi_sense_data), + NULL, BUS_DMA_NOWAIT); + if (error) { + printf("%s: unable to load sense DMA map: %d", + sc->sc_dev.dv_xname, error); + xs->error = XS_DRIVER_STUFFUP; + bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd); + goto out; + } + for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) { + siop_cmd->siop_table->data[i].count = + htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len); + siop_cmd->siop_table->data[i].addr = + htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr); + } + bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0, + siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_PREREAD); + bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0, + siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, 0, + sc->sc_scriptdma->dm_mapsize, BUS_DMASYNC_PREWRITE); + siop_start(sc); + return(1); + } else if (siop_cmd->status == CMDST_SENSE_DONE) { + bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0, + siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data); + } +out: + callout_stop(&siop_cmd->xs->xs_callout); + TAILQ_REMOVE(&sc->active_list[sc->current_target], siop_cmd, next); + siop_cmd->status = CMDST_FREE; + TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next); + xs->xs_status |= XS_STS_DONE; + xs->resid = 0; + scsipi_done (xs); + /* restart any pending cmd */ + siop_start(sc); + return 1; +} + +void +siop_minphys(bp) + struct buf *bp; +{ + minphys(bp); +} + +int +siop_scsicmd(xs) + struct scsipi_xfer *xs; +{ + struct siop_softc *sc = (struct siop_softc *)xs->sc_link->adapter_softc; + struct siop_cmd *siop_cmd; + int s, error, i; + u_int32_t id; + + s = splbio(); +#if 0 + printf("starting cmd for %d:%d\n", xs->sc_link->scsipi_scsi.target,xs->sc_link->scsipi_scsi.lun); +#endif + siop_cmd = sc->free_list.tqh_first; + if (siop_cmd) { + TAILQ_REMOVE(&sc->free_list, siop_cmd, next); + } + splx(s); + if (siop_cmd == NULL) { + xs->error = XS_DRIVER_STUFFUP; + return(TRY_AGAIN_LATER); + } +#ifdef DIAGNOSTIC + if (siop_cmd->status != CMDST_FREE) + panic("siop_scsicmd: new cmd not free"); +#endif + siop_cmd->xs = xs; + id = 0x3 << 24; /* scntl3 */ + id |= xs->sc_link->scsipi_scsi.target << 16; /* id */ + id |= 0xe0 << 8; /* scxfer */ + siop_cmd->siop_table->id = htole32(id); + siop_cmd->siop_table->msg_out = + MSG_IDENTIFY(xs->sc_link->scsipi_scsi.lun, 1); + siop_cmd->siop_table->status = 0xff; /* set invalid status */ + + /* load the DMA maps */ + error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd, + xs->cmd, xs->cmdlen, NULL, BUS_DMA_NOWAIT); + if (error) { + printf("%s: unable to load cmd DMA map: %d", + sc->sc_dev.dv_xname, error); + xs->error = XS_DRIVER_STUFFUP; + return(TRY_AGAIN_LATER); + } + siop_cmd->siop_table->cmd.count = + htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len); + siop_cmd->siop_table->cmd.addr = + htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr); + if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) { + error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data, + xs->data, xs->datalen, NULL, BUS_DMA_NOWAIT); + if (error) { + printf("%s: unable to load cmd DMA map: %d", + sc->sc_dev.dv_xname, error); + xs->error = XS_DRIVER_STUFFUP; + return(TRY_AGAIN_LATER); + bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd); + } + for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) { + siop_cmd->siop_table->data[i].count = + htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len); + siop_cmd->siop_table->data[i].addr = + htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr); + } + bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0, + siop_cmd->dmamap_data->dm_mapsize, + (xs->xs_control & XS_CTL_DATA_IN) ? + BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); + } + bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0, + siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, 0, + sc->sc_scriptdma->dm_mapsize, BUS_DMASYNC_PREWRITE); + + siop_cmd->status = CMDST_READY; + s = splbio(); + TAILQ_INSERT_TAIL(&sc->active_list[xs->sc_link->scsipi_scsi.target], + siop_cmd, next); + if ((sc->sc_flags & SC_CTRL_ACTIVE) == 0) { + siop_start(sc); + } + splx(s); + return (SUCCESSFULLY_QUEUED); +} + +void +siop_start(sc) + struct siop_softc *sc; +{ + struct siop_cmd *siop_cmd; + int timeout; + int i; + + for (i = 0; i < 16; i++) { + siop_cmd = sc->active_list[i].tqh_first; + if (siop_cmd) { + sc->current_target = i; + break; + } + } + if (siop_cmd == NULL) { + sc->sc_flags &= ~SC_CTRL_ACTIVE; + return; + } + + sc->sc_flags |= SC_CTRL_ACTIVE; + if (siop_cmd->status == CMDST_READY && + (siop_cmd->xs->xs_control & XS_CTL_POLL) == 0) { + /* start exire timer */ + timeout = siop_cmd->xs->timeout * hz / 1000; + if (timeout == 0) + timeout = 1; /* at last one tick */ + callout_reset(&siop_cmd->xs->xs_callout, timeout, + siop_timeout, siop_cmd); + } + /* load DSA */ + bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSA, + htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + + (((caddr_t)siop_cmd->siop_table) - ((caddr_t)sc->sc_script)))); + /* mark command as active (if not reqsense) and start script */ + if (siop_cmd->status == CMDST_READY) + siop_cmd->status = CMDST_ACTIVE; +#if 0 + printf("starting script, DSA 0x%lx\n", + htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + + (((caddr_t)siop_cmd->siop_table) - ((caddr_t)sc->sc_script)))); +#endif + bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, + htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + SCRIPT_OFF + Ent_select)); + /* now wait for IRQ */ +} + +void +siop_timeout(v) + void *v; +{ + struct siop_cmd *siop_cmd = v; + struct siop_softc *sc = siop_cmd->siop_sc; + int s; + u_int8_t scntl1; + + scsi_print_addr(siop_cmd->xs->sc_link); + printf("command timeout\n"); + + s = splbio(); + /* reset the scsi bus */ + scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, + scntl1 | SCNTL1_RST); + /* minimum 25 us, more time won't hurt */ + delay(100); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1); + + /* desactivate callout */ + callout_stop(&siop_cmd->xs->xs_callout); + /* mark command has being timed out; siop_intr will handle it */ + /* + * mark command has being timed out and just return; + * the bus reset will generate an interrupt, + * it will be handled in siop_intr() + */ + siop_cmd->flags |= CMDFL_TIMEOUT; + splx(s); + return; + +} + +void +siop_sdp(siop_cmd) + struct siop_cmd *siop_cmd; +{ + /* save data pointer. Handle async only for now */ + int offset, dbc, sstat; + struct siop_softc *sc = siop_cmd->siop_sc; + scr_table_t *table; /* table to patch */ + + if ((siop_cmd->xs->xs_control & (XS_CTL_DATA_OUT | XS_CTL_DATA_IN)) + == 0) + return; /* no data pointers to save */ + offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1); + if (offset >= SIOP_NSG) { + printf("%s: bad offset in siop_sdp (%d)\n", + sc->sc_dev.dv_xname, offset); + return; + } + table = &siop_cmd->siop_table->data[offset]; +#ifdef DEBUG_DR + printf("sdp: offset %d count=%d addr=0x%x ", offset, + table->count, table->addr); +#endif + dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff; + if (siop_cmd->xs->xs_control & XS_CTL_DATA_OUT) { + /* need to account stale data in FIFO */ + /* XXX check for large fifo */ + dbc += (bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO) - + (dbc & 0x7f)) & 0x7f; + sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0); + if (sstat & SSTAT0_OLF) + dbc++; + if (sstat & SSTAT0_ORF) + dbc++; + /* XXX check sstat1 for wide adapters */ + /* Flush the FIFO */ + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, + bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) | + CTEST3_CLF); + } + table->addr = + htole32(htole32(table->addr) + htole32(table->count) - dbc); + table->count = htole32(dbc); +#ifdef DEBUG_DR + printf("now count=%d addr=0x%x\n", table->count, table->addr); +#endif +} diff --git a/sys/dev/ic/siopreg.h b/sys/dev/ic/siopreg.h new file mode 100644 index 00000000000..480bdc147ca --- /dev/null +++ b/sys/dev/ic/siopreg.h @@ -0,0 +1,343 @@ + +/* $NetBSD: siopreg.h,v 1.1 2000/04/21 17:56:59 bouyer Exp $ */ + +/* + * Copyright (c) 2000 Manuel Bouyer. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + */ + +/* + * Devices definitions for Symbios/NCR M53c8xx PCI-SCSI I/O Processors + * Docs available from http://www.symbios.com/ + */ + +#define SIOP_SCNTL0 0x00 /* SCSI control 0, R/W */ +#define SCNTL0_ARB_MASK 0xc0 +#define SCNTL0_SARB 0x00 +#define SCNTL0_FARB 0xc0 +#define SCNTL0_START 0x20 +#define SCNTL0_WATM 0x10 +#define SCNTL0_EPC 0x08 +#define SCNTL0_AAP 0x02 +#define SCNTL0_TRG 0x01 + +#define SIOP_SCNTL1 0x01 /* SCSI control 1, R/W */ +#define SCNTL1_EXC 0x80 +#define SCNTL1_ADB 0x40 +#define SCNTL1_DHP 0x20 +#define SCNTL1_CON 0x10 +#define SCNTL1_RST 0x08 +#define SCNTL1_AESP 0x04 +#define SCNTL1_IARB 0x02 +#define SCNTL1_SST 0x01 + +#define SIOP_SCNTL2 0x02 /* SCSI control 2, R/W */ +#define SCNTL2_SDU 0x80 +#define SCNTL2_CHM 0x40 /* 875 only */ +#define SCNTL2_SLPMD 0x20 /* 875 only */ +#define SCNTL2_SLPHBEN 0x10 /* 875 only */ +#define SCNTL2_WSS 0x08 /* 875 only */ +#define SCNTL2_VUE0 0x04 /* 875 only */ +#define SCNTL2_VUE1 0x02 /* 875 only */ +#define SCNTL2_WSR 0x01 /* 875 only */ + +#define SIOP_SCNTL3 0x03 /* SCSI control 3, R/W */ +#define SCNTL3_ULTRA 0x80 /* 875 only */ +#define SCNTL3_SCF_SHIFT 4 +#define SCNTL3_SCF_MASK 0x70 +#define SCNTL3_EWS 0x04 /* 875 only */ +#define SCNTL3_CCF_SHIFT 0 +#define SCNTL3_MASK 0x07 + +#define SIOP_SCID 0x04 /* SCSI chip ID R/W */ +#define SCID_RRE 0x40 +#define SCID_SRE 0x20 +#define SCID_ENCID_SHIFT 0 +#define SCID_ENCID_MASK 0x07 + +#define SIOP_SCXFER 0x05 /* SCSI transfer, R/W */ +#define SCXFER_TP_SHIFT 5 +#define SCXFER_TP_MASK 0xe0 +#define SCXFER_MO_SHIFT 0 +#define SCXFER_MO_MASK 0x0f + +#define SIOP_SDID 0x06 /* SCSI destiation ID, R/W */ +#define SDID_ENCID_SHIFT 0 +#define SDID_ENCID_MASK 0x07 + +#define SIOP_GPREG 0x07 /* General purpose, R/W */ +#define GPREG_GPIO4 0x10 /* 875 only */ +#define GPREG_GPIO3 0x08 /* 875 only */ +#define GPREG_GPIO2 0x04 /* 875 only */ +#define GPREG_GPIO1 0x02 +#define GPREG_GPIO0 0x01 + +#define SIOP_SFBR 0x08 /* SCSI first byte received, R/W */ + +#define SIOP_SOCL 0x09 /* SCSI output control latch, RW */ + +#define SIOP_SSID 0x0A /* SCSI selector ID, RO */ +#define SSID_VAL 0x80 +#define SSID_ENCID_SHIFT 0 +#define SSID_ENCID_MASK 0x0f + +#define SIOP_SBCL 0x0B /* SCSI control line, RO */ + +#define SIOP_DSTAT 0x0C /* DMA status, RO */ +#define DSTAT_DFE 0x80 +#define DSTAT_MDPE 0x40 +#define DSTAT_BF 0x20 +#define DSTAT_ABRT 0x10 +#define DSTAT_SSI 0x08 +#define DSTAT_SIR 0x04 +#define DSTAT_IID 0x01 + +#define SIOP_SSTAT0 0x0D /* STSI status 0, RO */ +#define SSTAT0_ILF 0x80 +#define SSTAT0_ORF 0x40 +#define SSTAT0_OLF 0x20 +#define SSTAT0_AIP 0x10 +#define SSTAT0_LOA 0x08 +#define SSTAT0_WOA 0x04 +#define SSTAT0_RST 0x02 +#define SSTAT0_SDP 0x01 + +#define SIOP_SSTAT1 0x0E /* STSI status 1, RO */ +#define SSTAT1_FFO_SHIFT 4 +#define SSTAT1_FFO_MASK 0x80 +#define SSTAT1_SDPL 0x08 +#define SSTAT1_MSG 0x04 +#define SSTAT1_CD 0x02 +#define SSTAT1_IO 0x01 +#define SSTAT1_PHASE_MASK (SSTAT1_IO | SSTAT1_CD | SSTAT1_MSG) +#define SSTAT1_PHASE_DATAOUT 0 +#define SSTAT1_PHASE_DATAIN SSTAT1_IO +#define SSTAT1_PHASE_CMD SSTAT1_CD +#define SSTAT1_PHASE_STATUS (SSTAT1_CD | SSTAT1_IO) +#define SSTAT1_PHASE_MSGOUT (SSTAT1_MSG | SSTAT1_CD) +#define SSTAT1_PHASE_MSGIN (SSTAT1_MSG | SSTAT1_CD | SSTAT1_IO) + +#define SIOP_SSTAT2 0x0F /* STSI status 2, RO */ +#define SSTAT2_ILF1 0x80 /* 875 only */ +#define SSTAT2_ORF1 0x40 /* 875 only */ +#define SSTAT2_OLF1 0x20 /* 875 only */ +#define SSTAT2_FF4 0x10 /* 875 only */ +#define SSTAT2_SPL1 0x08 /* 875 only */ +#define SSTAT2_DF 0x04 /* 875 only */ +#define SSTAT2_LDSC 0x02 +#define SSTAT2_SDP1 0x01 /* 875 only */ + +#define SIOP_DSA 0x10 /* data struct addr, R/W */ + +#define SIOP_ISTAT 0x14 /* IRQ status, R/W */ +#define ISTAT_ABRT 0x80 +#define ISTAT_SRST 0x40 +#define ISTAT_SIGP 0x20 +#define ISTAT_SEM 0x10 +#define ISTAT_CON 0x08 +#define ISTAT_INTF 0x04 +#define ISTAT_SIP 0x02 +#define ISTAT_DIP 0x01 + +#define SIOP_CTEST0 0x18 /* Chip test 0, R/W */ + +#define SIOP_CTEST1 0x19 /* Chip test 1, R/W */ + +#define SIOP_CTEST2 0x1A /* Chip test 2, R/W */ +#define CTEST2_SRTCH 0x04 /* 875 only */ + +#define SIOP_CTEST3 0x1B /* Chip test 3, R/W */ +#define CTEST3_FLF 0x08 +#define CTEST3_CLF 0x04 +#define CTEST3_FM 0x02 +#define CTEST3_WRIE 0x01 + +#define SIOP_TEMP 0x1C /* Temp register (used by CALL/RET), R/W */ + +#define SIOP_DFIFO 0x20 /* DMA FIFO */ + +#define SIOP_CTEST4 0x21 /* Chip test 4, R/W */ +#define CTEST4_BDIS 0x80 +#define CTEST_ZMOD 0x40 +#define CTEST_ZSD 0x20 +#define CTEST_SRTM 0x10 +#define CTEST_MPEE 0x08 + +#define SIOP_CTEST5 0x22 /* Chip test 5, R/W */ +#define CTEST5_ADCK 0x80 +#define CTEST5_BBCK 0x40 +#define CTEST5_MASR 0x10 +#define CTEST5_DDIR 0x08 + +#define SIOP_CTEST6 0x23 /* Chip test 6, R/W */ + +#define SIOP_DBC 0x24 /* DMA byte counter, R/W */ + +#define SIOP_DCMD 0x27 /* DMA command, R/W */ + +#define SIOP_DNAD 0x28 /* DMA next addr, R/W */ + +#define SIOP_DSP 0x2C /* DMA scripts pointer, R/W */ + +#define SIOP_DSPS 0x30 /* DMA scripts pointer save, R/W */ + +#define SIOP_SCRATCHA 0x34 /* scratch register A. R/W */ + +#define SIOP_DMODE 0x38 /* DMA mode, R/W */ +#define DMODE_BL_SHIFT 6 +#define DMODE_BL_MASK 0xC0 +#define DMODE_SIOM 0x20 +#define DMODE_DIOM 0x10 +#define DMODE_ERL 0x08 +#define DMODE_ERMP 0x04 +#define DMODE_BOF 0x02 +#define DMODE_MAN 0x01 + +#define SIOP_DIEN 0x39 /* DMA interrupt enable, R/W */ +#define DIEN_MDPE 0x40 +#define DIEN_BF 0x20 +#define DIEN_AVRT 0x10 +#define DIEN_SSI 0x08 +#define DIEN_SIR 0x04 +#define DIEN_IID 0x01 + +#define SIOP_SBR 0x3A /* scratch byte register, R/W */ + +#define SIOP_DCNTL 0x3B /* DMA control, R/W */ +#define DCNTL_CLSE 0x80 +#define DCNTL_PFF 0x40 +#define DCNTL_PFEN 0x20 +#define DCNTL_SSM 0x10 +#define DCNTL_IRQM 0x08 +#define DCNTL_STD 0x04 +#define DCNTL_IRQD 0x02 +#define DCNTL_COM 0x01 + +#define SIOP_ADDER 0x3C /* adder output sum, RO */ + +#define SIOP_SIEN0 0x40 /* SCSI interrupt enable 0, R/W */ +#define SIEN0_MA 0x80 +#define SIEN0_CMP 0x40 +#define SIEN0_SEL 0x20 +#define SIEN0_RSL 0x10 +#define SIEN0_SGE 0x08 +#define SIEN0_UDC 0x04 +#define SIEN0_SRT 0x02 +#define SIEN0_PAR 0x01 + +#define SIOP_SIEN1 0x41 /* SCSI interrupt enable 1, R/W */ +#define SIEN1_STO 0x04 +#define SIEN1_GEN 0x02 +#define SIEN1_HTH 0x01 + +#define SIOP_SIST0 0x42 /* SCSI interrupt status 0, RO */ +#define SIST0_MA 0x80 +#define SIST0_CMP 0x40 +#define SIST0_SEL 0x20 +#define SIST0_RSL 0x10 +#define SIST0_SGE 0x08 +#define SIST0_UDC 0x04 +#define SIST0_RST 0x02 +#define SIST0_PAR 0x01 + +#define SIOP_SIST1 0x43 /* SCSI interrut status 1, RO */ +#define SIST1_STO 0x04 +#define SIST1_GEN 0x02 +#define SIST1_HTH 0x01 + +#define SIOP_SLPAR 0x44 /* scsi longitudinal parity, R/W */ + +#define SIOP_SWIDE 0x45 /* scsi wide residue, RW, 875 only */ + +#define SIOP_MACNTL 0x46 /* memory access control, R/W */ + +#define SIOP_GPCNTL 0x47 /* General Purpose Pin control, R/W */ +#define GPCNTL_ME 0x80 /* 875 only */ +#define GPCNTL_FE 0x40 /* 875 only */ +#define GPCNTL_IN4 0x10 /* 875 only */ +#define GPCNTL_IN3 0x08 /* 875 only */ +#define GPCNTL_IN2 0x04 /* 875 only */ +#define GPCNTL_IN1 0x02 +#define GPCNTL_IN0 0x01 + +#define SIOP_STIME0 0x48 /* SCSI timer 0, R/W */ +#define STIME0_HTH_SHIFT 4 +#define STIME0_HTH_MASK 0xf0 +#define STIME0_SEL_SHIFT 0 +#define STIME0_SEL_MASK 0x0f + +#define SIOP_STIME1 0x49 /* SCSI timer 1, R/W */ +#define STIME1_HTHBA 0x40 /* 875 only */ +#define STIME1_GENSF 0x20 /* 875 only */ +#define STIME1_HTHSF 0x10 /* 875 only */ +#define STIME1_GEN_SHIFT 0 +#define STIME1_GEN_MASK 0x0f + +#define SIOP_RESPID0 0x4A /* response ID, R/W */ + +#define SIOP_RESPID1 0x4B /* response ID, R/W, 875-only */ + +#define SIOP_STEST0 0x4C /* SCSI test 0, RO */ + +#define SIOP_STEST1 0x4D /* SCSI test 1, RO, RW on 875 */ +#define STEST1_DBLEN 0x08 /* 875-only */ +#define STEST1_DBLSEL 0x04 /* 875-only */ + +#define SIOP_STEST2 0x4E /* SCSI test 2, RO, R/W on 875 */ +#define STEST2_DIF 0x20 /* 875 only */ +#define STEST2_EXT 0x02 + +#define SIOP_STEST3 0x4F /* SCSI test 3, RO, RW on 875 */ +#define STEST3_TE 0x80 + +#define SIOP_SIDL 0x50 /* SCSI input data latch, RO */ + +#define SIOP_SODL 0x54 /* SCSI output data latch, R/W */ + +#define SIOP_SBDL 0x58 /* SCSI bus data lines, RO */ + +#define SIOP_SCRATCHB 0x5C /* Scratch register B, R/W */ + +#define SIOP_SCRATCHC 0x60 /* Scratch register C, R/W, 875 only */ + +#define SIOP_SCRATCHD 0x64 /* Scratch register D, R/W, 875-only */ + +#define SIOP_SCRATCHE 0x68 /* Scratch register E, R/W, 875-only */ + +#define SIOP_SCRATCHF 0x6c /* Scratch register F, R/W, 875-only */ + +#define SIOP_SCRATCHG 0x70 /* Scratch register G, R/W, 875-only */ + +#define SIOP_SCRATCHH 0x74 /* Scratch register H, R/W, 875-only */ + +#define SIOP_SCRATCHI 0x78 /* Scratch register I, R/W, 875-only */ + +#define SIOP_SCRATCHJ 0x7c /* Scratch register J, R/W, 875-only */ diff --git a/sys/dev/ic/siopvar.h b/sys/dev/ic/siopvar.h new file mode 100644 index 00000000000..84be8c697d6 --- /dev/null +++ b/sys/dev/ic/siopvar.h @@ -0,0 +1,83 @@ +/* $NetBSD: siopvar.h,v 1.1 2000/04/21 17:56:59 bouyer Exp $ */ + +/* + * Copyright (c) 2000 Manuel Bouyer. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + */ + +/* structure and definitions for the siop driver */ + +TAILQ_HEAD(cmd_list, siop_cmd); + +/* Driver internal state */ +struct siop_softc { + struct device sc_dev; + struct scsipi_link sc_link; /* link to upper level */ + int features; /* chip's features */ + u_int8_t maxburst; + u_int8_t maxoff; + u_int8_t clock_div; + bus_space_tag_t sc_rt; /* bus_space registers tag */ + bus_space_handle_t sc_rh; /* bus_space registers handle */ + bus_addr_t sc_raddr; /* register adresses */ + bus_dma_tag_t sc_dmat; /* bus DMA tag */ + bus_dmamap_t sc_scriptdma; /* DMA map for script */ + u_int32_t *sc_script; /* script location in memory */ + struct cmd_list free_list; /* cmd descr free list */ + struct cmd_list active_list[16]; /* per-target active cmds */ + int current_target; /* current target */ + u_int32_t sc_flags; +}; +/* defs for sc_flags */ +#define SC_CTRL_ACTIVE 0x00000001 /* controller already running */ + +/* features */ +#define SF_BUS_WIDE 0x00000001 /* wide bus */ +#define SF_BUS_ULTRA 0x00000002 /* Ultra (20Mhz) bus */ +#define SF_BUS_ULTRA2 0x00000004 /* Ultra2 (40Mhz) bus */ +#define SF_BUS_DIFF 0x00000008 /* differential bus */ + +#define SF_CHIP_LED0 0x00000100 /* led on GPIO0 */ +#define SF_CHIP_DBLR 0x00000200 /* clock doubler */ +#define SF_CHIP_QUAD 0x00000400 /* clock quadrupler */ +#define SF_CHIP_CLK80 0x00000800 /* 80Mhz clock */ +#define SF_CHIP_FIFO 0x00001000 /* large fifo */ +#define SF_CHIP_PF 0x00002000 /* Intructions prefetch */ +#define SF_CHIP_RAM 0x00004000 /* on-board RAM */ + +#define SF_PCI_RL 0x01000000 /* PCI read line */ +#define SF_PCI_RM 0x02000000 /* PCI read multiple */ +#define SF_PCI_BOF 0x04000000 /* PCI burst opcode fetch */ +#define SF_PCI_CLS 0x08000000 /* PCI cache line size */ +#define SF_PCI_WRI 0x10000000 /* PCI write and invalidate */ + +void siop_attach __P((struct siop_softc *)); +int siop_intr __P((void *)); diff --git a/sys/dev/microcode/siop/Makefile b/sys/dev/microcode/siop/Makefile new file mode 100644 index 00000000000..01461bfff26 --- /dev/null +++ b/sys/dev/microcode/siop/Makefile @@ -0,0 +1,15 @@ +# $NetBSD: Makefile,v 1.1 2000/04/21 17:57:01 bouyer Exp $ + +all: siop.out + +PROG= ncr53cxxx +MKSHARE=no + +.include <bsd.prog.mk> + +regen: siop.out +headers: siop.out + +siop.out: siop.ss ${PROG} + ./${PROG} siop.ss -o siop.out + diff --git a/sys/dev/microcode/siop/siop.out b/sys/dev/microcode/siop/siop.out new file mode 100644 index 00000000000..effe33a0b9f --- /dev/null +++ b/sys/dev/microcode/siop/siop.out @@ -0,0 +1,121 @@ +/* $NetBSD: siop.out,v 1.1 2000/04/21 17:57:01 bouyer Exp $ */ +/* + * DO NOT EDIT - this file is automatically generated. + * created from siop.ss on Thu Apr 20 23:36:33 2000 + */ +const u_int32_t siop_script[] = { + 0x47000004, 0x00000048, /* 000 - 0 */ + 0x78340000, 0x00000000, /* 008 - 8 */ + 0x78350000, 0x00000000, /* 010 - 16 */ + 0x868b0000, 0x000000a0, /* 018 - 24 */ + 0x878b0000, 0x00000068, /* 020 - 32 */ + 0x808b0000, 0x00000118, /* 028 - 40 */ + 0x818b0000, 0x000000c0, /* 030 - 48 */ + 0x828b0000, 0x00000098, /* 038 - 56 */ + 0x838b0000, 0x000000a0, /* 040 - 64 */ + 0x98080000, 0x0000ffff, /* 048 - 72 */ + 0x54000000, 0x00000030, /* 050 - 80 */ + 0x740a8f00, 0x00000000, /* 058 - 88 */ + 0x6a340000, 0x00000000, /* 060 - 96 */ + 0x9f030000, 0x0000ffff, /* 068 - 104 */ + 0x1f00000c, 0x0000000c, /* 070 - 112 */ + 0x60000040, 0x00000000, /* 078 - 120 */ + 0x98080000, 0x0000ff02, /* 080 - 128 */ + 0x98080000, 0x0000ff03, /* 088 - 136 */ + 0x60000008, 0x00000000, /* 090 - 144 */ + 0x1f00000c, 0x0000000c, /* 098 - 152 */ + 0x808c0004, 0x000001a8, /* 0a0 - 160 */ + 0x808c0000, 0x000001d0, /* 0a8 - 168 */ + 0x808c0002, 0x000001d8, /* 0b0 - 176 */ + 0x98080000, 0x0000ff01, /* 0b8 - 184 */ + 0x1e000014, 0x00000014, /* 0c0 - 192 */ + 0x60000008, 0x00000000, /* 0c8 - 200 */ + 0x80880000, 0xffffff40, /* 0d0 - 208 */ + 0x1a00001c, 0x0000001c, /* 0d8 - 216 */ + 0x80880000, 0xffffff30, /* 0e0 - 224 */ + 0x1b000024, 0x00000024, /* 0e8 - 232 */ + 0x80880000, 0xffffff20, /* 0f0 - 240 */ + 0x88880000, 0x00000098, /* 0f8 - 248 */ + 0x1900002c, 0x0000002c, /* 100 - 256 */ + 0x7e350100, 0x00000000, /* 108 - 264 */ + 0x7e100800, 0x00000000, /* 110 - 272 */ + 0x7f110000, 0x00000000, /* 118 - 280 */ + 0x7f120000, 0x00000000, /* 120 - 288 */ + 0x7f130000, 0x00000000, /* 128 - 296 */ + 0x818b0000, 0xffffffc8, /* 130 - 304 */ + 0x88880000, 0x000000a0, /* 138 - 312 */ + 0x80880000, 0xfffffed0, /* 140 - 320 */ + 0x88880000, 0x00000048, /* 148 - 328 */ + 0x1800002c, 0x0000002c, /* 150 - 336 */ + 0x7e350100, 0x00000000, /* 158 - 344 */ + 0x7e100800, 0x00000000, /* 160 - 352 */ + 0x7f110000, 0x00000000, /* 168 - 360 */ + 0x7f120000, 0x00000000, /* 170 - 368 */ + 0x7f130000, 0x00000000, /* 178 - 376 */ + 0x808b0000, 0xffffffc8, /* 180 - 384 */ + 0x88880000, 0x00000050, /* 188 - 392 */ + 0x80880000, 0xfffffe80, /* 190 - 400 */ + 0x72100000, 0x00000000, /* 198 - 408 */ + 0x6a5c0000, 0x00000000, /* 1a0 - 416 */ + 0x72110000, 0x00000000, /* 1a8 - 424 */ + 0x6a5d0000, 0x00000000, /* 1b0 - 432 */ + 0x72120000, 0x00000000, /* 1b8 - 440 */ + 0x6a5e0000, 0x00000000, /* 1c0 - 448 */ + 0x72130000, 0x00000000, /* 1c8 - 456 */ + 0x6a5f0000, 0x00000000, /* 1d0 - 464 */ + 0x90080000, 0x00000000, /* 1d8 - 472 */ + 0x725c0000, 0x00000000, /* 1e0 - 480 */ + 0x6a100000, 0x00000000, /* 1e8 - 488 */ + 0x725d0000, 0x00000000, /* 1f0 - 496 */ + 0x6a110000, 0x00000000, /* 1f8 - 504 */ + 0x725e0000, 0x00000000, /* 200 - 512 */ + 0x6a120000, 0x00000000, /* 208 - 520 */ + 0x725f0000, 0x00000000, /* 210 - 528 */ + 0x6a130000, 0x00000000, /* 218 - 536 */ + 0x90080000, 0x00000000, /* 220 - 544 */ + 0x7c027f00, 0x00000000, /* 228 - 552 */ + 0x60000008, 0x00000000, /* 230 - 560 */ + 0x60000040, 0x00000000, /* 238 - 568 */ + 0x48000000, 0x00000000, /* 240 - 576 */ + 0x90080000, 0x00000000, /* 248 - 584 */ + 0x88880000, 0xffffffd0, /* 250 - 592 */ + 0x74340100, 0x00000000, /* 258 - 600 */ + 0x808c0000, 0xfffffde8, /* 260 - 608 */ + 0x72350000, 0x00000000, /* 268 - 616 */ + 0x808c0000, 0xfffffdd8, /* 270 - 624 */ + 0x98080000, 0x0000ff04, /* 278 - 632 */ + 0x88880000, 0xffffffa0, /* 280 - 640 */ + 0x98080000, 0x0000ff00, /* 288 - 648 */ + 0x60000040, 0x00000000, /* 290 - 656 */ + 0x7a340100, 0x00000000, /* 298 - 664 */ + 0x80880000, 0xfffffde8, /* 2a0 - 672 */ +}; + +#define A_t_id 0x00000004 +#define A_t_msg_in 0x0000000c +#define A_t_msg_out 0x00000014 +#define A_t_cmd 0x0000001c +#define A_t_status 0x00000024 +#define A_t_data 0x0000002c +#define A_int_done 0x0000ff00 +#define A_int_msgin 0x0000ff01 +#define A_int_resel 0x0000ff02 +#define A_int_resfail 0x0000ff03 +#define A_int_disc 0x0000ff04 +#define A_int_err 0x0000ffff +#define A_flag_sdp 0x00000001 +#define Ent_waitphase 0x00000018 +#define Ent_select 0x00000000 +#define Ent_msgout 0x000000c0 +#define Ent_msgin 0x00000090 +#define Ent_dataout 0x00000148 +#define Ent_datain 0x000000f8 +#define Ent_cmdout 0x000000d8 +#define Ent_status 0x000000e8 +#define Ent_disconnect 0x00000228 +#define Ent_reselect 0x00000050 +#define Ent_reselected 0x00000008 +#define Ent_handle_reselect 0x00000000 + +u_int32_t INSTRUCTIONS = 0x00000055; +u_int32_t PATCHES = 0x00000000; diff --git a/sys/dev/microcode/siop/siop.ss b/sys/dev/microcode/siop/siop.ss new file mode 100644 index 00000000000..e7e6b61220f --- /dev/null +++ b/sys/dev/microcode/siop/siop.ss @@ -0,0 +1,153 @@ +ARCH 720 + +; offsets of sym_xfer +ABSOLUTE t_id = 4; +ABSOLUTE t_msg_in = 12; +ABSOLUTE t_msg_out = 20; +ABSOLUTE t_cmd = 28; +ABSOLUTE t_status = 36; +ABSOLUTE t_data = 44; + +;; interrupt codes +ABSOLUTE int_done = 0xff00; +ABSOLUTE int_msgin = 0xff01; +ABSOLUTE int_resel = 0xff02; +ABSOLUTE int_resfail = 0xff03; +ABSOLUTE int_disc = 0xff04; +ABSOLUTE int_err = 0xffff; + +; flags for scratcha0 +ABSOLUTE flag_sdp = 0x01 ; got save data pointer + +ENTRY waitphase; +ENTRY select; +ENTRY msgout; +ENTRY msgin; +ENTRY dataout; +ENTRY datain; +ENTRY cmdout; +ENTRY status; +ENTRY disconnect; +ENTRY reselect; +ENTRY reselected; +ENTRY handle_reselect; + +PROC siop_script: + +select: + SELECT ATN FROM t_id, REL(reselect); +reselected: +; starting a new session, init 'local variables' + MOVE 0 to SCRATCHA0 ; flags + MOVE 0 to SCRATCHA1 ; DSA offset (for S/G save data pointer) +waitphase: + JUMP REL(msgout), WHEN MSG_OUT; + JUMP REL(msgin), WHEN MSG_IN; + JUMP REL(dataout), WHEN DATA_OUT; + JUMP REL(datain), WHEN DATA_IN; + JUMP REL(cmdout), WHEN CMD; + JUMP REL(status), WHEN STATUS; +err: + INT int_err; + +reselect: + WAIT RESELECT REL(reselect_fail) + MOVE SSID & 0x8f to SFBR + MOVE SFBR to SCRATCHA0 ; save reselect ID + INT int_err, WHEN NOT MSG_IN; + MOVE FROM t_msg_in, WHEN MSG_IN; + CLEAR ACK; + INT int_resel; + +reselect_fail: + INT int_resfail; + +msgin: + CLEAR ATN + MOVE FROM t_msg_in, WHEN MSG_IN; + JUMP REL(handle_dis), IF 0x04 ; disconnect message + JUMP REL(handle_cmpl), IF 0x00 ; command complete message + JUMP REL(handle_sdp), IF 0x02 ; save data pointer message + INT int_msgin; +msgout: + MOVE FROM t_msg_out, WHEN MSG_OUT; + CLEAR ATN; + JUMP REL(waitphase); +cmdout: + MOVE FROM t_cmd, WHEN CMD; + JUMP REL(waitphase); +status: + MOVE FROM t_status, WHEN STATUS; + JUMP REL(waitphase); +datain: + CALL REL(savedsa); +datain_loop: + MOVE FROM t_data, WHEN DATA_IN; + MOVE SCRATCHA1 + 1 TO SCRATCHA1 ; adjust offset + MOVE DSA0 + 8 to DSA0; + MOVE DSA1 + 0 to DSA1 WITH CARRY; + MOVE DSA2 + 0 to DSA2 WITH CARRY; + MOVE DSA3 + 0 to DSA3 WITH CARRY; + JUMP REL(datain_loop), WHEN DATA_IN; + CALL REL(restoredsa); + JUMP REL(waitphase); + +dataout: + CALL REL(savedsa); +dataout_loop: + MOVE FROM t_data, WHEN DATA_OUT; + MOVE SCRATCHA1 + 1 TO SCRATCHA1 ; adjust offset + MOVE DSA0 + 8 to DSA0; + MOVE DSA1 + 0 to DSA1 WITH CARRY; + MOVE DSA2 + 0 to DSA2 WITH CARRY; + MOVE DSA3 + 0 to DSA3 WITH CARRY; + JUMP REL(dataout_loop), WHEN DATA_OUT; + CALL REL(restoredsa); + JUMP REL(waitphase); + +savedsa: + MOVE DSA0 to SFBR; + MOVE SFBR to SCRATCHB0; + MOVE DSA1 to SFBR; + MOVE SFBR to SCRATCHB1; + MOVE DSA2 to SFBR; + MOVE SFBR to SCRATCHB2; + MOVE DSA3 to SFBR; + MOVE SFBR to SCRATCHB3; + RETURN; + +restoredsa: + MOVE SCRATCHB0 TO SFBR; + MOVE SFBR TO DSA0; + MOVE SCRATCHB1 TO SFBR; + MOVE SFBR TO DSA1; + MOVE SCRATCHB2 TO SFBR; + MOVE SFBR TO DSA2; + MOVE SCRATCHB3 TO SFBR; + MOVE SFBR TO DSA3; + RETURN; + +disconnect: + MOVE SCNTL2 & 0x7f TO SCNTL2; + CLEAR ATN; + CLEAR ACK; + WAIT DISCONNECT; + RETURN; + +handle_dis: + CALL REL(disconnect); +; if we didn't get sdp, or if offset is 0, no need to interrupt + MOVE SCRATCHA0 & flag_sdp TO SFBR; + JUMP REL(reselect), if 0x00; + MOVE SCRATCHA1 TO SFBR; + JUMP REL(reselect), if 0x00; +; Ok, we need to save data pointers + INT int_disc; + +handle_cmpl: + CALL REL(disconnect); + INT int_done; +handle_sdp: + CLEAR ACK; + MOVE SCRATCHA0 | flag_sdp TO SCRATCHA0; + JUMP REL(msgin) ; should get a disconnect message now diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci index 8b61e5f3186..acc2560e6a8 100644 --- a/sys/dev/pci/files.pci +++ b/sys/dev/pci/files.pci @@ -1,4 +1,4 @@ -# $NetBSD: files.pci,v 1.87 2000/04/20 05:25:20 nathanw Exp $ +# $NetBSD: files.pci,v 1.88 2000/04/21 17:57:00 bouyer Exp $ # # Config file and device description for machine-independent PCI code. # Included by ports that need it. Requires that the SCSI files be @@ -90,6 +90,11 @@ device ncr: scsi attach ncr at pci file dev/pci/ncr.c ncr +# Symbios 53c8xx SCSI chips +# device declaration in sys/conf/files +attach siop at pci with siop_pci +file dev/pci/siop_pci.c siop_pci + # PCI IDE controllers device pciide {[channel = -1]}: wdc_base, ata, atapi attach pciide at pci diff --git a/sys/dev/pci/siop_pci.c b/sys/dev/pci/siop_pci.c new file mode 100644 index 00000000000..7ab571cfa20 --- /dev/null +++ b/sys/dev/pci/siop_pci.c @@ -0,0 +1,280 @@ +/* $NetBSD: siop_pci.c,v 1.1 2000/04/21 17:57:00 bouyer Exp $ */ + +/* + * Copyright (c) 2000 Manuel Bouyer. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + */ + +/* SYM53c8xx PCI-SCSI I/O Processors driver: PCI front-end */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/buf.h> +#include <sys/kernel.h> + +#include <machine/endian.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> + +#include <dev/scsipi/scsipi_all.h> +#include <dev/scsipi/scsipiconf.h> + +#include <dev/ic/siopvar.h> + +/* structure describing each chip */ +struct siop_product_desc { + u_int32_t product; + int revision; + const char *name; + int features; /* features are defined in siopvar.h */ + u_int8_t maxburst; + u_int8_t maxoff; + u_int8_t clock_div; +}; + +/* List (array, really :) of chips we know how to handle */ +const struct siop_product_desc siop_products[] = { + { PCI_PRODUCT_SYMBIOS_810, + 0x00, + "Symbios Logic 53c810 (fast scsi)", + SF_PCI_RL, + 4, 8, 4 + }, + { PCI_PRODUCT_SYMBIOS_810, + 0x10, + "Symbios Logic 53c810a (fast scsi)", + SF_PCI_RL | SF_PCI_BOF | SF_CHIP_PF, + 4, 8, 4 + }, + { PCI_PRODUCT_SYMBIOS_815, + 0x00, + "Symbios Logic 53c815 (fast scsi)", + SF_PCI_RL | SF_PCI_BOF, + 4, 8, 4 + }, + { PCI_PRODUCT_SYMBIOS_820, + 0x00, + "Symbios Logic 53c820 (fast wide scsi)", + SF_PCI_RL | SF_BUS_WIDE, + 4, 8, 4 + }, + { PCI_PRODUCT_SYMBIOS_825, + 0x00, + "Symbios Logic 53c825 (fast wide scsi)", + SF_PCI_RL | SF_PCI_BOF | SF_BUS_WIDE, + 4, 8, 4 + }, + { PCI_PRODUCT_SYMBIOS_825, + 0x10, + "Symbios Logic 53c825a (fast wide scsi)", + SF_PCI_RL | SF_PCI_CLS | SF_PCI_WRI | SF_PCI_RM | + SF_CHIP_FIFO | SF_CHIP_PF | SF_CHIP_RAM | + SF_BUS_WIDE, + 7, 8, 4 + }, + { PCI_PRODUCT_SYMBIOS_860, + 0x00, + "Symbios Logic 53c860 (ultra scsi)", + SF_PCI_RL | SF_PCI_CLS | SF_PCI_WRI | SF_PCI_RM | + SF_CHIP_PF | SF_CHIP_CLK80 | + SF_BUS_ULTRA, + 4, 8, 5 + }, + { PCI_PRODUCT_SYMBIOS_875, + 0x00, + "Symbios Logic 53c875 (ultra-wide scsi)", + SF_PCI_RL | SF_PCI_CLS | SF_PCI_WRI | SF_PCI_RM | + SF_CHIP_FIFO | SF_CHIP_PF | SF_CHIP_RAM | SF_CHIP_CLK80 | + SF_BUS_ULTRA | SF_BUS_WIDE, + 7, 16, 5 + }, + { PCI_PRODUCT_SYMBIOS_875, + 0x02, + "Symbios Logic 53c875 (ultra-wide scsi)", + SF_PCI_RL | SF_PCI_CLS | SF_PCI_WRI | SF_PCI_RM | + SF_CHIP_FIFO | SF_CHIP_PF | SF_CHIP_RAM | SF_CHIP_DBLR | + SF_BUS_ULTRA | SF_BUS_WIDE, + 7, 16, 5 + }, + { PCI_PRODUCT_SYMBIOS_875J, + 0x00, + "Symbios Logic 53c875j (ultra-wide scsi)", + SF_PCI_RL | SF_PCI_CLS | SF_PCI_WRI | SF_PCI_RM | + SF_CHIP_FIFO | SF_CHIP_PF | SF_CHIP_RAM | SF_CHIP_DBLR | + SF_BUS_ULTRA | SF_BUS_WIDE, + 7, 16, 5 + }, + { PCI_PRODUCT_SYMBIOS_885, + 0x00, + "Symbios Logic 53c885 (ultra-wide scsi)", + SF_PCI_RL | SF_PCI_CLS | SF_PCI_WRI | SF_PCI_RM | + SF_CHIP_FIFO | SF_CHIP_PF | SF_CHIP_RAM | SF_CHIP_DBLR | + SF_BUS_ULTRA | SF_BUS_WIDE, + 7, 16, 5 + }, + { PCI_PRODUCT_SYMBIOS_895, + 0x00, + "Symbios Logic 53c895 (ultra2-wide scsi)", + SF_PCI_RL | SF_PCI_CLS | SF_PCI_WRI | SF_PCI_RM | + SF_CHIP_FIFO | SF_CHIP_PF | SF_CHIP_RAM | SF_CHIP_QUAD | + SF_BUS_ULTRA2 | SF_BUS_WIDE, + 7, 31, 7 + }, + { PCI_PRODUCT_SYMBIOS_896, + 0x00, + "Symbios Logic 53c896 (ultra2-wide scsi)", + SF_PCI_RL | SF_PCI_CLS | SF_PCI_WRI | SF_PCI_RM | + SF_CHIP_FIFO | SF_CHIP_PF | SF_CHIP_RAM | SF_CHIP_QUAD | + SF_BUS_ULTRA2 | SF_BUS_WIDE, + 7, 31, 7 + }, + { 0, + 0x00, + NULL, + 0x00, + 7, 31, 7 + }, +}; + +const struct siop_product_desc * siop_lookup_product __P((u_int32_t, int)); + +const struct siop_product_desc * +siop_lookup_product(id, rev) + u_int32_t id; + int rev; +{ + const struct siop_product_desc *pp; + const struct siop_product_desc *rp = NULL; + for (pp = siop_products; pp->name != NULL; pp++) { + if (PCI_PRODUCT(id) == pp->product && pp->revision <= rev) + if (rp == NULL || pp->revision > rp->revision) + rp = pp; + } + return rp; +} + +/* Driver internal state */ +struct siop_pci_softc { + struct siop_softc siop; + pci_chipset_tag_t sc_pc; /* PCI registers info */ + pcitag_t sc_tag; + void *sc_ih; /* PCI interrupt handle */ + const struct siop_product_desc *sc_pp; /* Adapter description */ +}; + +int siop_pci_match __P((struct device *, struct cfdata *, void *)); +void siop_pci_attach __P((struct device *, struct device *, void *)); + +struct cfattach siop_pci_ca = { + sizeof(struct siop_pci_softc), siop_pci_match, siop_pci_attach +}; + +int +siop_pci_match(parent, match, aux) + struct device *parent; + struct cfdata *match; + void *aux; +{ + struct pci_attach_args *pa = aux; + const struct siop_product_desc *pp; + + /* look if it's a known product */ + pp = siop_lookup_product(pa->pa_id, PCI_REVISION(pa->pa_class)); + if (pp) + return 1; + return 0; +} + +void +siop_pci_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct pci_attach_args *pa = aux; + pci_chipset_tag_t pc = pa->pa_pc; + pcitag_t tag = pa->pa_tag; + struct siop_pci_softc *sc = (struct siop_pci_softc *)self; + const char *intrstr; + pci_intr_handle_t intrhandle; + + sc->sc_pp = siop_lookup_product(pa->pa_id, PCI_REVISION(pa->pa_class)); + if (sc->sc_pp == NULL) { + printf("sym: broken match/attach!!\n"); + return; + } + printf(": %s\n", sc->sc_pp->name); + sc->sc_pc = pc; + sc->sc_tag = tag; + sc->siop.sc_dmat = pa->pa_dmat; + if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, + &sc->siop.sc_rt, &sc->siop.sc_rh, &sc->siop.sc_raddr, NULL) != 0) { + /* Try to map memory addr */ + if (pci_mapreg_map(pa, 0x14, + PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0, + &sc->siop.sc_rt, &sc->siop.sc_rh, + &sc->siop.sc_raddr, NULL) != 0) { + printf("%s: unable to map device registers\n", + sc->siop.sc_dev.dv_xname); + } + } + if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin, + pa->pa_intrline, &intrhandle) != 0) { + printf("%s: couldn't map native-PCI interrupt\n", + sc->siop.sc_dev.dv_xname); + return; + } + intrstr = pci_intr_string(pa->pa_pc, intrhandle); + sc->sc_ih = pci_intr_establish(pa->pa_pc, intrhandle, IPL_BIO, + siop_intr, &sc->siop); + if (sc->sc_ih != NULL) { + printf("%s: using %s for native-PCI interrupt\n", + sc->siop.sc_dev.dv_xname, + intrstr ? intrstr : "unknown interrupt"); + } else { + printf("%s: couldn't establish interrupt", + sc->siop.sc_dev.dv_xname); + if (intrstr != NULL) + printf(" at %s", intrstr); + printf("\n"); + return; + } + /* copy interesting infos about the chip */ + sc->siop.features = sc->sc_pp->features; + sc->siop.maxburst = sc->sc_pp->maxburst; + sc->siop.maxoff = sc->sc_pp->maxoff; + sc->siop.clock_div = sc->sc_pp->clock_div; + /* attach generic code */ + siop_attach(&sc->siop); +} |
