/*-
* Copyright (c) 1996 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Adam Glass, David Jones, Gordon W. Ross, and Jens A. Nilsson.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
/*
* This file contains the machine-dependent parts of the NCR-5380
* controller. The machine-independent parts are in ncr5380sbc.c.
*
* Jens A. Nilsson.
*
* Credits:
*
* This code is based on arch/sun3/dev/si*
* Written by David Jones, Gordon Ross, and Adam Glass.
*/
struct si_dma_handle {
int dh_flags;
#define SIDH_BUSY 1
#define SIDH_OUT 2
void *dh_addr;
int dh_len;
struct proc *dh_proc;
};
struct si_softc {
struct ncr5380_softc ncr_sc;
struct evcnt ncr_intrcnt;
void *ncr_addr;
int ncr_off;
int ncr_dmaaddr;
int ncr_dmacount;
int ncr_dmadir;
struct si_dma_handle ncr_dma[SCI_OPENINGS];
struct vsbus_dma sc_vd;
int onlyscsi; /* This machine needs no queueing */
};
/*
* Get the SCSI chip target address out of NVRAM.
* This do not apply to the VS2000.
*/
tweak = clk_tweak + (va->va_paddr & 0x100 ? 3 : 0);
if (vax_boardtype == VAX_BTYP_410)
target = 7;
else
target = (clk_page[0xbc/2] >> tweak) & 7;
/*
* Explicitly enable upto 128KB "Big DMA" on KA420.
* (It looks KA420 firmware doesn't enable it on network boot)
*/
#define STC_MODE_OFF (KA420_STC_MODE - KA420_SCS_BASE)
if (vax_boardtype == VAX_BTYP_420) {
bus_space_write_1(ncr_sc->sc_regt, ncr_sc->sc_regh,
STC_MODE_OFF, 1);
}
aprint_normal("\n");
aprint_normal_dev(self, "NCR5380, SCSI ID %d\n", target);
/*
* Initialize si board itself.
*/
ncr5380_attach(ncr_sc);
}
/*
* Adjust the max transfer size. The DMA buffer is only 16k on VS2000.
*/
static void
si_minphys(struct buf *bp)
{
if (bp->b_bcount > ncr_dmasize)
bp->b_bcount = ncr_dmasize;
}
#ifdef DIAGNOSTIC
if (sr->sr_dma_hand != NULL)
panic("si_dma_alloc: already have DMA handle");
#endif
/* Polled transfers shouldn't allocate a DMA handle. */
if (sr->sr_flags & SR_IMMED)
return;
xlen = ncr_sc->sc_datalen;
/* Make sure our caller checked sc_min_dma_len. */
if (xlen < MIN_DMA_LEN)
panic("si_dma_alloc: len=0x%x", xlen);
/*
* Find free PDMA handle. Guaranteed to find one since we
* have as many PDMA handles as the driver has processes.
* (instances?)
*/
for (i = 0; i < SCI_OPENINGS; i++) {
if ((sc->ncr_dma[i].dh_flags & SIDH_BUSY) == 0)
goto found;
}
panic("sbc: no free PDMA handles");
found:
dh = &sc->ncr_dma[i];
dh->dh_flags = SIDH_BUSY;
dh->dh_addr = ncr_sc->sc_dataptr;
dh->dh_len = xlen;
if (((vaddr_t)ncr_sc->sc_dataptr & KERNBASE) == 0) {
if (xs->bp == NULL)
panic("si_dma_alloc");
dh->dh_proc = xs->bp->b_proc;
}
/* Remember dest buffer parameters */
if (xs->xs_control & XS_CTL_DATA_OUT)
dh->dh_flags |= SIDH_OUT;
if (ncr_sc->sc_state & NCR_DOINGDMA)
ncr_sc->sc_state &= ~NCR_DOINGDMA;
/*
* Sometimes the FIFO buffer isn't drained when the
* interrupt is posted. Just loop here and hope that
* it will drain soon.
*/
for (i = 0; i < 20000; i++) {
count = bus_space_read_4(ncr_sc->sc_regt,
ncr_sc->sc_regh, sc->ncr_dmacount);
if (count == 0)
break;
DELAY(100);
}
if (count == 0) {
if (((dh->dh_flags & SIDH_OUT) == 0)) {
vsbus_copytoproc(dh->dh_proc,
(char *)sc->ncr_addr + sc->ncr_off,
dh->dh_addr, dh->dh_len);
}
ncr_sc->sc_dataptr += dh->dh_len;
ncr_sc->sc_datalen -= dh->dh_len;
}
NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) &
~(SCI_MODE_DMA | SCI_MODE_DMA_IE));
NCR5380_WRITE(ncr_sc, sci_icmd, 0);
if (sc->onlyscsi == 0)
vsbus_dma_intr(); /* Try to start more transfers */
}