diff --git a/sys/conf/files b/sys/conf/files index cc6ac5bac686..cffb9aa3045f 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $NetBSD: files,v 1.604 2003/03/16 11:50:27 jdolecek Exp $ +# $NetBSD: files,v 1.605 2003/04/06 09:48:41 tsutsui Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -385,6 +385,10 @@ device lfmport: scsi attach lfmport at lfmiop file dev/ic/lfmiop.c lfmiop +# Symbios/NCR 53c700 SCSI controllers +device oosiop: scsi +file dev/ic/oosiop.c oosiop + # Symbios/NCR 53c710 SCSI controllers # device osiop: scsi diff --git a/sys/dev/ic/oosiop.c b/sys/dev/ic/oosiop.c new file mode 100644 index 000000000000..a76f299d2b11 --- /dev/null +++ b/sys/dev/ic/oosiop.c @@ -0,0 +1,1325 @@ +/* $NetBSD: oosiop.c,v 1.1 2003/04/06 09:48:43 tsutsui Exp $ */ + +/* + * Copyright (c) 2001 Shuichiro URATA. 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. + */ + +/* + * NCR53C700 SCSI I/O processor (OOSIOP) driver + * + * TODO: + * - More better error handling. + * - Implement tagged queuing. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +static int oosiop_alloc_cb(struct oosiop_softc *, int); + +static __inline void oosiop_relocate_io(struct oosiop_softc *, bus_addr_t); +static __inline void oosiop_relocate_tc(struct oosiop_softc *, bus_addr_t); +static __inline void oosiop_fixup_select(struct oosiop_softc *, bus_addr_t, + int); +static __inline void oosiop_fixup_jump(struct oosiop_softc *, bus_addr_t, + bus_addr_t); +static __inline void oosiop_fixup_move(struct oosiop_softc *, bus_addr_t, + bus_size_t, bus_addr_t); + +static void oosiop_load_script(struct oosiop_softc *); +static void oosiop_setup_sgdma(struct oosiop_softc *, struct oosiop_cb *); +static void oosiop_setup_dma(struct oosiop_softc *); +static void oosiop_flush_fifo(struct oosiop_softc *); +static void oosiop_clear_fifo(struct oosiop_softc *); +static void oosiop_phasemismatch(struct oosiop_softc *); +static void oosiop_setup_syncxfer(struct oosiop_softc *); +static void oosiop_set_syncparam(struct oosiop_softc *, int, int, int); +static void oosiop_minphys(struct buf *); +static void oosiop_scsipi_request(struct scsipi_channel *, + scsipi_adapter_req_t, void *); +static void oosiop_done(struct oosiop_softc *, struct oosiop_cb *); +static void oosiop_timeout(void *); +static void oosiop_reset(struct oosiop_softc *); +static void oosiop_reset_bus(struct oosiop_softc *); +static void oosiop_scriptintr(struct oosiop_softc *); +static void oosiop_msgin(struct oosiop_softc *, struct oosiop_cb *); + +/* Trap interrupt code for unexpected data I/O */ +#define DATAIN_TRAP 0xdead0001 +#define DATAOUT_TRAP 0xdead0002 + +/* Possible TP and SCF conbination */ +static const struct { + u_int8_t tp; + u_int8_t scf; +} synctbl[] = { + {0, 1}, /* SCLK / 4.0 */ + {1, 1}, /* SCLK / 5.0 */ + {2, 1}, /* SCLK / 6.0 */ + {3, 1}, /* SCLK / 7.0 */ + {1, 2}, /* SCLK / 7.5 */ + {4, 1}, /* SCLK / 8.0 */ + {5, 1}, /* SCLK / 9.0 */ + {6, 1}, /* SCLK / 10.0 */ + {3, 2}, /* SCLK / 10.5 */ + {7, 1}, /* SCLK / 11.0 */ + {4, 2}, /* SCLK / 12.0 */ + {5, 2}, /* SCLK / 13.5 */ + {3, 3}, /* SCLK / 14.0 */ + {6, 2}, /* SCLK / 15.0 */ + {4, 3}, /* SCLK / 16.0 */ + {7, 2}, /* SCLK / 16.5 */ + {5, 3}, /* SCLK / 18.0 */ + {6, 3}, /* SCLK / 20.0 */ + {7, 3} /* SCLK / 22.0 */ +}; +#define NSYNCTBL (sizeof(synctbl) / sizeof(synctbl[0])) + +#define oosiop_period(sc, tp, scf) \ + (((1000000000 / (sc)->sc_freq) * (tp) * (scf)) / 40) + +void +oosiop_attach(struct oosiop_softc *sc) +{ + bus_size_t scrsize; + bus_dma_segment_t seg; + struct oosiop_cb *cb; + int err, i, nseg; + + /* + * Allocate DMA-safe memory for the script and map it. + */ + scrsize = sizeof(oosiop_script); + err = bus_dmamem_alloc(sc->sc_dmat, scrsize, PAGE_SIZE, 0, &seg, 1, + &nseg, BUS_DMA_NOWAIT); + if (err) { + printf(": failed to allocate script memory, err=%d\n", err); + return; + } + err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, scrsize, + (caddr_t *)&sc->sc_scr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT); + if (err) { + printf(": failed to map script memory, err=%d\n", err); + return; + } + err = bus_dmamap_create(sc->sc_dmat, scrsize, 1, scrsize, 0, + BUS_DMA_NOWAIT, &sc->sc_scrdma); + if (err) { + printf(": failed to create script map, err=%d\n", err); + return; + } + err = bus_dmamap_load(sc->sc_dmat, sc->sc_scrdma, sc->sc_scr, scrsize, + NULL, BUS_DMA_NOWAIT | BUS_DMA_WRITE); + if (err) { + printf(": failed to load script map, err=%d\n", err); + return; + } + sc->sc_scrbase = sc->sc_scrdma->dm_segs[0].ds_addr; + + /* Initialize command block array */ + TAILQ_INIT(&sc->sc_free_cb); + TAILQ_INIT(&sc->sc_cbq); + if (oosiop_alloc_cb(sc, OOSIOP_NCB) != 0) + return; + + /* Use first cb to reselection msgin buffer */ + cb = TAILQ_FIRST(&sc->sc_free_cb); + sc->sc_reselbuf = cb->xferdma->dm_segs[0].ds_addr + + offsetof(struct oosiop_xfer, msgin[0]); + + for (i = 0; i < OOSIOP_NTGT; i++) { + sc->sc_tgt[i].nexus = NULL; + sc->sc_tgt[i].flags = 0; + } + + /* Setup asynchronous clock divisor parameters */ + if (sc->sc_freq <= 25000000) { + sc->sc_ccf = 10; + sc->sc_dcntl = OOSIOP_DCNTL_CF_1; + } else if (sc->sc_freq <= 37500000) { + sc->sc_ccf = 15; + sc->sc_dcntl = OOSIOP_DCNTL_CF_1_5; + } else if (sc->sc_freq <= 50000000) { + sc->sc_ccf = 20; + sc->sc_dcntl = OOSIOP_DCNTL_CF_2; + } else { + sc->sc_ccf = 30; + sc->sc_dcntl = OOSIOP_DCNTL_CF_3; + } + + if (sc->sc_chip == OOSIOP_700) + sc->sc_minperiod = oosiop_period(sc, 4, sc->sc_ccf); + else + sc->sc_minperiod = oosiop_period(sc, 4, 10); + + if (sc->sc_minperiod < 25) + sc->sc_minperiod = 25; /* limit to 10MB/s */ + + printf(": NCR53C700%s rev %d, %dMHz, SCSI ID %d\n", + sc->sc_chip == OOSIOP_700_66 ? "-66" : "", + oosiop_read_1(sc, OOSIOP_CTEST7) >> 4, + sc->sc_freq / 1000000, sc->sc_id); + /* + * Reset all + */ + oosiop_reset(sc); + oosiop_reset_bus(sc); + + /* + * Start SCRIPTS processor + */ + oosiop_load_script(sc); + sc->sc_active = 0; + oosiop_write_4(sc, OOSIOP_DSP, sc->sc_scrbase + Ent_wait_reselect); + + /* + * Fill in the scsipi_adapter. + */ + sc->sc_adapter.adapt_dev = &sc->sc_dev; + sc->sc_adapter.adapt_nchannels = 1; + sc->sc_adapter.adapt_openings = OOSIOP_NCB; + sc->sc_adapter.adapt_max_periph = 1; + sc->sc_adapter.adapt_ioctl = NULL; + sc->sc_adapter.adapt_minphys = oosiop_minphys; + sc->sc_adapter.adapt_request = oosiop_scsipi_request; + + /* + * Fill in the scsipi_channel. + */ + sc->sc_channel.chan_adapter = &sc->sc_adapter; + sc->sc_channel.chan_bustype = &scsi_bustype; + sc->sc_channel.chan_channel = 0; + sc->sc_channel.chan_ntargets = OOSIOP_NTGT; + sc->sc_channel.chan_nluns = 8; + sc->sc_channel.chan_id = sc->sc_id; + + /* + * Now try to attach all the sub devices. + */ + config_found(&sc->sc_dev, &sc->sc_channel, scsiprint); +} + +static int +oosiop_alloc_cb(struct oosiop_softc *sc, int ncb) +{ + struct oosiop_cb *cb; + struct oosiop_xfer *xfer; + bus_size_t xfersize; + bus_dma_segment_t seg; + int i, s, err, nseg; + + /* + * Allocate oosiop_cb. + */ + cb = malloc(sizeof(struct oosiop_cb) * ncb, M_DEVBUF, M_NOWAIT|M_ZERO); + if (cb == NULL) { + printf(": failed to allocate cb memory\n"); + return (ENOMEM); + } + + /* + * Allocate DMA-safe memory for the oosiop_xfer and map it. + */ + xfersize = sizeof(struct oosiop_xfer) * ncb; + err = bus_dmamem_alloc(sc->sc_dmat, xfersize, PAGE_SIZE, 0, &seg, 1, + &nseg, BUS_DMA_NOWAIT); + if (err) { + printf(": failed to allocate xfer block memory, err=%d\n", err); + return (err); + } + err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, xfersize, + (caddr_t *)&xfer, BUS_DMA_NOWAIT | BUS_DMA_COHERENT); + if (err) { + printf(": failed to map xfer block memory, err=%d\n", err); + return (err); + } + + /* Initialize each command block */ + for (i = 0; i < ncb; i++) { + err = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, + 0, BUS_DMA_NOWAIT, &cb->cmddma); + if (err) { + printf(": failed to create cmddma map, err=%d\n", err); + return (err); + } + err = bus_dmamap_create(sc->sc_dmat, OOSIOP_MAX_XFER, + OOSIOP_NSG, OOSIOP_DBC_MAX, 0, BUS_DMA_NOWAIT, + &cb->datadma); + if (err) { + printf(": failed to create datadma map, err=%d\n", err); + return (err); + } + + err = bus_dmamap_create(sc->sc_dmat, + sizeof(struct oosiop_xfer), 1, sizeof(struct oosiop_xfer), + 0, BUS_DMA_NOWAIT, &cb->xferdma); + if (err) { + printf(": failed to create xfer block map, err=%d\n", + err); + return (err); + } + err = bus_dmamap_load(sc->sc_dmat, cb->xferdma, xfer, + sizeof(struct oosiop_xfer), NULL, BUS_DMA_NOWAIT); + if (err) { + printf(": failed to load xfer block, err=%d\n", err); + return (err); + } + + cb->xfer = xfer; + + s = splbio(); + TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain); + splx(s); + + cb++; + xfer++; + } + + return (0); +} + +static __inline void +oosiop_relocate_io(struct oosiop_softc *sc, bus_addr_t addr) +{ + u_int32_t dcmd; + int32_t dsps; + + dcmd = le32toh(sc->sc_scr[addr / 4 + 0]); + dsps = le32toh(sc->sc_scr[addr / 4 + 1]); + + /* convert relative to absolute */ + if (dcmd & 0x04000000) { + dcmd &= ~0x04000000; +#if 0 + /* + * sign extention isn't needed here because + * ncr53cxxx.c generates 32 bit dsps. + */ + dsps <<= 8; + dsps >>= 8; +#endif + sc->sc_scr[addr / 4 + 0] = htole32(dcmd); + dsps += addr + 8; + } + + sc->sc_scr[addr / 4 + 1] = htole32(dsps + sc->sc_scrbase); +} + +static __inline void +oosiop_relocate_tc(struct oosiop_softc *sc, bus_addr_t addr) +{ + u_int32_t dcmd; + int32_t dsps; + + dcmd = le32toh(sc->sc_scr[addr / 4 + 0]); + dsps = le32toh(sc->sc_scr[addr / 4 + 1]); + + /* convert relative to absolute */ + if (dcmd & 0x00800000) { + dcmd &= ~0x00800000; + sc->sc_scr[addr / 4] = htole32(dcmd); +#if 0 + /* + * sign extention isn't needed here because + * ncr53cxxx.c generates 32 bit dsps. + */ + dsps <<= 8; + dsps >>= 8; +#endif + dsps += addr + 8; + } + + sc->sc_scr[addr / 4 + 1] = htole32(dsps + sc->sc_scrbase); +} + +static __inline void +oosiop_fixup_select(struct oosiop_softc *sc, bus_addr_t addr, int id) +{ + u_int32_t dcmd; + + dcmd = le32toh(sc->sc_scr[addr / 4]); + dcmd &= 0xff00ffff; + dcmd |= 0x00010000 << id; + sc->sc_scr[addr / 4] = htole32(dcmd); +} + +static __inline void +oosiop_fixup_jump(struct oosiop_softc *sc, bus_addr_t addr, bus_addr_t dst) +{ + + sc->sc_scr[addr / 4 + 1] = htole32(dst); +} + +static __inline void +oosiop_fixup_move(struct oosiop_softc *sc, bus_addr_t addr, bus_size_t dbc, + bus_addr_t dsps) +{ + u_int32_t dcmd; + + dcmd = le32toh(sc->sc_scr[addr / 4]); + dcmd &= 0xff000000; + dcmd |= dbc & 0x00ffffff; + sc->sc_scr[addr / 4 + 0] = htole32(dcmd); + sc->sc_scr[addr / 4 + 1] = htole32(dsps); +} + +static void +oosiop_load_script(struct oosiop_softc *sc) +{ + int i; + + /* load script */ + for (i = 0; i < sizeof(oosiop_script) / sizeof(oosiop_script[0]); i++) + sc->sc_scr[i] = htole32(oosiop_script[i]); + + /* relocate script */ + for (i = 0; i < (sizeof(oosiop_script) / 8); i++) { + switch (oosiop_script[i * 2] >> 27) { + case 0x08: /* select */ + case 0x0a: /* wait reselect */ + oosiop_relocate_io(sc, i * 8); + break; + case 0x10: /* jump */ + case 0x11: /* call */ + oosiop_relocate_tc(sc, i * 8); + break; + } + } + + oosiop_fixup_move(sc, Ent_p_resel_msgin_move, 1, sc->sc_reselbuf); + OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE); +} + +static void +oosiop_setup_sgdma(struct oosiop_softc *sc, struct oosiop_cb *cb) +{ + int i, n, off; + struct oosiop_xfer *xfer; + + OOSIOP_XFERSCR_SYNC(sc, cb, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + + off = cb->curdp; + xfer = cb->xfer; + + /* Find start segment */ + if (cb->xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) { + for (i = 0; i < cb->datadma->dm_nsegs; i++) { + if (off < cb->datadma->dm_segs[i].ds_len) + break; + off -= cb->datadma->dm_segs[i].ds_len; + } + } + + /* build MOVE block */ + if (cb->xs->xs_control & XS_CTL_DATA_IN) { + n = 0; + while (i < cb->datadma->dm_nsegs) { + xfer->datain_scr[n * 2 + 0] = htole32(0x09000000 | + (cb->datadma->dm_segs[i].ds_len - off)); + xfer->datain_scr[n * 2 + 1] = + htole32(cb->datadma->dm_segs[i].ds_addr + off); + n++; + i++; + off = 0; + } + xfer->datain_scr[n * 2 + 0] = htole32(0x80080000); + xfer->datain_scr[n * 2 + 1] = + htole32(sc->sc_scrbase + Ent_phasedispatch); + } else { + xfer->datain_scr[0] = htole32(0x98080000); + xfer->datain_scr[1] = htole32(DATAIN_TRAP); + } + + if (cb->xs->xs_control & XS_CTL_DATA_OUT) { + n = 0; + while (i < cb->datadma->dm_nsegs) { + xfer->dataout_scr[n * 2 + 0] = htole32(0x08000000 | + (cb->datadma->dm_segs[i].ds_len - off)); + xfer->dataout_scr[n * 2 + 1] = + htole32(cb->datadma->dm_segs[i].ds_addr + off); + n++; + i++; + off = 0; + } + xfer->dataout_scr[n * 2 + 0] = htole32(0x80080000); + xfer->dataout_scr[n * 2 + 1] = + htole32(sc->sc_scrbase + Ent_phasedispatch); + } else { + xfer->dataout_scr[0] = htole32(0x98080000); + xfer->dataout_scr[1] = htole32(DATAOUT_TRAP); + } + OOSIOP_XFERSCR_SYNC(sc, cb, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); +} + +/* + * Setup DMA pointer into script. + */ +static void +oosiop_setup_dma(struct oosiop_softc *sc) +{ + struct oosiop_cb *cb; + bus_addr_t xferbase; + + cb = sc->sc_curcb; + xferbase = cb->xferdma->dm_segs[0].ds_addr; + + OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE); + + oosiop_fixup_select(sc, Ent_p_select, cb->id); + oosiop_fixup_jump(sc, Ent_p_datain_jump, xferbase + + offsetof(struct oosiop_xfer, datain_scr[0])); + oosiop_fixup_jump(sc, Ent_p_dataout_jump, xferbase + + offsetof(struct oosiop_xfer, dataout_scr[0])); + oosiop_fixup_move(sc, Ent_p_msgin_move, 1, xferbase + + offsetof(struct oosiop_xfer, msgin[0])); + oosiop_fixup_move(sc, Ent_p_extmsglen_move, 1, xferbase + + offsetof(struct oosiop_xfer, msgin[1])); + oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen, xferbase + + offsetof(struct oosiop_xfer, msgout[0])); + oosiop_fixup_move(sc, Ent_p_status_move, 1, xferbase + + offsetof(struct oosiop_xfer, status)); + oosiop_fixup_move(sc, Ent_p_cmdout_move, cb->xs->cmdlen, + cb->cmddma->dm_segs[0].ds_addr); + + OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE); +} + +static void +oosiop_flush_fifo(struct oosiop_softc *sc) +{ + + oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) | + OOSIOP_DFIFO_FLF); + while ((oosiop_read_1(sc, OOSIOP_CTEST1) & OOSIOP_CTEST1_FMT) != + OOSIOP_CTEST1_FMT) + ; + oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) & + ~OOSIOP_DFIFO_FLF); +} + +static void +oosiop_clear_fifo(struct oosiop_softc *sc) +{ + + oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) | + OOSIOP_DFIFO_CLF); + while ((oosiop_read_1(sc, OOSIOP_CTEST1) & OOSIOP_CTEST1_FMT) != + OOSIOP_CTEST1_FMT) + ; + oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) & + ~OOSIOP_DFIFO_CLF); +} + +static void +oosiop_phasemismatch(struct oosiop_softc *sc) +{ + struct oosiop_cb *cb; + u_int32_t dsp, dbc, n, i, len; + u_int8_t dfifo, sstat1; + + cb = sc->sc_curcb; + if (cb == NULL) + return; + + dsp = oosiop_read_4(sc, OOSIOP_DSP); + dbc = oosiop_read_4(sc, OOSIOP_DBC) & OOSIOP_DBC_MAX; + len = 0; + + n = dsp - cb->xferdma->dm_segs[0].ds_addr - 8; + if (n >= offsetof(struct oosiop_xfer, datain_scr[0]) && + n < offsetof(struct oosiop_xfer, datain_scr[OOSIOP_NSG * 2])) { + n -= offsetof(struct oosiop_xfer, datain_scr[0]); + n >>= 3; + OOSIOP_DINSCR_SYNC(sc, cb, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + for (i = 0; i <= n; i++) + len += le32toh(cb->xfer->datain_scr[i * 2]) & + 0x00ffffff; + OOSIOP_DINSCR_SYNC(sc, cb, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + /* All data in the chip are already flushed */ + } else if (n >= offsetof(struct oosiop_xfer, dataout_scr[0]) && + n < offsetof(struct oosiop_xfer, dataout_scr[OOSIOP_NSG * 2])) { + n -= offsetof(struct oosiop_xfer, dataout_scr[0]); + n >>= 3; + OOSIOP_DOUTSCR_SYNC(sc, cb, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + for (i = 0; i <= n; i++) + len += le32toh(cb->xfer->dataout_scr[i * 2]) & + 0x00ffffff; + OOSIOP_DOUTSCR_SYNC(sc, cb, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + dfifo = oosiop_read_1(sc, OOSIOP_DFIFO); + dbc += ((dfifo & OOSIOP_DFIFO_BO) - (dbc & OOSIOP_DFIFO_BO)) & + OOSIOP_DFIFO_BO; + + sstat1 = oosiop_read_1(sc, OOSIOP_SSTAT1); + if (sstat1 & OOSIOP_SSTAT1_OLF) + dbc++; + if ((sc->sc_tgt[cb->id].sxfer != 0) && + (sstat1 & OOSIOP_SSTAT1_ORF) != 0) + dbc++; + + oosiop_clear_fifo(sc); + } else { + printf("%s: phase mismatch addr=%08x\n", sc->sc_dev.dv_xname, + oosiop_read_4(sc, OOSIOP_DSP) - 8); + oosiop_clear_fifo(sc); + return; + } + + len -= dbc; + if (len) { + cb->curdp += len; + oosiop_setup_sgdma(sc, cb); + } +} + +static void +oosiop_setup_syncxfer(struct oosiop_softc *sc) +{ + int id; + + id = sc->sc_curcb->id; + if (sc->sc_chip != OOSIOP_700) + oosiop_write_1(sc, OOSIOP_SBCL, sc->sc_tgt[id].scf); + + oosiop_write_1(sc, OOSIOP_SXFER, sc->sc_tgt[id].sxfer); +} + +static void +oosiop_set_syncparam(struct oosiop_softc *sc, int id, int period, int offset) +{ + int i, p; + struct scsipi_xfer_mode xm; + + xm.xm_target = id; + xm.xm_mode = 0; + xm.xm_period = 0; + xm.xm_offset = 0; + + if (offset == 0) { + /* Asynchronous */ + sc->sc_tgt[id].scf = 0; + sc->sc_tgt[id].sxfer = 0; + } else { + /* Synchronous */ + if (sc->sc_chip == OOSIOP_700) { + for (i = 4; i < 12; i++) { + p = oosiop_period(sc, i, sc->sc_ccf); + if (p >= period) + break; + } + if (i == 12) { + printf("%s: target %d period too large\n", + sc->sc_dev.dv_xname, id); + i = 11; /* XXX */ + } + sc->sc_tgt[id].scf = 0; + sc->sc_tgt[id].sxfer = ((i - 4) << 4) | offset; + } else { + for (i = 0; i < NSYNCTBL; i++) { + p = oosiop_period(sc, synctbl[i].tp + 4, + (synctbl[i].scf + 1) * 5); + if (p >= period) + break; + } + if (i == NSYNCTBL) { + printf("%s: target %d period too large\n", + sc->sc_dev.dv_xname, id); + i = NSYNCTBL - 1; /* XXX */ + } + sc->sc_tgt[id].scf = synctbl[i].scf; + sc->sc_tgt[id].sxfer = (synctbl[i].tp << 4) | offset; + } + + xm.xm_mode |= PERIPH_CAP_SYNC; + xm.xm_period = period; + xm.xm_offset = offset; + } + + scsipi_async_event(&sc->sc_channel, ASYNC_EVENT_XFER_MODE, &xm); +} + +static void +oosiop_minphys(struct buf *bp) +{ + + if (bp->b_bcount > OOSIOP_MAX_XFER) + bp->b_bcount = OOSIOP_MAX_XFER; + minphys(bp); +} + +static void +oosiop_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req, + void *arg) +{ + struct scsipi_xfer *xs; + struct oosiop_softc *sc; + struct oosiop_cb *cb; + struct oosiop_xfer *xfer; + struct scsipi_xfer_mode *xm; + int s, err; + + sc = (struct oosiop_softc *)chan->chan_adapter->adapt_dev; + + switch (req) { + case ADAPTER_REQ_RUN_XFER: + xs = arg; + + s = splbio(); + cb = TAILQ_FIRST(&sc->sc_free_cb); + TAILQ_REMOVE(&sc->sc_free_cb, cb, chain); + splx(s); + + cb->xs = xs; + cb->flags = 0; + cb->id = xs->xs_periph->periph_target; + cb->lun = xs->xs_periph->periph_lun; + cb->curdp = 0; + cb->savedp = 0; + xfer = cb->xfer; + + /* Setup SCSI command buffer DMA */ + err = bus_dmamap_load(sc->sc_dmat, cb->cmddma, xs->cmd, + xs->cmdlen, NULL, ((xs->xs_control & XS_CTL_NOSLEEP) ? + BUS_DMA_NOWAIT : BUS_DMA_WAITOK) | BUS_DMA_WRITE); + if (err) { + printf("%s: unable to load cmd DMA map: %d", + sc->sc_dev.dv_xname, err); + xs->error = XS_RESOURCE_SHORTAGE; + TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain); + scsipi_done(xs); + return; + } + bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, xs->cmdlen, + BUS_DMASYNC_PREWRITE); + + /* Setup data buffer DMA */ + if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) { + err = bus_dmamap_load(sc->sc_dmat, cb->datadma, + xs->data, xs->datalen, NULL, + ((xs->xs_control & XS_CTL_NOSLEEP) ? + BUS_DMA_NOWAIT : BUS_DMA_WAITOK) | + BUS_DMA_STREAMING | + ((xs->xs_control & XS_CTL_DATA_IN) ? BUS_DMA_READ : + BUS_DMA_WRITE)); + if (err) { + printf("%s: unable to load data DMA map: %d", + sc->sc_dev.dv_xname, err); + xs->error = XS_RESOURCE_SHORTAGE; + bus_dmamap_unload(sc->sc_dmat, cb->cmddma); + TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain); + scsipi_done(xs); + return; + } + bus_dmamap_sync(sc->sc_dmat, cb->datadma, + 0, xs->datalen, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + } + + oosiop_setup_sgdma(sc, cb); + + /* Setup msgout buffer */ + OOSIOP_XFERMSG_SYNC(sc, cb, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + xfer->msgout[0] = MSG_IDENTIFY(cb->lun, + (xs->xs_control & XS_CTL_REQSENSE) == 0); + cb->msgoutlen = 1; + + if (sc->sc_tgt[cb->id].flags & TGTF_SYNCNEG) { + /* Send SDTR */ + xfer->msgout[1] = MSG_EXTENDED; + xfer->msgout[2] = MSG_EXT_SDTR_LEN; + xfer->msgout[3] = MSG_EXT_SDTR; + xfer->msgout[4] = sc->sc_minperiod; + xfer->msgout[5] = OOSIOP_MAX_OFFSET; + cb->msgoutlen = 6; + sc->sc_tgt[cb->id].flags &= ~TGTF_SYNCNEG; + sc->sc_tgt[cb->id].flags |= TGTF_WAITSDTR; + } + + xfer->status = SCSI_OOSIOP_NOSTATUS; + + OOSIOP_XFERMSG_SYNC(sc, cb, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + s = splbio(); + + TAILQ_INSERT_TAIL(&sc->sc_cbq, cb, chain); + + if (!sc->sc_active) { + /* Abort script to start selection */ + oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT); + } + if (xs->xs_control & XS_CTL_POLL) { + /* Poll for command completion */ + while ((xs->xs_status & XS_STS_DONE) == 0) { + delay(1000); + oosiop_intr(sc); + } + } + + splx(s); + + return; + + case ADAPTER_REQ_GROW_RESOURCES: + return; + + case ADAPTER_REQ_SET_XFER_MODE: + xm = arg; + if (xm->xm_mode & PERIPH_CAP_SYNC) + sc->sc_tgt[xm->xm_target].flags |= TGTF_SYNCNEG; + else + oosiop_set_syncparam(sc, xm->xm_target, 0, 0); + + return; + } +} + +static void +oosiop_done(struct oosiop_softc *sc, struct oosiop_cb *cb) +{ + struct scsipi_xfer *xs; + + xs = cb->xs; + if (cb == sc->sc_curcb) + sc->sc_curcb = NULL; + if (cb == sc->sc_lastcb) + sc->sc_lastcb = NULL; + sc->sc_tgt[cb->id].nexus = NULL; + + callout_stop(&xs->xs_callout); + + bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, xs->cmdlen, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dmat, cb->cmddma); + + if (xs->datalen > 0) { + bus_dmamap_sync(sc->sc_dmat, cb->datadma, 0, xs->datalen, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dmat, cb->datadma); + } + + xs->status = cb->xfer->status; + xs->resid = 0; /* XXX */ + + if (cb->flags & CBF_SELTOUT) + xs->error = XS_SELTIMEOUT; + else if (cb->flags & CBF_TIMEOUT) + xs->error = XS_TIMEOUT; + else switch (xs->status) { + case SCSI_OK: + xs->error = XS_NOERROR; + break; + + case SCSI_BUSY: + case SCSI_CHECK: + xs->error = XS_BUSY; + break; + case SCSI_OOSIOP_NOSTATUS: + /* the status byte was not updated, cmd was aborted. */ + xs->error = XS_SELTIMEOUT; + break; + + default: + xs->error = XS_RESET; + break; + } + + scsipi_done(xs); + + /* Put it on the free list. */ + TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain); +} + +static void +oosiop_timeout(void *arg) +{ + struct oosiop_cb *cb; + struct scsipi_periph *periph; + struct oosiop_softc *sc; + int s; + + cb = arg; + periph = cb->xs->xs_periph; + sc = (void *)periph->periph_channel->chan_adapter->adapt_dev; + scsipi_printaddr(periph); + printf("timed out\n"); + + s = splbio(); + + cb->flags |= CBF_TIMEOUT; + oosiop_done(sc, cb); + + splx(s); +} + +static void +oosiop_reset(struct oosiop_softc *sc) +{ + int i, s; + + s = splbio(); + + /* Stop SCRIPTS processor */ + oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT); + delay(100); + oosiop_write_1(sc, OOSIOP_ISTAT, 0); + + /* Reset the chip */ + oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl | OOSIOP_DCNTL_RST); + delay(100); + oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl); + delay(10000); + + /* Set up various chip parameters */ + oosiop_write_1(sc, OOSIOP_SCNTL0, OOSIOP_ARB_FULL | OOSIOP_SCNTL0_EPG); + oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_ESR); + oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl); + oosiop_write_1(sc, OOSIOP_DMODE, OOSIOP_DMODE_BL_8); + oosiop_write_1(sc, OOSIOP_SCID, OOSIOP_SCID_VALUE(sc->sc_id)); + oosiop_write_1(sc, OOSIOP_DWT, 0xff); /* Enable DMA timeout */ + oosiop_write_1(sc, OOSIOP_CTEST7, 0); + oosiop_write_1(sc, OOSIOP_SXFER, 0); + + /* Clear all interrupts */ + (void)oosiop_read_1(sc, OOSIOP_SSTAT0); + (void)oosiop_read_1(sc, OOSIOP_SSTAT1); + (void)oosiop_read_1(sc, OOSIOP_DSTAT); + + /* Enable interrupts */ + oosiop_write_1(sc, OOSIOP_SIEN, + OOSIOP_SIEN_M_A | OOSIOP_SIEN_STO | OOSIOP_SIEN_SGE | + OOSIOP_SIEN_UDC | OOSIOP_SIEN_RST | OOSIOP_SIEN_PAR); + oosiop_write_1(sc, OOSIOP_DIEN, + OOSIOP_DIEN_ABRT | OOSIOP_DIEN_SSI | OOSIOP_DIEN_SIR | + OOSIOP_DIEN_WTD | OOSIOP_DIEN_IID); + + /* Set target state to asynchronous */ + for (i = 0; i < OOSIOP_NTGT; i++) { + sc->sc_tgt[i].flags = 0; + sc->sc_tgt[i].scf = 0; + sc->sc_tgt[i].sxfer = 0; + } + + splx(s); +} + +static void +oosiop_reset_bus(struct oosiop_softc *sc) +{ + int s, i; + + s = splbio(); + + /* Assert SCSI RST */ + oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_RST); + delay(25); /* Reset hold time (25us) */ + oosiop_write_1(sc, OOSIOP_SCNTL1, 0); + + /* Remove all nexuses */ + for (i = 0; i < OOSIOP_NTGT; i++) { + if (sc->sc_tgt[i].nexus) { + sc->sc_tgt[i].nexus->xfer->status = + SCSI_OOSIOP_NOSTATUS; /* XXX */ + oosiop_done(sc, sc->sc_tgt[i].nexus); + } + } + + sc->sc_curcb = NULL; + + delay(250000); /* Reset to selection (250ms) */ + + splx(s); +} + +/* + * interrupt handler + */ +int +oosiop_intr(struct oosiop_softc *sc) +{ + struct oosiop_cb *cb; + u_int32_t dcmd; + int timeout; + u_int8_t istat, dstat, sstat0; + + istat = oosiop_read_1(sc, OOSIOP_ISTAT); + + if ((istat & (OOSIOP_ISTAT_SIP | OOSIOP_ISTAT_DIP)) == 0) + return (0); + + sc->sc_nextdsp = Ent_wait_reselect; + + /* DMA interrupts */ + if (istat & OOSIOP_ISTAT_DIP) { + oosiop_write_1(sc, OOSIOP_ISTAT, 0); + + dstat = oosiop_read_1(sc, OOSIOP_DSTAT); + + if (dstat & OOSIOP_DSTAT_ABRT) { + sc->sc_nextdsp = oosiop_read_4(sc, OOSIOP_DSP) - + sc->sc_scrbase - 8; + + if (sc->sc_nextdsp == Ent_p_resel_msgin_move && + (oosiop_read_1(sc, OOSIOP_SBCL) & OOSIOP_ACK)) { + if ((dstat & OOSIOP_DSTAT_DFE) == 0) + oosiop_flush_fifo(sc); + sc->sc_nextdsp += 8; + } + } + + if (dstat & OOSIOP_DSTAT_SSI) { + sc->sc_nextdsp = oosiop_read_4(sc, OOSIOP_DSP) - + sc->sc_scrbase; + printf("%s: single step %08x\n", sc->sc_dev.dv_xname, + sc->sc_nextdsp); + } + + if (dstat & OOSIOP_DSTAT_SIR) { + if ((dstat & OOSIOP_DSTAT_DFE) == 0) + oosiop_flush_fifo(sc); + oosiop_scriptintr(sc); + } + + if (dstat & OOSIOP_DSTAT_WTD) { + printf("%s: DMA time out\n", sc->sc_dev.dv_xname); + oosiop_reset(sc); + } + + if (dstat & OOSIOP_DSTAT_IID) { + dcmd = oosiop_read_4(sc, OOSIOP_DBC); + if ((dcmd & 0xf8000000) == 0x48000000) { + printf("%s: REQ asserted on WAIT DISCONNECT\n", + sc->sc_dev.dv_xname); + sc->sc_nextdsp = Ent_phasedispatch; /* XXX */ + } else { + printf("%s: invalid SCRIPTS instruction " + "addr=%08x dcmd=%08x dsps=%08x\n", + sc->sc_dev.dv_xname, + oosiop_read_4(sc, OOSIOP_DSP) - 8, dcmd, + oosiop_read_4(sc, OOSIOP_DSPS)); + oosiop_reset(sc); + OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE); + oosiop_load_script(sc); + } + } + + if ((dstat & OOSIOP_DSTAT_DFE) == 0) + oosiop_clear_fifo(sc); + } + + /* SCSI interrupts */ + if (istat & OOSIOP_ISTAT_SIP) { + if (istat & OOSIOP_ISTAT_DIP) + delay(1); + sstat0 = oosiop_read_1(sc, OOSIOP_SSTAT0); + + if (sstat0 & OOSIOP_SSTAT0_M_A) { + /* SCSI phase mismatch during MOVE operation */ + oosiop_phasemismatch(sc); + sc->sc_nextdsp = Ent_phasedispatch; + } + + if (sstat0 & OOSIOP_SSTAT0_STO) { + if (sc->sc_curcb) { + sc->sc_curcb->flags |= CBF_SELTOUT; + oosiop_done(sc, sc->sc_curcb); + } + } + + if (sstat0 & OOSIOP_SSTAT0_SGE) { + printf("%s: SCSI gross error\n", sc->sc_dev.dv_xname); + oosiop_reset(sc); + } + + if (sstat0 & OOSIOP_SSTAT0_UDC) { + /* XXX */ + if (sc->sc_curcb) { + printf("%s: unexpected disconnect\n", + sc->sc_dev.dv_xname); + oosiop_done(sc, sc->sc_curcb); + } + } + + if (sstat0 & OOSIOP_SSTAT0_RST) + oosiop_reset(sc); + + if (sstat0 & OOSIOP_SSTAT0_PAR) + printf("%s: parity error\n", sc->sc_dev.dv_xname); + } + + /* Start next command if available */ + if (sc->sc_nextdsp == Ent_wait_reselect && TAILQ_FIRST(&sc->sc_cbq)) { + cb = sc->sc_curcb = TAILQ_FIRST(&sc->sc_cbq); + TAILQ_REMOVE(&sc->sc_cbq, cb, chain); + sc->sc_tgt[cb->id].nexus = cb; + + oosiop_setup_dma(sc); + oosiop_setup_syncxfer(sc); + sc->sc_lastcb = cb; + sc->sc_nextdsp = Ent_start_select; + + /* Schedule timeout */ + if ((cb->xs->xs_control & XS_CTL_POLL) == 0) { + timeout = mstohz(cb->xs->timeout) + 1; + callout_reset(&cb->xs->xs_callout, timeout, + oosiop_timeout, cb); + } + } + + sc->sc_active = (sc->sc_nextdsp != Ent_wait_reselect); + + /* Restart script */ + oosiop_write_4(sc, OOSIOP_DSP, sc->sc_nextdsp + sc->sc_scrbase); + + return (1); +} + +static void +oosiop_scriptintr(struct oosiop_softc *sc) +{ + struct oosiop_cb *cb; + u_int32_t icode; + u_int32_t dsp; + int i; + u_int8_t sfbr, resid, resmsg; + + cb = sc->sc_curcb; + icode = oosiop_read_4(sc, OOSIOP_DSPS); + + switch (icode) { + case A_int_done: + if (cb) + oosiop_done(sc, cb); + break; + + case A_int_msgin: + if (cb) + oosiop_msgin(sc, cb); + break; + + case A_int_extmsg: + /* extended message in DMA setup request */ + sfbr = oosiop_read_1(sc, OOSIOP_SFBR); + OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE); + oosiop_fixup_move(sc, Ent_p_extmsgin_move, sfbr, + cb->xferdma->dm_segs[0].ds_addr + + offsetof(struct oosiop_xfer, msgin[2])); + OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE); + sc->sc_nextdsp = Ent_rcv_extmsg; + break; + + case A_int_resel: + /* reselected */ + resid = oosiop_read_1(sc, OOSIOP_SFBR); + for (i = 0; i < OOSIOP_NTGT; i++) + if (resid & (1 << i)) + break; + if (i == OOSIOP_NTGT) { + printf("%s: missing reselection target id\n", + sc->sc_dev.dv_xname); + break; + } + sc->sc_resid = i; + sc->sc_nextdsp = Ent_wait_resel_identify; + + if (cb) { + /* Current command was lost arbitration */ + sc->sc_tgt[cb->id].nexus = NULL; + TAILQ_INSERT_HEAD(&sc->sc_cbq, cb, chain); + sc->sc_curcb = NULL; + } + + break; + + case A_int_res_id: + cb = sc->sc_tgt[sc->sc_resid].nexus; + resmsg = oosiop_read_1(sc, OOSIOP_SFBR); + if (MSG_ISIDENTIFY(resmsg) && cb && + (resmsg & MSG_IDENTIFY_LUNMASK) == cb->lun) { + sc->sc_curcb = cb; + if (cb != sc->sc_lastcb) { + oosiop_setup_dma(sc); + oosiop_setup_syncxfer(sc); + sc->sc_lastcb = cb; + } + if (cb->curdp != cb->savedp) { + cb->curdp = cb->savedp; + oosiop_setup_sgdma(sc, cb); + } + sc->sc_nextdsp = Ent_ack_msgin; + } else { + /* Reselection from invalid target */ + oosiop_reset_bus(sc); + } + break; + + case A_int_resfail: + /* reselect failed */ + break; + + case A_int_disc: + /* disconnected */ + sc->sc_curcb = NULL; + break; + + case A_int_err: + /* generic error */ + dsp = oosiop_read_4(sc, OOSIOP_DSP); + printf("%s: script error at 0x%08x\n", sc->sc_dev.dv_xname, + dsp - 8); + sc->sc_curcb = NULL; + break; + + case DATAIN_TRAP: + printf("%s: unexpected datain\n", sc->sc_dev.dv_xname); + /* XXX: need to reset? */ + break; + + case DATAOUT_TRAP: + printf("%s: unexpected dataout\n", sc->sc_dev.dv_xname); + /* XXX: need to reset? */ + break; + + default: + printf("%s: unknown intr code %08x\n", sc->sc_dev.dv_xname, + icode); + break; + } +} + +static void +oosiop_msgin(struct oosiop_softc *sc, struct oosiop_cb *cb) +{ + struct oosiop_xfer *xfer; + int msgout; + + xfer = cb->xfer; + sc->sc_nextdsp = Ent_ack_msgin; + msgout = 0; + + OOSIOP_XFERMSG_SYNC(sc, cb, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + + switch (xfer->msgin[0]) { + case MSG_EXTENDED: + switch (xfer->msgin[2]) { + case MSG_EXT_SDTR: + if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) { + /* Host initiated SDTR */ + sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR; + } else { + /* Target initiated SDTR */ + if (xfer->msgin[3] < sc->sc_minperiod) + xfer->msgin[3] = sc->sc_minperiod; + if (xfer->msgin[4] > OOSIOP_MAX_OFFSET) + xfer->msgin[4] = OOSIOP_MAX_OFFSET; + xfer->msgout[0] = MSG_EXTENDED; + xfer->msgout[1] = MSG_EXT_SDTR_LEN; + xfer->msgout[2] = MSG_EXT_SDTR; + xfer->msgout[3] = xfer->msgin[3]; + xfer->msgout[4] = xfer->msgin[4]; + cb->msgoutlen = 5; + msgout = 1; + } + oosiop_set_syncparam(sc, cb->id, (int)xfer->msgin[3], + (int)xfer->msgin[4]); + oosiop_setup_syncxfer(sc); + break; + + default: + /* Reject message */ + xfer->msgout[0] = MSG_MESSAGE_REJECT; + cb->msgoutlen = 1; + msgout = 1; + break; + } + break; + + case MSG_SAVEDATAPOINTER: + cb->savedp = cb->curdp; + break; + + case MSG_RESTOREPOINTERS: + if (cb->curdp != cb->savedp) { + cb->curdp = cb->savedp; + oosiop_setup_sgdma(sc, cb); + } + break; + + case MSG_MESSAGE_REJECT: + if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) { + /* SDTR rejected */ + sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR; + oosiop_set_syncparam(sc, cb->id, 0, 0); + oosiop_setup_syncxfer(sc); + } + break; + + default: + /* Reject message */ + xfer->msgout[0] = MSG_MESSAGE_REJECT; + cb->msgoutlen = 1; + msgout = 1; + } + + OOSIOP_XFERMSG_SYNC(sc, cb, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + if (msgout) { + OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE); + oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen, + cb->xferdma->dm_segs[0].ds_addr + + offsetof(struct oosiop_xfer, msgout[0])); + OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE); + sc->sc_nextdsp = Ent_sendmsg; + } +} diff --git a/sys/dev/ic/oosiopreg.h b/sys/dev/ic/oosiopreg.h new file mode 100644 index 000000000000..6f6499c9fb42 --- /dev/null +++ b/sys/dev/ic/oosiopreg.h @@ -0,0 +1,327 @@ +/* $NetBSD: oosiopreg.h,v 1.1 2003/04/06 09:48:43 tsutsui Exp $ */ + +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Van Jacobson of Lawrence Berkeley Laboratory. + * + * 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. + * + * @(#)siopreg.h 7.3 (Berkeley) 2/5/91 + */ + +/* + * NCR 53C700 SCSI interface hardware description. + * + * From the Mach scsi driver for the 53C700 and amiga siop driver + */ + +#define OOSIOP_SCNTL0 0x00 /* rw: SCSI control reg 0 */ +#define OOSIOP_SCNTL1 0x01 /* rw: SCSI control reg 1 */ +#define OOSIOP_SDID 0x02 /* rw: SCSI destination ID */ +#define OOSIOP_SIEN 0x03 /* rw: SCSI interrupt enable */ +#define OOSIOP_SCID 0x04 /* rw: SCSI Chip ID reg */ +#define OOSIOP_SXFER 0x05 /* rw: SCSI Transfer reg */ +#define OOSIOP_SODL 0x06 /* rw: SCSI Output Data Latch */ +#define OOSIOP_SOCL 0x07 /* rw: SCSI Output Control Latch */ +#define OOSIOP_SFBR 0x08 /* ro: SCSI First Byte Received */ +#define OOSIOP_SIDL 0x09 /* ro: SCSI Input Data Latch */ +#define OOSIOP_SBDL 0x0a /* ro: SCSI Bus Data Lines */ +#define OOSIOP_SBCL 0x0b /* rw: SCSI Bus Control Lines */ +#define OOSIOP_DSTAT 0x0c /* ro: DMA status */ +#define OOSIOP_SSTAT0 0x0d /* ro: SCSI status reg 0 */ +#define OOSIOP_SSTAT1 0x0e /* ro: SCSI status reg 1 */ +#define OOSIOP_SSTAT2 0x0f /* ro: SCSI status reg 2 */ +#define OOSIOP_SCRA0 0x10 /* rw: Scratch A */ +#define OOSIOP_SCRA1 0x11 +#define OOSIOP_SCRA2 0x12 +#define OOSIOP_SCRA3 0x13 +#define OOSIOP_CTEST0 0x14 /* ro: Chip test register 0 */ +#define OOSIOP_CTEST1 0x15 /* ro: Chip test register 1 */ +#define OOSIOP_CTEST2 0x16 /* ro: Chip test register 2 */ +#define OOSIOP_CTEST3 0x17 /* ro: Chip test register 3 */ +#define OOSIOP_CTEST4 0x18 /* rw: Chip test register 4 */ +#define OOSIOP_CTEST5 0x19 /* rw: Chip test register 5 */ +#define OOSIOP_CTEST6 0x1a /* rw: Chip test register 6 */ +#define OOSIOP_CTEST7 0x1b /* rw: Chip test register 7 */ +#define OOSIOP_TEMP 0x1c /* rw: Temporary Stack reg */ +#define OOSIOP_DFIFO 0x20 /* rw: DMA FIFO */ +#define OOSIOP_ISTAT 0x21 /* rw: Interrupt Status reg */ +#define OOSIOP_CTEST8 0x22 /* rw: Chip test register 8 */ +#define OOSIOP_CTEST9 0x23 /* ro: Chip test register 9 */ +#define OOSIOP_DBC 0x24 /* rw: DMA Byte Counter reg */ +#define OOSIOP_DCMD 0x27 /* rw: DMA Command Register */ +#define OOSIOP_DNAD 0x28 /* rw: DMA Next Address */ +#define OOSIOP_DSP 0x2c /* rw: DMA SCRIPTS Pointer reg */ +#define OOSIOP_DSPS 0x30 /* rw: DMA SCRIPTS Pointer Save reg */ +#define OOSIOP_DMODE 0x34 /* rw: DMA Mode reg */ +#define OOSIOP_RES35 0x35 +#define OOSIOP_RES36 0x36 +#define OOSIOP_RES37 0x37 +#define OOSIOP_RES38 0x38 +#define OOSIOP_DIEN 0x39 /* rw: DMA Interrupt Enable */ +#define OOSIOP_DWT 0x3a /* rw: DMA Watchdog Timer */ +#define OOSIOP_DCNTL 0x3b /* rw: DMA Control reg */ +#define OOSIOP_SCRB0 0x3c /* rw: Scratch B */ +#define OOSIOP_SCRB1 0x3d +#define OOSIOP_SCRB2 0x3e +#define OOSIOP_SCRB3 0x3f + +#define OOSIOP_NREGS 0x40 + + +/* + * Register defines + */ + +/* Scsi control register 0 (scntl0) */ + +#define OOSIOP_SCNTL0_ARB 0xc0 /* Arbitration mode */ +#define OOSIOP_ARB_SIMPLE 0x00 +#define OOSIOP_ARB_FULL 0xc0 +#define OOSIOP_SCNTL0_START 0x20 /* Start Sequence */ +#define OOSIOP_SCNTL0_WATN 0x10 /* (Select) With ATN */ +#define OOSIOP_SCNTL0_EPC 0x08 /* Enable Parity Checking */ +#define OOSIOP_SCNTL0_EPG 0x04 /* Enable Parity Generation */ +#define OOSIOP_SCNTL0_AAP 0x02 /* Assert ATN on Parity Error */ +#define OOSIOP_SCNTL0_TRG 0x01 /* Target Mode */ + +/* Scsi control register 1 (scntl1) */ + +#define OOSIOP_SCNTL1_EXC 0x80 /* Extra Clock Cycle of data setup */ +#define OOSIOP_SCNTL1_ADB 0x40 /* Assert Data Bus */ +#define OOSIOP_SCNTL1_ESR 0x20 /* Enable Selection/Reselection */ +#define OOSIOP_SCNTL1_CON 0x10 /* Connected */ +#define OOSIOP_SCNTL1_RST 0x08 /* Assert RST */ +#define OOSIOP_SCNTL1_AESP 0x04 /* Assert even SCSI parity */ +#define OOSIOP_SCNTL1_SND 0x02 /* Start Send operation */ +#define OOSIOP_SCNTL1_RCV 0x01 /* Start Receive operation */ + +/* Scsi interrupt enable register (sien) */ + +#define OOSIOP_SIEN_M_A 0x80 /* Phase Mismatch or ATN active */ +#define OOSIOP_SIEN_FC 0x40 /* Function Complete */ +#define OOSIOP_SIEN_STO 0x20 /* (Re)Selection timeout */ +#define OOSIOP_SIEN_SEL 0x10 /* (Re)Selected */ +#define OOSIOP_SIEN_SGE 0x08 /* SCSI Gross Error */ +#define OOSIOP_SIEN_UDC 0x04 /* Unexpected Disconnect */ +#define OOSIOP_SIEN_RST 0x02 /* RST asserted */ +#define OOSIOP_SIEN_PAR 0x01 /* Parity Error */ + +/* Scsi chip ID (scid) */ + +#define OOSIOP_SCID_VALUE(i) (1 << i) + +/* Scsi transfer register (sxfer) */ + +#define OOSIOP_SXFER_DHP 0x80 /* Disable Halt on Parity error/ + ATN asserted */ +#define OOSIOP_SXFER_TP 0x70 /* Synch Transfer Period */ + /* see specs for formulas: + Period = TCP * (4 + XFERP ) + TCP = 1 + CLK + 1..2; + */ +#define OOSIOP_SXFER_MO 0x0f /* Synch Max Offset */ +#define OOSIOP_MAX_OFFSET 8 + +/* Scsi output data latch register (sodl) */ + +/* Scsi output control latch register (socl) */ + +#define OOSIOP_REQ 0x80 /* SCSI signal asserted */ +#define OOSIOP_ACK 0x40 +#define OOSIOP_BSY 0x20 +#define OOSIOP_SEL 0x10 +#define OOSIOP_ATN 0x08 +#define OOSIOP_MSG 0x04 +#define OOSIOP_CD 0x02 +#define OOSIOP_IO 0x01 + +#define OOSIOP_PHASE(socl) SCSI_PHASE(socl) + +/* Scsi first byte received register (sfbr) */ + +/* Scsi input data latch register (sidl) */ + +/* Scsi bus data lines register (sbdl) */ + +/* Scsi bus control lines register (sbcl). Same as socl */ + +#define OOSIOP_SBCL_SSCF1 0x02 /* wo */ +#define OOSIOP_SBCL_SSCF0 0x01 /* wo */ + +/* DMA status register (dstat) */ + +#define OOSIOP_DSTAT_DFE 0x80 /* DMA FIFO empty */ +#define OOSIOP_DSTAT_ABRT 0x10 /* Aborted */ +#define OOSIOP_DSTAT_SSI 0x08 /* SCRIPT Single Step */ +#define OOSIOP_DSTAT_SIR 0x04 /* SCRIPT Interrupt Instruction */ +#define OOSIOP_DSTAT_WTD 0x02 /* Watchdog Timeout Detected */ +#define OOSIOP_DSTAT_IID 0x01 /* Invalid Instruction Detected */ + +/* Scsi status register 0 (sstat0) */ + +#define OOSIOP_SSTAT0_M_A 0x80 /* Phase Mismatch or ATN active */ +#define OOSIOP_SSTAT0_FC 0x40 /* Function Complete */ +#define OOSIOP_SSTAT0_STO 0x20 /* (Re)Selection timeout */ +#define OOSIOP_SSTAT0_SEL 0x10 /* (Re)Selected */ +#define OOSIOP_SSTAT0_SGE 0x08 /* SCSI Gross Error */ +#define OOSIOP_SSTAT0_UDC 0x04 /* Unexpected Disconnect */ +#define OOSIOP_SSTAT0_RST 0x02 /* RST asserted */ +#define OOSIOP_SSTAT0_PAR 0x01 /* Parity Error */ + +/* Scsi status register 1 (sstat1) */ + +#define OOSIOP_SSTAT1_ILF 0x80 /* Input latch (sidl) full */ +#define OOSIOP_SSTAT1_ORF 0x40 /* output reg (sodr) full */ +#define OOSIOP_SSTAT1_OLF 0x20 /* output latch (sodl) full */ +#define OOSIOP_SSTAT1_AIP 0x10 /* Arbitration in progress */ +#define OOSIOP_SSTAT1_LOA 0x08 /* Lost arbitration */ +#define OOSIOP_SSTAT1_WOA 0x04 /* Won arbitration */ +#define OOSIOP_SSTAT1_RST 0x02 /* SCSI RST current value */ +#define OOSIOP_SSTAT1_SDP 0x01 /* SCSI SDP current value */ + +/* Scsi status register 2 (sstat2) */ + +#define OOSIOP_SSTAT2_FF 0xf0 /* SCSI FIFO flags (bytecount) */ +#define OOSIOP_SCSI_FIFO_DEEP 8 +#define OOSIOP_SSTAT2_SDP 0x08 /* Latched (on REQ) SCSI SDP */ +#define OOSIOP_SSTAT2_MSG 0x04 /* Latched SCSI phase */ +#define OOSIOP_SSTAT2_CD 0x02 +#define OOSIOP_SSTAT2_IO 0x01 + +/* Chip test register 0 (ctest0) */ + +#define OOSIOP_CTEST0_RTRG 0x02 /* Real Target Mode */ +#define OOSIOP_CTEST0_DDIR 0x01 /* Xfer direction (1-> from SCSI bus) */ + +/* Chip test register 1 (ctest1) */ + +#define OOSIOP_CTEST1_FMT 0xf0 /* Byte empty in DMA FIFO bottom + (high->byte3) */ +#define OOSIOP_CTEST1_FFL 0x0f /* Byte full in DMA FIFO top, same */ + +/* Chip test register 2 (ctest2) */ + +#define OOSIOP_CTEST2_SOFF 0x20 /* Synch Offset compare + (1-> zero Init, max Tgt) */ +#define OOSIOP_CTEST2_SFP 0x10 /* SCSI FIFO Parity */ +#define OOSIOP_CTEST2_DFP 0x08 /* DMA FIFO Parity */ +#define OOSIOP_CTEST2_TEOP 0x04 /* True EOP (a-la 5380) */ +#define OOSIOP_CTEST2_DREQ 0x02 /* DREQ status */ +#define OOSIOP_CTEST2_DACK 0x01 /* DACK status */ + +/* Chip test register 3 (ctest3) read-only, top of SCSI FIFO */ + +/* Chip test register 4 (ctest4) */ + +#define OOSIOP_CTEST4_ZMOD 0x40 /* High-impedance outputs */ +#define OOSIOP_CTEST4_SZM 0x20 /* ditto, SCSI "outputs" */ +#define OOSIOP_CTEST4_SLBE 0x10 /* SCSI loobpack enable */ +#define OOSIOP_CTEST4_SFWR 0x08 /* SCSI FIFO write enable (from sodl) */ +#define OOSIOP_CTEST4_FBL 0x07 /* DMA FIFO Byte Lane select + (from ctest6) 4->0, .. 7->3 */ + +/* Chip test register 5 (ctest5) */ + +#define OOSIOP_CTEST5_ADCK 0x80 /* Clock Address Incrementor */ +#define OOSIOP_CTEST5_BBCK 0x40 /* Clock Byte counter */ +#define OOSIOP_CTEST5_ROFF 0x20 /* Reset SCSI offset */ +#define OOSIOP_CTEST5_MASR 0x10 /* Master set/reset pulses + (of bits 3-0) */ +#define OOSIOP_CTEST5_DDIR 0x08 /* (re)set internal DMA direction */ +#define OOSIOP_CTEST5_EOP 0x04 /* (re)set internal EOP */ +#define OOSIOP_CTEST5_DREQ 0x02 /* (re)set internal REQ */ +#define OOSIOP_CTEST5_DACK 0x01 /* (re)set internal ACK */ + +/* Chip test register 6 (ctest6) DMA FIFO access */ + +/* Chip test register 7 (ctest7) */ + +#define OOSIOP_CTEST7_STD 0x10 /* Selection timeout disable */ +#define OOSIOP_CTEST7_DFP 0x08 /* DMA FIFO parity bit */ +#define OOSIOP_CTEST7_EVP 0x04 /* Even parity (to host bus) */ +#define OOSIOP_CTEST7_DIFF 0x01 /* Differential mode */ + +/* DMA FIFO register (dfifo) */ + +#define OOSIOP_DFIFO_FLF 0x80 /* Flush (spill) DMA FIFO */ +#define OOSIOP_DFIFO_CLF 0x40 /* Clear DMA and SCSI FIFOs */ +#define OOSIOP_DFIFO_BO 0x3f /* FIFO byte offset counter */ + +/* Interrupt status register (istat) */ + +#define OOSIOP_ISTAT_ABRT 0x80 /* Abort operation */ +#define OOSIOP_ISTAT_CON 0x08 /* Connected */ +#define OOSIOP_ISTAT_PRE 0x04 /* Pointer register empty */ +#define OOSIOP_ISTAT_SIP 0x02 /* SCSI Interrupt pending */ +#define OOSIOP_ISTAT_DIP 0x01 /* DMA Interrupt pending */ + +/* Chip test register 8 (ctest8) */ + +/* DMA Byte Counter register (dbc) */ +#define OOSIOP_DBC_MAX 0x00ffffff + +/* DMA Mode register (dmode) */ + +#define OOSIOP_DMODE_BL_MASK 0xc0 /* 0->1 1->2 2->4 3->8 */ +#define OOSIOP_DMODE_BL_1 0x00 +#define OOSIOP_DMODE_BL_2 0x40 +#define OOSIOP_DMODE_BL_4 0x80 +#define OOSIOP_DMODE_BL_8 0xc0 +#define OOSIOP_DMODE_BW16 0x20 /* Bus Width is 16 bits */ +#define OOSIOP_DMODE_286 0x10 /* 286 mode */ +#define OOSIOP_DMODE_IO_M 0x08 /* xfer data to memory or I/O space */ +#define OOSIOP_DMODE_FAM 0x04 /* fixed address mode */ +#define OOSIOP_DMODE_PIPE 0x02 /* SCRIPTS in Pipeline mode */ +#define OOSIOP_DMODE_MAN 0x01 /* SCRIPTS in Manual start mode */ + +/* DMA interrupt enable register (dien) */ + +#define OOSIOP_DIEN_BF 0x20 /* On Bus Fault */ +#define OOSIOP_DIEN_ABRT 0x10 /* On Abort */ +#define OOSIOP_DIEN_SSI 0x08 /* On SCRIPTS sstep */ +#define OOSIOP_DIEN_SIR 0x04 /* On SCRIPTS intr instruction */ +#define OOSIOP_DIEN_WTD 0x02 /* On watchdog timeout */ +#define OOSIOP_DIEN_IID 0x01 /* On illegal instruction detected */ + +/* DMA control register (dcntl) */ + +#define OOSIOP_DCNTL_CF_MASK 0xc0 /* Clock frequency dividers: */ +#define OOSIOP_DCNTL_CF_2 0x00 /* 0 --> 37.51..50.00 MHz, div=2 */ +#define OOSIOP_DCNTL_CF_1_5 0x40 /* 1 --> 25.01..37.50 MHz, div=1.5 */ +#define OOSIOP_DCNTL_CF_1 0x80 /* 2 --> 16.67..25.00 MHz, div=1 */ +#define OOSIOP_DCNTL_CF_3 0xc0 /* 3 --> 50.01..66.67 MHz, div=3 */ +#define OOSIOP_DCNTL_S16 0x20 /* SCRIPTS fetches 16bits at a time */ +#define OOSIOP_DCNTL_SSM 0x10 /* Single step mode */ +#define OOSIOP_DCNTL_LLM 0x08 /* Enable SCSI Low-level mode */ +#define OOSIOP_DCNTL_STD 0x04 /* Start DMA operation */ +#define OOSIOP_DCNTL_RST 0x01 /* Software reset */ diff --git a/sys/dev/ic/oosiopvar.h b/sys/dev/ic/oosiopvar.h new file mode 100644 index 000000000000..8237b2497e03 --- /dev/null +++ b/sys/dev/ic/oosiopvar.h @@ -0,0 +1,157 @@ +/* $NetBSD: oosiopvar.h,v 1.1 2003/04/06 09:48:43 tsutsui Exp $ */ + +/* + * Copyright (c) 2001 Shuichiro URATA. 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. + */ + +#define OOSIOP_NTGT 8 /* Max targets */ +#define OOSIOP_NCB 32 /* Initial command buffers */ +#define OOSIOP_NSG (MIN(btoc(MAXPHYS) + 1, 32)) /* Max S/G operation */ +#define OOSIOP_MAX_XFER ctob(OOSIOP_NSG - 1) + +struct oosiop_xfer { + /* script for scatter/gather DMA (move*nsg+jump) */ + u_int32_t datain_scr[(OOSIOP_NSG + 1) * 2]; + u_int32_t dataout_scr[(OOSIOP_NSG + 1) * 2]; + + u_int8_t msgin[8]; + u_int8_t msgout[8]; + u_int8_t status; + u_int8_t pad[7]; +} __attribute__((__packed__)); + +#define SCSI_OOSIOP_NOSTATUS 0xff /* device didn't report status */ + +#define OOSIOP_XFEROFF(x) offsetof(struct oosiop_xfer, x) +#define OOSIOP_DINSCROFF OOSIOP_XFEROFF(datain_scr[0]) +#define OOSIOP_DOUTSCROFF OOSIOP_XFEROFF(dataout_scr[0]) +#define OOSIOP_MSGINOFF OOSIOP_XFEROFF(msgin[0]) +#define OOSIOP_MSGOUTOFF OOSIOP_XFEROFF(msgout[0]) + +#define OOSIOP_XFERSCR_SYNC(sc, cb, ops) \ + bus_dmamap_sync((sc)->sc_dmat, (cb)->xferdma, OOSIOP_DINSCROFF, \ + OOSIOP_MSGINOFF - OOSIOP_DINSCROFF, (ops)) +#define OOSIOP_DINSCR_SYNC(sc, cb, ops) \ + bus_dmamap_sync((sc)->sc_dmat, (cb)->xferdma, OOSIOP_DINSCROFF, \ + OOSIOP_DOUTSCROFF - OOSIOP_DINSCROFF, (ops)) +#define OOSIOP_DOUTSCR_SYNC(sc, cb, ops) \ + bus_dmamap_sync((sc)->sc_dmat, (cb)->xferdma, OOSIOP_DOUTSCROFF,\ + OOSIOP_MSGINOFF - OOSIOP_DOUTSCROFF, (ops)) +#define OOSIOP_XFERMSG_SYNC(sc, cb, ops) \ + bus_dmamap_sync((sc)->sc_dmat, (cb)->xferdma, OOSIOP_MSGINOFF, \ + sizeof(struct oosiop_xfer) - OOSIOP_MSGINOFF, (ops)) + +#define OOSIOP_SCRIPT_SYNC(sc, ops) \ + bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_scrdma, \ + 0, sizeof(oosiop_script), (ops)) + +struct oosiop_cb { + TAILQ_ENTRY(oosiop_cb) chain; + + struct scsipi_xfer *xs; /* SCSI xfer ctrl block from above */ + int flags; + int id; /* target scsi id */ + int lun; /* target lun */ + + bus_dmamap_t cmddma; /* DMA map for command out */ + bus_dmamap_t datadma; /* DMA map for data I/O */ + bus_dmamap_t xferdma; /* DMA map for xfer block */ + + int curdp; /* current data pointer */ + int savedp; /* saved data pointer */ + int msgoutlen; + + struct oosiop_xfer *xfer; /* DMA xfer block */ +}; + +/* oosiop_cb flags */ +#define CBF_SELTOUT 0x01 /* Selection timeout */ +#define CBF_TIMEOUT 0x02 /* Command timeout */ + +TAILQ_HEAD(oosiop_cb_queue, oosiop_cb); + +struct oosiop_target { + struct oosiop_cb *nexus; + int flags; + u_int8_t scf; /* synchronous clock divisor */ + u_int8_t sxfer; /* synchronous period and offset */ +}; + +/* target flags */ +#define TGTF_SYNCNEG 0x01 /* Trigger synchronous negotiation */ +#define TGTF_WAITSDTR 0x02 /* Waiting SDTR from target */ + +struct oosiop_softc { + struct device sc_dev; + + bus_space_tag_t sc_bst; /* bus space tag */ + bus_space_handle_t sc_bsh; /* bus space handle */ + + bus_dma_tag_t sc_dmat; /* bus dma tag */ + bus_dmamap_t sc_scrdma; /* script dma map */ + + bus_addr_t sc_scrbase; /* script dma base address */ + u_int32_t *sc_scr; /* ptr to script memory */ + + int sc_chip; /* 700 or 700-66 */ +#define OOSIOP_700 0 +#define OOSIOP_700_66 1 + + int sc_id; /* SCSI ID of this interface */ + int sc_freq; /* SCLK frequency */ + int sc_ccf; /* asynchronous divisor (*10) */ + u_int8_t sc_dcntl; + u_int8_t sc_minperiod; + + struct oosiop_target sc_tgt[OOSIOP_NTGT]; + + struct scsipi_adapter sc_adapter; + struct scsipi_channel sc_channel; + + /* Lists of command blocks */ + struct oosiop_cb_queue sc_free_cb; + struct oosiop_cb_queue sc_cbq; /* command issue queue */ + struct oosiop_cb *sc_curcb; /* current command */ + struct oosiop_cb *sc_lastcb; /* last activated command */ + + bus_addr_t sc_reselbuf; /* msgin buffer for reselection */ + int sc_resid; /* reselected target id */ + + int sc_active; + int sc_nextdsp; +}; + +#define oosiop_read_1(sc, addr) \ + bus_space_read_1((sc)->sc_bst, (sc)->sc_bsh, (addr)) +#define oosiop_write_1(sc, addr, data) \ + bus_space_write_1((sc)->sc_bst, (sc)->sc_bsh, (addr), (data)) +/* XXX byte swapping should be handled by MD bus_space(9)? */ +#define oosiop_read_4(sc, addr) \ + le32toh(bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (addr))) +#define oosiop_write_4(sc, addr, data) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (addr), htole32(data)) + +void oosiop_attach(struct oosiop_softc *); +int oosiop_intr(struct oosiop_softc *); diff --git a/sys/dev/microcode/siop/oosiop.ss b/sys/dev/microcode/siop/oosiop.ss index 284b0aeca563..b1c084f803ce 100644 --- a/sys/dev/microcode/siop/oosiop.ss +++ b/sys/dev/microcode/siop/oosiop.ss @@ -1,9 +1,7 @@ -; $NetBSD: oosiop.ss,v 1.1 2001/12/05 18:27:13 fredette Exp $ +; $NetBSD: oosiop.ss,v 1.2 2003/04/06 09:48:42 tsutsui Exp $ ; -; Copyright (c) 2001 Matt Fredette -; Copyright (c) 1995 Michael L. Hitch -; All rights reserved. +; Copyright (c) 2001 Shuichiro URATA. All rights reserved. ; ; Redistribution and use in source and binary forms, with or without ; modification, are permitted provided that the following conditions @@ -13,11 +11,8 @@ ; 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 Michael L. Hitch. -; 4. The name of the author may not be used to endorse or promote products -; derived from this software without specific prior written permission +; 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 @@ -33,211 +28,123 @@ ; NCR 53c700 script ; + ARCH 700 -; -EXTERNAL ds_Device -EXTERNAL ds_MsgOut -EXTERNAL ds_Cmd -EXTERNAL ds_Status -EXTERNAL ds_Msg -EXTERNAL ds_MsgIn -EXTERNAL ds_ExtMsg -EXTERNAL ds_SyncMsg -EXTERNAL ds_Data1 + +; interrupt codes +ABSOLUTE int_done = 0xbeef0000 +ABSOLUTE int_msgin = 0xbeef0001 +ABSOLUTE int_extmsg = 0xbeef0002 +ABSOLUTE int_resel = 0xbeef0003 +ABSOLUTE int_res_id = 0xbeef0004 +ABSOLUTE int_resfail = 0xbeef0005 +ABSOLUTE int_disc = 0xbeef0006 +ABSOLUTE int_err = 0xdeadbeef + +; patch entries +ENTRY p_resel_msgin_move +ENTRY p_select +ENTRY p_datain_jump +ENTRY p_dataout_jump +ENTRY p_msgin_move +ENTRY p_msgout_move +ENTRY p_cmdout_move +ENTRY p_status_move +ENTRY p_extmsglen_move +ENTRY p_extmsgin_move -ABSOLUTE ok = 0xff00 -ABSOLUTE int_disc = 0xff01 -ABSOLUTE int_disc_wodp = 0xff02 -ABSOLUTE int_reconnect = 0xff03 -ABSOLUTE int_connect = 0xff04 -ABSOLUTE int_phase = 0xff05 -ABSOLUTE int_msgin = 0xff06 -ABSOLUTE int_extmsg = 0xff07 -ABSOLUTE int_msgsdp = 0xff08 -ABSOLUTE int_identify = 0xff09 -ABSOLUTE int_status = 0xff0a -ABSOLUTE int_syncmsg = 0xff0b +PROC oosiop_script: -ENTRY scripts -ENTRY switch -ENTRY wait_reselect -ENTRY dataout -ENTRY datain -ENTRY clear_ack +ENTRY wait_reselect +wait_reselect: + WAIT RESELECT REL(reselect_fail) + INT int_resel +reselect_fail: + INT int_resfail -PROC oosiop_script: +ENTRY wait_resel_identify +wait_resel_identify: + INT int_err, WHEN NOT MSG_IN +p_resel_msgin_move: + MOVE 0, 0, WHEN MSG_IN + INT int_res_id -scripts: +ENTRY start_select +start_select: +p_select: + SELECT ATN 0, REL(wait_reselect) - SELECT ATN ds_Device, reselect -; -switch: - JUMP msgin, WHEN MSG_IN - JUMP msgout, IF MSG_OUT - JUMP command_phase, IF CMD - JUMP dataout, IF DATA_OUT - JUMP datain, IF DATA_IN - JUMP end, IF STATUS - - INT int_phase ; Unrecognized phase +ENTRY phasedispatch +phasedispatch: + JUMP REL(msgin), WHEN MSG_IN + JUMP REL(msgout), WHEN MSG_OUT + JUMP REL(status), WHEN STATUS + JUMP REL(cmdout), WHEN CMD +p_datain_jump: + JUMP 0, WHEN DATA_IN +p_dataout_jump: + JUMP 0, WHEN DATA_OUT + INT int_err msgin: - MOVE 0, ds_MsgIn, WHEN MSG_IN - JUMP ext_msg, IF 0x01 ; extended message - JUMP disc, IF 0x04 ; disconnect message - JUMP msg_sdp, IF 0x02 ; save data pointers - JUMP msg_rej, IF 0x07 ; message reject - JUMP msg_rdp, IF 0x03 ; restore data pointers - INT int_msgin ; unrecognized message - -msg_rej: -; Do we need to interrupt host here to let it handle the reject? -msg_rdp: -clear_ack: - CLEAR ACK CLEAR ATN - JUMP switch +p_msgin_move: + MOVE 0, 0, WHEN MSG_IN + JUMP REL(complete), IF 0x00 + JUMP REL(extmsgsetup), IF 0x01 + JUMP REL(disconnect), IF 0x04 + INT int_msgin -ext_msg: +ENTRY ack_msgin +ack_msgin: CLEAR ACK - MOVE 0, ds_ExtMsg, WHEN MSG_IN - JUMP sync_msg, IF 0x03 - int int_extmsg ; extended message not SDTR + JUMP REL(phasedispatch) -sync_msg: - CLEAR ACK - MOVE 0, ds_SyncMsg, WHEN MSG_IN - int int_syncmsg ; Let host handle the message -; If we continue from the interrupt, the host has set up a response -; message to be sent. Set ATN, clear ACK, and continue. +ENTRY sendmsg +sendmsg: SET ATN CLEAR ACK - JUMP switch - -disc: - CLEAR ACK - WAIT DISCONNECT - - int int_disc_wodp ; signal disconnect w/o save DP - -msg_sdp: - CLEAR ACK ; acknowledge message - JUMP switch, WHEN NOT MSG_IN - MOVE 0, ds_ExtMsg, WHEN MSG_IN - INT int_msgsdp, IF NOT 0x04 ; interrupt if not disconnect - CLEAR ACK - WAIT DISCONNECT - - INT int_disc ; signal disconnect - -reselect: -wait_reselect: - WAIT RESELECT select_adr - ; NB: these NOPs are CRITICAL to preserve the 1:1 - ; correspondence between instructions in this script - ; and instructions in the osiop (53c710) script: - NOP - NOP ; reselect ID already in SFBR - - INT int_identify, WHEN NOT MSG_IN - MOVE 0, ds_Msg, WHEN MSG_IN - INT int_reconnect ; let host know about reconnect - CLEAR ACK ; acknowlege the message - JUMP switch - -select_adr: - MOVE SCNTL1 & 0x10 to SFBR ; get connected status - INT int_connect, IF 0x00 ; tell host if not connected - NOP ; Sig_P doesn't exist on the 53c700 - JUMP wait_reselect ; and try reselect again - msgout: - MOVE 0, ds_MsgOut, WHEN MSG_OUT - JUMP switch - -command_phase: +p_msgout_move: + MOVE 0, 0, WHEN MSG_OUT CLEAR ATN - MOVE 0, ds_Cmd, WHEN CMD - JUMP switch + JUMP REL(phasedispatch) -dataout: - MOVE 0, ds_Data1, WHEN DATA_OUT - CALL switch, WHEN NOT DATA_OUT - MOVE 0, ds_Data1, WHEN DATA_OUT - CALL switch, WHEN NOT DATA_OUT - MOVE 0, ds_Data1, WHEN DATA_OUT - CALL switch, WHEN NOT DATA_OUT - MOVE 0, ds_Data1, WHEN DATA_OUT - CALL switch, WHEN NOT DATA_OUT - MOVE 0, ds_Data1, WHEN DATA_OUT - CALL switch, WHEN NOT DATA_OUT - MOVE 0, ds_Data1, WHEN DATA_OUT - CALL switch, WHEN NOT DATA_OUT - MOVE 0, ds_Data1, WHEN DATA_OUT - CALL switch, WHEN NOT DATA_OUT - MOVE 0, ds_Data1, WHEN DATA_OUT - CALL switch, WHEN NOT DATA_OUT - MOVE 0, ds_Data1, WHEN DATA_OUT - CALL switch, WHEN NOT DATA_OUT - MOVE 0, ds_Data1, WHEN DATA_OUT - CALL switch, WHEN NOT DATA_OUT - MOVE 0, ds_Data1, WHEN DATA_OUT - CALL switch, WHEN NOT DATA_OUT - MOVE 0, ds_Data1, WHEN DATA_OUT - CALL switch, WHEN NOT DATA_OUT - MOVE 0, ds_Data1, WHEN DATA_OUT - CALL switch, WHEN NOT DATA_OUT - MOVE 0, ds_Data1, WHEN DATA_OUT - CALL switch, WHEN NOT DATA_OUT - MOVE 0, ds_Data1, WHEN DATA_OUT - CALL switch, WHEN NOT DATA_OUT - MOVE 0, ds_Data1, WHEN DATA_OUT - CALL switch, WHEN NOT DATA_OUT - MOVE 0, ds_Data1, WHEN DATA_OUT - CALL switch +cmdout: + CLEAR ATN +p_cmdout_move: + MOVE 0, 0, WHEN CMD + JUMP REL(phasedispatch) -datain: - MOVE 0, ds_Data1, WHEN DATA_IN - CALL switch, WHEN NOT DATA_IN - MOVE 0, ds_Data1, WHEN DATA_IN - CALL switch, WHEN NOT DATA_IN - MOVE 0, ds_Data1, WHEN DATA_IN - CALL switch, WHEN NOT DATA_IN - MOVE 0, ds_Data1, WHEN DATA_IN - CALL switch, WHEN NOT DATA_IN - MOVE 0, ds_Data1, WHEN DATA_IN - CALL switch, WHEN NOT DATA_IN - MOVE 0, ds_Data1, WHEN DATA_IN - CALL switch, WHEN NOT DATA_IN - MOVE 0, ds_Data1, WHEN DATA_IN - CALL switch, WHEN NOT DATA_IN - MOVE 0, ds_Data1, WHEN DATA_IN - CALL switch, WHEN NOT DATA_IN - MOVE 0, ds_Data1, WHEN DATA_IN - CALL switch, WHEN NOT DATA_IN - MOVE 0, ds_Data1, WHEN DATA_IN - CALL switch, WHEN NOT DATA_IN - MOVE 0, ds_Data1, WHEN DATA_IN - CALL switch, WHEN NOT DATA_IN - MOVE 0, ds_Data1, WHEN DATA_IN - CALL switch, WHEN NOT DATA_IN - MOVE 0, ds_Data1, WHEN DATA_IN - CALL switch, WHEN NOT DATA_IN - MOVE 0, ds_Data1, WHEN DATA_IN - CALL switch, WHEN NOT DATA_IN - MOVE 0, ds_Data1, WHEN DATA_IN - CALL switch, WHEN NOT DATA_IN - MOVE 0, ds_Data1, WHEN DATA_IN - CALL switch, WHEN NOT DATA_IN - MOVE 0, ds_Data1, WHEN DATA_IN - CALL switch +status: +p_status_move: + MOVE 0, 0, WHEN STATUS + JUMP REL(phasedispatch) -end: - MOVE 0, ds_Status, WHEN STATUS - int int_status, WHEN NOT MSG_IN ; status not followed by msg - MOVE 0, ds_Msg, WHEN MSG_IN +disconnect: CLEAR ACK WAIT DISCONNECT - INT ok ; signal completion - JUMP wait_reselect + INT int_disc + +complete: + CLEAR ACK + WAIT DISCONNECT + INT int_done + +; receive extended message length +extmsgsetup: + CLEAR ACK + INT int_err, IF NOT MSG_IN +p_extmsglen_move: + MOVE 0, 0, WHEN MSG_IN + INT int_extmsg + +; receive extended message +ENTRY rcv_extmsg +rcv_extmsg: + CLEAR ACK + INT int_err, IF NOT MSG_IN +p_extmsgin_move: + MOVE 0, 0, WHEN MSG_IN + INT int_msgin