LCOV - code coverage report
Current view: top level - dev/pci - pcscp.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 210 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 11 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: pcscp.c,v 1.20 2015/03/14 03:38:48 jsg Exp $  */
       2             : /*      $NetBSD: pcscp.c,v 1.26 2003/10/19 10:25:42 tsutsui Exp $       */
       3             : 
       4             : /*-
       5             :  * Copyright (c) 1997, 1998, 1999 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; Izumi Tsutsui.
      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             :  *
      21             :  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
      22             :  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
      23             :  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
      24             :  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
      25             :  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      26             :  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      27             :  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      28             :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      29             :  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      30             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      31             :  * POSSIBILITY OF SUCH DAMAGE.
      32             :  */
      33             : 
      34             : /*
      35             :  * pcscp.c: device dependent code for AMD Am53c974 (PCscsi-PCI)
      36             :  * written by Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
      37             :  *
      38             :  * Technical manual available at
      39             :  * http://www.amd.com/files/connectivitysolutions/networking/archivednetworking/19113.pdf
      40             :  */
      41             : 
      42             : #include <sys/param.h>
      43             : #include <sys/systm.h>
      44             : #include <sys/device.h>
      45             : #include <sys/buf.h>
      46             : 
      47             : #include <machine/bus.h>
      48             : 
      49             : #include <scsi/scsi_all.h>
      50             : #include <scsi/scsiconf.h>
      51             : #include <scsi/scsi_message.h>
      52             : 
      53             : #include <dev/pci/pcireg.h>
      54             : #include <dev/pci/pcivar.h>
      55             : #include <dev/pci/pcidevs.h>
      56             : 
      57             : #include <dev/ic/ncr53c9xreg.h>
      58             : #include <dev/ic/ncr53c9xvar.h>
      59             : 
      60             : #include <dev/pci/pcscpreg.h>
      61             : 
      62             : #define IO_MAP_REG      0x10
      63             : 
      64             : struct pcscp_softc {
      65             :         struct ncr53c9x_softc sc_ncr53c9x;      /* glue to MI code */
      66             : 
      67             :         bus_space_tag_t sc_st;          /* bus space tag */
      68             :         bus_space_handle_t sc_sh;       /* bus space handle */
      69             :         void *sc_ih;                    /* interrupt cookie */
      70             : 
      71             :         bus_dma_tag_t sc_dmat;          /* DMA tag */
      72             : 
      73             :         bus_dmamap_t sc_xfermap;        /* DMA map for transfers */
      74             : 
      75             :         u_int32_t *sc_mdladdr;          /* MDL array */
      76             :         bus_dmamap_t sc_mdldmap;        /* MDL DMA map */
      77             : 
      78             :         int     sc_active;              /* DMA state */
      79             :         int     sc_datain;              /* DMA Data Direction */
      80             :         size_t  sc_dmasize;             /* DMA size */
      81             :         char    **sc_dmaaddr;           /* DMA address */
      82             :         size_t  *sc_dmalen;             /* DMA length */
      83             : };
      84             : 
      85             : #define READ_DMAREG(sc, reg) \
      86             :         bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (reg))
      87             : #define WRITE_DMAREG(sc, reg, var) \
      88             :         bus_space_write_4((sc)->sc_st, (sc)->sc_sh, (reg), (var))
      89             : 
      90             : #define PCSCP_READ_REG(sc, reg) \
      91             :         bus_space_read_1((sc)->sc_st, (sc)->sc_sh, (reg) << 2)
      92             : #define PCSCP_WRITE_REG(sc, reg, val) \
      93             :         bus_space_write_1((sc)->sc_st, (sc)->sc_sh, (reg) << 2, (val))
      94             : 
      95             : int     pcscp_match(struct device *, void *, void *); 
      96             : void    pcscp_attach(struct device *, struct device *, void *);  
      97             : 
      98             : struct cfattach pcscp_ca = {
      99             :         sizeof(struct pcscp_softc), pcscp_match, pcscp_attach
     100             : };
     101             : 
     102             : struct cfdriver pcscp_cd = {
     103             :         NULL, "pcscp", DV_DULL
     104             : };
     105             : 
     106             : /*
     107             :  * Functions and the switch for the MI code.
     108             :  */
     109             : 
     110             : u_char  pcscp_read_reg(struct ncr53c9x_softc *, int);
     111             : void    pcscp_write_reg(struct ncr53c9x_softc *, int, u_char);
     112             : int     pcscp_dma_isintr(struct ncr53c9x_softc *);
     113             : void    pcscp_dma_reset(struct ncr53c9x_softc *);
     114             : int     pcscp_dma_intr(struct ncr53c9x_softc *);
     115             : int     pcscp_dma_setup(struct ncr53c9x_softc *, caddr_t *,
     116             :                                size_t *, int, size_t *);
     117             : void    pcscp_dma_go(struct ncr53c9x_softc *);
     118             : void    pcscp_dma_stop(struct ncr53c9x_softc *);
     119             : int     pcscp_dma_isactive(struct ncr53c9x_softc *);
     120             : 
     121             : struct ncr53c9x_glue pcscp_glue = {
     122             :         pcscp_read_reg,
     123             :         pcscp_write_reg,
     124             :         pcscp_dma_isintr,
     125             :         pcscp_dma_reset,
     126             :         pcscp_dma_intr,
     127             :         pcscp_dma_setup,
     128             :         pcscp_dma_go,
     129             :         pcscp_dma_stop,
     130             :         pcscp_dma_isactive,
     131             :         NULL,                   /* gl_clear_latched_intr */
     132             : };
     133             : 
     134             : int
     135           0 : pcscp_match(struct device *parent, void *match, void *aux)
     136             : {
     137           0 :         struct pci_attach_args *pa = aux;
     138             : 
     139           0 :         if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_AMD)
     140           0 :                 return 0;
     141             : 
     142           0 :         switch (PCI_PRODUCT(pa->pa_id)) {
     143             :         case PCI_PRODUCT_AMD_PCSCSI_PCI:
     144           0 :                 return 1;
     145             :         }
     146           0 :         return 0;
     147           0 : }
     148             : 
     149             : /*
     150             :  * Attach this instance, and then all the sub-devices
     151             :  */
     152             : void
     153           0 : pcscp_attach(struct device *parent, struct device *self, void *aux)
     154             : {
     155           0 :         struct pci_attach_args *pa = aux;
     156           0 :         struct pcscp_softc *esc = (void *)self;
     157           0 :         struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
     158           0 :         bus_space_tag_t iot;
     159           0 :         bus_space_handle_t ioh;
     160           0 :         pci_intr_handle_t ih;
     161             :         const char *intrstr;
     162           0 :         bus_dma_segment_t seg;
     163           0 :         int error, rseg;
     164             : 
     165           0 :         if (pci_mapreg_map(pa, IO_MAP_REG, PCI_MAPREG_TYPE_IO, 0,
     166             :              &iot, &ioh, NULL, NULL, 0)) {
     167           0 :                 printf("%s: unable to map registers\n", sc->sc_dev.dv_xname);
     168           0 :                 return;
     169             :         }
     170             : 
     171           0 :         sc->sc_glue = &pcscp_glue;
     172             : 
     173           0 :         esc->sc_st = iot;
     174           0 :         esc->sc_sh = ioh;
     175           0 :         esc->sc_dmat = pa->pa_dmat;
     176             : 
     177             :         /*
     178             :          * XXX More of this should be in ncr53c9x_attach(), but
     179             :          * XXX should we really poke around the chip that much in
     180             :          * XXX the MI code?  Think about this more...
     181             :          */
     182             : 
     183             :         /*
     184             :          * Set up static configuration info.
     185             :          */
     186             : 
     187             :         /*
     188             :          * XXX should read configuration from EEPROM?
     189             :          *
     190             :          * MI ncr53c9x driver does not support configuration
     191             :          * per each target device, though...
     192             :          */
     193           0 :         sc->sc_id = 7;
     194           0 :         sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB;
     195           0 :         sc->sc_cfg2 = NCRCFG2_SCSI2 | NCRCFG2_FE;
     196           0 :         sc->sc_cfg3 = NCRAMDCFG3_IDM | NCRAMDCFG3_FCLK;
     197           0 :         sc->sc_cfg4 = NCRAMDCFG4_GE12NS | NCRAMDCFG4_RADE;
     198           0 :         sc->sc_rev = NCR_VARIANT_AM53C974;
     199           0 :         sc->sc_features = NCR_F_FASTSCSI;
     200           0 :         sc->sc_cfg3_fscsi = NCRAMDCFG3_FSCSI;
     201           0 :         sc->sc_freq = 40; /* MHz */
     202             : 
     203             :         /*
     204             :          * XXX minsync and maxxfer _should_ be set up in MI code,
     205             :          * XXX but it appears to have some dependency on what sort
     206             :          * XXX of DMA we're hooked up to, etc.
     207             :          */
     208             : 
     209             :         /*
     210             :          * This is the value used to start sync negotiations
     211             :          * Note that the NCR register "SYNCTP" is programmed
     212             :          * in "clocks per byte", and has a minimum value of 4.
     213             :          * The SCSI period used in negotiation is one-fourth
     214             :          * of the time (in nanoseconds) needed to transfer one byte.
     215             :          * Since the chip's clock is given in MHz, we have the following
     216             :          * formula: 4 * period = (1000 / freq) * 4
     217             :          */
     218             : 
     219           0 :         sc->sc_minsync = 1000 / sc->sc_freq; 
     220             : 
     221             :         /* Really no limit, but since we want to fit into the TCR... */
     222           0 :         sc->sc_maxxfer = 16 * 1024 * 1024;
     223             : 
     224             :         /*
     225             :          * Create the DMA maps for the data transfers.
     226             :          */
     227             : 
     228             : #define MDL_SEG_SIZE    0x1000 /* 4kbyte per segment */
     229             : #define MDL_SEG_OFFSET  0x0FFF
     230             : #define MDL_SIZE        (MAXPHYS / MDL_SEG_SIZE + 1) /* no hardware limit? */
     231             : 
     232           0 :         if (bus_dmamap_create(esc->sc_dmat, MAXPHYS, MDL_SIZE, MDL_SEG_SIZE,
     233             :             MDL_SEG_SIZE, BUS_DMA_NOWAIT, &esc->sc_xfermap)) {
     234           0 :                 printf("%s: can't create dma maps\n", sc->sc_dev.dv_xname);
     235           0 :                 return;
     236             :         }
     237             : 
     238             :         /*
     239             :          * Allocate and map memory for the MDL.
     240             :          */
     241             : 
     242           0 :         if ((error = bus_dmamem_alloc(esc->sc_dmat,
     243             :             sizeof(u_int32_t) * MDL_SIZE, PAGE_SIZE, 0, &seg, 1, &rseg,
     244           0 :             BUS_DMA_NOWAIT)) != 0) {
     245           0 :                 printf("%s: unable to allocate memory for the MDL, "
     246           0 :                     "error = %d\n", sc->sc_dev.dv_xname, error);
     247           0 :                 goto fail_0;
     248             :         }
     249           0 :         if ((error = bus_dmamem_map(esc->sc_dmat, &seg, rseg,
     250             :             sizeof(u_int32_t) * MDL_SIZE , (caddr_t *)&esc->sc_mdladdr,
     251           0 :             BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
     252           0 :                 printf("%s: unable to map the MDL memory, error = %d\n",
     253           0 :                     sc->sc_dev.dv_xname, error);
     254           0 :                 goto fail_1;
     255             :         }
     256           0 :         if ((error = bus_dmamap_create(esc->sc_dmat, 
     257             :             sizeof(u_int32_t) * MDL_SIZE, 1, sizeof(u_int32_t) * MDL_SIZE,
     258           0 :             0, BUS_DMA_NOWAIT, &esc->sc_mdldmap)) != 0) {
     259           0 :                 printf("%s: unable to map_create for the MDL, error = %d\n",
     260           0 :                     sc->sc_dev.dv_xname, error);
     261           0 :                 goto fail_2;
     262             :         }
     263           0 :         if ((error = bus_dmamap_load(esc->sc_dmat, esc->sc_mdldmap,
     264             :              esc->sc_mdladdr, sizeof(u_int32_t) * MDL_SIZE,
     265           0 :              NULL, BUS_DMA_NOWAIT)) != 0) {
     266           0 :                 printf("%s: unable to load for the MDL, error = %d\n",
     267           0 :                     sc->sc_dev.dv_xname, error);
     268           0 :                 goto fail_3;
     269             :         }
     270             : 
     271             :         /* map and establish interrupt */
     272           0 :         if (pci_intr_map(pa, &ih)) {
     273           0 :                 printf(": couldn't map interrupt\n");
     274           0 :                 goto fail_4;
     275             :         }
     276             : 
     277           0 :         intrstr = pci_intr_string(pa->pa_pc, ih);
     278           0 :         esc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
     279           0 :             ncr53c9x_intr, esc, sc->sc_dev.dv_xname);
     280           0 :         if (esc->sc_ih == NULL) {
     281           0 :                 printf(": couldn't establish interrupt");
     282           0 :                 if (intrstr != NULL)
     283           0 :                         printf(" at %s", intrstr);
     284           0 :                 printf("\n");
     285           0 :                 goto fail_4;
     286             :         }
     287           0 :         if (intrstr != NULL)
     288           0 :                 printf(": %s\n", intrstr);
     289             : 
     290             :         /* Do the common parts of attachment. */
     291           0 :         printf("%s", sc->sc_dev.dv_xname);
     292             : 
     293           0 :         ncr53c9x_attach(sc);
     294             : 
     295             :         /* Turn on target selection using the `dma' method */
     296           0 :         sc->sc_features |= NCR_F_DMASELECT;
     297             : 
     298           0 :         return;
     299             : 
     300             : fail_4:
     301           0 :         bus_dmamap_unload(esc->sc_dmat, esc->sc_mdldmap);
     302             : fail_3:
     303           0 :         bus_dmamap_destroy(esc->sc_dmat, esc->sc_mdldmap);
     304             : fail_2:
     305           0 :         bus_dmamem_unmap(esc->sc_dmat, (caddr_t)esc->sc_mdldmap,
     306             :             sizeof(uint32_t) * MDL_SIZE);
     307             : fail_1:
     308           0 :         bus_dmamem_free(esc->sc_dmat, &seg, rseg);
     309             : fail_0:
     310           0 :         bus_dmamap_destroy(esc->sc_dmat, esc->sc_xfermap);
     311           0 : }
     312             : 
     313             : /*
     314             :  * Glue functions.
     315             :  */
     316             : 
     317             : u_char
     318           0 : pcscp_read_reg(struct ncr53c9x_softc *sc, int reg)
     319             : {
     320           0 :         struct pcscp_softc *esc = (struct pcscp_softc *)sc;
     321             : 
     322           0 :         return PCSCP_READ_REG(esc, reg);
     323             : }
     324             : 
     325             : void
     326           0 : pcscp_write_reg(struct ncr53c9x_softc *sc, int reg, u_char v)
     327             : {
     328           0 :         struct pcscp_softc *esc = (struct pcscp_softc *)sc;
     329             : 
     330           0 :         PCSCP_WRITE_REG(esc, reg, v);
     331           0 : }
     332             : 
     333             : int
     334           0 : pcscp_dma_isintr(struct ncr53c9x_softc *sc)
     335             : {
     336           0 :         struct pcscp_softc *esc = (struct pcscp_softc *)sc;
     337             : 
     338           0 :         return (PCSCP_READ_REG(esc, NCR_STAT) & NCRSTAT_INT) != 0;
     339             : }
     340             : 
     341             : void
     342           0 : pcscp_dma_reset(struct ncr53c9x_softc *sc)
     343             : {
     344           0 :         struct pcscp_softc *esc = (struct pcscp_softc *)sc;
     345             : 
     346           0 :         WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE);
     347             : 
     348           0 :         esc->sc_active = 0;
     349           0 : }
     350             : 
     351             : int
     352           0 : pcscp_dma_intr(struct ncr53c9x_softc *sc)
     353             : {
     354           0 :         struct pcscp_softc *esc = (struct pcscp_softc *)sc;
     355             :         int trans, resid, i;
     356           0 :         bus_dmamap_t dmap = esc->sc_xfermap;
     357           0 :         int datain = esc->sc_datain;
     358             :         u_int32_t dmastat;
     359             :         char *p = NULL;
     360             : 
     361           0 :         dmastat = READ_DMAREG(esc, DMA_STAT);
     362             : 
     363           0 :         if (dmastat & DMASTAT_ERR) {
     364             :                 /* XXX not tested... */
     365           0 :                 WRITE_DMAREG(esc, DMA_CMD,
     366             :                     DMACMD_ABORT | (datain ? DMACMD_DIR : 0));
     367             : 
     368           0 :                 printf("%s: error: DMA error detected; Aborting.\n",
     369           0 :                     sc->sc_dev.dv_xname);
     370           0 :                 bus_dmamap_unload(esc->sc_dmat, dmap);
     371           0 :                 return -1;
     372             :         }
     373             : 
     374           0 :         if (dmastat & DMASTAT_ABT) {
     375             :                 /* XXX What should be done? */
     376           0 :                 printf("%s: dma_intr: DMA aborted.\n", sc->sc_dev.dv_xname);
     377           0 :                 WRITE_DMAREG(esc, DMA_CMD,
     378             :                     DMACMD_IDLE | (datain ? DMACMD_DIR : 0));
     379           0 :                 esc->sc_active = 0;
     380           0 :                 return 0;
     381             :         }
     382             : 
     383             : #ifdef DIAGNOSTIC
     384             :         /* This is an "assertion" :) */
     385           0 :         if (esc->sc_active == 0)
     386           0 :                 panic("pcscp dmaintr: DMA wasn't active");
     387             : #endif
     388             : 
     389             :         /* DMA has stopped */
     390             : 
     391           0 :         esc->sc_active = 0;
     392             : 
     393           0 :         if (esc->sc_dmasize == 0) {
     394             :                 /* A "Transfer Pad" operation completed */
     395           0 :                 NCR_DMA(("dmaintr: discarded %d bytes (tcl=%d, tcm=%d)\n",
     396             :                     PCSCP_READ_REG(esc, NCR_TCL) |
     397             :                     (PCSCP_READ_REG(esc, NCR_TCM) << 8),
     398             :                     PCSCP_READ_REG(esc, NCR_TCL),
     399             :                     PCSCP_READ_REG(esc, NCR_TCM)));
     400           0 :                 return 0;
     401             :         }
     402             : 
     403             :         resid = 0;
     404             :         /*
     405             :          * If a transfer onto the SCSI bus gets interrupted by the device
     406             :          * (e.g. for a SAVEPOINTER message), the data in the FIFO counts
     407             :          * as residual since the ESP counter registers get decremented as
     408             :          * bytes are clocked into the FIFO.
     409             :          */
     410           0 :         if (!datain &&
     411           0 :             (resid = (PCSCP_READ_REG(esc, NCR_FFLAG) & NCRFIFO_FF)) != 0) {
     412           0 :                 NCR_DMA(("pcscp_dma_intr: empty esp FIFO of %d ", resid));
     413             :         }
     414             : 
     415           0 :         if ((sc->sc_espstat & NCRSTAT_TC) == 0) {
     416             :                 /*
     417             :                  * `Terminal count' is off, so read the residue
     418             :                  * out of the ESP counter registers.
     419             :                  */
     420           0 :                 if (datain) {
     421           0 :                         resid = PCSCP_READ_REG(esc, NCR_FFLAG) & NCRFIFO_FF;
     422           0 :                         while (resid > 1)
     423             :                                 resid =
     424           0 :                                     PCSCP_READ_REG(esc, NCR_FFLAG) & NCRFIFO_FF;
     425           0 :                         WRITE_DMAREG(esc, DMA_CMD, DMACMD_BLAST | DMACMD_MDL |
     426             :                             (datain ? DMACMD_DIR : 0));
     427             : 
     428           0 :                         for (i = 0; i < 0x8000; i++) /* XXX 0x8000 ? */
     429           0 :                                 if (READ_DMAREG(esc, DMA_STAT) & DMASTAT_BCMP)
     430             :                                         break;
     431             : 
     432             :                         /* See the below comments... */
     433           0 :                         if (resid)
     434           0 :                                 p = *esc->sc_dmaaddr;
     435             :                 }
     436             :                 
     437           0 :                 resid += PCSCP_READ_REG(esc, NCR_TCL) |
     438           0 :                     (PCSCP_READ_REG(esc, NCR_TCM) << 8) |
     439           0 :                     (PCSCP_READ_REG(esc, NCR_TCH) << 16);
     440           0 :         } else {
     441           0 :                 while ((dmastat & DMASTAT_DONE) == 0)
     442           0 :                         dmastat = READ_DMAREG(esc, DMA_STAT);
     443             :         }
     444             : 
     445           0 :         WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE | (datain ? DMACMD_DIR : 0));
     446             : 
     447             :         /* sync MDL */
     448           0 :         bus_dmamap_sync(esc->sc_dmat, esc->sc_mdldmap,
     449             :             0, sizeof(u_int32_t) * dmap->dm_nsegs, BUS_DMASYNC_POSTWRITE);
     450             :         /* sync transfer buffer */
     451           0 :         bus_dmamap_sync(esc->sc_dmat, dmap, 0, dmap->dm_mapsize,
     452             :             datain ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
     453           0 :         bus_dmamap_unload(esc->sc_dmat, dmap);
     454             : 
     455           0 :         trans = esc->sc_dmasize - resid;
     456             : 
     457             :         /*
     458             :          * From the technical manual notes:
     459             :          *
     460             :          * `In some odd byte conditions, one residual byte will be left
     461             :          *  in the SCSI FIFO, and the FIFO flags will never count to 0.
     462             :          *  When this happens, the residual byte should be retrieved
     463             :          *  via PIO following completion of the BLAST operation.'
     464             :          */
     465             :         
     466           0 :         if (p) {
     467           0 :                 p += trans;
     468           0 :                 *p = PCSCP_READ_REG(esc, NCR_FIFO);
     469           0 :                 trans++;
     470           0 :         }
     471             : 
     472           0 :         if (trans < 0) {                     /* transferred < 0 ? */
     473             : #if 0
     474             :                 /*
     475             :                  * This situation can happen in perfectly normal operation
     476             :                  * if the ESP is reselected while using DMA to select
     477             :                  * another target.  As such, don't print the warning.
     478             :                  */
     479             :                 printf("%s: xfer (%d) > req (%d)\n",
     480             :                     sc->sc_dev.dv_xname, trans, esc->sc_dmasize);
     481             : #endif
     482           0 :                 trans = esc->sc_dmasize;
     483           0 :         }
     484             : 
     485           0 :         NCR_DMA(("dmaintr: tcl=%d, tcm=%d, tch=%d; trans=%d, resid=%d\n",
     486             :             PCSCP_READ_REG(esc, NCR_TCL),
     487             :             PCSCP_READ_REG(esc, NCR_TCM),
     488             :             PCSCP_READ_REG(esc, NCR_TCH),
     489             :             trans, resid));
     490             : 
     491           0 :         *esc->sc_dmalen -= trans;
     492           0 :         *esc->sc_dmaaddr += trans;
     493             : 
     494           0 :         return 0;
     495           0 : }
     496             : 
     497             : int
     498           0 : pcscp_dma_setup(struct ncr53c9x_softc *sc, caddr_t *addr, size_t *len,
     499             :     int datain, size_t *dmasize)
     500             : {
     501           0 :         struct pcscp_softc *esc = (struct pcscp_softc *)sc;
     502           0 :         bus_dmamap_t dmap = esc->sc_xfermap;
     503             :         u_int32_t *mdl;
     504             :         int error, nseg, seg;
     505             :         bus_addr_t s_offset, s_addr;
     506             : 
     507           0 :         WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE | (datain ? DMACMD_DIR : 0));
     508             : 
     509           0 :         esc->sc_dmaaddr = addr;
     510           0 :         esc->sc_dmalen = len;
     511           0 :         esc->sc_dmasize = *dmasize;
     512           0 :         esc->sc_datain = datain;
     513             : 
     514             : #ifdef DIAGNOSTIC
     515           0 :         if ((*dmasize / MDL_SEG_SIZE) > MDL_SIZE)
     516           0 :                 panic("pcscp: transfer size too large");
     517             : #endif
     518             : 
     519             :         /*
     520             :          * No need to set up DMA in `Transfer Pad' operation.
     521             :          * (case of *dmasize == 0)
     522             :          */
     523           0 :         if (*dmasize == 0)
     524           0 :                 return 0;
     525             : 
     526           0 :         error = bus_dmamap_load(esc->sc_dmat, dmap, *esc->sc_dmaaddr,
     527             :             *esc->sc_dmalen, NULL,
     528             :             ((sc->sc_nexus->xs->flags & SCSI_NOSLEEP) ?
     529             :             BUS_DMA_NOWAIT : BUS_DMA_WAITOK) | BUS_DMA_STREAMING |
     530             :             ((sc->sc_nexus->xs->flags & SCSI_DATA_IN) ?
     531             :              BUS_DMA_READ : BUS_DMA_WRITE));
     532           0 :         if (error) {
     533           0 :                 printf("%s: unable to load dmamap, error = %d\n",
     534           0 :                     sc->sc_dev.dv_xname, error);
     535           0 :                 return error;
     536             :         }
     537             : 
     538             :         /* set transfer length */
     539           0 :         WRITE_DMAREG(esc, DMA_STC, *dmasize); 
     540             : 
     541             :         /* set up MDL */
     542           0 :         mdl = esc->sc_mdladdr;
     543           0 :         nseg = dmap->dm_nsegs;
     544             : 
     545             :         /* the first segment is possibly not aligned with 4k MDL boundary */
     546           0 :         s_addr = dmap->dm_segs[0].ds_addr;
     547           0 :         s_offset = s_addr & MDL_SEG_OFFSET;
     548           0 :         s_addr -= s_offset;
     549             : 
     550             :         /* set the first MDL and offset */
     551           0 :         WRITE_DMAREG(esc, DMA_SPA, s_offset); 
     552           0 :         *mdl++ = htole32(s_addr);
     553             : 
     554             :         /* the rest dmamap segments are aligned with 4k boundary */
     555           0 :         for (seg = 1; seg < nseg; seg++)
     556           0 :                 *mdl++ = htole32(dmap->dm_segs[seg].ds_addr);
     557             : 
     558           0 :         return 0;
     559           0 : }
     560             : 
     561             : void
     562           0 : pcscp_dma_go(struct ncr53c9x_softc *sc)
     563             : {
     564           0 :         struct pcscp_softc *esc = (struct pcscp_softc *)sc;
     565           0 :         bus_dmamap_t dmap = esc->sc_xfermap, mdldmap = esc->sc_mdldmap;
     566           0 :         int datain = esc->sc_datain;
     567             : 
     568             :         /* No DMA transfer in Transfer Pad operation */
     569           0 :         if (esc->sc_dmasize == 0)
     570           0 :                 return;
     571             : 
     572             :         /* sync transfer buffer */
     573           0 :         bus_dmamap_sync(esc->sc_dmat, dmap, 0, dmap->dm_mapsize,
     574             :             datain ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
     575             : 
     576             :         /* sync MDL */
     577           0 :         bus_dmamap_sync(esc->sc_dmat, mdldmap,
     578             :             0, sizeof(u_int32_t) * dmap->dm_nsegs, BUS_DMASYNC_PREWRITE); 
     579             : 
     580             :         /* set Starting MDL Address */
     581           0 :         WRITE_DMAREG(esc, DMA_SMDLA, mdldmap->dm_segs[0].ds_addr);
     582             : 
     583             :         /* set DMA command register bits */
     584             :         /* XXX DMA Transfer Interrupt Enable bit is broken? */
     585           0 :         WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE | DMACMD_MDL |
     586             :             /* DMACMD_INTE | */
     587             :             (datain ? DMACMD_DIR : 0));
     588             : 
     589             :         /* issue DMA start command */
     590           0 :         WRITE_DMAREG(esc, DMA_CMD, DMACMD_START | DMACMD_MDL |
     591             :             /* DMACMD_INTE | */
     592             :             (datain ? DMACMD_DIR : 0));
     593             : 
     594           0 :         esc->sc_active = 1;
     595           0 : }
     596             : 
     597             : void
     598           0 : pcscp_dma_stop(struct ncr53c9x_softc *sc)
     599             : {
     600           0 :         struct pcscp_softc *esc = (struct pcscp_softc *)sc;
     601             : 
     602             :         /* dma stop */
     603             :         /* XXX What should we do here ? */
     604           0 :         WRITE_DMAREG(esc, DMA_CMD,
     605             :             DMACMD_ABORT | (esc->sc_datain ? DMACMD_DIR : 0));
     606           0 :         bus_dmamap_unload(esc->sc_dmat, esc->sc_xfermap);
     607             : 
     608           0 :         esc->sc_active = 0;
     609           0 : }
     610             : 
     611             : int
     612           0 : pcscp_dma_isactive(struct ncr53c9x_softc *sc)
     613             : {
     614           0 :         struct pcscp_softc *esc = (struct pcscp_softc *)sc;
     615             : 
     616             :         /* XXX should check esc->sc_active? */
     617           0 :         if ((READ_DMAREG(esc, DMA_CMD) & DMACMD_CMD) != DMACMD_IDLE)
     618           0 :                 return 1;
     619           0 :         return 0;
     620           0 : }

Generated by: LCOV version 1.13