/* $NetBSD: ncr.c,v 1.20 1995/09/26 20:16:08 phil Exp $ */ /* * Copyright (c) 1994 Matthias Pfaller. * 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Matthias Pfaller. * 4. 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. * * $Id: ncr.c,v 1.20 1995/09/26 20:16:08 phil Exp $ */ #include #include #include #include #include #include #include #include #include /* * Include the driver definitions */ #include "ncr5380reg.h" #include "ncrreg.h" /* * Set the various driver options */ #define NREQ 18 /* Size of issue queue */ #define AUTO_SENSE 1 /* Automatically issue a request-sense */ #define DRNAME ncr /* used in various prints */ #undef DBG_SEL /* Show the selection process */ #undef DBG_REQ /* Show enqueued/ready requests */ #undef DBG_NOWRITE /* Do not allow writes to the targets */ #undef DBG_PIO /* Show the polled-I/O process */ #undef DBG_INF /* Show information transfer process */ #undef DBG_NOSTATIC /* No static functions, all in DDB trace*/ #define DBG_PID /* Keep track of driver */ #undef REAL_DMA /* Use DMA if sensible */ #undef REAL_DMA_POLL 0 /* 1: Poll for end of DMA-transfer */ #define USE_PDMA /* Use special pdma-transfer function */ /* * Softc of currently active controller (a bit of fake; we only have one) */ static struct ncr_softc *cur_softc; /* * Function decls: */ static int transfer_pdma __P((u_char *, u_char *, u_long *)); static void ncr_intr __P((void *)); static void ncr_soft_intr __P((void *)); #define scsi_dmaok(x) 0 #define pdma_ready() 0 #define fair_to_keep_dma() 1 #define claimed_dma() 1 #define reconsider_dma() #define ENABLE_NCR5380(sc) do { \ scsi_select_ctlr(DP8490); \ cur_softc = sc; \ } while (0) void delay(timeo) int timeo; { int len; for (len=0; len < timeo * 2; len++); } static int machine_match(pdp, cdp, auxp, cfd) struct device *pdp; struct cfdata *cdp; void *auxp; struct cfdriver *cfd; { if(cdp->cf_unit != 0) /* Only one unit */ return(0); return(1); } static void scsi_mach_init(sc) struct ncr_softc *sc; { register int i; intr_disable(IR_SCSI1); i = intr_establish(SOFTINT, ncr_soft_intr, sc, sc->sc_dev.dv_xname, IPL_BIO, 0); intr_establish(IR_SCSI1, ncr_intr, (void *)i, sc->sc_dev.dv_xname, IPL_BIO, RISING_EDGE); printf(" addr 0x%x, irq %d", NCR5380, IR_SCSI1); } /* * 5380 interrupt. */ static void ncr_intr(softint) void *softint; { int ctrlr; ctrlr = scsi_select_ctlr(DP8490); if (NCR5380->ncr_dmstat & SC_IRQ_SET) { intr_disable(IR_SCSI1); softintr((int)softint); } scsi_select_ctlr(ctrlr); } static void ncr_soft_intr(sc) void *sc; { int ctrlr = scsi_select_ctlr(DP8490); ncr_ctrl_intr(sc); scsi_select_ctlr(ctrlr); } /* * PDMA stuff */ #define movsd(from, to, n) do { \ register int r0 __asm ("r0") = n; \ register u_char *r1 __asm("r1") = from; \ register u_char *r2 __asm("r2") = to; \ __asm volatile ("movsd" \ : "=r" (r1), "=r" (r2) \ : "0" (r1), "1" (r2), "r" (r0) \ : "r0", "memory" \ ); \ from = r1; to = r2; \ } while (0) #define movsb(from, to, n) do { \ register int r0 __asm ("r0") = n; \ register u_char *r1 __asm("r1") = from; \ register u_char *r2 __asm("r2") = to; \ __asm volatile ("movsb" \ : "=r" (r1), "=r" (r2) \ : "0" (r1), "1" (r2), "r" (r0) \ : "r0", "memory" \ ); \ from = r1; to = r2; \ } while (0) #define TIMEOUT 1000000 #define READY(dataout) do { \ for (i = TIMEOUT; i > 0; i --) { \ /*if (!(NCR5380->ncr_dmstat & SC_PHS_MTCH)) {*/ \ if (NCR5380->ncr_dmstat & SC_IRQ_SET) { \ if (dataout) NCR5380->ncr_icom &= ~SC_ADTB; \ NCR5380->ncr_mode &= ~SC_M_DMA; \ *count = len; \ if ((idstat = NCR5380->ncr_idstat) & SC_S_REQ) \ *phase = (idstat >> 2) & 7; \ else \ *phase = NR_PHASE; \ return(1); \ } \ if (NCR5380->ncr_dmstat & SC_DMA_REQ) break; \ delay(1); \ } \ if (i <= 0) panic("ncr0: pdma timeout"); \ } while (0) #define byte_data ((volatile u_char *)pdma) #define word_data ((volatile u_short *)pdma) #define long_data ((volatile u_long *)pdma) #define W1(n) *byte_data = *(data + n) #define W2(n) *word_data = *((u_short *)data + n) #define W4(n) *long_data = *((u_long *)data + n) #define R1(n) *(data + n) = *byte_data #define R4(n) *((u_long *)data + n) = *long_data static int transfer_pdma(phase, data, count) u_char *phase; u_char *data; u_long *count; { register volatile u_char *pdma = PDMA_ADDRESS; register int len = *count, i, idstat; if (len < 256) { __asm volatile ("lmr ivar0,%0" : : "g" (data)); transfer_pio(phase, data, count, 0); return(1); } NCR5380->ncr_tcom = *phase; scsi_clr_ipend(); if (PH_IN(*phase)) { NCR5380->ncr_icom = 0; NCR5380->ncr_mode = IMODE_BASE | SC_M_DMA; NCR5380->ncr_ircv = 0; while (len >= 256) { if (!((u_long) data & 0xfff)) __asm volatile ("lmr ivar0,%0" : : "g" (data)); READY(0); di(); movsd((u_char *)pdma, data, 64); len -= 256; ei(); } if (len) { di(); while (len) { READY(0); R1(0); data++; len--; } ei(); } } else { NCR5380->ncr_mode = IMODE_BASE | SC_M_DMA; NCR5380->ncr_icom = SC_ADTB; NCR5380->ncr_dmstat = SC_S_SEND; while (len >= 256) { /* The second ready is to * compensate for DMA-prefetch. * Since we adjust len only at * the end of the block, there * is no need to correct the * residue. */ READY(1); di(); W1(0); READY(1); W1(1); W2(1); data += 4; movsd(data, (u_char *)pdma, 63); ei(); len -= 256; } if (len) { READY(1); di(); while (len) { W1(0); READY(1); data++; len--; } ei(); } i = TIMEOUT; while (((NCR5380->ncr_dmstat & (SC_DMA_REQ|SC_PHS_MTCH)) == SC_PHS_MTCH) && --i); if (!i) printf("ncr0: timeout waiting for SC_DMA_REQ.\n"); *byte_data = 0; } ncr_timeout_error: NCR5380->ncr_mode &= ~SC_M_DMA; if((idstat = NCR5380->ncr_idstat) & SC_S_REQ) *phase = (idstat >> 2) & 7; else *phase = NR_PHASE; *count = len; return(1); } /* * Last but not least... Include the general driver code */ #include "ncr5380.c"