root/dev/ic/oosiop.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. oosiop_attach
  2. oosiop_alloc_cb
  3. oosiop_relocate_io
  4. oosiop_relocate_tc
  5. oosiop_fixup_select
  6. oosiop_fixup_jump
  7. oosiop_fixup_move
  8. oosiop_load_script
  9. oosiop_setup_sgdma
  10. oosiop_setup_dma
  11. oosiop_flush_fifo
  12. oosiop_clear_fifo
  13. oosiop_phasemismatch
  14. oosiop_setup_syncxfer
  15. oosiop_set_syncparam
  16. oosiop_minphys
  17. oosiop_scsicmd
  18. oosiop_poll
  19. oosiop_setup
  20. oosiop_done
  21. oosiop_timeout
  22. oosiop_reset
  23. oosiop_reset_bus
  24. oosiop_intr
  25. oosiop_processintr
  26. oosiop_scriptintr
  27. oosiop_msgin

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

/* [<][>][^][v][top][bottom][index][help] */