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

Cache object: ac715f5d9658826c44d4e2c19311ff4c


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