root/dev/tc/asc_tcds.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. asc_tcds_match
  2. asc_tcds_attach
  3. tcds_dma_reset
  4. tcds_dma_setup
  5. tcds_dma_go
  6. tcds_dma_stop
  7. tcds_dma_intr
  8. tcds_dma_isintr
  9. tcds_dma_isactive
  10. tcds_clear_latched_intr

    1 /* $OpenBSD: asc_tcds.c,v 1.4 2005/05/22 19:40:51 art Exp $ */
    2 /* $NetBSD: asc_tcds.c,v 1.5 2001/11/15 09:48:19 lukem Exp $ */
    3 
    4 /*-
    5  * Copyright (c) 1998 The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
   10  * NASA Ames Research Center.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. All advertising materials mentioning features or use of this software
   21  *    must display the following acknowledgement:
   22  *      This product includes software developed by the NetBSD
   23  *      Foundation, Inc. and its contributors.
   24  * 4. Neither the name of The NetBSD Foundation nor the names of its
   25  *    contributors may be used to endorse or promote products derived
   26  *    from this software without specific prior written permission.
   27  *
   28  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   29  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   31  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   32  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   38  * POSSIBILITY OF SUCH DAMAGE.
   39  */
   40 
   41 /*
   42  * Copyright (c) 1994 Peter Galbavy.  All rights reserved.
   43  *
   44  * Redistribution and use in source and binary forms, with or without
   45  * modification, are permitted provided that the following conditions
   46  * are met:
   47  * 1. Redistributions of source code must retain the above copyright
   48  *    notice, this list of conditions and the following disclaimer.
   49  * 2. Redistributions in binary form must reproduce the above copyright
   50  *    notice, this list of conditions and the following disclaimer in the
   51  *    documentation and/or other materials provided with the distribution.
   52  *
   53  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   54  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   55  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   56  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   57  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   58  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   59  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   60  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   61  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   62  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   63  */
   64 
   65 #include <sys/param.h>
   66 #include <sys/systm.h>
   67 #include <sys/device.h>
   68 #include <sys/buf.h>
   69 
   70 #include <scsi/scsi_all.h>
   71 #include <scsi/scsiconf.h>
   72 
   73 #include <dev/ic/ncr53c9xreg.h>
   74 #include <dev/ic/ncr53c9xvar.h>
   75 #include <dev/tc/ascvar.h>
   76 
   77 #include <machine/bus.h>
   78 
   79 #include <dev/tc/tcvar.h>
   80 #include <dev/tc/tcdsreg.h>
   81 #include <dev/tc/tcdsvar.h>
   82 
   83 struct asc_tcds_softc {
   84         struct asc_softc asc;
   85 
   86         struct tcds_slotconfig *sc_tcds;
   87 };
   88 
   89 int  asc_tcds_match (struct device *, void *, void *);
   90 void asc_tcds_attach(struct device *, struct device *, void *);
   91 
   92 /* Linkup to the rest of the kernel */
   93 struct cfattach asc_tcds_ca = {
   94         sizeof(struct asc_tcds_softc), asc_tcds_match, asc_tcds_attach
   95 };
   96 
   97 /*
   98  * Functions and the switch for the MI code.
   99  */
  100 int     tcds_dma_isintr(struct ncr53c9x_softc *);
  101 void    tcds_dma_reset(struct ncr53c9x_softc *);
  102 int     tcds_dma_intr(struct ncr53c9x_softc *);
  103 int     tcds_dma_setup(struct ncr53c9x_softc *, caddr_t *,
  104             size_t *, int, size_t *);
  105 void    tcds_dma_go(struct ncr53c9x_softc *);
  106 void    tcds_dma_stop(struct ncr53c9x_softc *);
  107 int     tcds_dma_isactive(struct ncr53c9x_softc *);
  108 void    tcds_clear_latched_intr(struct ncr53c9x_softc *);
  109 
  110 struct ncr53c9x_glue asc_tcds_glue = {
  111         asc_read_reg,
  112         asc_write_reg,
  113         tcds_dma_isintr,
  114         tcds_dma_reset,
  115         tcds_dma_intr,
  116         tcds_dma_setup,
  117         tcds_dma_go,
  118         tcds_dma_stop,
  119         tcds_dma_isactive,
  120         tcds_clear_latched_intr,
  121 };
  122 
  123 extern struct scsi_adapter asc_switch;
  124 extern struct scsi_device asc_dev;
  125 
  126 int
  127 asc_tcds_match(parent, cf, aux)
  128         struct device *parent;
  129         void *cf, *aux;
  130 {
  131 
  132         /* We always exist. */
  133         return 1;
  134 }
  135 
  136 #define DMAMAX(a)       (NBPG - ((a) & (NBPG - 1)))
  137 
  138 /*
  139  * Attach this instance, and then all the sub-devices
  140  */
  141 void
  142 asc_tcds_attach(parent, self, aux)
  143         struct device *parent, *self;
  144         void *aux;
  145 {
  146         struct tcdsdev_attach_args *tcdsdev = aux;
  147         struct asc_tcds_softc *asc = (struct asc_tcds_softc *)self;
  148         struct ncr53c9x_softc *sc = &asc->asc.sc_ncr53c9x;
  149         int error;
  150 
  151         /*
  152          * Set up glue for MI code early; we use some of it here.
  153          */
  154         sc->sc_glue = &asc_tcds_glue;
  155 
  156         asc->asc.sc_bst = tcdsdev->tcdsda_bst;
  157         asc->asc.sc_bsh = tcdsdev->tcdsda_bsh;
  158         asc->sc_tcds = tcdsdev->tcdsda_sc;
  159 
  160         /*
  161          * The TCDS ASIC cannot DMA across 8k boundaries, and this
  162          * driver is written such that each DMA segment gets a new
  163          * call to tcds_dma_setup().  Thus, the DMA map only needs
  164          * to support 8k transfers.
  165          */
  166         asc->asc.sc_dmat = tcdsdev->tcdsda_dmat;
  167         if ((error = bus_dmamap_create(asc->asc.sc_dmat, NBPG, 1, NBPG,
  168             NBPG, BUS_DMA_NOWAIT, &asc->asc.sc_dmamap)) < 0) {
  169                 printf("failed to create dma map, error = %d\n", error);
  170         }
  171 
  172         sc->sc_id = tcdsdev->tcdsda_id;
  173         sc->sc_freq = tcdsdev->tcdsda_freq;
  174 
  175         /* gimme MHz */
  176         sc->sc_freq /= 1000000;
  177 
  178         tcds_intr_establish(parent, tcdsdev->tcdsda_chip, ncr53c9x_intr, sc);
  179 
  180         /*
  181          * XXX More of this should be in ncr53c9x_attach(), but
  182          * XXX should we really poke around the chip that much in
  183          * XXX the MI code?  Think about this more...
  184          */
  185 
  186         /*
  187          * Set up static configuration info.
  188          */
  189         sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB;
  190         sc->sc_cfg2 = NCRCFG2_SCSI2;
  191         sc->sc_cfg3 = NCRCFG3_CDB;
  192         if (sc->sc_freq > 25)
  193                 sc->sc_cfg3 |= NCRF9XCFG3_FCLK;
  194         sc->sc_rev = tcdsdev->tcdsda_variant;
  195         if (tcdsdev->tcdsda_fast) {
  196                 sc->sc_features |= NCR_F_FASTSCSI;
  197                 sc->sc_cfg3_fscsi = NCRF9XCFG3_FSCSI;
  198         }
  199 
  200         /*
  201          * XXX minsync and maxxfer _should_ be set up in MI code,
  202          * XXX but it appears to have some dependency on what sort
  203          * XXX of DMA we're hooked up to, etc.
  204          */
  205 
  206         /*
  207          * This is the value used to start sync negotiations
  208          * Note that the NCR register "SYNCTP" is programmed
  209          * in "clocks per byte", and has a minimum value of 4.
  210          * The SCSI period used in negotiation is one-fourth
  211          * of the time (in nanoseconds) needed to transfer one byte.
  212          * Since the chip's clock is given in MHz, we have the following
  213          * formula: 4 * period = (1000 / freq) * 4
  214          */
  215         sc->sc_minsync = (1000 / sc->sc_freq) * tcdsdev->tcdsda_period / 4;
  216 
  217         sc->sc_maxxfer = 64 * 1024;
  218 
  219         /* Do the common parts of attachment. */
  220         ncr53c9x_attach(sc, &asc_switch, &asc_dev);
  221 }
  222 
  223 void
  224 tcds_dma_reset(sc)
  225         struct ncr53c9x_softc *sc;
  226 {
  227         struct asc_tcds_softc *asc = (struct asc_tcds_softc *)sc;
  228 
  229         /* TCDS SCSI disable/reset/enable. */
  230         tcds_scsi_reset(asc->sc_tcds);                  /* XXX */
  231 
  232         if (asc->asc.sc_flags & ASC_MAPLOADED)
  233                 bus_dmamap_unload(asc->asc.sc_dmat, asc->asc.sc_dmamap);
  234         asc->asc.sc_flags &= ~(ASC_DMAACTIVE|ASC_MAPLOADED);
  235 }
  236 
  237 /*
  238  * start a dma transfer or keep it going
  239  */
  240 int
  241 tcds_dma_setup(sc, addr, len, ispullup, dmasize)
  242         struct ncr53c9x_softc *sc;
  243         caddr_t *addr;
  244         size_t *len, *dmasize;
  245         int ispullup;                           /* DMA into main memory */
  246 {
  247         struct asc_tcds_softc *asc = (struct asc_tcds_softc *)sc;
  248         struct tcds_slotconfig *tcds = asc->sc_tcds;
  249         size_t size;
  250         u_int32_t dic;
  251 
  252         NCR_DMA(("tcds_dma %d: start %d@%p,%s\n", tcds->sc_slot,
  253                 (int)*asc->asc.sc_dmalen, *asc->asc.sc_dmaaddr,
  254                 (ispullup) ? "IN" : "OUT"));
  255 
  256         /*
  257          * the rules say we cannot transfer more than the limit
  258          * of this DMA chip (64k) and we cannot cross a 8k boundary.
  259          */
  260         size = min(*dmasize, DMAMAX((size_t)*addr));
  261         asc->asc.sc_dmaaddr = addr;
  262         asc->asc.sc_dmalen = len;
  263         asc->asc.sc_flags = (ispullup) ? ASC_ISPULLUP : 0;
  264         *dmasize = asc->asc.sc_dmasize = size;
  265 
  266         NCR_DMA(("dma_start: dmasize = %d\n", (int)size));
  267 
  268         if (size == 0)
  269                 return 0;
  270 
  271         if (bus_dmamap_load(asc->asc.sc_dmat, asc->asc.sc_dmamap, *addr, size,
  272             NULL, BUS_DMA_NOWAIT | (ispullup ? BUS_DMA_READ : BUS_DMA_WRITE))) {
  273                 /*
  274                  * XXX Should return an error, here, but the upper-layer
  275                  * XXX doesn't check the return value!
  276                  */
  277                 panic("tcds_dma_setup: dmamap load failed");
  278         }
  279 
  280         /* synchronize dmamap contents with memory image */
  281         bus_dmamap_sync(asc->asc.sc_dmat, asc->asc.sc_dmamap, 0, size,
  282                 (ispullup) ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
  283 
  284         /* load address, set/clear unaligned transfer and read/write bits. */
  285         bus_space_write_4(tcds->sc_bst, tcds->sc_bsh, tcds->sc_sda,
  286             asc->asc.sc_dmamap->dm_segs[0].ds_addr >> 2);
  287         dic = bus_space_read_4(tcds->sc_bst, tcds->sc_bsh, tcds->sc_dic);
  288         dic &= ~TCDS_DIC_ADDRMASK;
  289         dic |= asc->asc.sc_dmamap->dm_segs[0].ds_addr & TCDS_DIC_ADDRMASK;
  290         if (ispullup)
  291                 dic |= TCDS_DIC_WRITE;
  292         else
  293                 dic &= ~TCDS_DIC_WRITE;
  294         bus_space_write_4(tcds->sc_bst, tcds->sc_bsh, tcds->sc_dic, dic);
  295 
  296         asc->asc.sc_flags |= ASC_MAPLOADED;
  297         return 0;
  298 }
  299 
  300 void
  301 tcds_dma_go(sc)
  302         struct ncr53c9x_softc *sc;
  303 {
  304         struct asc_tcds_softc *asc = (struct asc_tcds_softc *)sc;
  305 
  306         /* mark unit as DMA-active */
  307         asc->asc.sc_flags |= ASC_DMAACTIVE;
  308 
  309         /* start DMA */
  310         tcds_dma_enable(asc->sc_tcds, 1);
  311 }
  312 
  313 void
  314 tcds_dma_stop(sc)
  315         struct ncr53c9x_softc *sc;
  316 {
  317 #if 0
  318         struct asc_tcds_softc *asc = (struct asc_tcds_softc *)sc;
  319 #endif
  320 
  321         /*
  322          * XXX STOP DMA HERE!
  323          */
  324 }
  325 
  326 /*
  327  * Pseudo (chained) interrupt from the asc driver to kick the
  328  * current running DMA transfer. Called from ncr53c9x_intr()
  329  * for now.
  330  *
  331  * return 1 if it was a DMA continue.
  332  */
  333 int
  334 tcds_dma_intr(sc)
  335         struct ncr53c9x_softc *sc;
  336 {
  337         struct asc_tcds_softc *asc = (struct asc_tcds_softc *)sc;
  338         struct tcds_slotconfig *tcds = asc->sc_tcds;
  339         int trans, resid;
  340         u_int32_t tcl, tcm;
  341         u_int32_t dud, dudmask, *addr;
  342         bus_addr_t pa;
  343 
  344         NCR_DMA(("tcds_dma %d: intr", tcds->sc_slot));
  345 
  346         if (tcds_scsi_iserr(tcds))
  347                 return 0;
  348 
  349         /* This is an "assertion" :) */
  350         if ((asc->asc.sc_flags & ASC_DMAACTIVE) == 0)
  351                 panic("tcds_dma_intr: DMA wasn't active");
  352 
  353         /* DMA has stopped */
  354         tcds_dma_enable(tcds, 0);
  355         asc->asc.sc_flags &= ~ASC_DMAACTIVE;
  356 
  357         if (asc->asc.sc_dmasize == 0) {
  358                 /* A "Transfer Pad" operation completed */
  359                 tcl = NCR_READ_REG(sc, NCR_TCL);
  360                 tcm = NCR_READ_REG(sc, NCR_TCM);
  361                 NCR_DMA(("dma_intr: discarded %d bytes (tcl=%d, tcm=%d)\n",
  362                     tcl | (tcm << 8), tcl, tcm));
  363                 return 0;
  364         }
  365 
  366         resid = 0;
  367         if ((asc->asc.sc_flags & ASC_ISPULLUP) == 0 &&
  368             (resid = (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF)) != 0) {
  369                 NCR_DMA(("dma_intr: empty esp FIFO of %d ", resid));
  370                 DELAY(1);
  371         }
  372 
  373         resid += (tcl = NCR_READ_REG(sc, NCR_TCL));
  374         resid += (tcm = NCR_READ_REG(sc, NCR_TCM)) << 8;
  375 
  376         trans = asc->asc.sc_dmasize - resid;
  377         if (trans < 0) {                        /* transferred < 0 ? */
  378                 printf("tcds_dma %d: xfer (%d) > req (%d)\n",
  379                     tcds->sc_slot, trans, (int)asc->asc.sc_dmasize);
  380                 trans = asc->asc.sc_dmasize;
  381         }
  382 
  383         NCR_DMA(("dma_intr: tcl=%d, tcm=%d; trans=%d, resid=%d\n",
  384             tcl, tcm, trans, resid));
  385 
  386         *asc->asc.sc_dmalen -= trans;
  387         *asc->asc.sc_dmaaddr += trans;
  388 
  389         bus_dmamap_sync(asc->asc.sc_dmat, asc->asc.sc_dmamap,
  390                         0, asc->asc.sc_dmamap->dm_mapsize,
  391                         (asc->asc.sc_flags & ASC_ISPULLUP)
  392                                 ? BUS_DMASYNC_POSTREAD
  393                                 : BUS_DMASYNC_POSTWRITE);
  394 
  395         /*
  396          * Clean up unaligned DMAs into main memory.
  397          */
  398         if (asc->asc.sc_flags & ASC_ISPULLUP) {
  399                 /* Handle unaligned starting address, length. */
  400                 dud = bus_space_read_4(tcds->sc_bst,
  401                     tcds->sc_bsh, tcds->sc_dud0);
  402                 if ((dud & TCDS_DUD0_VALIDBITS) != 0) {
  403                         addr = (u_int32_t *)
  404                             ((paddr_t)*asc->asc.sc_dmaaddr & ~0x3);
  405                         dudmask = 0;
  406                         if (dud & TCDS_DUD0_VALID00)
  407                                 panic("tcds_dma: dud0 byte 0 valid");
  408                         if (dud & TCDS_DUD0_VALID01)
  409                                 dudmask |= TCDS_DUD_BYTE01;
  410                         if (dud & TCDS_DUD0_VALID10)
  411                                 dudmask |= TCDS_DUD_BYTE10;
  412 #ifdef DIAGNOSTIC
  413                         if (dud & TCDS_DUD0_VALID11)
  414                                 dudmask |= TCDS_DUD_BYTE11;
  415 #endif
  416                         NCR_DMA(("dud0 at %p dudmask 0x%x\n",
  417                             addr, dudmask));
  418                         *addr = (*addr & ~dudmask) | (dud & dudmask);
  419                 }
  420                 dud = bus_space_read_4(tcds->sc_bst,
  421                     tcds->sc_bsh, tcds->sc_dud1);
  422                 if ((dud & TCDS_DUD1_VALIDBITS) != 0) {
  423                         pa = bus_space_read_4(tcds->sc_bst, tcds->sc_bsh,
  424                             tcds->sc_sda) << 2;
  425                         dudmask = 0;
  426                         if (dud & TCDS_DUD1_VALID00)
  427                                 dudmask |= TCDS_DUD_BYTE00;
  428                         if (dud & TCDS_DUD1_VALID01)
  429                                 dudmask |= TCDS_DUD_BYTE01;
  430                         if (dud & TCDS_DUD1_VALID10)
  431                                 dudmask |= TCDS_DUD_BYTE10;
  432 #ifdef DIAGNOSTIC
  433                         if (dud & TCDS_DUD1_VALID11)
  434                                 panic("tcds_dma: dud1 byte 3 valid");
  435 #endif
  436                         NCR_DMA(("dud1 at 0x%lx dudmask 0x%x\n",
  437                             pa, dudmask));
  438                         /* XXX Fix TC_PHYS_TO_UNCACHED() */
  439 #if defined(__alpha__)
  440                         addr = (u_int32_t *)ALPHA_PHYS_TO_K0SEG(pa);
  441 #elif defined(__mips__)
  442                         addr = (u_int32_t *)MIPS_PHYS_TO_KSEG1(pa);
  443 #else
  444 #error TURBOchannel only exists on DECs, folks...
  445 #endif
  446                         *addr = (*addr & ~dudmask) | (dud & dudmask);
  447                 }
  448                 /* XXX deal with saved residual byte? */
  449         }
  450 
  451         bus_dmamap_unload(asc->asc.sc_dmat, asc->asc.sc_dmamap);
  452         asc->asc.sc_flags &= ~ASC_MAPLOADED;
  453 
  454         return 0;
  455 }
  456 
  457 /*
  458  * Glue functions.
  459  */
  460 int
  461 tcds_dma_isintr(sc)
  462         struct ncr53c9x_softc *sc;
  463 {
  464         struct asc_tcds_softc *asc = (struct asc_tcds_softc *)sc;
  465         int x;
  466 
  467         x = tcds_scsi_isintr(asc->sc_tcds, 1);
  468 
  469         /* XXX */
  470         return x;
  471 }
  472 
  473 int
  474 tcds_dma_isactive(sc)
  475         struct ncr53c9x_softc *sc;
  476 {
  477         struct asc_tcds_softc *asc = (struct asc_tcds_softc *)sc;
  478 
  479         return !!(asc->asc.sc_flags & ASC_DMAACTIVE);
  480 }
  481 
  482 void
  483 tcds_clear_latched_intr(sc)
  484         struct ncr53c9x_softc *sc;
  485 {
  486         struct asc_tcds_softc *asc = (struct asc_tcds_softc *)sc;
  487 
  488         /* Clear the TCDS interrupt bit. */
  489         (void)tcds_scsi_isintr(asc->sc_tcds, 1);
  490 }

/* [<][>][^][v][top][bottom][index][help] */