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