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

Cache object: 0feeae6b9382be60cc41fab218719a8b


[ 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.