The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/podulebus/oak.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: oak.c,v 1.19 2008/04/28 20:23:56 martin Exp $  */
    2 
    3 /*
    4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Mark Brinicombe of Causality Limited.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 /*
   33  * Oak Solutions SCSI 1 driver using the generic NCR5380 driver.
   34  *
   35  * From <URL:http://foldoc.doc.ic.ac.uk/acorn/doc/scsi>:
   36  * --------8<--------
   37  * From: Hugo Fiennes
   38  * [...]
   39  * The oak scsi plays some other tricks to get max around 2.2Mb/sec:
   40  * it is a 16- bit interface (using their own hardware and an 8-bit
   41  * scsi controller to 'double-up' the data). What it does is: every
   42  * 128 bytes it uses a polling loop (see above) to check data is
   43  * present and the drive has reported no errors, etc.  Inside each 128
   44  * byte block it just reads data as fast as it can: on a normal card
   45  * this would result in disaster if the drive wasn't fast enough to
   46  * feed the machine: on the oak card however, the hardware will not
   47  * assert IOGT (IO grant), so hanging the machine in a wait state
   48  * until data is ready. This can have problems: if the drive is to
   49  * slow (unlikely) the machine will completely stiff as the ARM3 can't
   50  * be kept in such a state for more than 10(?) us.
   51  * -------->8--------
   52  *
   53  * So far, my attempts at doing this have failed, though.
   54  *
   55  * This card has to be polled: it doesn't have anything connected to
   56  * PIRQ*.  This seems to be a common failing of Archimedes disc
   57  * controllers.
   58  */
   59 
   60 #include <sys/cdefs.h>
   61 __KERNEL_RCSID(0, "$NetBSD: oak.c,v 1.19 2008/04/28 20:23:56 martin Exp $");
   62 
   63 #include <sys/param.h>
   64 
   65 #include <sys/systm.h>
   66 #include <sys/kernel.h>
   67 #include <sys/device.h>
   68 #include <sys/buf.h>
   69 #include <dev/scsipi/scsi_all.h>
   70 #include <dev/scsipi/scsipi_all.h>
   71 #include <dev/scsipi/scsiconf.h>
   72 
   73 #include <dev/ic/ncr5380reg.h>
   74 #include <dev/ic/ncr5380var.h>
   75 
   76 #include <machine/bootconfig.h>
   77 
   78 #include <dev/podulebus/podulebus.h>
   79 #include <dev/podulebus/podules.h>
   80 #include <dev/podulebus/powerromreg.h>
   81 
   82 #include <dev/podulebus/oakreg.h>
   83 
   84 int  oak_match(device_t, cfdata_t, void *);
   85 void oak_attach(device_t, device_t, void *);
   86 
   87 #if 0
   88 static int oak_pdma_in(struct ncr5380_softc *, int, int, uint8_t *);
   89 static int oak_pdma_out(struct ncr5380_softc *, int, int, uint8_t *);
   90 #endif
   91 
   92 /*
   93  * Oak SCSI 1 softc structure.
   94  *
   95  * Contains the generic ncr5380 device node, podule information and
   96  * global information required by the driver.
   97  */
   98 
   99 struct oak_softc {
  100         struct ncr5380_softc    sc_ncr5380;
  101         bus_space_tag_t         sc_pdmat;
  102         bus_space_handle_t      sc_pdmah;
  103 };
  104 
  105 CFATTACH_DECL_NEW(oak, sizeof(struct oak_softc),
  106     oak_match, oak_attach, NULL, NULL);
  107 
  108 /*
  109  * Card probe function
  110  *
  111  * Just match the manufacturer and podule ID's
  112  */
  113 
  114 int
  115 oak_match(device_t parent, cfdata_t cf, void *aux)
  116 {
  117         struct podulebus_attach_args *pa = aux;
  118 
  119         if (pa->pa_product == PODULE_OAK_SCSI)
  120                 return 1;
  121 
  122         /* PowerROM */
  123         if (pa->pa_product == PODULE_ALSYSTEMS_SCSI &&
  124             podulebus_initloader(pa) == 0 &&
  125             podloader_callloader(pa, 0, 0) == PRID_OAK_SCSI1)
  126                 return 1;
  127 
  128         return 0;
  129 }
  130 
  131 /*
  132  * Card attach function
  133  *
  134  */
  135 
  136 void
  137 oak_attach(device_t parent, device_t self, void *aux)
  138 {
  139         struct oak_softc *sc = device_private(self);
  140         struct ncr5380_softc *ncr_sc = &sc->sc_ncr5380;
  141         struct podulebus_attach_args *pa = aux;
  142 #ifndef NCR5380_USE_BUS_SPACE
  143         uint8_t *iobase;
  144 #endif
  145         char hi_option[sizeof(self->dv_xname) + 8];
  146 
  147         ncr_sc->sc_dev = self;
  148         ncr_sc->sc_flags |= NCR5380_FORCE_POLLING;
  149         ncr_sc->sc_min_dma_len = 0;
  150         ncr_sc->sc_no_disconnect = 0xff;
  151         ncr_sc->sc_parity_disable = 0;
  152 
  153         ncr_sc->sc_dma_alloc = NULL;
  154         ncr_sc->sc_dma_free = NULL;
  155         ncr_sc->sc_dma_poll = NULL;
  156         ncr_sc->sc_dma_setup = NULL;
  157         ncr_sc->sc_dma_start = NULL;
  158         ncr_sc->sc_dma_eop = NULL;
  159         ncr_sc->sc_dma_stop = NULL;
  160         ncr_sc->sc_intr_on = NULL;
  161         ncr_sc->sc_intr_off = NULL;
  162 
  163 #ifdef NCR5380_USE_BUS_SPACE
  164         ncr_sc->sc_regt = pa->pa_mod_t;
  165         bus_space_map(ncr_sc->sc_regt, pa->pa_mod_base, 8, 0,
  166             &ncr_sc->sc_regh);
  167         ncr_sc->sci_r0 = 0;
  168         ncr_sc->sci_r1 = 1;
  169         ncr_sc->sci_r2 = 2;
  170         ncr_sc->sci_r3 = 3;
  171         ncr_sc->sci_r4 = 4;
  172         ncr_sc->sci_r5 = 5;
  173         ncr_sc->sci_r6 = 6;
  174         ncr_sc->sci_r7 = 7;
  175 #else
  176         iobase = (uint8_t *)pa->pa_mod_base;
  177         ncr_sc->sci_r0 = iobase + 0;
  178         ncr_sc->sci_r1 = iobase + 4;
  179         ncr_sc->sci_r2 = iobase + 8;
  180         ncr_sc->sci_r3 = iobase + 12;
  181         ncr_sc->sci_r4 = iobase + 16;
  182         ncr_sc->sci_r5 = iobase + 20;
  183         ncr_sc->sci_r6 = iobase + 24;
  184         ncr_sc->sci_r7 = iobase + 28;
  185 #endif
  186         sc->sc_pdmat = pa->pa_mod_t;
  187         bus_space_map(sc->sc_pdmat, pa->pa_mod_base + OAK_PDMA_OFFSET, 0x20, 0,
  188             &sc->sc_pdmah);
  189 
  190         ncr_sc->sc_rev = NCR_VARIANT_NCR5380;
  191 
  192         ncr_sc->sc_pio_in = ncr5380_pio_in;
  193         ncr_sc->sc_pio_out = ncr5380_pio_out;
  194 
  195         /* Provide an override for the host id */
  196         ncr_sc->sc_channel.chan_id = 7;
  197         snprintf(hi_option, sizeof(hi_option), "%s.hostid",
  198             device_xname(self));
  199         (void)get_bootconf_option(boot_args, hi_option,
  200             BOOTOPT_TYPE_INT, &ncr_sc->sc_channel.chan_id);
  201         ncr_sc->sc_adapter.adapt_minphys = minphys;
  202 
  203         aprint_normal(": host=%d, using 8 bit PIO\n",
  204             ncr_sc->sc_channel.chan_id);
  205 
  206         ncr5380_attach(ncr_sc);
  207 }
  208 
  209 /*
  210  * XXX The code below doesn't work correctly.  I probably need more
  211  * details on how the card works.  [bjh21 20011202]
  212  */
  213 #if 0
  214 
  215 #ifndef OAK_TSIZE_OUT
  216 #define OAK_TSIZE_OUT   128
  217 #endif
  218 
  219 #ifndef OAK_TSIZE_IN
  220 #define OAK_TSIZE_IN    128
  221 #endif
  222 
  223 #define TIMEOUT 1000000
  224 
  225 static inline int
  226 oak_ready(struct ncr5380_softc *sc)
  227 {
  228         int i;
  229         int status;
  230 
  231         for (i = TIMEOUT; i > 0; i--) {
  232                 status = NCR5380_READ(sc, sci_csr);
  233                     if ((status & (SCI_CSR_DREQ | SCI_CSR_PHASE_MATCH)) ==
  234                         (SCI_CSR_DREQ | SCI_CSR_PHASE_MATCH))
  235                         return 1;
  236 
  237                 if ((status & SCI_CSR_PHASE_MATCH) == 0 ||
  238                     SCI_BUSY(sc) == 0)
  239                         return 0;
  240         }
  241         printf("%s: ready timeout\n", device_xname(sc->sc_dev));
  242         return 0;
  243 
  244 #if 0 /* The Linux driver does this: */
  245         struct oak_softc *sc = (void *)ncr_sc;
  246         bus_space_tag_t pdmat = sc->sc_pdmat;
  247         bus_space_handle_t pdmah = sc->sc_pdmah;
  248         int i, status;
  249 
  250         for (i = TIMEOUT; i > 0; i--) {
  251                 status = bus_space_read_2(pdmat, pdmah, OAK_PDMA_STATUS);
  252                 if (status & 0x200)
  253                         return 0;
  254                 if (status & 0x100)
  255                         return 1;
  256         }
  257         printf("%s: ready timeout, status = 0x%x\n",
  258             device_xname(ncr_sc->sc_dev), status);
  259         return 0;
  260 #endif
  261 }
  262 
  263 
  264 
  265 /* Return zero on success. */
  266 static inline void oak_wait_not_req(struct ncr5380_softc *sc)
  267 {
  268         int timo;
  269         for (timo = TIMEOUT; timo; timo--) {
  270                 if ((NCR5380_READ(sc, sci_bus_csr) & SCI_BUS_REQ) == 0 ||
  271                     (NCR5380_READ(sc, sci_csr) & SCI_CSR_PHASE_MATCH) == 0 ||
  272                     SCI_BUSY(sc) == 0) {
  273                         return;
  274                 }
  275         }
  276         printf("%s: pdma not_req timeout\n", device_xname(sc->sc_dev));
  277 }
  278 
  279 static int
  280 oak_pdma_in(struct ncr5380_softc *ncr_sc, int phase, int datalen,
  281     uint8_t *data)
  282 {
  283         struct oak_softc *sc = (void *)ncr_sc;
  284         bus_space_tag_t pdmat = sc->sc_pdmat;
  285         bus_space_handle_t pdmah = sc->sc_pdmah;
  286         int s, resid, len;
  287 
  288         s = splbio();
  289 
  290         NCR5380_WRITE(ncr_sc, sci_mode,
  291             NCR5380_READ(ncr_sc, sci_mode) | SCI_MODE_DMA);
  292         NCR5380_WRITE(ncr_sc, sci_irecv, 0);
  293 
  294         resid = datalen;
  295         while (resid > 0) {
  296                 len = min(resid, OAK_TSIZE_IN);
  297                 if (oak_ready(ncr_sc) == 0)
  298                         goto interrupt;
  299                 KASSERT(BUS_SPACE_ALIGNED_POINTER(data, uint16_t));
  300                 bus_space_read_multi_2(pdmat, pdmah, OAK_PDMA_READ,
  301                     (uint16_t *)data, len / 2);
  302                 data += len;
  303                 resid -= len;
  304         }
  305 
  306         oak_wait_not_req(ncr_sc);
  307 
  308 interrupt:
  309         SCI_CLR_INTR(ncr_sc);
  310         NCR5380_WRITE(ncr_sc, sci_mode,
  311             NCR5380_READ(ncr_sc, sci_mode) & ~SCI_MODE_DMA);
  312         splx(s);
  313         return datalen - resid;
  314 }
  315 
  316 static int
  317 oak_pdma_out(struct ncr5380_softc *ncr_sc, int phase, int datalen,
  318     uint8_t *data)
  319 {
  320         struct oak_softc *sc = (struct oak_softc *)ncr_sc;
  321         bus_space_tag_t pdmat = sc->sc_pdmat;
  322         bus_space_handle_t pdmah = sc->sc_pdmah;
  323         int i, s, icmd, resid;
  324 
  325         s = splbio();
  326         icmd = NCR5380_READ(ncr_sc, sci_icmd) & SCI_ICMD_RMASK;
  327         NCR5380_WRITE(ncr_sc, sci_icmd, icmd | SCI_ICMD_DATA);
  328         NCR5380_WRITE(ncr_sc, sci_mode,
  329             NCR5380_READ(ncr_sc, sci_mode) | SCI_MODE_DMA);
  330         NCR5380_WRITE(ncr_sc, sci_dma_send, 0);
  331 
  332         resid = datalen;
  333         if (oak_ready(ncr_sc) == 0)
  334                 goto interrupt;
  335 
  336         if (resid > OAK_TSIZE_OUT) {
  337                 /*
  338                  * Because of the chips DMA prefetch, phase changes
  339                  * etc, won't be detected until we have written at
  340                  * least one byte more. We pre-write 4 bytes so
  341                  * subsequent transfers will be aligned to a 4 byte
  342                  * boundary. Assuming disconects will only occur on
  343                  * block boundaries, we then correct for the pre-write
  344                  * when and if we get a phase change. If the chip had
  345                  * DMA byte counting hardware, the assumption would not
  346                  * be necessary.
  347                  */
  348                 KASSERT(BUS_SPACE_ALIGNED_POINTER(data, uint16_t));
  349                 bus_space_write_multi_2(pdmat, pdmah, OAK_PDMA_WRITE,
  350                     (uint16_t *)data, 4 / 2);
  351                 data += 4;
  352                 resid -= 4;
  353 
  354                 for (; resid >= OAK_TSIZE_OUT; resid -= OAK_TSIZE_OUT) {
  355                         if (oak_ready(ncr_sc) == 0) {
  356                                 resid += 4; /* Overshot */
  357                                 goto interrupt;
  358                         }
  359                         bus_space_write_multi_2(pdmat, pdmah, OAK_PDMA_WRITE,
  360                             (uint16_t *)data, OAK_TSIZE_OUT / 2);
  361                         data += OAK_TSIZE_OUT;
  362                 }
  363                 if (oak_ready(ncr_sc) == 0) {
  364                         resid += 4; /* Overshot */
  365                         goto interrupt;
  366                 }
  367         }
  368 
  369         if (resid) {
  370                 bus_space_write_multi_2(pdmat, pdmah, OAK_PDMA_WRITE,
  371                     (uint16_t *)data, resid / 2);
  372                 resid = 0;
  373         }
  374         for (i = TIMEOUT; i > 0; i--) {
  375                 if ((NCR5380_READ(ncr_sc, sci_csr)
  376                     & (SCI_CSR_DREQ|SCI_CSR_PHASE_MATCH))
  377                     != SCI_CSR_DREQ)
  378                         break;
  379         }
  380         if (i != 0)
  381                 bus_space_write_2(pdmat, pdmah, OAK_PDMA_WRITE, 0);
  382         else
  383                 printf("%s: timeout waiting for final SCI_DSR_DREQ.\n",
  384                     device_xname(ncr_sc->sc_dev));
  385 
  386         oak_wait_not_req(ncr_sc);
  387 interrupt:
  388         SCI_CLR_INTR(ncr_sc);
  389         NCR5380_WRITE(ncr_sc, sci_mode,
  390             NCR5380_READ(ncr_sc, sci_mode) & ~SCI_MODE_DMA);
  391         NCR5380_WRITE(ncr_sc, sci_icmd, icmd);
  392         splx(s);
  393         return datalen - resid;
  394 }
  395 #endif

Cache object: 5f8f7fd8d94e64687bf1a899d9031419


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.