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/ic/oosiop.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: oosiop.c,v 1.18 2021/08/07 16:19:12 thorpej Exp $      */
    2 
    3 /*
    4  * Copyright (c) 2001 Shuichiro URATA.  All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. The name of the author may not be used to endorse or promote products
   15  *    derived from this software without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 
   29 /*
   30  * NCR53C700 SCSI I/O processor (OOSIOP) driver
   31  *
   32  * TODO:
   33  *   - More better error handling.
   34  *   - Implement tagged queuing.
   35  */
   36 
   37 #include <sys/cdefs.h>
   38 __KERNEL_RCSID(0, "$NetBSD: oosiop.c,v 1.18 2021/08/07 16:19:12 thorpej Exp $");
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/callout.h>
   43 #include <sys/kernel.h>
   44 #include <sys/device.h>
   45 #include <sys/buf.h>
   46 #include <sys/malloc.h>
   47 #include <sys/queue.h>
   48 
   49 #include <dev/scsipi/scsi_all.h>
   50 #include <dev/scsipi/scsipi_all.h>
   51 #include <dev/scsipi/scsiconf.h>
   52 #include <dev/scsipi/scsi_message.h>
   53 
   54 #include <sys/cpu.h>
   55 #include <sys/bus.h>
   56 
   57 #include <dev/ic/oosiopreg.h>
   58 #include <dev/ic/oosiopvar.h>
   59 #include <dev/microcode/siop/oosiop.out>
   60 
   61 static int      oosiop_alloc_cb(struct oosiop_softc *, int);
   62 
   63 static inline void oosiop_relocate_io(struct oosiop_softc *, bus_addr_t);
   64 static inline void oosiop_relocate_tc(struct oosiop_softc *, bus_addr_t);
   65 static inline void oosiop_fixup_select(struct oosiop_softc *, bus_addr_t,
   66                          int);
   67 static inline void oosiop_fixup_jump(struct oosiop_softc *, bus_addr_t,
   68                          bus_addr_t);
   69 static inline void oosiop_fixup_move(struct oosiop_softc *, bus_addr_t,
   70                          bus_size_t, bus_addr_t);
   71 
   72 static void     oosiop_load_script(struct oosiop_softc *);
   73 static void     oosiop_setup_sgdma(struct oosiop_softc *, struct oosiop_cb *);
   74 static void     oosiop_setup_dma(struct oosiop_softc *);
   75 static void     oosiop_flush_fifo(struct oosiop_softc *);
   76 static void     oosiop_clear_fifo(struct oosiop_softc *);
   77 static void     oosiop_phasemismatch(struct oosiop_softc *);
   78 static void     oosiop_setup_syncxfer(struct oosiop_softc *);
   79 static void     oosiop_set_syncparam(struct oosiop_softc *, int, int, int);
   80 static void     oosiop_minphys(struct buf *);
   81 static void     oosiop_scsipi_request(struct scsipi_channel *,
   82                     scsipi_adapter_req_t, void *);
   83 static void     oosiop_done(struct oosiop_softc *, struct oosiop_cb *);
   84 static void     oosiop_timeout(void *);
   85 static void     oosiop_reset(struct oosiop_softc *);
   86 static void     oosiop_reset_bus(struct oosiop_softc *);
   87 static void     oosiop_scriptintr(struct oosiop_softc *);
   88 static void     oosiop_msgin(struct oosiop_softc *, struct oosiop_cb *);
   89 
   90 /* Trap interrupt code for unexpected data I/O */
   91 #define DATAIN_TRAP     0xdead0001
   92 #define DATAOUT_TRAP    0xdead0002
   93 
   94 /* Possible TP and SCF conbination */
   95 static const struct {
   96         uint8_t         tp;
   97         uint8_t         scf;
   98 } synctbl[] = {
   99         {0, 1},         /* SCLK /  4.0 */
  100         {1, 1},         /* SCLK /  5.0 */
  101         {2, 1},         /* SCLK /  6.0 */
  102         {3, 1},         /* SCLK /  7.0 */
  103         {1, 2},         /* SCLK /  7.5 */
  104         {4, 1},         /* SCLK /  8.0 */
  105         {5, 1},         /* SCLK /  9.0 */
  106         {6, 1},         /* SCLK / 10.0 */
  107         {3, 2},         /* SCLK / 10.5 */
  108         {7, 1},         /* SCLK / 11.0 */
  109         {4, 2},         /* SCLK / 12.0 */
  110         {5, 2},         /* SCLK / 13.5 */
  111         {3, 3},         /* SCLK / 14.0 */
  112         {6, 2},         /* SCLK / 15.0 */
  113         {4, 3},         /* SCLK / 16.0 */
  114         {7, 2},         /* SCLK / 16.5 */
  115         {5, 3},         /* SCLK / 18.0 */
  116         {6, 3},         /* SCLK / 20.0 */
  117         {7, 3}          /* SCLK / 22.0 */
  118 };
  119 #define NSYNCTBL        (sizeof(synctbl) / sizeof(synctbl[0]))
  120 
  121 #define oosiop_period(sc, tp, scf)                                      \
  122             (((1000000000 / (sc)->sc_freq) * (tp) * (scf)) / 40)
  123 
  124 void
  125 oosiop_attach(struct oosiop_softc *sc)
  126 {
  127         bus_size_t scrsize;
  128         bus_dma_segment_t seg;
  129         struct oosiop_cb *cb;
  130         int err, i, nseg;
  131 
  132         /*
  133          * Allocate DMA-safe memory for the script and map it.
  134          */
  135         scrsize = sizeof(oosiop_script);
  136         err = bus_dmamem_alloc(sc->sc_dmat, scrsize, PAGE_SIZE, 0, &seg, 1,
  137             &nseg, BUS_DMA_NOWAIT);
  138         if (err) {
  139                 aprint_error(": failed to allocate script memory, err=%d\n",
  140                     err);
  141                 return;
  142         }
  143         err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, scrsize,
  144             (void **)&sc->sc_scr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
  145         if (err) {
  146                 aprint_error(": failed to map script memory, err=%d\n", err);
  147                 return;
  148         }
  149         err = bus_dmamap_create(sc->sc_dmat, scrsize, 1, scrsize, 0,
  150             BUS_DMA_NOWAIT, &sc->sc_scrdma);
  151         if (err) {
  152                 aprint_error(": failed to create script map, err=%d\n", err);
  153                 return;
  154         }
  155         err = bus_dmamap_load(sc->sc_dmat, sc->sc_scrdma, sc->sc_scr, scrsize,
  156             NULL, BUS_DMA_NOWAIT | BUS_DMA_WRITE);
  157         if (err) {
  158                 aprint_error(": failed to load script map, err=%d\n", err);
  159                 return;
  160         }
  161         sc->sc_scrbase = sc->sc_scrdma->dm_segs[0].ds_addr;
  162 
  163         /* Initialize command block array */
  164         TAILQ_INIT(&sc->sc_free_cb);
  165         TAILQ_INIT(&sc->sc_cbq);
  166         if (oosiop_alloc_cb(sc, OOSIOP_NCB) != 0)
  167                 return;
  168 
  169         /* Use first cb to reselection msgin buffer */
  170         cb = TAILQ_FIRST(&sc->sc_free_cb);
  171         sc->sc_reselbuf = cb->xferdma->dm_segs[0].ds_addr +
  172             offsetof(struct oosiop_xfer, msgin[0]);
  173 
  174         for (i = 0; i < OOSIOP_NTGT; i++) {
  175                 sc->sc_tgt[i].nexus = NULL;
  176                 sc->sc_tgt[i].flags = 0;
  177         }
  178 
  179         /* Setup asynchronous clock divisor parameters */
  180         if (sc->sc_freq <= 25000000) {
  181                 sc->sc_ccf = 10;
  182                 sc->sc_dcntl = OOSIOP_DCNTL_CF_1;
  183         } else if (sc->sc_freq <= 37500000) {
  184                 sc->sc_ccf = 15;
  185                 sc->sc_dcntl = OOSIOP_DCNTL_CF_1_5;
  186         } else if (sc->sc_freq <= 50000000) {
  187                 sc->sc_ccf = 20;
  188                 sc->sc_dcntl = OOSIOP_DCNTL_CF_2;
  189         } else {
  190                 sc->sc_ccf = 30;
  191                 sc->sc_dcntl = OOSIOP_DCNTL_CF_3;
  192         }
  193 
  194         if (sc->sc_chip == OOSIOP_700)
  195                 sc->sc_minperiod = oosiop_period(sc, 4, sc->sc_ccf);
  196         else
  197                 sc->sc_minperiod = oosiop_period(sc, 4, 10);
  198 
  199         if (sc->sc_minperiod < 25)
  200                 sc->sc_minperiod = 25;  /* limit to 10MB/s */
  201 
  202         aprint_normal(": NCR53C700%s rev %d, %dMHz, SCSI ID %d\n",
  203             sc->sc_chip == OOSIOP_700_66 ? "-66" : "",
  204             oosiop_read_1(sc, OOSIOP_CTEST7) >> 4,
  205             sc->sc_freq / 1000000, sc->sc_id);
  206         /*
  207          * Reset all
  208          */
  209         oosiop_reset(sc);
  210         oosiop_reset_bus(sc);
  211 
  212         /*
  213          * Start SCRIPTS processor
  214          */
  215         oosiop_load_script(sc);
  216         sc->sc_active = 0;
  217         oosiop_write_4(sc, OOSIOP_DSP, sc->sc_scrbase + Ent_wait_reselect);
  218 
  219         /*
  220          * Fill in the scsipi_adapter.
  221          */
  222         sc->sc_adapter.adapt_dev = sc->sc_dev;
  223         sc->sc_adapter.adapt_nchannels = 1;
  224         sc->sc_adapter.adapt_openings = OOSIOP_NCB;
  225         sc->sc_adapter.adapt_max_periph = 1;
  226         sc->sc_adapter.adapt_ioctl = NULL;
  227         sc->sc_adapter.adapt_minphys = oosiop_minphys;
  228         sc->sc_adapter.adapt_request = oosiop_scsipi_request;
  229 
  230         /*
  231          * Fill in the scsipi_channel.
  232          */
  233         sc->sc_channel.chan_adapter = &sc->sc_adapter;
  234         sc->sc_channel.chan_bustype = &scsi_bustype;
  235         sc->sc_channel.chan_channel = 0;
  236         sc->sc_channel.chan_ntargets = OOSIOP_NTGT;
  237         sc->sc_channel.chan_nluns = 8;
  238         sc->sc_channel.chan_id = sc->sc_id;
  239 
  240         /*
  241          * Now try to attach all the sub devices.
  242          */
  243         config_found(sc->sc_dev, &sc->sc_channel, scsiprint, CFARGS_NONE);
  244 }
  245 
  246 static int
  247 oosiop_alloc_cb(struct oosiop_softc *sc, int ncb)
  248 {
  249         struct oosiop_cb *cb;
  250         void *xfer_kva;
  251         struct oosiop_xfer *xfer;
  252         bus_size_t xfersize;
  253         bus_dma_segment_t seg;
  254         int i, s, err, nseg;
  255 
  256         /*
  257          * Allocate oosiop_cb.
  258          */
  259         cb = malloc(sizeof(struct oosiop_cb) * ncb, M_DEVBUF, M_WAITOK|M_ZERO);
  260 
  261         /*
  262          * Allocate DMA-safe memory for the oosiop_xfer and map it.
  263          */
  264         xfersize = sizeof(struct oosiop_xfer) * ncb;
  265         err = bus_dmamem_alloc(sc->sc_dmat, xfersize, PAGE_SIZE, 0, &seg, 1,
  266             &nseg, BUS_DMA_NOWAIT);
  267         if (err) {
  268                 printf(": failed to allocate xfer block memory, err=%d\n", err);
  269                 goto fail1;
  270         }
  271         KASSERT(nseg == 1);
  272         err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, xfersize, &xfer_kva,
  273             BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
  274         if (err) {
  275                 printf(": failed to map xfer block memory, err=%d\n", err);
  276                 goto fail2;
  277         }
  278         xfer = xfer_kva;
  279 
  280         /* Initialize each command block */
  281         for (i = 0; i < ncb; i++) {
  282                 err = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE,
  283                     0, BUS_DMA_NOWAIT, &cb[i].cmddma);
  284                 if (err) {
  285                         printf(": failed to create cmddma map, err=%d\n", err);
  286                         goto loop_fail0;
  287                 }
  288                 err = bus_dmamap_create(sc->sc_dmat, OOSIOP_MAX_XFER,
  289                     OOSIOP_NSG, OOSIOP_DBC_MAX, 0, BUS_DMA_NOWAIT,
  290                     &cb[i].datadma);
  291                 if (err) {
  292                         printf(": failed to create datadma map, err=%d\n", err);
  293                         goto loop_fail1;
  294                 }
  295 
  296                 err = bus_dmamap_create(sc->sc_dmat,
  297                     sizeof(struct oosiop_xfer), 1, sizeof(struct oosiop_xfer),
  298                     0, BUS_DMA_NOWAIT, &cb[i].xferdma);
  299                 if (err) {
  300                         printf(": failed to create xfer block map, err=%d\n",
  301                             err);
  302                         goto loop_fail2;
  303                 }
  304                 err = bus_dmamap_load(sc->sc_dmat, cb[i].xferdma, &xfer[i],
  305                     sizeof(struct oosiop_xfer), NULL, BUS_DMA_NOWAIT);
  306                 if (err) {
  307                         printf(": failed to load xfer block, err=%d\n", err);
  308                         goto loop_fail3;
  309                 }
  310 
  311                 cb[i].xfer = &xfer[i];
  312                 continue;
  313 
  314 loop_fail4: __unused
  315                 bus_dmamap_unload(sc->sc_dmat, cb[i].xferdma);
  316 loop_fail3:     bus_dmamap_destroy(sc->sc_dmat, cb[i].xferdma);
  317 loop_fail2:     bus_dmamap_destroy(sc->sc_dmat, cb[i].datadma);
  318 loop_fail1:     bus_dmamap_destroy(sc->sc_dmat, cb[i].cmddma);
  319 loop_fail0:     goto fail3;
  320         }
  321 
  322         for (i = 0; i < ncb; i++) {
  323                 s = splbio();
  324                 TAILQ_INSERT_TAIL(&sc->sc_free_cb, &cb[i], chain);
  325                 splx(s);
  326         }
  327 
  328         /* Success!  */
  329         return 0;
  330 
  331 fail3:  while (i--) {
  332                 bus_dmamap_unload(sc->sc_dmat, cb[i].xferdma);
  333                 bus_dmamap_destroy(sc->sc_dmat, cb[i].xferdma);
  334                 bus_dmamap_destroy(sc->sc_dmat, cb[i].datadma);
  335                 bus_dmamap_destroy(sc->sc_dmat, cb[i].cmddma);
  336         }
  337         bus_dmamem_unmap(sc->sc_dmat, xfer_kva, xfersize);
  338 fail2:  bus_dmamem_free(sc->sc_dmat, &seg, 1);
  339 fail1:  free(cb, M_DEVBUF);
  340         KASSERT(err);
  341         return err;
  342 }
  343 
  344 static inline void
  345 oosiop_relocate_io(struct oosiop_softc *sc, bus_addr_t addr)
  346 {
  347         uint32_t dcmd;
  348         int32_t dsps;
  349 
  350         dcmd = le32toh(sc->sc_scr[addr / 4 + 0]);
  351         dsps = le32toh(sc->sc_scr[addr / 4 + 1]);
  352 
  353         /* convert relative to absolute */
  354         if (dcmd & 0x04000000) {
  355                 dcmd &= ~0x04000000;
  356 #if 0
  357                 /*
  358                  * sign extension isn't needed here because
  359                  * ncr53cxxx.c generates 32 bit dsps.
  360                  */
  361                 dsps <<= 8;
  362                 dsps >>= 8;
  363 #endif
  364                 sc->sc_scr[addr / 4 + 0] = htole32(dcmd);
  365                 dsps += addr + 8;
  366         }
  367 
  368         sc->sc_scr[addr / 4 + 1] = htole32(dsps + sc->sc_scrbase);
  369 }
  370 
  371 static inline void
  372 oosiop_relocate_tc(struct oosiop_softc *sc, bus_addr_t addr)
  373 {
  374         uint32_t dcmd;
  375         int32_t dsps;
  376 
  377         dcmd = le32toh(sc->sc_scr[addr / 4 + 0]);
  378         dsps = le32toh(sc->sc_scr[addr / 4 + 1]);
  379 
  380         /* convert relative to absolute */
  381         if (dcmd & 0x00800000) {
  382                 dcmd &= ~0x00800000;
  383                 sc->sc_scr[addr / 4] = htole32(dcmd);
  384 #if 0
  385                 /*
  386                  * sign extension isn't needed here because
  387                  * ncr53cxxx.c generates 32 bit dsps.
  388                  */
  389                 dsps <<= 8;
  390                 dsps >>= 8;
  391 #endif
  392                 dsps += addr + 8;
  393         }
  394 
  395         sc->sc_scr[addr / 4 + 1] = htole32(dsps + sc->sc_scrbase);
  396 }
  397 
  398 static inline void
  399 oosiop_fixup_select(struct oosiop_softc *sc, bus_addr_t addr, int id)
  400 {
  401         uint32_t dcmd;
  402 
  403         dcmd = le32toh(sc->sc_scr[addr / 4]);
  404         dcmd &= 0xff00ffff;
  405         dcmd |= 0x00010000 << id;
  406         sc->sc_scr[addr / 4] = htole32(dcmd);
  407 }
  408 
  409 static inline void
  410 oosiop_fixup_jump(struct oosiop_softc *sc, bus_addr_t addr, bus_addr_t dst)
  411 {
  412 
  413         sc->sc_scr[addr / 4 + 1] = htole32(dst);
  414 }
  415 
  416 static inline void
  417 oosiop_fixup_move(struct oosiop_softc *sc, bus_addr_t addr, bus_size_t dbc,
  418     bus_addr_t dsps)
  419 {
  420         uint32_t dcmd;
  421 
  422         dcmd = le32toh(sc->sc_scr[addr / 4]);
  423         dcmd &= 0xff000000;
  424         dcmd |= dbc & 0x00ffffff;
  425         sc->sc_scr[addr / 4 + 0] = htole32(dcmd);
  426         sc->sc_scr[addr / 4 + 1] = htole32(dsps);
  427 }
  428 
  429 static void
  430 oosiop_load_script(struct oosiop_softc *sc)
  431 {
  432         int i;
  433 
  434         /* load script */
  435         for (i = 0; i < sizeof(oosiop_script) / sizeof(oosiop_script[0]); i++)
  436                 sc->sc_scr[i] = htole32(oosiop_script[i]);
  437 
  438         /* relocate script */
  439         for (i = 0; i < (sizeof(oosiop_script) / 8); i++) {
  440                 switch (oosiop_script[i * 2] >> 27) {
  441                 case 0x08:      /* select */
  442                 case 0x0a:      /* wait reselect */
  443                         oosiop_relocate_io(sc, i * 8);
  444                         break;
  445                 case 0x10:      /* jump */
  446                 case 0x11:      /* call */
  447                         oosiop_relocate_tc(sc, i * 8);
  448                         break;
  449                 }
  450         }
  451 
  452         oosiop_fixup_move(sc, Ent_p_resel_msgin_move, 1, sc->sc_reselbuf);
  453         OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
  454 }
  455 
  456 static void
  457 oosiop_setup_sgdma(struct oosiop_softc *sc, struct oosiop_cb *cb)
  458 {
  459         int i, n, off, control;
  460         struct oosiop_xfer *xfer;
  461 
  462         OOSIOP_XFERSCR_SYNC(sc, cb,
  463             BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
  464 
  465         off = cb->curdp;
  466         xfer = cb->xfer;
  467         control = cb->xs->xs_control;
  468 
  469         if (control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
  470                 /* Find start segment */
  471                 for (i = 0; i < cb->datadma->dm_nsegs; i++) {
  472                         if (off < cb->datadma->dm_segs[i].ds_len)
  473                                 break;
  474                         off -= cb->datadma->dm_segs[i].ds_len;
  475                 }
  476 
  477                 /* build MOVE block */
  478                 if (control & XS_CTL_DATA_IN) {
  479                         n = 0;
  480                         while (i < cb->datadma->dm_nsegs) {
  481                                 xfer->datain_scr[n * 2 + 0] =
  482                                     htole32(0x09000000 |
  483                                     (cb->datadma->dm_segs[i].ds_len - off));
  484                                 xfer->datain_scr[n * 2 + 1] =
  485                                     htole32(cb->datadma->dm_segs[i].ds_addr +
  486                                     off);
  487                                 n++;
  488                                 i++;
  489                                 off = 0;
  490                         }
  491                         xfer->datain_scr[n * 2 + 0] = htole32(0x80080000);
  492                         xfer->datain_scr[n * 2 + 1] =
  493                             htole32(sc->sc_scrbase + Ent_phasedispatch);
  494                 }
  495                 if (control & XS_CTL_DATA_OUT) {
  496                         n = 0;
  497                         while (i < cb->datadma->dm_nsegs) {
  498                                 xfer->dataout_scr[n * 2 + 0] =
  499                                     htole32(0x08000000 |
  500                                     (cb->datadma->dm_segs[i].ds_len - off));
  501                                 xfer->dataout_scr[n * 2 + 1] =
  502                                     htole32(cb->datadma->dm_segs[i].ds_addr +
  503                                     off);
  504                                 n++;
  505                                 i++;
  506                                 off = 0;
  507                         }
  508                         xfer->dataout_scr[n * 2 + 0] = htole32(0x80080000);
  509                         xfer->dataout_scr[n * 2 + 1] =
  510                             htole32(sc->sc_scrbase + Ent_phasedispatch);
  511                 }
  512         }
  513         if ((control & XS_CTL_DATA_IN) == 0) {
  514                 xfer->datain_scr[0] = htole32(0x98080000);
  515                 xfer->datain_scr[1] = htole32(DATAIN_TRAP);
  516         }
  517         if ((control & XS_CTL_DATA_OUT) == 0) {
  518                 xfer->dataout_scr[0] = htole32(0x98080000);
  519                 xfer->dataout_scr[1] = htole32(DATAOUT_TRAP);
  520         }
  521         OOSIOP_XFERSCR_SYNC(sc, cb,
  522             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
  523 }
  524 
  525 /*
  526  * Setup DMA pointer into script.
  527  */
  528 static void
  529 oosiop_setup_dma(struct oosiop_softc *sc)
  530 {
  531         struct oosiop_cb *cb;
  532         bus_addr_t xferbase;
  533 
  534         cb = sc->sc_curcb;
  535         xferbase = cb->xferdma->dm_segs[0].ds_addr;
  536 
  537         OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
  538 
  539         oosiop_fixup_select(sc, Ent_p_select, cb->id);
  540         oosiop_fixup_jump(sc, Ent_p_datain_jump, xferbase +
  541             offsetof(struct oosiop_xfer, datain_scr[0]));
  542         oosiop_fixup_jump(sc, Ent_p_dataout_jump, xferbase +
  543             offsetof(struct oosiop_xfer, dataout_scr[0]));
  544         oosiop_fixup_move(sc, Ent_p_msgin_move, 1, xferbase +
  545             offsetof(struct oosiop_xfer, msgin[0]));
  546         oosiop_fixup_move(sc, Ent_p_extmsglen_move, 1, xferbase +
  547             offsetof(struct oosiop_xfer, msgin[1]));
  548         oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen, xferbase +
  549             offsetof(struct oosiop_xfer, msgout[0]));
  550         oosiop_fixup_move(sc, Ent_p_status_move, 1, xferbase +
  551             offsetof(struct oosiop_xfer, status));
  552         oosiop_fixup_move(sc, Ent_p_cmdout_move, cb->xs->cmdlen,
  553             cb->cmddma->dm_segs[0].ds_addr);
  554 
  555         OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
  556 }
  557 
  558 static void
  559 oosiop_flush_fifo(struct oosiop_softc *sc)
  560 {
  561 
  562         oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) |
  563             OOSIOP_DFIFO_FLF);
  564         while ((oosiop_read_1(sc, OOSIOP_CTEST1) & OOSIOP_CTEST1_FMT) !=
  565             OOSIOP_CTEST1_FMT)
  566                 ;
  567         oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) &
  568             ~OOSIOP_DFIFO_FLF);
  569 }
  570 
  571 static void
  572 oosiop_clear_fifo(struct oosiop_softc *sc)
  573 {
  574 
  575         oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) |
  576             OOSIOP_DFIFO_CLF);
  577         while ((oosiop_read_1(sc, OOSIOP_CTEST1) & OOSIOP_CTEST1_FMT) !=
  578             OOSIOP_CTEST1_FMT)
  579                 ;
  580         oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) &
  581             ~OOSIOP_DFIFO_CLF);
  582 }
  583 
  584 static void
  585 oosiop_phasemismatch(struct oosiop_softc *sc)
  586 {
  587         struct oosiop_cb *cb;
  588         uint32_t dsp, dbc, n, i, len;
  589         uint8_t dfifo, sstat1;
  590 
  591         cb = sc->sc_curcb;
  592         if (cb == NULL)
  593                 return;
  594 
  595         dsp = oosiop_read_4(sc, OOSIOP_DSP);
  596         dbc = oosiop_read_4(sc, OOSIOP_DBC) & OOSIOP_DBC_MAX;
  597         len = 0;
  598 
  599         n = dsp - cb->xferdma->dm_segs[0].ds_addr - 8;
  600         if (n >= offsetof(struct oosiop_xfer, datain_scr[0]) &&
  601             n < offsetof(struct oosiop_xfer, datain_scr[OOSIOP_NSG * 2])) {
  602                 n -= offsetof(struct oosiop_xfer, datain_scr[0]);
  603                 n >>= 3;
  604                 OOSIOP_DINSCR_SYNC(sc, cb,
  605                     BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
  606                 for (i = 0; i <= n; i++)
  607                         len += le32toh(cb->xfer->datain_scr[i * 2]) &
  608                             0x00ffffff;
  609                 OOSIOP_DINSCR_SYNC(sc, cb,
  610                     BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
  611                 /* All data in the chip are already flushed */
  612         } else if (n >= offsetof(struct oosiop_xfer, dataout_scr[0]) &&
  613             n < offsetof(struct oosiop_xfer, dataout_scr[OOSIOP_NSG * 2])) {
  614                 n -= offsetof(struct oosiop_xfer, dataout_scr[0]);
  615                 n >>= 3;
  616                 OOSIOP_DOUTSCR_SYNC(sc, cb,
  617                     BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
  618                 for (i = 0; i <= n; i++)
  619                         len += le32toh(cb->xfer->dataout_scr[i * 2]) &
  620                             0x00ffffff;
  621                 OOSIOP_DOUTSCR_SYNC(sc, cb,
  622                     BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
  623 
  624                 dfifo = oosiop_read_1(sc, OOSIOP_DFIFO);
  625                 dbc += ((dfifo & OOSIOP_DFIFO_BO) - (dbc & OOSIOP_DFIFO_BO)) &
  626                     OOSIOP_DFIFO_BO;
  627 
  628                 sstat1 = oosiop_read_1(sc, OOSIOP_SSTAT1);
  629                 if (sstat1 & OOSIOP_SSTAT1_OLF)
  630                         dbc++;
  631                 if ((sc->sc_tgt[cb->id].sxfer != 0) &&
  632                     (sstat1 & OOSIOP_SSTAT1_ORF) != 0)
  633                         dbc++;
  634 
  635                 oosiop_clear_fifo(sc);
  636         } else {
  637                 printf("%s: phase mismatch addr=%08x\n",
  638                     device_xname(sc->sc_dev),
  639                     oosiop_read_4(sc, OOSIOP_DSP) - 8);
  640                 oosiop_clear_fifo(sc);
  641                 return;
  642         }
  643 
  644         len -= dbc;
  645         if (len) {
  646                 cb->curdp += len;
  647                 oosiop_setup_sgdma(sc, cb);
  648         }
  649 }
  650 
  651 static void
  652 oosiop_setup_syncxfer(struct oosiop_softc *sc)
  653 {
  654         int id;
  655 
  656         id = sc->sc_curcb->id;
  657         if (sc->sc_chip != OOSIOP_700)
  658                 oosiop_write_1(sc, OOSIOP_SBCL, sc->sc_tgt[id].scf);
  659 
  660         oosiop_write_1(sc, OOSIOP_SXFER, sc->sc_tgt[id].sxfer);
  661 }
  662 
  663 static void
  664 oosiop_set_syncparam(struct oosiop_softc *sc, int id, int period, int offset)
  665 {
  666         int i, p;
  667         struct scsipi_xfer_mode xm;
  668 
  669         xm.xm_target = id;
  670         xm.xm_mode = 0;
  671         xm.xm_period = 0;
  672         xm.xm_offset = 0;
  673 
  674         if (offset == 0) {
  675                 /* Asynchronous */
  676                 sc->sc_tgt[id].scf = 0;
  677                 sc->sc_tgt[id].sxfer = 0;
  678         } else {
  679                 /* Synchronous */
  680                 if (sc->sc_chip == OOSIOP_700) {
  681                         for (i = 4; i < 12; i++) {
  682                                 p = oosiop_period(sc, i, sc->sc_ccf);
  683                                 if (p >= period)
  684                                         break;
  685                         }
  686                         if (i == 12) {
  687                                 printf("%s: target %d period too large\n",
  688                                     device_xname(sc->sc_dev), id);
  689                                 i = 11; /* XXX */
  690                         }
  691                         sc->sc_tgt[id].scf = 0;
  692                         sc->sc_tgt[id].sxfer = ((i - 4) << 4) | offset;
  693                 } else {
  694                         for (i = 0; i < NSYNCTBL; i++) {
  695                                 p = oosiop_period(sc, synctbl[i].tp + 4,
  696                                     (synctbl[i].scf + 1) * 5);
  697                                 if (p >= period)
  698                                         break;
  699                         }
  700                         if (i == NSYNCTBL) {
  701                                 printf("%s: target %d period too large\n",
  702                                     device_xname(sc->sc_dev), id);
  703                                 i = NSYNCTBL - 1;       /* XXX */
  704                         }
  705                         sc->sc_tgt[id].scf = synctbl[i].scf;
  706                         sc->sc_tgt[id].sxfer = (synctbl[i].tp << 4) | offset;
  707                 }
  708 
  709                 xm.xm_mode |= PERIPH_CAP_SYNC;
  710                 xm.xm_period = period;
  711                 xm.xm_offset = offset;
  712         }
  713 
  714         scsipi_async_event(&sc->sc_channel, ASYNC_EVENT_XFER_MODE, &xm);
  715 }
  716 
  717 static void
  718 oosiop_minphys(struct buf *bp)
  719 {
  720 
  721         if (bp->b_bcount > OOSIOP_MAX_XFER)
  722                 bp->b_bcount = OOSIOP_MAX_XFER;
  723         minphys(bp);
  724 }
  725 
  726 static void
  727 oosiop_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req,
  728     void *arg)
  729 {
  730         struct scsipi_xfer *xs;
  731         struct oosiop_softc *sc;
  732         struct oosiop_cb *cb;
  733         struct oosiop_xfer *xfer;
  734         struct scsipi_xfer_mode *xm;
  735         int s, err;
  736 
  737         sc = device_private(chan->chan_adapter->adapt_dev);
  738 
  739         switch (req) {
  740         case ADAPTER_REQ_RUN_XFER:
  741                 xs = arg;
  742 
  743                 s = splbio();
  744                 cb = TAILQ_FIRST(&sc->sc_free_cb);
  745                 TAILQ_REMOVE(&sc->sc_free_cb, cb, chain);
  746                 splx(s);
  747 
  748                 cb->xs = xs;
  749                 cb->flags = 0;
  750                 cb->id = xs->xs_periph->periph_target;
  751                 cb->lun = xs->xs_periph->periph_lun;
  752                 cb->curdp = 0;
  753                 cb->savedp = 0;
  754                 xfer = cb->xfer;
  755 
  756                 /* Setup SCSI command buffer DMA */
  757                 err = bus_dmamap_load(sc->sc_dmat, cb->cmddma, xs->cmd,
  758                     xs->cmdlen, NULL, ((xs->xs_control & XS_CTL_NOSLEEP) ?
  759                     BUS_DMA_NOWAIT : BUS_DMA_WAITOK) | BUS_DMA_WRITE);
  760                 if (err) {
  761                         printf("%s: unable to load cmd DMA map: %d",
  762                             device_xname(sc->sc_dev), err);
  763                         xs->error = XS_RESOURCE_SHORTAGE;
  764                         TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
  765                         scsipi_done(xs);
  766                         return;
  767                 }
  768                 bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, xs->cmdlen,
  769                     BUS_DMASYNC_PREWRITE);
  770 
  771                 /* Setup data buffer DMA */
  772                 if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
  773                         err = bus_dmamap_load(sc->sc_dmat, cb->datadma,
  774                             xs->data, xs->datalen, NULL,
  775                             ((xs->xs_control & XS_CTL_NOSLEEP) ?
  776                             BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
  777                             BUS_DMA_STREAMING |
  778                             ((xs->xs_control & XS_CTL_DATA_IN) ? BUS_DMA_READ :
  779                             BUS_DMA_WRITE));
  780                         if (err) {
  781                                 printf("%s: unable to load data DMA map: %d",
  782                                     device_xname(sc->sc_dev), err);
  783                                 xs->error = XS_RESOURCE_SHORTAGE;
  784                                 bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
  785                                 TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
  786                                 scsipi_done(xs);
  787                                 return;
  788                         }
  789                         bus_dmamap_sync(sc->sc_dmat, cb->datadma,
  790                             0, xs->datalen,
  791                             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
  792                 }
  793 
  794                 oosiop_setup_sgdma(sc, cb);
  795 
  796                 /* Setup msgout buffer */
  797                 OOSIOP_XFERMSG_SYNC(sc, cb,
  798                    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
  799                 xfer->msgout[0] = MSG_IDENTIFY(cb->lun,
  800                     (xs->xs_control & XS_CTL_REQSENSE) == 0);
  801                 cb->msgoutlen = 1;
  802 
  803                 if (sc->sc_tgt[cb->id].flags & TGTF_SYNCNEG) {
  804                         /* Send SDTR */
  805                         xfer->msgout[1] = MSG_EXTENDED;
  806                         xfer->msgout[2] = MSG_EXT_SDTR_LEN;
  807                         xfer->msgout[3] = MSG_EXT_SDTR;
  808                         xfer->msgout[4] = sc->sc_minperiod;
  809                         xfer->msgout[5] = OOSIOP_MAX_OFFSET;
  810                         cb->msgoutlen = 6;
  811                         sc->sc_tgt[cb->id].flags &= ~TGTF_SYNCNEG;
  812                         sc->sc_tgt[cb->id].flags |= TGTF_WAITSDTR;
  813                 }
  814 
  815                 xfer->status = SCSI_OOSIOP_NOSTATUS;
  816 
  817                 OOSIOP_XFERMSG_SYNC(sc, cb,
  818                     BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
  819 
  820                 s = splbio();
  821 
  822                 TAILQ_INSERT_TAIL(&sc->sc_cbq, cb, chain);
  823 
  824                 if (!sc->sc_active) {
  825                         /* Abort script to start selection */
  826                         oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT);
  827                 }
  828                 if (xs->xs_control & XS_CTL_POLL) {
  829                         /* Poll for command completion */
  830                         while ((xs->xs_status & XS_STS_DONE) == 0) {
  831                                 delay(1000);
  832                                 oosiop_intr(sc);
  833                         }
  834                 }
  835 
  836                 splx(s);
  837 
  838                 return;
  839 
  840         case ADAPTER_REQ_GROW_RESOURCES:
  841                 return;
  842 
  843         case ADAPTER_REQ_SET_XFER_MODE:
  844                 xm = arg;
  845                 if (xm->xm_mode & PERIPH_CAP_SYNC)
  846                         sc->sc_tgt[xm->xm_target].flags |= TGTF_SYNCNEG;
  847                 else
  848                         oosiop_set_syncparam(sc, xm->xm_target, 0, 0);
  849 
  850                 return;
  851         }
  852 }
  853 
  854 static void
  855 oosiop_done(struct oosiop_softc *sc, struct oosiop_cb *cb)
  856 {
  857         struct scsipi_xfer *xs;
  858 
  859         xs = cb->xs;
  860         if (cb == sc->sc_curcb)
  861                 sc->sc_curcb = NULL;
  862         if (cb == sc->sc_lastcb)
  863                 sc->sc_lastcb = NULL;
  864         sc->sc_tgt[cb->id].nexus = NULL;
  865 
  866         callout_stop(&xs->xs_callout);
  867 
  868         bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, xs->cmdlen,
  869             BUS_DMASYNC_POSTWRITE);
  870         bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
  871 
  872         if (xs->datalen > 0) {
  873                 bus_dmamap_sync(sc->sc_dmat, cb->datadma, 0, xs->datalen,
  874                     BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
  875                 bus_dmamap_unload(sc->sc_dmat, cb->datadma);
  876         }
  877 
  878         xs->status = cb->xfer->status;
  879         xs->resid = 0;  /* XXX */
  880 
  881         if (cb->flags & CBF_SELTOUT)
  882                 xs->error = XS_SELTIMEOUT;
  883         else if (cb->flags & CBF_TIMEOUT)
  884                 xs->error = XS_TIMEOUT;
  885         else switch (xs->status) {
  886         case SCSI_OK:
  887                 xs->error = XS_NOERROR;
  888                 break;
  889 
  890         case SCSI_BUSY:
  891         case SCSI_CHECK:
  892                 xs->error = XS_BUSY;
  893                 break;
  894         case SCSI_OOSIOP_NOSTATUS:
  895                 /* the status byte was not updated, cmd was aborted. */
  896                 xs->error = XS_SELTIMEOUT;
  897                 break;
  898 
  899         default:
  900                 xs->error = XS_RESET;
  901                 break;
  902         }
  903 
  904         scsipi_done(xs);
  905 
  906         /* Put it on the free list. */
  907         TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
  908 }
  909 
  910 static void
  911 oosiop_timeout(void *arg)
  912 {
  913         struct oosiop_cb *cb;
  914         struct scsipi_periph *periph;
  915         struct oosiop_softc *sc;
  916         int s;
  917 
  918         cb = arg;
  919         periph = cb->xs->xs_periph;
  920         sc = device_private(periph->periph_channel->chan_adapter->adapt_dev);
  921         scsipi_printaddr(periph);
  922         printf("timed out\n");
  923 
  924         s = splbio();
  925 
  926         cb->flags |= CBF_TIMEOUT;
  927         oosiop_done(sc, cb);
  928 
  929         splx(s);
  930 }
  931 
  932 static void
  933 oosiop_reset(struct oosiop_softc *sc)
  934 {
  935         int i, s;
  936 
  937         s = splbio();
  938 
  939         /* Stop SCRIPTS processor */
  940         oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT);
  941         delay(100);
  942         oosiop_write_1(sc, OOSIOP_ISTAT, 0);
  943 
  944         /* Reset the chip */
  945         oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl | OOSIOP_DCNTL_RST);
  946         delay(100);
  947         oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl);
  948         delay(10000);
  949 
  950         /* Set up various chip parameters */
  951         oosiop_write_1(sc, OOSIOP_SCNTL0, OOSIOP_ARB_FULL | OOSIOP_SCNTL0_EPG);
  952         oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_ESR);
  953         oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl);
  954         oosiop_write_1(sc, OOSIOP_DMODE, OOSIOP_DMODE_BL_8);
  955         oosiop_write_1(sc, OOSIOP_SCID, OOSIOP_SCID_VALUE(sc->sc_id));
  956         oosiop_write_1(sc, OOSIOP_DWT, 0xff);   /* Enable DMA timeout */
  957         oosiop_write_1(sc, OOSIOP_CTEST7, 0);
  958         oosiop_write_1(sc, OOSIOP_SXFER, 0);
  959 
  960         /* Clear all interrupts */
  961         (void)oosiop_read_1(sc, OOSIOP_SSTAT0);
  962         (void)oosiop_read_1(sc, OOSIOP_SSTAT1);
  963         (void)oosiop_read_1(sc, OOSIOP_DSTAT);
  964 
  965         /* Enable interrupts */
  966         oosiop_write_1(sc, OOSIOP_SIEN,
  967             OOSIOP_SIEN_M_A | OOSIOP_SIEN_STO | OOSIOP_SIEN_SGE |
  968             OOSIOP_SIEN_UDC | OOSIOP_SIEN_RST | OOSIOP_SIEN_PAR);
  969         oosiop_write_1(sc, OOSIOP_DIEN,
  970             OOSIOP_DIEN_ABRT | OOSIOP_DIEN_SSI | OOSIOP_DIEN_SIR |
  971             OOSIOP_DIEN_WTD | OOSIOP_DIEN_IID);
  972 
  973         /* Set target state to asynchronous */
  974         for (i = 0; i < OOSIOP_NTGT; i++) {
  975                 sc->sc_tgt[i].flags = 0;
  976                 sc->sc_tgt[i].scf = 0;
  977                 sc->sc_tgt[i].sxfer = 0;
  978         }
  979 
  980         splx(s);
  981 }
  982 
  983 static void
  984 oosiop_reset_bus(struct oosiop_softc *sc)
  985 {
  986         int s, i;
  987 
  988         s = splbio();
  989 
  990         /* Assert SCSI RST */
  991         oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_RST);
  992         delay(25);      /* Reset hold time (25us) */
  993         oosiop_write_1(sc, OOSIOP_SCNTL1, 0);
  994 
  995         /* Remove all nexuses */
  996         for (i = 0; i < OOSIOP_NTGT; i++) {
  997                 if (sc->sc_tgt[i].nexus) {
  998                         sc->sc_tgt[i].nexus->xfer->status =
  999                             SCSI_OOSIOP_NOSTATUS; /* XXX */
 1000                         oosiop_done(sc, sc->sc_tgt[i].nexus);
 1001                 }
 1002         }
 1003 
 1004         sc->sc_curcb = NULL;
 1005 
 1006         delay(250000);  /* Reset to selection (250ms) */
 1007 
 1008         splx(s);
 1009 }
 1010 
 1011 /*
 1012  * interrupt handler
 1013  */
 1014 int
 1015 oosiop_intr(struct oosiop_softc *sc)
 1016 {
 1017         struct oosiop_cb *cb;
 1018         uint32_t dcmd;
 1019         int timeout;
 1020         uint8_t istat, dstat, sstat0;
 1021 
 1022         istat = oosiop_read_1(sc, OOSIOP_ISTAT);
 1023 
 1024         if ((istat & (OOSIOP_ISTAT_SIP | OOSIOP_ISTAT_DIP)) == 0)
 1025                 return (0);
 1026 
 1027         sc->sc_nextdsp = Ent_wait_reselect;
 1028 
 1029         /* DMA interrupts */
 1030         if (istat & OOSIOP_ISTAT_DIP) {
 1031                 oosiop_write_1(sc, OOSIOP_ISTAT, 0);
 1032 
 1033                 dstat = oosiop_read_1(sc, OOSIOP_DSTAT);
 1034 
 1035                 if (dstat & OOSIOP_DSTAT_ABRT) {
 1036                         sc->sc_nextdsp = oosiop_read_4(sc, OOSIOP_DSP) -
 1037                             sc->sc_scrbase - 8;
 1038 
 1039                         if (sc->sc_nextdsp == Ent_p_resel_msgin_move &&
 1040                             (oosiop_read_1(sc, OOSIOP_SBCL) & OOSIOP_ACK)) {
 1041                                 if ((dstat & OOSIOP_DSTAT_DFE) == 0)
 1042                                         oosiop_flush_fifo(sc);
 1043                                 sc->sc_nextdsp += 8;
 1044                         }
 1045                 }
 1046 
 1047                 if (dstat & OOSIOP_DSTAT_SSI) {
 1048                         sc->sc_nextdsp = oosiop_read_4(sc, OOSIOP_DSP) -
 1049                             sc->sc_scrbase;
 1050                         printf("%s: single step %08x\n",
 1051                             device_xname(sc->sc_dev), sc->sc_nextdsp);
 1052                 }
 1053 
 1054                 if (dstat & OOSIOP_DSTAT_SIR) {
 1055                         if ((dstat & OOSIOP_DSTAT_DFE) == 0)
 1056                                 oosiop_flush_fifo(sc);
 1057                         oosiop_scriptintr(sc);
 1058                 }
 1059 
 1060                 if (dstat & OOSIOP_DSTAT_WTD) {
 1061                         printf("%s: DMA time out\n", device_xname(sc->sc_dev));
 1062                         oosiop_reset(sc);
 1063                 }
 1064 
 1065                 if (dstat & OOSIOP_DSTAT_IID) {
 1066                         dcmd = oosiop_read_4(sc, OOSIOP_DBC);
 1067                         if ((dcmd & 0xf8000000) == 0x48000000) {
 1068                                 printf("%s: REQ asserted on WAIT DISCONNECT\n",
 1069                                     device_xname(sc->sc_dev));
 1070                                 sc->sc_nextdsp = Ent_phasedispatch; /* XXX */
 1071                         } else {
 1072                                 printf("%s: invalid SCRIPTS instruction "
 1073                                     "addr=%08x dcmd=%08x dsps=%08x\n",
 1074                                     device_xname(sc->sc_dev),
 1075                                     oosiop_read_4(sc, OOSIOP_DSP) - 8, dcmd,
 1076                                     oosiop_read_4(sc, OOSIOP_DSPS));
 1077                                 oosiop_reset(sc);
 1078                                 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
 1079                                 oosiop_load_script(sc);
 1080                         }
 1081                 }
 1082 
 1083                 if ((dstat & OOSIOP_DSTAT_DFE) == 0)
 1084                         oosiop_clear_fifo(sc);
 1085         }
 1086 
 1087         /* SCSI interrupts */
 1088         if (istat & OOSIOP_ISTAT_SIP) {
 1089                 if (istat & OOSIOP_ISTAT_DIP)
 1090                         delay(1);
 1091                 sstat0 = oosiop_read_1(sc, OOSIOP_SSTAT0);
 1092 
 1093                 if (sstat0 & OOSIOP_SSTAT0_M_A) {
 1094                         /* SCSI phase mismatch during MOVE operation */
 1095                         oosiop_phasemismatch(sc);
 1096                         sc->sc_nextdsp = Ent_phasedispatch;
 1097                 }
 1098 
 1099                 if (sstat0 & OOSIOP_SSTAT0_STO) {
 1100                         if (sc->sc_curcb) {
 1101                                 sc->sc_curcb->flags |= CBF_SELTOUT;
 1102                                 oosiop_done(sc, sc->sc_curcb);
 1103                         }
 1104                 }
 1105 
 1106                 if (sstat0 & OOSIOP_SSTAT0_SGE) {
 1107                         printf("%s: SCSI gross error\n",
 1108                             device_xname(sc->sc_dev));
 1109                         oosiop_reset(sc);
 1110                 }
 1111 
 1112                 if (sstat0 & OOSIOP_SSTAT0_UDC) {
 1113                         /* XXX */
 1114                         if (sc->sc_curcb) {
 1115                                 printf("%s: unexpected disconnect\n",
 1116                                     device_xname(sc->sc_dev));
 1117                                 oosiop_done(sc, sc->sc_curcb);
 1118                         }
 1119                 }
 1120 
 1121                 if (sstat0 & OOSIOP_SSTAT0_RST)
 1122                         oosiop_reset(sc);
 1123 
 1124                 if (sstat0 & OOSIOP_SSTAT0_PAR)
 1125                         printf("%s: parity error\n", device_xname(sc->sc_dev));
 1126         }
 1127 
 1128         /* Start next command if available */
 1129         if (sc->sc_nextdsp == Ent_wait_reselect && TAILQ_FIRST(&sc->sc_cbq)) {
 1130                 cb = sc->sc_curcb = TAILQ_FIRST(&sc->sc_cbq);
 1131                 TAILQ_REMOVE(&sc->sc_cbq, cb, chain);
 1132                 sc->sc_tgt[cb->id].nexus = cb;
 1133 
 1134                 oosiop_setup_dma(sc);
 1135                 oosiop_setup_syncxfer(sc);
 1136                 sc->sc_lastcb = cb;
 1137                 sc->sc_nextdsp = Ent_start_select;
 1138 
 1139                 /* Schedule timeout */
 1140                 if ((cb->xs->xs_control & XS_CTL_POLL) == 0) {
 1141                         timeout = mstohz(cb->xs->timeout) + 1;
 1142                         callout_reset(&cb->xs->xs_callout, timeout,
 1143                             oosiop_timeout, cb);
 1144                 }
 1145         }
 1146 
 1147         sc->sc_active = (sc->sc_nextdsp != Ent_wait_reselect);
 1148 
 1149         /* Restart script */
 1150         oosiop_write_4(sc, OOSIOP_DSP, sc->sc_nextdsp + sc->sc_scrbase);
 1151 
 1152         return (1);
 1153 }
 1154 
 1155 static void
 1156 oosiop_scriptintr(struct oosiop_softc *sc)
 1157 {
 1158         struct oosiop_cb *cb;
 1159         uint32_t icode;
 1160         uint32_t dsp;
 1161         int i;
 1162         uint8_t sfbr, resid, resmsg;
 1163 
 1164         cb = sc->sc_curcb;
 1165         icode = oosiop_read_4(sc, OOSIOP_DSPS);
 1166 
 1167         switch (icode) {
 1168         case A_int_done:
 1169                 if (cb)
 1170                         oosiop_done(sc, cb);
 1171                 break;
 1172 
 1173         case A_int_msgin:
 1174                 if (cb)
 1175                         oosiop_msgin(sc, cb);
 1176                 break;
 1177 
 1178         case A_int_extmsg:
 1179                 /* extended message in DMA setup request */
 1180                 sfbr = oosiop_read_1(sc, OOSIOP_SFBR);
 1181                 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
 1182                 oosiop_fixup_move(sc, Ent_p_extmsgin_move, sfbr,
 1183                     cb->xferdma->dm_segs[0].ds_addr +
 1184                     offsetof(struct oosiop_xfer, msgin[2]));
 1185                 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
 1186                 sc->sc_nextdsp = Ent_rcv_extmsg;
 1187                 break;
 1188 
 1189         case A_int_resel:
 1190                 /* reselected */
 1191                 resid = oosiop_read_1(sc, OOSIOP_SFBR);
 1192                 for (i = 0; i < OOSIOP_NTGT; i++)
 1193                         if (resid & (1 << i))
 1194                                 break;
 1195                 if (i == OOSIOP_NTGT) {
 1196                         printf("%s: missing reselection target id\n",
 1197                             device_xname(sc->sc_dev));
 1198                         break;
 1199                 }
 1200                 sc->sc_resid = i;
 1201                 sc->sc_nextdsp = Ent_wait_resel_identify;
 1202 
 1203                 if (cb) {
 1204                         /* Current command was lost arbitration */
 1205                         sc->sc_tgt[cb->id].nexus = NULL;
 1206                         TAILQ_INSERT_HEAD(&sc->sc_cbq, cb, chain);
 1207                         sc->sc_curcb = NULL;
 1208                 }
 1209 
 1210                 break;
 1211 
 1212         case A_int_res_id:
 1213                 cb = sc->sc_tgt[sc->sc_resid].nexus;
 1214                 resmsg = oosiop_read_1(sc, OOSIOP_SFBR);
 1215                 if (MSG_ISIDENTIFY(resmsg) && cb &&
 1216                     (resmsg & MSG_IDENTIFY_LUNMASK) == cb->lun) {
 1217                         sc->sc_curcb = cb;
 1218                         if (cb != sc->sc_lastcb) {
 1219                                 oosiop_setup_dma(sc);
 1220                                 oosiop_setup_syncxfer(sc);
 1221                                 sc->sc_lastcb = cb;
 1222                         }
 1223                         if (cb->curdp != cb->savedp) {
 1224                                 cb->curdp = cb->savedp;
 1225                                 oosiop_setup_sgdma(sc, cb);
 1226                         }
 1227                         sc->sc_nextdsp = Ent_ack_msgin;
 1228                 } else {
 1229                         /* Reselection from invalid target */
 1230                         oosiop_reset_bus(sc);
 1231                 }
 1232                 break;
 1233 
 1234         case A_int_resfail:
 1235                 /* reselect failed */
 1236                 break;
 1237 
 1238         case A_int_disc:
 1239                 /* disconnected */
 1240                 sc->sc_curcb = NULL;
 1241                 break;
 1242 
 1243         case A_int_err:
 1244                 /* generic error */
 1245                 dsp = oosiop_read_4(sc, OOSIOP_DSP);
 1246                 printf("%s: script error at 0x%08x\n",
 1247                     device_xname(sc->sc_dev), dsp - 8);
 1248                 sc->sc_curcb = NULL;
 1249                 break;
 1250 
 1251         case DATAIN_TRAP:
 1252                 printf("%s: unexpected datain\n", device_xname(sc->sc_dev));
 1253                 /* XXX: need to reset? */
 1254                 break;
 1255 
 1256         case DATAOUT_TRAP:
 1257                 printf("%s: unexpected dataout\n", device_xname(sc->sc_dev));
 1258                 /* XXX: need to reset? */
 1259                 break;
 1260 
 1261         default:
 1262                 printf("%s: unknown intr code %08x\n",
 1263                     device_xname(sc->sc_dev), icode);
 1264                 break;
 1265         }
 1266 }
 1267 
 1268 static void
 1269 oosiop_msgin(struct oosiop_softc *sc, struct oosiop_cb *cb)
 1270 {
 1271         struct oosiop_xfer *xfer;
 1272         int msgout;
 1273 
 1274         xfer = cb->xfer;
 1275         sc->sc_nextdsp = Ent_ack_msgin;
 1276         msgout = 0;
 1277 
 1278         OOSIOP_XFERMSG_SYNC(sc, cb,
 1279             BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 1280 
 1281         switch (xfer->msgin[0]) {
 1282         case MSG_EXTENDED:
 1283                 switch (xfer->msgin[2]) {
 1284                 case MSG_EXT_SDTR:
 1285                         if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) {
 1286                                 /* Host initiated SDTR */
 1287                                 sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR;
 1288                         } else {
 1289                                 /* Target initiated SDTR */
 1290                                 if (xfer->msgin[3] < sc->sc_minperiod)
 1291                                         xfer->msgin[3] = sc->sc_minperiod;
 1292                                 if (xfer->msgin[4] > OOSIOP_MAX_OFFSET)
 1293                                         xfer->msgin[4] = OOSIOP_MAX_OFFSET;
 1294                                 xfer->msgout[0] = MSG_EXTENDED;
 1295                                 xfer->msgout[1] = MSG_EXT_SDTR_LEN;
 1296                                 xfer->msgout[2] = MSG_EXT_SDTR;
 1297                                 xfer->msgout[3] = xfer->msgin[3];
 1298                                 xfer->msgout[4] = xfer->msgin[4];
 1299                                 cb->msgoutlen = 5;
 1300                                 msgout = 1;
 1301                         }
 1302                         oosiop_set_syncparam(sc, cb->id, (int)xfer->msgin[3],
 1303                             (int)xfer->msgin[4]);
 1304                         oosiop_setup_syncxfer(sc);
 1305                         break;
 1306 
 1307                 default:
 1308                         /* Reject message */
 1309                         xfer->msgout[0] = MSG_MESSAGE_REJECT;
 1310                         cb->msgoutlen = 1;
 1311                         msgout = 1;
 1312                         break;
 1313                 }
 1314                 break;
 1315 
 1316         case MSG_SAVEDATAPOINTER:
 1317                 cb->savedp = cb->curdp;
 1318                 break;
 1319 
 1320         case MSG_RESTOREPOINTERS:
 1321                 if (cb->curdp != cb->savedp) {
 1322                         cb->curdp = cb->savedp;
 1323                         oosiop_setup_sgdma(sc, cb);
 1324                 }
 1325                 break;
 1326 
 1327         case MSG_MESSAGE_REJECT:
 1328                 if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) {
 1329                         /* SDTR rejected */
 1330                         sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR;
 1331                         oosiop_set_syncparam(sc, cb->id, 0, 0);
 1332                         oosiop_setup_syncxfer(sc);
 1333                 }
 1334                 break;
 1335 
 1336         default:
 1337                 /* Reject message */
 1338                 xfer->msgout[0] = MSG_MESSAGE_REJECT;
 1339                 cb->msgoutlen = 1;
 1340                 msgout = 1;
 1341         }
 1342 
 1343         OOSIOP_XFERMSG_SYNC(sc, cb,
 1344             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 1345 
 1346         if (msgout) {
 1347                 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
 1348                 oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen,
 1349                     cb->xferdma->dm_segs[0].ds_addr +
 1350                     offsetof(struct oosiop_xfer, msgout[0]));
 1351                 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
 1352                 sc->sc_nextdsp = Ent_sendmsg;
 1353         }
 1354 }

Cache object: 0caf5bb05e275b6afb024b21393d619a


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