Home | History | Annotate | Line # | Download | only in dev
wdsc.c revision 1.27
      1 /*	$NetBSD: wdsc.c,v 1.27 2003/08/07 16:28:41 agc Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1982, 1990 The Regents of the University of California.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  *
     31  *  @(#)wdsc.c
     32  */
     33 
     34 /*
     35  * Copyright (c) 1996 Steve Woodford
     36  *
     37  * Redistribution and use in source and binary forms, with or without
     38  * modification, are permitted provided that the following conditions
     39  * are met:
     40  * 1. Redistributions of source code must retain the above copyright
     41  *    notice, this list of conditions and the following disclaimer.
     42  * 2. Redistributions in binary form must reproduce the above copyright
     43  *    notice, this list of conditions and the following disclaimer in the
     44  *    documentation and/or other materials provided with the distribution.
     45  * 3. All advertising materials mentioning features or use of this software
     46  *    must display the following acknowledgement:
     47  *  This product includes software developed by the University of
     48  *  California, Berkeley and its contributors.
     49  * 4. Neither the name of the University nor the names of its contributors
     50  *    may be used to endorse or promote products derived from this software
     51  *    without specific prior written permission.
     52  *
     53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     63  * SUCH DAMAGE.
     64  *
     65  *  @(#)wdsc.c
     66  */
     67 
     68 #include <sys/cdefs.h>
     69 __KERNEL_RCSID(0, "$NetBSD: wdsc.c,v 1.27 2003/08/07 16:28:41 agc Exp $");
     70 
     71 #include <sys/param.h>
     72 #include <sys/systm.h>
     73 #include <sys/kernel.h>
     74 #include <sys/device.h>
     75 
     76 #include <dev/scsipi/scsi_all.h>
     77 #include <dev/scsipi/scsipi_all.h>
     78 #include <dev/scsipi/scsiconf.h>
     79 
     80 #include <machine/cpu.h>
     81 #include <machine/bus.h>
     82 #include <machine/autoconf.h>
     83 
     84 #include <mvme68k/dev/dmavar.h>
     85 #include <mvme68k/dev/pccreg.h>
     86 #include <mvme68k/dev/pccvar.h>
     87 #include <mvme68k/dev/sbicreg.h>
     88 #include <mvme68k/dev/sbicvar.h>
     89 #include <mvme68k/dev/wdscreg.h>
     90 
     91 void    wdsc_pcc_attach __P((struct device *, struct device *, void *));
     92 int     wdsc_pcc_match  __P((struct device *, struct cfdata *, void *));
     93 
     94 CFATTACH_DECL(wdsc_pcc, sizeof(struct sbic_softc),
     95     wdsc_pcc_match, wdsc_pcc_attach, NULL, NULL);
     96 
     97 extern struct cfdriver wdsc_cd;
     98 
     99 void    wdsc_enintr     __P((struct sbic_softc *));
    100 int     wdsc_dmago      __P((struct sbic_softc *, char *, int, int));
    101 int     wdsc_dmanext    __P((struct sbic_softc *));
    102 void    wdsc_dmastop    __P((struct sbic_softc *));
    103 int     wdsc_dmaintr    __P((void *));
    104 int     wdsc_scsiintr   __P((void *));
    105 
    106 /*
    107  * Match for SCSI devices on the onboard WD33C93 chip
    108  */
    109 int
    110 wdsc_pcc_match(pdp, cf, auxp)
    111     struct device *pdp;
    112 	struct cfdata *cf;
    113     void *auxp;
    114 {
    115     struct pcc_attach_args *pa = auxp;
    116 
    117     if (strcmp(pa->pa_name, wdsc_cd.cd_name))
    118 	return (0);
    119 
    120     pa->pa_ipl = cf->pcccf_ipl;
    121     return (1);
    122 }
    123 
    124 /*
    125  * Attach the wdsc driver
    126  */
    127 void
    128 wdsc_pcc_attach(pdp, dp, auxp)
    129     struct device *pdp, *dp;
    130     void *auxp;
    131 {
    132     struct sbic_softc *sc;
    133     struct pcc_attach_args *pa;
    134     bus_space_handle_t bush;
    135     static struct evcnt evcnt;	/* XXXSCW: Temporary hack */
    136 
    137     sc = (struct sbic_softc *)dp;
    138     pa = auxp;
    139 
    140     bus_space_map(pa->pa_bust, pa->pa_offset, 0x20, 0, &bush);
    141 
    142     /*
    143      * XXXSCW: We *need* an MI, bus_spaced WD33C93 driver...
    144      */
    145     sc->sc_sbicp = (sbic_regmap_p) bush;
    146 
    147     sc->sc_driver  = (void *) &evcnt;
    148     sc->sc_enintr  = wdsc_enintr;
    149     sc->sc_dmago   = wdsc_dmago;
    150     sc->sc_dmanext = wdsc_dmanext;
    151     sc->sc_dmastop = wdsc_dmastop;
    152     sc->sc_dmacmd  = 0;
    153 
    154     sc->sc_adapter.adapt_dev = &sc->sc_dev;
    155     sc->sc_adapter.adapt_nchannels = 1;
    156     sc->sc_adapter.adapt_openings = 7;
    157     sc->sc_adapter.adapt_max_periph = 1;
    158     sc->sc_adapter.adapt_ioctl = NULL;
    159     sc->sc_adapter.adapt_minphys = sbic_minphys;
    160     sc->sc_adapter.adapt_request = sbic_scsi_request;
    161 
    162     sc->sc_channel.chan_adapter = &sc->sc_adapter;
    163     sc->sc_channel.chan_bustype = &scsi_bustype;
    164     sc->sc_channel.chan_channel = 0;
    165     sc->sc_channel.chan_ntargets = 8;
    166     sc->sc_channel.chan_nluns = 8;
    167     sc->sc_channel.chan_id = 7;
    168 
    169     printf(": WD33C93 SCSI, target %d\n", sc->sc_channel.chan_id);
    170 
    171     /*
    172      * Everything is a valid DMA address.
    173      */
    174     sc->sc_dmamask = 0;
    175 
    176     /*
    177      * The onboard WD33C93 of the '147 is usually clocked at 10MHz...
    178      * (We use 10 times this for accuracy in later calculations)
    179      */
    180     sc->sc_clkfreq = 100;
    181 
    182     /*
    183      * Initialise the hardware
    184      */
    185     sbicinit(sc);
    186 
    187     /*
    188      * Fix up the interrupts
    189      */
    190     sc->sc_ipl = pa->pa_ipl & PCC_IMASK;
    191 
    192     pcc_reg_write(sys_pcc, PCCREG_SCSI_INTR_CTRL, PCC_ICLEAR);
    193     pcc_reg_write(sys_pcc, PCCREG_DMA_INTR_CTRL, PCC_ICLEAR);
    194     pcc_reg_write(sys_pcc, PCCREG_DMA_CONTROL, 0);
    195 
    196     evcnt_attach_dynamic(&evcnt, EVCNT_TYPE_INTR, pccintr_evcnt(sc->sc_ipl),
    197 	"disk", sc->sc_dev.dv_xname);
    198     pccintr_establish(PCCV_DMA, wdsc_dmaintr,  sc->sc_ipl, sc, &evcnt);
    199     pccintr_establish(PCCV_SCSI, wdsc_scsiintr, sc->sc_ipl, sc, &evcnt);
    200     pcc_reg_write(sys_pcc, PCCREG_SCSI_INTR_CTRL,
    201         sc->sc_ipl | PCC_IENABLE | PCC_ICLEAR);
    202 
    203     (void)config_found(dp, &sc->sc_channel, scsiprint);
    204 }
    205 
    206 /*
    207  * Enable DMA interrupts
    208  */
    209 void
    210 wdsc_enintr(dev)
    211     struct sbic_softc *dev;
    212 {
    213     dev->sc_flags |= SBICF_INTR;
    214 
    215     pcc_reg_write(sys_pcc, PCCREG_DMA_INTR_CTRL,
    216         dev->sc_ipl | PCC_IENABLE | PCC_ICLEAR);
    217 }
    218 
    219 /*
    220  * Prime the hardware for a DMA transfer
    221  */
    222 int
    223 wdsc_dmago(dev, addr, count, flags)
    224     struct sbic_softc *dev;
    225     char *addr;
    226     int count, flags;
    227 {
    228     /*
    229      * Set up the command word based on flags
    230      */
    231     if ( (flags & DMAGO_READ) == 0 )
    232         dev->sc_dmacmd = DMAC_CSR_ENABLE | DMAC_CSR_WRITE;
    233     else
    234         dev->sc_dmacmd = DMAC_CSR_ENABLE;
    235 
    236     dev->sc_flags |= SBICF_INTR;
    237     dev->sc_tcnt   = dev->sc_cur->dc_count << 1;
    238 
    239     /*
    240      * Prime the hardware.
    241      * Note, it's probably not necessary to do this here, since dmanext
    242      * is called just prior to the actual transfer.
    243      */
    244     pcc_reg_write(sys_pcc, PCCREG_DMA_CONTROL, 0);
    245     pcc_reg_write(sys_pcc, PCCREG_DMA_INTR_CTRL,
    246         dev->sc_ipl | PCC_IENABLE | PCC_ICLEAR);
    247     pcc_reg_write32(sys_pcc, PCCREG_DMA_DATA_ADDR,
    248 	(u_int32_t) dev->sc_cur->dc_addr);
    249     pcc_reg_write32(sys_pcc, PCCREG_DMA_BYTE_COUNT,
    250 	(u_int32_t) dev->sc_tcnt | (1 << 24));
    251     pcc_reg_write(sys_pcc, PCCREG_DMA_CONTROL, dev->sc_dmacmd);
    252 
    253     return(dev->sc_tcnt);
    254 }
    255 
    256 /*
    257  * Prime the hardware for the next DMA transfer
    258  */
    259 int
    260 wdsc_dmanext(dev)
    261     struct sbic_softc *dev;
    262 {
    263     if ( dev->sc_cur > dev->sc_last ) {
    264         /*
    265          * Shouldn't happen !!
    266          */
    267         printf("wdsc_dmanext at end !!!\n");
    268         wdsc_dmastop(dev);
    269         return(0);
    270     }
    271 
    272     dev->sc_tcnt = dev->sc_cur->dc_count << 1;
    273 
    274     /*
    275      * Load the next DMA address
    276      */
    277     pcc_reg_write(sys_pcc, PCCREG_DMA_CONTROL, 0);
    278     pcc_reg_write(sys_pcc, PCCREG_DMA_INTR_CTRL,
    279         dev->sc_ipl | PCC_IENABLE | PCC_ICLEAR);
    280     pcc_reg_write32(sys_pcc, PCCREG_DMA_DATA_ADDR,
    281 	(u_int32_t) dev->sc_cur->dc_addr);
    282     pcc_reg_write32(sys_pcc, PCCREG_DMA_BYTE_COUNT,
    283 	(u_int32_t) dev->sc_tcnt | (1 << 24));
    284     pcc_reg_write(sys_pcc, PCCREG_DMA_CONTROL, dev->sc_dmacmd);
    285 
    286     return(dev->sc_tcnt);
    287 }
    288 
    289 /*
    290  * Stop DMA, and disable interrupts
    291  */
    292 void
    293 wdsc_dmastop(dev)
    294     struct sbic_softc *dev;
    295 {
    296     int s;
    297 
    298     s = splbio();
    299 
    300     pcc_reg_write(sys_pcc, PCCREG_DMA_CONTROL, 0);
    301     pcc_reg_write(sys_pcc, PCCREG_DMA_INTR_CTRL, dev->sc_ipl | PCC_ICLEAR);
    302 
    303     splx(s);
    304 }
    305 
    306 /*
    307  * Come here following a DMA interrupt
    308  */
    309 int
    310 wdsc_dmaintr(arg)
    311     void *arg;
    312 {
    313     struct sbic_softc *dev = arg;
    314     int found = 0;
    315 
    316     /*
    317      * Really a DMA interrupt?
    318      */
    319     if ( (pcc_reg_read(sys_pcc, PCCREG_DMA_INTR_CTRL) & 0x80) == 0 )
    320         return(0);
    321 
    322     /*
    323      * Was it a completion interrupt?
    324      * XXXSCW Note: Support for other DMA interrupts is required, eg. buserr
    325      */
    326     if ( pcc_reg_read(sys_pcc, PCCREG_DMA_CONTROL) & DMAC_CSR_DONE ) {
    327         ++found;
    328 
    329 	pcc_reg_write(sys_pcc, PCCREG_DMA_INTR_CTRL,
    330 	    dev->sc_ipl | PCC_IENABLE | PCC_ICLEAR);
    331     }
    332 
    333     return(found);
    334 }
    335 
    336 /*
    337  * Come here for SCSI interrupts
    338  */
    339 int
    340 wdsc_scsiintr(arg)
    341     void *arg;
    342 {
    343     struct sbic_softc *dev = arg;
    344     int found;
    345 
    346     /*
    347      * Really a SCSI interrupt?
    348      */
    349     if ( (pcc_reg_read(sys_pcc, PCCREG_SCSI_INTR_CTRL) & 0x80) == 0 )
    350         return(0);
    351 
    352     /*
    353      * Go handle it
    354      */
    355     found = sbicintr(dev);
    356 
    357     /*
    358      * Acknowledge and clear the interrupt
    359      */
    360     pcc_reg_write(sys_pcc, PCCREG_SCSI_INTR_CTRL,
    361 	    dev->sc_ipl | PCC_IENABLE | PCC_ICLEAR);
    362 
    363     return(found);
    364 }
    365