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 /*      $OpenBSD: oosiop.c,v 1.36 2022/04/16 19:19:59 naddy 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 <scsi/scsi_all.h>
   48 #include <scsi/scsiconf.h>
   49 #include <scsi/scsi_message.h>
   50 
   51 #include <machine/cpu.h>
   52 #include <machine/bus.h>
   53 
   54 #include <dev/ic/oosiopreg.h>
   55 #include <dev/ic/oosiopvar.h>
   56 
   57 /* 53C700 script */
   58 #include <dev/microcode/siop/oosiop.out>
   59 
   60 int     oosiop_alloc_cb(struct oosiop_softc *, int);
   61 
   62 static __inline void oosiop_relocate_io(struct oosiop_softc *, bus_addr_t);
   63 static __inline void oosiop_relocate_tc(struct oosiop_softc *, bus_addr_t);
   64 static __inline void oosiop_fixup_select(struct oosiop_softc *, bus_addr_t,
   65                          int);
   66 static __inline void oosiop_fixup_jump(struct oosiop_softc *, bus_addr_t,
   67                          bus_addr_t);
   68 static __inline void oosiop_fixup_move(struct oosiop_softc *, bus_addr_t,
   69                          bus_size_t, bus_addr_t);
   70 
   71 void    oosiop_load_script(struct oosiop_softc *);
   72 void    oosiop_setup_sgdma(struct oosiop_softc *, struct oosiop_cb *);
   73 void    oosiop_setup_dma(struct oosiop_softc *);
   74 void    oosiop_flush_fifo(struct oosiop_softc *);
   75 void    oosiop_clear_fifo(struct oosiop_softc *);
   76 void    oosiop_phasemismatch(struct oosiop_softc *);
   77 void    oosiop_setup_syncxfer(struct oosiop_softc *);
   78 void    oosiop_set_syncparam(struct oosiop_softc *, int, int, int);
   79 void    oosiop_scsicmd(struct scsi_xfer *);
   80 void    oosiop_done(struct oosiop_softc *, struct oosiop_cb *);
   81 void    oosiop_timeout(void *);
   82 void    oosiop_reset(struct oosiop_softc *, int);
   83 void    oosiop_reset_bus(struct oosiop_softc *);
   84 void    oosiop_scriptintr(struct oosiop_softc *);
   85 void    oosiop_msgin(struct oosiop_softc *, struct oosiop_cb *);
   86 void    oosiop_setup(struct oosiop_softc *, struct oosiop_cb *);
   87 void    oosiop_poll(struct oosiop_softc *, struct oosiop_cb *);
   88 void    oosiop_processintr(struct oosiop_softc *, u_int8_t);
   89 
   90 void    *oosiop_cb_alloc(void *);
   91 void    oosiop_cb_free(void *, void *);
   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 combination */
   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 const struct scsi_adapter oosiop_switch = {
  132         oosiop_scsicmd, NULL, NULL, NULL, NULL
  133 };
  134 
  135 void *
  136 oosiop_cb_alloc(void *xsc)
  137 {
  138         struct oosiop_softc *sc = xsc;
  139         struct oosiop_cb *cb;
  140 
  141         mtx_enter(&sc->sc_cb_mtx);
  142         cb = TAILQ_FIRST(&sc->sc_free_cb);
  143         if (cb)
  144                 TAILQ_REMOVE(&sc->sc_free_cb, cb, chain);
  145         mtx_leave(&sc->sc_cb_mtx);
  146 
  147         return (cb);
  148 }
  149 
  150 void
  151 oosiop_cb_free(void *xsc, void *xcb)
  152 {
  153         struct oosiop_softc *sc = xsc;
  154         struct oosiop_cb *cb = xcb;
  155 
  156         mtx_enter(&sc->sc_cb_mtx);
  157         TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
  158         mtx_leave(&sc->sc_cb_mtx);
  159 }
  160 
  161 void
  162 oosiop_attach(struct oosiop_softc *sc)
  163 {
  164         struct scsibus_attach_args saa;
  165         bus_size_t scrsize;
  166         bus_dma_segment_t seg;
  167         struct oosiop_cb *cb;
  168         int err, i, nseg;
  169 
  170         /*
  171          * Allocate DMA-safe memory for the script and map it.
  172          */
  173         scrsize = round_page(sizeof(oosiop_script));
  174         err = bus_dmamem_alloc(sc->sc_dmat, scrsize, PAGE_SIZE, 0, &seg, 1,
  175             &nseg, BUS_DMA_NOWAIT | BUS_DMA_ZERO);
  176         if (err) {
  177                 printf(": failed to allocate script memory, err=%d\n", err);
  178                 return;
  179         }
  180         err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, scrsize,
  181             (caddr_t *)&sc->sc_scr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
  182         if (err) {
  183                 printf(": failed to map script memory, err=%d\n", err);
  184                 return;
  185         }
  186         err = bus_dmamap_create(sc->sc_dmat, scrsize, 1, scrsize, 0,
  187             BUS_DMA_NOWAIT, &sc->sc_scrdma);
  188         if (err) {
  189                 printf(": failed to create script map, err=%d\n", err);
  190                 return;
  191         }
  192         err = bus_dmamap_load_raw(sc->sc_dmat, sc->sc_scrdma,
  193             &seg, nseg, scrsize, BUS_DMA_NOWAIT | BUS_DMA_WRITE);
  194         if (err) {
  195                 printf(": failed to load script map, err=%d\n", err);
  196                 return;
  197         }
  198         sc->sc_scrbase = sc->sc_scrdma->dm_segs[0].ds_addr;
  199 
  200         /* Initialize command block array */
  201         TAILQ_INIT(&sc->sc_free_cb);
  202         TAILQ_INIT(&sc->sc_cbq);
  203         if (oosiop_alloc_cb(sc, OOSIOP_NCB) != 0)
  204                 return;
  205 
  206         /* Use first cb to reselection msgin buffer */
  207         cb = TAILQ_FIRST(&sc->sc_free_cb);
  208         sc->sc_reselbuf = cb->xferdma->dm_segs[0].ds_addr +
  209             offsetof(struct oosiop_xfer, msgin[0]);
  210 
  211         for (i = 0; i < OOSIOP_NTGT; i++) {
  212                 sc->sc_tgt[i].nexus = NULL;
  213                 sc->sc_tgt[i].flags = 0;
  214         }
  215 
  216         /* Setup asynchronous clock divisor parameters */
  217         if (sc->sc_freq <= 25000000) {
  218                 sc->sc_ccf = 10;
  219                 sc->sc_dcntl = OOSIOP_DCNTL_CF_1;
  220         } else if (sc->sc_freq <= 37500000) {
  221                 sc->sc_ccf = 15;
  222                 sc->sc_dcntl = OOSIOP_DCNTL_CF_1_5;
  223         } else if (sc->sc_freq <= 50000000) {
  224                 sc->sc_ccf = 20;
  225                 sc->sc_dcntl = OOSIOP_DCNTL_CF_2;
  226         } else {
  227                 sc->sc_ccf = 30;
  228                 sc->sc_dcntl = OOSIOP_DCNTL_CF_3;
  229         }
  230 
  231         if (sc->sc_chip == OOSIOP_700)
  232                 sc->sc_minperiod = oosiop_period(sc, 4, sc->sc_ccf);
  233         else
  234                 sc->sc_minperiod = oosiop_period(sc, 4, 10);
  235 
  236         if (sc->sc_minperiod < 25)
  237                 sc->sc_minperiod = 25;  /* limit to 10MB/s */
  238 
  239         mtx_init(&sc->sc_cb_mtx, IPL_BIO);
  240         scsi_iopool_init(&sc->sc_iopool, sc, oosiop_cb_alloc, oosiop_cb_free);
  241 
  242         printf(": NCR53C700%s rev %d, %dMHz\n",
  243             sc->sc_chip == OOSIOP_700_66 ? "-66" : "",
  244             oosiop_read_1(sc, OOSIOP_CTEST7) >> 4,
  245             sc->sc_freq / 1000000);
  246         /*
  247          * Reset all
  248          */
  249         oosiop_reset(sc, TRUE);
  250         oosiop_reset_bus(sc);
  251 
  252         /*
  253          * Start SCRIPTS processor
  254          */
  255         oosiop_load_script(sc);
  256         sc->sc_active = 0;
  257         oosiop_write_4(sc, OOSIOP_DSP, sc->sc_scrbase + Ent_wait_reselect);
  258 
  259         saa.saa_adapter = &oosiop_switch;
  260         saa.saa_adapter_softc = sc;
  261         saa.saa_adapter_buswidth = OOSIOP_NTGT;
  262         saa.saa_adapter_target = sc->sc_id;
  263         saa.saa_luns = 8;
  264         saa.saa_openings = 1;   /* XXX */
  265         saa.saa_pool = &sc->sc_iopool;
  266         saa.saa_quirks = ADEV_NODOORLOCK;
  267         saa.saa_flags = 0;
  268         saa.saa_wwpn = saa.saa_wwnn = 0;
  269 
  270         config_found(&sc->sc_dev, &saa, scsiprint);
  271 }
  272 
  273 int
  274 oosiop_alloc_cb(struct oosiop_softc *sc, int ncb)
  275 {
  276         struct oosiop_cb *cb;
  277         struct oosiop_xfer *xfer;
  278         bus_size_t xfersize;
  279         bus_dma_segment_t seg;
  280         int i, s, err, nseg;
  281 
  282         /*
  283          * Allocate oosiop_cb.
  284          */
  285         cb = mallocarray(ncb, sizeof(*cb), M_DEVBUF, M_NOWAIT | M_ZERO);
  286         if (cb == NULL) {
  287                 printf(": failed to allocate cb memory\n");
  288                 return (ENOMEM);
  289         }
  290 
  291         /*
  292          * Allocate DMA-safe memory for the oosiop_xfer and map it.
  293          */
  294         xfersize = sizeof(struct oosiop_xfer) * ncb;
  295         err = bus_dmamem_alloc(sc->sc_dmat, xfersize, PAGE_SIZE, 0, &seg, 1,
  296             &nseg, BUS_DMA_NOWAIT);
  297         if (err) {
  298                 printf(": failed to allocate xfer block memory, err=%d\n", err);
  299                 return (err);
  300         }
  301         err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, xfersize,
  302             (caddr_t *)(void *)&xfer, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
  303         if (err) {
  304                 printf(": failed to map xfer block memory, err=%d\n", err);
  305                 return (err);
  306         }
  307 
  308         /* Initialize each command block */
  309         for (i = 0; i < ncb; i++) {
  310                 err = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE,
  311                     0, BUS_DMA_NOWAIT, &cb->cmddma);
  312                 if (err) {
  313                         printf(": failed to create cmddma map, err=%d\n", err);
  314                         return (err);
  315                 }
  316 
  317                 err = bus_dmamap_create(sc->sc_dmat, OOSIOP_MAX_XFER,
  318                     OOSIOP_NSG, OOSIOP_DBC_MAX, 0, BUS_DMA_NOWAIT,
  319                     &cb->datadma);
  320                 if (err) {
  321                         printf(": failed to create datadma map, err=%d\n", err);
  322                         return (err);
  323                 }
  324 
  325                 err = bus_dmamap_create(sc->sc_dmat,
  326                     sizeof(struct oosiop_xfer), 1, sizeof(struct oosiop_xfer),
  327                     0, BUS_DMA_NOWAIT, &cb->xferdma);
  328                 if (err) {
  329                         printf(": failed to create xfer block map, err=%d\n",
  330                             err);
  331                         return (err);
  332                 }
  333                 err = bus_dmamap_load(sc->sc_dmat, cb->xferdma, xfer,
  334                     sizeof(struct oosiop_xfer), NULL, BUS_DMA_NOWAIT);
  335                 if (err) {
  336                         printf(": failed to load xfer block, err=%d\n", err);
  337                         return (err);
  338                 }
  339 
  340                 cb->xfer = xfer;
  341 
  342                 s = splbio();
  343                 TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
  344                 splx(s);
  345 
  346                 cb++;
  347                 xfer++;
  348         }
  349 
  350         return (0);
  351 }
  352 
  353 static __inline void
  354 oosiop_relocate_io(struct oosiop_softc *sc, bus_addr_t addr)
  355 {
  356         u_int32_t dcmd;
  357         int32_t dsps;
  358 
  359         dcmd = letoh32(sc->sc_scr[addr / 4 + 0]);
  360         dsps = letoh32(sc->sc_scr[addr / 4 + 1]);
  361 
  362         /* convert relative to absolute */
  363         if (dcmd & 0x04000000) {
  364                 dcmd &= ~0x04000000;
  365 #if 0
  366                 /*
  367                  * sign extension isn't needed here because
  368                  * ncr53cxxx.c generates 32 bit dsps.
  369                  */
  370                 dsps <<= 8;
  371                 dsps >>= 8;
  372 #endif
  373                 sc->sc_scr[addr / 4 + 0] = htole32(dcmd);
  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_relocate_tc(struct oosiop_softc *sc, bus_addr_t addr)
  382 {
  383         u_int32_t dcmd;
  384         int32_t dsps;
  385 
  386         dcmd = letoh32(sc->sc_scr[addr / 4 + 0]);
  387         dsps = letoh32(sc->sc_scr[addr / 4 + 1]);
  388 
  389         /* convert relative to absolute */
  390         if (dcmd & 0x00800000) {
  391                 dcmd &= ~0x00800000;
  392                 sc->sc_scr[addr / 4] = htole32(dcmd);
  393 #if 0
  394                 /*
  395                  * sign extension isn't needed here because
  396                  * ncr53cxxx.c generates 32 bit dsps.
  397                  */
  398                 dsps <<= 8;
  399                 dsps >>= 8;
  400 #endif
  401                 dsps += addr + 8;
  402         }
  403 
  404         sc->sc_scr[addr / 4 + 1] = htole32(dsps + sc->sc_scrbase);
  405 }
  406 
  407 static __inline void
  408 oosiop_fixup_select(struct oosiop_softc *sc, bus_addr_t addr, int id)
  409 {
  410         u_int32_t dcmd;
  411 
  412         dcmd = letoh32(sc->sc_scr[addr / 4]);
  413         dcmd &= 0xff00ffff;
  414         dcmd |= 0x00010000 << id;
  415         sc->sc_scr[addr / 4] = htole32(dcmd);
  416 }
  417 
  418 static __inline void
  419 oosiop_fixup_jump(struct oosiop_softc *sc, bus_addr_t addr, bus_addr_t dst)
  420 {
  421 
  422         sc->sc_scr[addr / 4 + 1] = htole32(dst);
  423 }
  424 
  425 static __inline void
  426 oosiop_fixup_move(struct oosiop_softc *sc, bus_addr_t addr, bus_size_t dbc,
  427     bus_addr_t dsps)
  428 {
  429         u_int32_t dcmd;
  430 
  431         dcmd = letoh32(sc->sc_scr[addr / 4]);
  432         dcmd &= 0xff000000;
  433         dcmd |= dbc & 0x00ffffff;
  434         sc->sc_scr[addr / 4 + 0] = htole32(dcmd);
  435         sc->sc_scr[addr / 4 + 1] = htole32(dsps);
  436 }
  437 
  438 void
  439 oosiop_load_script(struct oosiop_softc *sc)
  440 {
  441         int i;
  442 
  443         /* load script */
  444         for (i = 0; i < sizeof(oosiop_script) / sizeof(oosiop_script[0]); i++)
  445                 sc->sc_scr[i] = htole32(oosiop_script[i]);
  446 
  447         /* relocate script */
  448         for (i = 0; i < (sizeof(oosiop_script) / 8); i++) {
  449                 switch (oosiop_script[i * 2] >> 27) {
  450                 case 0x08:      /* select */
  451                 case 0x0a:      /* wait reselect */
  452                         oosiop_relocate_io(sc, i * 8);
  453                         break;
  454                 case 0x10:      /* jump */
  455                 case 0x11:      /* call */
  456                         oosiop_relocate_tc(sc, i * 8);
  457                         break;
  458                 }
  459         }
  460 
  461         oosiop_fixup_move(sc, Ent_p_resel_msgin_move, 1, sc->sc_reselbuf);
  462         OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
  463 }
  464 
  465 void
  466 oosiop_setup_sgdma(struct oosiop_softc *sc, struct oosiop_cb *cb)
  467 {
  468         struct oosiop_xfer *xfer = cb->xfer;
  469         struct scsi_xfer *xs = cb->xs;
  470         int i, n, off;
  471 
  472         OOSIOP_XFERSCR_SYNC(sc, cb,
  473             BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
  474 
  475         off = cb->curdp;
  476 
  477         if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
  478                 /* Find start segment */
  479                 for (i = 0; i < cb->datadma->dm_nsegs; i++) {
  480                         if (off < cb->datadma->dm_segs[i].ds_len)
  481                                 break;
  482                         off -= cb->datadma->dm_segs[i].ds_len;
  483                 }
  484 
  485                 /* build MOVE block */
  486                 if (xs->flags & SCSI_DATA_IN) {
  487                         n = 0;
  488                         while (i < cb->datadma->dm_nsegs) {
  489                                 xfer->datain_scr[n * 2 + 0] =
  490                                     htole32(0x09000000 |
  491                                     (cb->datadma->dm_segs[i].ds_len - off));
  492                                 xfer->datain_scr[n * 2 + 1] =
  493                                     htole32(cb->datadma->dm_segs[i].ds_addr +
  494                                     off);
  495                                 n++;
  496                                 i++;
  497                                 off = 0;
  498                         }
  499                         xfer->datain_scr[n * 2 + 0] = htole32(0x80080000);
  500                         xfer->datain_scr[n * 2 + 1] =
  501                             htole32(sc->sc_scrbase + Ent_phasedispatch);
  502                 }
  503                 if (xs->flags & SCSI_DATA_OUT) {
  504                         n = 0;
  505                         while (i < cb->datadma->dm_nsegs) {
  506                                 xfer->dataout_scr[n * 2 + 0] =
  507                                     htole32(0x08000000 |
  508                                     (cb->datadma->dm_segs[i].ds_len - off));
  509                                 xfer->dataout_scr[n * 2 + 1] =
  510                                     htole32(cb->datadma->dm_segs[i].ds_addr +
  511                                     off);
  512                                 n++;
  513                                 i++;
  514                                 off = 0;
  515                         }
  516                         xfer->dataout_scr[n * 2 + 0] = htole32(0x80080000);
  517                         xfer->dataout_scr[n * 2 + 1] =
  518                             htole32(sc->sc_scrbase + Ent_phasedispatch);
  519                 }
  520         }
  521         if ((xs->flags & SCSI_DATA_IN) == 0) {
  522                 xfer->datain_scr[0] = htole32(0x98080000);
  523                 xfer->datain_scr[1] = htole32(DATAIN_TRAP);
  524         }
  525         if ((xs->flags & SCSI_DATA_OUT) == 0) {
  526                 xfer->dataout_scr[0] = htole32(0x98080000);
  527                 xfer->dataout_scr[1] = htole32(DATAOUT_TRAP);
  528         }
  529         OOSIOP_XFERSCR_SYNC(sc, cb,
  530             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
  531 }
  532 
  533 /*
  534  * Setup DMA pointer into script.
  535  */
  536 void
  537 oosiop_setup_dma(struct oosiop_softc *sc)
  538 {
  539         struct oosiop_cb *cb;
  540         bus_addr_t xferbase;
  541 
  542         cb = sc->sc_curcb;
  543         xferbase = cb->xferdma->dm_segs[0].ds_addr;
  544 
  545         OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
  546 
  547         oosiop_fixup_select(sc, Ent_p_select, cb->id);
  548         oosiop_fixup_jump(sc, Ent_p_datain_jump, xferbase +
  549             offsetof(struct oosiop_xfer, datain_scr[0]));
  550         oosiop_fixup_jump(sc, Ent_p_dataout_jump, xferbase +
  551             offsetof(struct oosiop_xfer, dataout_scr[0]));
  552         oosiop_fixup_move(sc, Ent_p_msgin_move, 1, xferbase +
  553             offsetof(struct oosiop_xfer, msgin[0]));
  554         oosiop_fixup_move(sc, Ent_p_extmsglen_move, 1, xferbase +
  555             offsetof(struct oosiop_xfer, msgin[1]));
  556         oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen, xferbase +
  557             offsetof(struct oosiop_xfer, msgout[0]));
  558         oosiop_fixup_move(sc, Ent_p_status_move, 1, xferbase +
  559             offsetof(struct oosiop_xfer, status));
  560         oosiop_fixup_move(sc, Ent_p_cmdout_move, cb->cmdlen,
  561             cb->cmddma->dm_segs[0].ds_addr);
  562 
  563         OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
  564 }
  565 
  566 void
  567 oosiop_flush_fifo(struct oosiop_softc *sc)
  568 {
  569 
  570         oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) |
  571             OOSIOP_DFIFO_FLF);
  572         while ((oosiop_read_1(sc, OOSIOP_CTEST1) & OOSIOP_CTEST1_FMT) !=
  573             OOSIOP_CTEST1_FMT)
  574                 ;
  575         oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) &
  576             ~OOSIOP_DFIFO_FLF);
  577 }
  578 
  579 void
  580 oosiop_clear_fifo(struct oosiop_softc *sc)
  581 {
  582 
  583         oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) |
  584             OOSIOP_DFIFO_CLF);
  585         while ((oosiop_read_1(sc, OOSIOP_CTEST1) & OOSIOP_CTEST1_FMT) !=
  586             OOSIOP_CTEST1_FMT)
  587                 ;
  588         oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) &
  589             ~OOSIOP_DFIFO_CLF);
  590 }
  591 
  592 void
  593 oosiop_phasemismatch(struct oosiop_softc *sc)
  594 {
  595         struct oosiop_cb *cb;
  596         u_int32_t dsp, dbc, n, i, len;
  597         u_int8_t dfifo, sstat1;
  598 
  599         cb = sc->sc_curcb;
  600         if (cb == NULL)
  601                 return;
  602 
  603         dsp = oosiop_read_4(sc, OOSIOP_DSP);
  604         dbc = oosiop_read_4(sc, OOSIOP_DBC) & OOSIOP_DBC_MAX;
  605         len = 0;
  606 
  607         n = dsp - cb->xferdma->dm_segs[0].ds_addr - 8;
  608         if (n >= offsetof(struct oosiop_xfer, datain_scr[0]) &&
  609             n < offsetof(struct oosiop_xfer, datain_scr[OOSIOP_NSG * 2])) {
  610                 n -= offsetof(struct oosiop_xfer, datain_scr[0]);
  611                 n >>= 3;
  612                 OOSIOP_DINSCR_SYNC(sc, cb,
  613                     BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
  614                 for (i = 0; i <= n; i++)
  615                         len += letoh32(cb->xfer->datain_scr[i * 2]) &
  616                             0x00ffffff;
  617                 OOSIOP_DINSCR_SYNC(sc, cb,
  618                     BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
  619                 /* All data in the chip are already flushed */
  620         } else if (n >= offsetof(struct oosiop_xfer, dataout_scr[0]) &&
  621             n < offsetof(struct oosiop_xfer, dataout_scr[OOSIOP_NSG * 2])) {
  622                 n -= offsetof(struct oosiop_xfer, dataout_scr[0]);
  623                 n >>= 3;
  624                 OOSIOP_DOUTSCR_SYNC(sc, cb,
  625                     BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
  626                 for (i = 0; i <= n; i++)
  627                         len += letoh32(cb->xfer->dataout_scr[i * 2]) &
  628                             0x00ffffff;
  629                 OOSIOP_DOUTSCR_SYNC(sc, cb,
  630                     BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
  631 
  632                 dfifo = oosiop_read_1(sc, OOSIOP_DFIFO);
  633                 dbc += ((dfifo & OOSIOP_DFIFO_BO) - (dbc & OOSIOP_DFIFO_BO)) &
  634                     OOSIOP_DFIFO_BO;
  635 
  636                 sstat1 = oosiop_read_1(sc, OOSIOP_SSTAT1);
  637                 if (sstat1 & OOSIOP_SSTAT1_OLF)
  638                         dbc++;
  639                 if ((sc->sc_tgt[cb->id].sxfer != 0) &&
  640                     (sstat1 & OOSIOP_SSTAT1_ORF) != 0)
  641                         dbc++;
  642 
  643                 oosiop_clear_fifo(sc);
  644         } else {
  645                 printf("%s: phase mismatch addr=%08x\n", sc->sc_dev.dv_xname,
  646                     oosiop_read_4(sc, OOSIOP_DSP) - 8);
  647                 oosiop_clear_fifo(sc);
  648                 return;
  649         }
  650 
  651         len -= dbc;
  652         if (len) {
  653                 cb->curdp += len;
  654                 oosiop_setup_sgdma(sc, cb);
  655         }
  656 }
  657 
  658 void
  659 oosiop_setup_syncxfer(struct oosiop_softc *sc)
  660 {
  661         int id;
  662 
  663         id = sc->sc_curcb->id;
  664         if (sc->sc_chip != OOSIOP_700)
  665                 oosiop_write_1(sc, OOSIOP_SBCL, sc->sc_tgt[id].scf);
  666 
  667         oosiop_write_1(sc, OOSIOP_SXFER, sc->sc_tgt[id].sxfer);
  668 }
  669 
  670 void
  671 oosiop_set_syncparam(struct oosiop_softc *sc, int id, int period, int offset)
  672 {
  673         int i, p;
  674 
  675         printf("%s: target %d now using 8 bit ", sc->sc_dev.dv_xname, id);
  676 
  677         if (offset == 0) {
  678                 /* Asynchronous */
  679                 sc->sc_tgt[id].scf = 0;
  680                 sc->sc_tgt[id].sxfer = 0;
  681                 printf("asynchronous");
  682         } else {
  683                 /* Synchronous */
  684                 if (sc->sc_chip == OOSIOP_700) {
  685                         for (i = 4; i < 12; i++) {
  686                                 p = oosiop_period(sc, i, sc->sc_ccf);
  687                                 if (p >= period)
  688                                         break;
  689                         }
  690                         if (i == 12) {
  691                                 printf("%s: target %d period too large\n",
  692                                     sc->sc_dev.dv_xname, id);
  693                                 i = 11; /* XXX */
  694                         }
  695                         sc->sc_tgt[id].scf = 0;
  696                         sc->sc_tgt[id].sxfer = ((i - 4) << 4) | offset;
  697                 } else {
  698                         for (i = 0; i < NSYNCTBL; i++) {
  699                                 p = oosiop_period(sc, synctbl[i].tp + 4,
  700                                     (synctbl[i].scf + 1) * 5);
  701                                 if (p >= period)
  702                                         break;
  703                         }
  704                         if (i == NSYNCTBL) {
  705                                 printf("%s: target %d period too large\n",
  706                                     sc->sc_dev.dv_xname, id);
  707                                 i = NSYNCTBL - 1;       /* XXX */
  708                         }
  709                         sc->sc_tgt[id].scf = synctbl[i].scf;
  710                         sc->sc_tgt[id].sxfer = (synctbl[i].tp << 4) | offset;
  711                 }
  712                 /* XXX print actual ns period... */
  713                 printf("synchronous");
  714         }
  715         printf(" xfers\n");
  716 }
  717 
  718 void
  719 oosiop_scsicmd(struct scsi_xfer *xs)
  720 {
  721         struct oosiop_softc *sc;
  722         struct oosiop_cb *cb;
  723         struct oosiop_xfer *xfer;
  724         int s, err;
  725         int dopoll;
  726 
  727         sc = xs->sc_link->bus->sb_adapter_softc;
  728 
  729         s = splbio();
  730 
  731         cb = xs->io;
  732 
  733         cb->xs = xs;
  734         cb->xsflags = xs->flags;
  735         cb->cmdlen = xs->cmdlen;
  736         cb->datalen = 0;
  737         cb->flags = 0;
  738         cb->id = xs->sc_link->target;
  739         cb->lun = xs->sc_link->lun;
  740         xfer = cb->xfer;
  741 
  742         /* Setup SCSI command buffer DMA */
  743         err = bus_dmamap_load(sc->sc_dmat, cb->cmddma, &xs->cmd,
  744             xs->cmdlen, NULL, ((xs->flags & SCSI_NOSLEEP) ?
  745             BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
  746             BUS_DMA_STREAMING | BUS_DMA_WRITE);
  747         if (err) {
  748                 printf("%s: unable to load cmd DMA map: %d",
  749                     sc->sc_dev.dv_xname, err);
  750                 splx(s);
  751                 xs->error = XS_DRIVER_STUFFUP;
  752                 scsi_done(xs);
  753                 return;
  754         }
  755         bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, xs->cmdlen,
  756             BUS_DMASYNC_PREWRITE);
  757 
  758         /* Setup data buffer DMA */
  759         if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
  760                 cb->datalen = xs->datalen;
  761                 err = bus_dmamap_load(sc->sc_dmat, cb->datadma,
  762                     xs->data, xs->datalen, NULL,
  763                     ((xs->flags & SCSI_NOSLEEP) ?
  764                     BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
  765                     BUS_DMA_STREAMING |
  766                     ((xs->flags & SCSI_DATA_IN) ? BUS_DMA_READ :
  767                     BUS_DMA_WRITE));
  768                 if (err) {
  769                         printf("%s: unable to load data DMA map: %d",
  770                             sc->sc_dev.dv_xname, err);
  771                         bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
  772                         splx(s);
  773                         xs->error = XS_DRIVER_STUFFUP;
  774                         scsi_done(xs);
  775                         return;
  776                 }
  777                 bus_dmamap_sync(sc->sc_dmat, cb->datadma,
  778                     0, xs->datalen,
  779                     BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
  780         }
  781 
  782         xfer->status = SCSI_OOSIOP_NOSTATUS;
  783 
  784         /*
  785          * Always initialize timeout so it does not contain trash
  786          * that could confuse timeout_del().
  787          */
  788         timeout_set(&xs->stimeout, oosiop_timeout, cb);
  789 
  790         if (xs->flags & SCSI_POLL)
  791                 dopoll = 1;
  792         else {
  793                 dopoll = 0;
  794                 /* start expire timer */
  795                 timeout_add_msec(&xs->stimeout, xs->timeout);
  796         }
  797 
  798         splx(s);
  799 
  800         oosiop_setup(sc, cb);
  801 
  802         TAILQ_INSERT_TAIL(&sc->sc_cbq, cb, chain);
  803 
  804         if (!sc->sc_active) {
  805                 /* Abort script to start selection */
  806                 oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT);
  807         }
  808         if (dopoll)
  809                 oosiop_poll(sc, cb);
  810 }
  811 
  812 void
  813 oosiop_poll(struct oosiop_softc *sc, struct oosiop_cb *cb)
  814 {
  815         struct scsi_xfer *xs = cb->xs;
  816         int i, s, to;
  817         u_int8_t istat;
  818 
  819         s = splbio();
  820         to = xs->timeout / 1000;
  821         for (;;) {
  822                 i = 1000;
  823                 while (((istat = oosiop_read_1(sc, OOSIOP_ISTAT)) &
  824                     (OOSIOP_ISTAT_SIP | OOSIOP_ISTAT_DIP)) == 0) {
  825                         if (i <= 0) {
  826                                 i = 1000;
  827                                 to--;
  828                                 if (to <= 0) {
  829                                         oosiop_reset(sc, TRUE);
  830                                         splx(s);
  831                                         return;
  832                                 }
  833                         }
  834                         delay(1000);
  835                         i--;
  836                 }
  837                 oosiop_processintr(sc, istat);
  838 
  839                 if (xs->flags & ITSDONE)
  840                         break;
  841         }
  842 
  843         splx(s);
  844 }
  845 
  846 void
  847 oosiop_setup(struct oosiop_softc *sc, struct oosiop_cb *cb)
  848 {
  849         struct oosiop_xfer *xfer = cb->xfer;
  850 
  851         cb->curdp = 0;
  852         cb->savedp = 0;
  853 
  854         oosiop_setup_sgdma(sc, cb);
  855 
  856         /* Setup msgout buffer */
  857         OOSIOP_XFERMSG_SYNC(sc, cb,
  858            BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
  859         xfer->msgout[0] = MSG_IDENTIFY(cb->lun,
  860             (cb->xs->cmd.opcode != REQUEST_SENSE));
  861         cb->msgoutlen = 1;
  862 
  863         if (sc->sc_tgt[cb->id].flags & TGTF_SYNCNEG) {
  864                 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_WAITSDTR;
  873         }
  874 
  875         OOSIOP_XFERMSG_SYNC(sc, cb,
  876             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
  877 }
  878 
  879 void
  880 oosiop_done(struct oosiop_softc *sc, struct oosiop_cb *cb)
  881 {
  882         struct scsi_xfer *xs;
  883         struct scsi_link *periph;
  884         int autosense;
  885 
  886         xs = cb->xs;
  887         periph = xs->sc_link;
  888 
  889         /*
  890          * Record if this is the completion of an auto sense
  891          * scsi command, and then reset the flag so we don't loop
  892          * when such a command fails or times out.
  893          */
  894         autosense = cb->flags & CBF_AUTOSENSE;
  895         cb->flags &= ~CBF_AUTOSENSE;
  896 
  897         bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, cb->cmdlen,
  898             BUS_DMASYNC_POSTWRITE);
  899         bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
  900 
  901         if (cb->xsflags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
  902                 bus_dmamap_sync(sc->sc_dmat, cb->datadma, 0, cb->datalen,
  903                     (cb->xsflags & SCSI_DATA_IN) ?
  904                     BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
  905                 bus_dmamap_unload(sc->sc_dmat, cb->datadma);
  906         }
  907 
  908         timeout_del(&xs->stimeout);
  909 
  910         xs->status = cb->xfer->status;
  911 
  912         if (cb->flags & CBF_SELTOUT)
  913                 xs->error = XS_SELTIMEOUT;
  914         else if (cb->flags & CBF_TIMEOUT)
  915                 xs->error = XS_TIMEOUT;
  916         else switch (xs->status) {
  917         case SCSI_OK:
  918                 if (autosense == 0)
  919                         xs->error = XS_NOERROR;
  920                 else
  921                         xs->error = XS_SENSE;
  922                 break;
  923 
  924         case SCSI_BUSY:
  925                 xs->error = XS_BUSY;
  926                 break;
  927         case SCSI_CHECK:
  928 #ifdef notyet
  929                 if (autosense == 0)
  930                         cb->flags |= CBF_AUTOSENSE;
  931                 else
  932 #endif
  933                         xs->error = XS_DRIVER_STUFFUP;
  934                 break;
  935         case SCSI_OOSIOP_NOSTATUS:
  936                 /* the status byte was not updated, cmd was aborted. */
  937                 xs->error = XS_SELTIMEOUT;
  938                 break;
  939 
  940         default:
  941                 xs->error = XS_RESET;
  942                 break;
  943         }
  944 
  945         if ((cb->flags & CBF_AUTOSENSE) == 0) {
  946                 /* Put it on the free list. */
  947 FREE:
  948                 xs->resid = 0;
  949                 scsi_done(xs);
  950 
  951                 if (cb == sc->sc_curcb)
  952                         sc->sc_curcb = NULL;
  953                 if (cb == sc->sc_lastcb)
  954                         sc->sc_lastcb = NULL;
  955                 sc->sc_tgt[cb->id].nexus = NULL;
  956         } else {
  957                 /* Set up REQUEST_SENSE command */
  958                 struct scsi_sense *cmd = (struct scsi_sense *)&xs->cmd;
  959                 int err;
  960 
  961                 bzero(cmd, sizeof(*cmd));
  962                 cmd->opcode = REQUEST_SENSE;
  963                 cmd->byte2 = xs->sc_link->lun << 5;
  964                 cb->cmdlen = cmd->length = sizeof(xs->sense);
  965 
  966                 cb->xsflags &= SCSI_POLL | SCSI_NOSLEEP;
  967                 cb->xsflags |= SCSI_DATA_IN;
  968                 cb->datalen = sizeof xs->sense;
  969 
  970                 /* Setup SCSI command buffer DMA */
  971                 err = bus_dmamap_load(sc->sc_dmat, cb->cmddma, cmd,
  972                     cb->cmdlen, NULL,
  973                     BUS_DMA_NOWAIT | BUS_DMA_STREAMING | BUS_DMA_WRITE);
  974                 if (err) {
  975                         printf("%s: unable to load REQUEST_SENSE cmd DMA map: %d",
  976                             sc->sc_dev.dv_xname, err);
  977                         xs->error = XS_DRIVER_STUFFUP;
  978                         goto FREE;
  979                 }
  980                 bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, cb->cmdlen,
  981                     BUS_DMASYNC_PREWRITE);
  982 
  983                 /* Setup data buffer DMA */
  984                 err = bus_dmamap_load(sc->sc_dmat, cb->datadma,
  985                     &xs->sense, sizeof(xs->sense), NULL,
  986                     BUS_DMA_NOWAIT | BUS_DMA_STREAMING | BUS_DMA_READ);
  987                 if (err) {
  988                         printf("%s: unable to load REQUEST_SENSE data DMA map: %d",
  989                             sc->sc_dev.dv_xname, err);
  990                         xs->error = XS_DRIVER_STUFFUP;
  991                         bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
  992                         goto FREE;
  993                 }
  994                 bus_dmamap_sync(sc->sc_dmat, cb->datadma,
  995                     0, sizeof(xs->sense), BUS_DMASYNC_PREREAD);
  996 
  997                 oosiop_setup(sc, cb);
  998 
  999                 TAILQ_INSERT_HEAD(&sc->sc_cbq, cb, chain);
 1000                 if ((cb->xs->flags & SCSI_POLL) == 0) {
 1001                         /* start expire timer */
 1002                         timeout_add_msec(&xs->stimeout, xs->timeout);
 1003                 }
 1004         }
 1005 }
 1006 
 1007 void
 1008 oosiop_timeout(void *arg)
 1009 {
 1010         struct oosiop_cb *cb = arg;
 1011         struct scsi_xfer *xs = cb->xs;
 1012         struct oosiop_softc *sc = xs->sc_link->bus->sb_adapter_softc;
 1013         int s;
 1014 
 1015         sc_print_addr(xs->sc_link);
 1016         printf("command 0x%02x timeout on xs %p\n", xs->cmd.opcode, xs);
 1017 
 1018         s = splbio();
 1019 
 1020         oosiop_reset_bus(sc);
 1021 
 1022         cb->flags |= CBF_TIMEOUT;
 1023         oosiop_done(sc, cb);
 1024 
 1025         splx(s);
 1026 }
 1027 
 1028 void
 1029 oosiop_reset(struct oosiop_softc *sc, int allflags)
 1030 {
 1031         int i, s;
 1032 
 1033         s = splbio();
 1034 
 1035         /* Stop SCRIPTS processor */
 1036         oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT);
 1037         delay(100);
 1038         oosiop_write_1(sc, OOSIOP_ISTAT, 0);
 1039 
 1040         /* Reset the chip */
 1041         oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl | OOSIOP_DCNTL_RST);
 1042         delay(100);
 1043         oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl);
 1044         delay(10000);
 1045 
 1046         /* Set up various chip parameters */
 1047         oosiop_write_1(sc, OOSIOP_SCNTL0, OOSIOP_ARB_FULL | sc->sc_scntl0);
 1048         oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_ESR);
 1049         oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl);
 1050         oosiop_write_1(sc, OOSIOP_DMODE, sc->sc_dmode);
 1051         oosiop_write_1(sc, OOSIOP_SCID, OOSIOP_SCID_VALUE(sc->sc_id));
 1052         oosiop_write_1(sc, OOSIOP_DWT, sc->sc_dwt);
 1053         oosiop_write_1(sc, OOSIOP_CTEST7, sc->sc_ctest7);
 1054         oosiop_write_1(sc, OOSIOP_SXFER, 0);
 1055 
 1056         /* Clear all interrupts */
 1057         (void)oosiop_read_1(sc, OOSIOP_SSTAT0);
 1058         (void)oosiop_read_1(sc, OOSIOP_SSTAT1);
 1059         (void)oosiop_read_1(sc, OOSIOP_DSTAT);
 1060 
 1061         /* Enable interrupts */
 1062         oosiop_write_1(sc, OOSIOP_SIEN,
 1063             OOSIOP_SIEN_M_A | OOSIOP_SIEN_STO | OOSIOP_SIEN_SGE |
 1064             OOSIOP_SIEN_UDC | OOSIOP_SIEN_RST | OOSIOP_SIEN_PAR);
 1065         oosiop_write_1(sc, OOSIOP_DIEN,
 1066             OOSIOP_DIEN_ABRT | OOSIOP_DIEN_SSI | OOSIOP_DIEN_SIR |
 1067             OOSIOP_DIEN_WTD | OOSIOP_DIEN_IID);
 1068 
 1069         /* Set target state to asynchronous */
 1070         for (i = 0; i < OOSIOP_NTGT; i++) {
 1071                 if (allflags)
 1072                         sc->sc_tgt[i].flags = 0;
 1073                 else
 1074                         sc->sc_tgt[i].flags |= TGTF_SYNCNEG;
 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, TRUE);
 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, TRUE);
 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, TRUE);
 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                         /*
 1229                          * This may happen during sync request negotiation;
 1230                          * be sure not to reset TGTF_WAITSDTR in that case.
 1231                          */
 1232                         oosiop_reset(sc, FALSE);
 1233                 }
 1234 
 1235                 if (sstat0 & OOSIOP_SSTAT0_PAR)
 1236                         printf("%s: parity error\n", sc->sc_dev.dv_xname);
 1237         }
 1238 
 1239         /* Start next command if available */
 1240         if (sc->sc_nextdsp == Ent_wait_reselect && TAILQ_FIRST(&sc->sc_cbq)) {
 1241                 cb = sc->sc_curcb = TAILQ_FIRST(&sc->sc_cbq);
 1242                 TAILQ_REMOVE(&sc->sc_cbq, cb, chain);
 1243                 sc->sc_tgt[cb->id].nexus = cb;
 1244 
 1245                 oosiop_setup_dma(sc);
 1246                 oosiop_setup_syncxfer(sc);
 1247                 sc->sc_lastcb = cb;
 1248                 sc->sc_nextdsp = Ent_start_select;
 1249 
 1250                 /* Schedule timeout */
 1251                 if ((cb->xs->flags & SCSI_POLL) == 0) {
 1252                         /* start expire timer */
 1253                         timeout_add_msec(&cb->xs->stimeout, cb->xs->timeout);
 1254                 }
 1255         }
 1256 
 1257         sc->sc_active = (sc->sc_nextdsp != Ent_wait_reselect);
 1258 
 1259         /* Restart script */
 1260         oosiop_write_4(sc, OOSIOP_DSP, sc->sc_nextdsp + sc->sc_scrbase);
 1261 }
 1262 
 1263 void
 1264 oosiop_scriptintr(struct oosiop_softc *sc)
 1265 {
 1266         struct oosiop_cb *cb;
 1267         u_int32_t icode;
 1268         u_int32_t dsp;
 1269         int i;
 1270         u_int8_t sfbr, resid, resmsg;
 1271 
 1272         cb = sc->sc_curcb;
 1273         icode = oosiop_read_4(sc, OOSIOP_DSPS);
 1274 
 1275         switch (icode) {
 1276         case A_int_done:
 1277                 if (cb)
 1278                         oosiop_done(sc, cb);
 1279                 break;
 1280 
 1281         case A_int_msgin:
 1282                 if (cb)
 1283                         oosiop_msgin(sc, cb);
 1284                 break;
 1285 
 1286         case A_int_extmsg:
 1287                 /* extended message in DMA setup request */
 1288                 sfbr = oosiop_read_1(sc, OOSIOP_SFBR);
 1289                 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
 1290                 oosiop_fixup_move(sc, Ent_p_extmsgin_move, sfbr,
 1291                     cb->xferdma->dm_segs[0].ds_addr +
 1292                     offsetof(struct oosiop_xfer, msgin[2]));
 1293                 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
 1294                 sc->sc_nextdsp = Ent_rcv_extmsg;
 1295                 break;
 1296 
 1297         case A_int_resel:
 1298                 /* reselected */
 1299                 resid = oosiop_read_1(sc, OOSIOP_SFBR);
 1300                 for (i = 0; i < OOSIOP_NTGT; i++)
 1301                         if (resid & (1 << i))
 1302                                 break;
 1303                 if (i == OOSIOP_NTGT) {
 1304                         printf("%s: missing reselection target id\n",
 1305                             sc->sc_dev.dv_xname);
 1306                         break;
 1307                 }
 1308                 sc->sc_resid = i;
 1309                 sc->sc_nextdsp = Ent_wait_resel_identify;
 1310 
 1311                 if (cb) {
 1312                         /* Current command was lost arbitration */
 1313                         sc->sc_tgt[cb->id].nexus = NULL;
 1314                         TAILQ_INSERT_HEAD(&sc->sc_cbq, cb, chain);
 1315                         sc->sc_curcb = NULL;
 1316                 }
 1317 
 1318                 break;
 1319 
 1320         case A_int_res_id:
 1321                 cb = sc->sc_tgt[sc->sc_resid].nexus;
 1322                 resmsg = oosiop_read_1(sc, OOSIOP_SFBR);
 1323                 if (MSG_ISIDENTIFY(resmsg) && cb &&
 1324                     (resmsg & MSG_IDENTIFY_LUNMASK) == cb->lun) {
 1325                         sc->sc_curcb = cb;
 1326                         if (cb != sc->sc_lastcb) {
 1327                                 oosiop_setup_dma(sc);
 1328                                 oosiop_setup_syncxfer(sc);
 1329                                 sc->sc_lastcb = cb;
 1330                         }
 1331                         if (cb->curdp != cb->savedp) {
 1332                                 cb->curdp = cb->savedp;
 1333                                 oosiop_setup_sgdma(sc, cb);
 1334                         }
 1335                         sc->sc_nextdsp = Ent_ack_msgin;
 1336                 } else {
 1337                         /* Reselection from invalid target */
 1338                         oosiop_reset_bus(sc);
 1339                 }
 1340                 break;
 1341 
 1342         case A_int_resfail:
 1343                 /* reselect failed */
 1344                 break;
 1345 
 1346         case A_int_disc:
 1347                 /* disconnected */
 1348                 sc->sc_curcb = NULL;
 1349                 break;
 1350 
 1351         case A_int_err:
 1352                 /* generic error */
 1353                 dsp = oosiop_read_4(sc, OOSIOP_DSP);
 1354                 printf("%s: script error at 0x%08x\n", sc->sc_dev.dv_xname,
 1355                     dsp - 8);
 1356                 sc->sc_curcb = NULL;
 1357                 break;
 1358 
 1359         case DATAIN_TRAP:
 1360                 printf("%s: unexpected datain\n", sc->sc_dev.dv_xname);
 1361                 /* XXX: need to reset? */
 1362                 break;
 1363 
 1364         case DATAOUT_TRAP:
 1365                 printf("%s: unexpected dataout\n", sc->sc_dev.dv_xname);
 1366                 /* XXX: need to reset? */
 1367                 break;
 1368 
 1369         default:
 1370                 printf("%s: unknown intr code %08x\n", sc->sc_dev.dv_xname,
 1371                     icode);
 1372                 break;
 1373         }
 1374 }
 1375 
 1376 void
 1377 oosiop_msgin(struct oosiop_softc *sc, struct oosiop_cb *cb)
 1378 {
 1379         struct oosiop_xfer *xfer;
 1380         int msgout;
 1381 
 1382         xfer = cb->xfer;
 1383         sc->sc_nextdsp = Ent_ack_msgin;
 1384         msgout = 0;
 1385 
 1386         OOSIOP_XFERMSG_SYNC(sc, cb,
 1387             BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 1388 
 1389         switch (xfer->msgin[0]) {
 1390         case MSG_EXTENDED:
 1391                 switch (xfer->msgin[2]) {
 1392                 case MSG_EXT_SDTR:
 1393                         if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) {
 1394                                 /* Host initiated SDTR */
 1395                                 sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR;
 1396                         } else {
 1397                                 /* Target initiated SDTR */
 1398                                 if (xfer->msgin[3] < sc->sc_minperiod)
 1399                                         xfer->msgin[3] = sc->sc_minperiod;
 1400                                 if (xfer->msgin[4] > OOSIOP_MAX_OFFSET)
 1401                                         xfer->msgin[4] = OOSIOP_MAX_OFFSET;
 1402                                 xfer->msgout[0] = MSG_EXTENDED;
 1403                                 xfer->msgout[1] = MSG_EXT_SDTR_LEN;
 1404                                 xfer->msgout[2] = MSG_EXT_SDTR;
 1405                                 xfer->msgout[3] = xfer->msgin[3];
 1406                                 xfer->msgout[4] = xfer->msgin[4];
 1407                                 cb->msgoutlen = 5;
 1408                                 msgout = 1;
 1409                         }
 1410                         oosiop_set_syncparam(sc, cb->id, (int)xfer->msgin[3],
 1411                             (int)xfer->msgin[4]);
 1412                         oosiop_setup_syncxfer(sc);
 1413                         break;
 1414 
 1415                 default:
 1416                         /* Reject message */
 1417                         xfer->msgout[0] = MSG_MESSAGE_REJECT;
 1418                         cb->msgoutlen = 1;
 1419                         msgout = 1;
 1420                         break;
 1421                 }
 1422                 break;
 1423 
 1424         case MSG_SAVEDATAPOINTER:
 1425                 cb->savedp = cb->curdp;
 1426                 break;
 1427 
 1428         case MSG_RESTOREPOINTERS:
 1429                 if (cb->curdp != cb->savedp) {
 1430                         cb->curdp = cb->savedp;
 1431                         oosiop_setup_sgdma(sc, cb);
 1432                 }
 1433                 break;
 1434 
 1435         case MSG_MESSAGE_REJECT:
 1436                 if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) {
 1437                         /* SDTR rejected */
 1438                         sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR;
 1439                         oosiop_set_syncparam(sc, cb->id, 0, 0);
 1440                         oosiop_setup_syncxfer(sc);
 1441                 }
 1442                 break;
 1443 
 1444         default:
 1445                 /* Reject message */
 1446                 xfer->msgout[0] = MSG_MESSAGE_REJECT;
 1447                 cb->msgoutlen = 1;
 1448                 msgout = 1;
 1449         }
 1450 
 1451         OOSIOP_XFERMSG_SYNC(sc, cb,
 1452             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 1453 
 1454         if (msgout) {
 1455                 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
 1456                 oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen,
 1457                     cb->xferdma->dm_segs[0].ds_addr +
 1458                     offsetof(struct oosiop_xfer, msgout[0]));
 1459                 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
 1460                 sc->sc_nextdsp = Ent_sendmsg;
 1461         }
 1462 }

Cache object: 21254c75be64feb6551146851071db7c


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