/* $NetBSD: oak.c,v 1.9 1996/10/14 23:42:18 mark Exp $ */ /* * Copyright (c) 1995 Melvin Tang-Richardson 1996. * 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 RiscBSD. * 4. The name of the company nor the name of the author may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY RISCBSD ``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 RISCBSD 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. */ /* * Oak SCSI Driver using the NCR5380 generic driver */ #undef USE_OWN_PIO_ROUTINES /* Some system includes *****************************************************/ #include #include #include #include #include #include #include #include #include #include /*#include */ /* SCSI bus includes */ #include #include /* Hardware related include chip/card/bus ***********************************/ #include #include #include #include #include #include #include /****************************************************************************/ /* Some useful definitions **************************************************/ /****************************************************************************/ #define MAX_DMA_LEN (0xe000) /****************************************************************************/ /* Prototype internal data structures ***************************************/ /****************************************************************************/ struct oak_softc { struct ncr5380_softc ncr_sc; int sc_podule_number; podule_t *sc_podule; int sc_base; }; /****************************************************************************/ /* Function and data prototypes *********************************************/ /****************************************************************************/ int oakprobe __P((struct device *, void *, void *)); void oakattach __P((struct device *, struct device *, void *)); void oakminphys __P((struct buf *)); #ifdef USE_OWN_PIO_ROUTINES int oak_pio_in __P((struct ncr5380_softc *, int, int, unsigned char *)); int oak_pio_out __P((struct ncr5380_softc *, int, int, unsigned char *)); #endif struct scsi_adapter oak_adapter = { ncr5380_scsi_cmd, oakminphys, NULL, NULL, }; struct scsi_device oak_device = { NULL, NULL, NULL, NULL, }; int oakprobe(parent, match, aux) struct device *parent; void *match; void *aux; { struct podule_attach_args *pa = (void *) aux; /* Look for the card */ if (matchpodule(pa, MANUFACTURER_OAK, PODULE_OAK_SCSI, -1) == 0) return(0); return 1; } void oakattach(parent, self, aux) struct device *parent; struct device *self; void *aux; { struct oak_softc *sc = (void *) self; struct ncr5380_softc *ncr_sc = (struct ncr5380_softc *)sc; struct podule_attach_args *pa = (void *)aux; if (pa->pa_podule_number == -1) panic("Podule has disappeared !"); sc->sc_podule_number = pa->pa_podule_number; sc->sc_podule = pa->pa_podule; podules[sc->sc_podule_number].attached = 1; sc->sc_base = sc->sc_podule->mod_base; printf(" 16-bit"); ncr_sc->sc_link.channel = SCSI_CHANNEL_ONLY_ONE; ncr_sc->sc_link.adapter_softc = sc; ncr_sc->sc_link.adapter_target = 7; ncr_sc->sc_link.adapter = &oak_adapter; ncr_sc->sc_link.device = &oak_device; ncr_sc->sci_r0 = (volatile u_char *)sc->sc_base + 0x00; ncr_sc->sci_r1 = (volatile u_char *)sc->sc_base + 0x04; ncr_sc->sci_r2 = (volatile u_char *)sc->sc_base + 0x08; ncr_sc->sci_r3 = (volatile u_char *)sc->sc_base + 0x0c; ncr_sc->sci_r4 = (volatile u_char *)sc->sc_base + 0x10; ncr_sc->sci_r5 = (volatile u_char *)sc->sc_base + 0x14; ncr_sc->sci_r6 = (volatile u_char *)sc->sc_base + 0x18; ncr_sc->sci_r7 = (volatile u_char *)sc->sc_base + 0x1c; #ifdef USE_OWN_PIO_ROUTINES printf ( ", my pio" ); ncr_sc->sc_pio_out = oak_pio_out; ncr_sc->sc_pio_in = oak_pio_in; #else printf ( ", normal pio" ); ncr_sc->sc_pio_out = ncr5380_pio_out; ncr_sc->sc_pio_in = ncr5380_pio_in; #endif ncr_sc->sc_dma_alloc = NULL; ncr_sc->sc_dma_free = NULL; ncr_sc->sc_dma_poll = NULL; ncr_sc->sc_dma_setup = NULL; ncr_sc->sc_dma_start = NULL; ncr_sc->sc_dma_eop = NULL; ncr_sc->sc_dma_stop = NULL; printf(", polling"); ncr_sc->sc_intr_on = NULL; ncr_sc->sc_intr_off = NULL; ncr_sc->sc_flags = NCR5380_FORCE_POLLING; ncr5380_init(ncr_sc); ncr5380_reset_scsibus(ncr_sc); printf(" UNDER DEVELOPMENT\n"); config_found(self, &(ncr_sc->sc_link), scsiprint); } void oakminphys(bp) struct buf *bp; { if (bp->b_bcount > MAX_DMA_LEN) { printf("oak: DEBUG reducing dma length\n"); bp->b_bcount = MAX_DMA_LEN; } minphys(bp); } struct cfattach oak_ca = { sizeof(struct oak_softc), oakprobe, oakattach }; struct cfdriver oak_cd = { NULL, "oak", DV_DISK, NULL, 0, }; #ifdef USE_OWN_PIO_ROUTINES /****************************************************************************/ /* Copyright (c) 1996 Melvin Tang-Richardson */ /* Copyright (c) 1995 David Jones, Gordon W. Rose */ /* Copyright (c) 1994 Jarle Greipsland */ /****************************************************************************/ static ncr5380_wait_req_timo = 1000 * 50; /* X2 = 100 mS */ static ncr5380_wait_nrq_timo = 1000 * 25; /* X2 = 50 mS */ /* Return zero on success. */ static __inline__ int ncr5380_wait_req(sc) struct ncr5380_softc *sc; { register int timo = ncr5380_wait_req_timo; for (;;) { if (*sc->sci_bus_csr & SCI_BUS_REQ) { timo = 0; /* return 0 */ break; } if (--timo < 0) break; /* return -1 */ delay(2); } return (timo); } /* Return zero on success. */ static __inline__ int ncr5380_wait_not_req(sc) struct ncr5380_softc *sc; { register int timo = ncr5380_wait_nrq_timo; for (;;) { if ((*sc->sci_bus_csr & SCI_BUS_REQ) == 0) { timo = 0; /* return 0 */ break; } if (--timo < 0) break; /* return -1 */ delay(2); } return (timo); } int oak_pio_out(sc, phase, count, data) struct ncr5380_softc *sc; int phase, count; unsigned char *data; { register u_char icmd; register int resid; register int error; printf("oak: pio_out %d %d\n", phase, count); icmd = *(sc->sci_icmd) & SCI_ICMD_RMASK; icmd |= SCI_ICMD_DATA; *sc->sci_icmd = icmd; resid = count; while (resid > 0) { if (!SCI_BUSY(sc)) { NCR_TRACE("pio_out: lost BSY, resid=%d\n", resid); break; } if (ncr5380_wait_req(sc)) { NCR_TRACE("pio_out: no REQ, resid=%d\n", resid); break; } if (SCI_BUS_PHASE(*sc->sci_bus_csr) != phase) break; /* Put the data on the bus. */ *sc->sci_odata = *data++; /* Tell the target it's there. */ icmd |= SCI_ICMD_ACK; *sc->sci_icmd = icmd; /* Wait for target to get it. */ error = ncr5380_wait_not_req(sc); /* OK, it's got it (or we gave up waiting). */ icmd &= ~SCI_ICMD_ACK; *sc->sci_icmd = icmd; if (error) { NCR_TRACE("pio_out: stuck REQ, resid=%d\n", resid); break; } --resid; } /* Stop driving the data bus. */ icmd &= ~SCI_ICMD_DATA; *sc->sci_icmd = icmd; return (count - resid); } int oak_pio_in(sc, phase, count, data) struct ncr5380_softc *sc; int phase, count; unsigned char *data; { register u_char icmd; register int resid; register int error; printf("oak: pio_in %d %d\n", phase, count); icmd = *(sc->sci_icmd) & SCI_ICMD_RMASK; resid = count; while (resid > 0) { if (!SCI_BUSY(sc)) { NCR_TRACE("pio_in: lost BSY, resid=%d\n", resid); break; } if (ncr5380_wait_req(sc)) { NCR_TRACE("pio_in: no REQ, resid=%d\n", resid); break; } /* A phase change is not valid until AFTER REQ rises! */ if (SCI_BUS_PHASE(*sc->sci_bus_csr) != phase) break; /* Read the data bus. */ *data++ = *sc->sci_data; /* Tell target we got it. */ icmd |= SCI_ICMD_ACK; *sc->sci_icmd = icmd; /* Wait for target to drop REQ... */ error = ncr5380_wait_not_req(sc); /* OK, we can drop ACK. */ icmd &= ~SCI_ICMD_ACK; *sc->sci_icmd = icmd; if (error) { NCR_TRACE("pio_in: stuck REQ, resid=%d\n", resid); break; } --resid; } return (count - resid); } #endif /* USE_OWN_PIO_ROUTINES */