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/osiop.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: osiop.c,v 1.43 2021/08/07 16:19:12 thorpej Exp $       */
    2 
    3 /*-
    4  * Copyright (c) 2001 Izumi Tsutsui.  All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 /*
   28  * Copyright (c) 1990 The Regents of the University of California.
   29  * All rights reserved.
   30  *
   31  * This code is derived from software contributed to Berkeley by
   32  * Van Jacobson of Lawrence Berkeley Laboratory.
   33  *
   34  * Redistribution and use in source and binary forms, with or without
   35  * modification, are permitted provided that the following conditions
   36  * are met:
   37  * 1. Redistributions of source code must retain the above copyright
   38  *    notice, this list of conditions and the following disclaimer.
   39  * 2. Redistributions in binary form must reproduce the above copyright
   40  *    notice, this list of conditions and the following disclaimer in the
   41  *    documentation and/or other materials provided with the distribution.
   42  * 3. Neither the name of the University nor the names of its contributors
   43  *    may be used to endorse or promote products derived from this software
   44  *    without specific prior written permission.
   45  *
   46  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   47  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   48  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   49  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   50  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   51  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   52  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   53  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   54  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   55  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   56  * SUCH DAMAGE.
   57  *
   58  *      @(#)siop.c      7.5 (Berkeley) 5/4/91
   59  */
   60 
   61 /*
   62  * Copyright (c) 1994 Michael L. Hitch
   63  *
   64  * This code is derived from software contributed to Berkeley by
   65  * Van Jacobson of Lawrence Berkeley Laboratory.
   66  *
   67  * Redistribution and use in source and binary forms, with or without
   68  * modification, are permitted provided that the following conditions
   69  * are met:
   70  * 1. Redistributions of source code must retain the above copyright
   71  *    notice, this list of conditions and the following disclaimer.
   72  * 2. Redistributions in binary form must reproduce the above copyright
   73  *    notice, this list of conditions and the following disclaimer in the
   74  *    documentation and/or other materials provided with the distribution.
   75  *
   76  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   77  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   78  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   79  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   80  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   81  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   82  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   83  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   84  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   85  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   86  *
   87  *      @(#)siop.c      7.5 (Berkeley) 5/4/91
   88  */
   89 
   90 /*
   91  * MI NCR53C710 scsi adaptor driver; based on arch/amiga/dev/siop.c:
   92  *      NetBSD: siop.c,v 1.43 1999/09/30 22:59:53 thorpej Exp
   93  *
   94  * bus_space/bus_dma'fied by Izumi Tsutsui <tsutsui@NetBSD.org>
   95  */
   96 
   97 #include <sys/cdefs.h>
   98 __KERNEL_RCSID(0, "$NetBSD: osiop.c,v 1.43 2021/08/07 16:19:12 thorpej Exp $");
   99 
  100 /* #define OSIOP_DEBUG */
  101 
  102 #include "opt_ddb.h"
  103 
  104 #include <sys/param.h>
  105 #include <sys/systm.h>
  106 #include <sys/device.h>
  107 #include <sys/malloc.h>
  108 #include <sys/buf.h>
  109 #include <sys/kernel.h>
  110 
  111 #include <dev/scsipi/scsi_all.h>
  112 #include <dev/scsipi/scsipi_all.h>
  113 #include <dev/scsipi/scsiconf.h>
  114 #include <dev/scsipi/scsi_message.h>
  115 
  116 #include <sys/cpu.h>
  117 #include <sys/bus.h>
  118 
  119 #include <dev/ic/osiopreg.h>
  120 #include <dev/ic/osiopvar.h>
  121 
  122 /* 53C710 script */
  123 #include <dev/microcode/siop/osiop.out>
  124 
  125 static void osiop_minphys(struct buf *);
  126 static void osiop_scsipi_request(struct scsipi_channel *, scsipi_adapter_req_t,
  127     void *);
  128 static void osiop_poll(struct osiop_softc *, struct osiop_acb *);
  129 static void osiop_sched(struct osiop_softc *);
  130 static void osiop_scsidone(struct osiop_acb *, int);
  131 static void osiop_abort(struct osiop_softc *, const char *);
  132 static void osiop_init(struct osiop_softc *);
  133 static void osiop_reset(struct osiop_softc *);
  134 static void osiop_resetbus(struct osiop_softc *);
  135 static void osiop_start(struct osiop_softc *);
  136 static int osiop_checkintr(struct osiop_softc *, uint8_t, uint8_t, uint8_t,
  137     int *);
  138 static void osiop_select(struct osiop_softc *);
  139 static void osiop_update_xfer_mode(struct osiop_softc *, int);
  140 static void scsi_period_to_osiop(struct osiop_softc *, int);
  141 static void osiop_timeout(void *);
  142 
  143 int osiop_reset_delay = 250;    /* delay after reset, in milliseconds */
  144 
  145 #ifdef OSIOP_DEBUG
  146 #define DEBUG_DMA       0x01
  147 #define DEBUG_INT       0x02
  148 #define DEBUG_PHASE     0x04
  149 #define DEBUG_UNEXCEPT  0x08
  150 #define DEBUG_DISC      0x10
  151 #define DEBUG_CMD       0x20
  152 #define DEBUG_ALL       0xff
  153 int osiop_debug = 0; /*DEBUG_ALL;*/
  154 
  155 int osiopsync_debug = 0;
  156 int osiopdma_hits = 1;
  157 int osiopstarts = 0;
  158 int osiopints = 0;
  159 int osiopphmm = 0;
  160 int osiop_trix = 0;
  161 #define OSIOP_TRACE_SIZE        128
  162 #define OSIOP_TRACE(a,b,c,d)    do {                            \
  163         osiop_trbuf[osiop_trix + 0] = (a);                      \
  164         osiop_trbuf[osiop_trix + 1] = (b);                      \
  165         osiop_trbuf[osiop_trix + 2] = (c);                      \
  166         osiop_trbuf[osiop_trix + 3] = (d);                      \
  167         osiop_trix = (osiop_trix + 4) & (OSIOP_TRACE_SIZE - 1); \
  168 } while (0)
  169 uint8_t osiop_trbuf[OSIOP_TRACE_SIZE];
  170 void osiop_dump_trace(void);
  171 void osiop_dump_acb(struct osiop_acb *);
  172 void osiop_dump(struct osiop_softc *);
  173 #else
  174 #define OSIOP_TRACE(a,b,c,d)
  175 #endif
  176 
  177 void
  178 osiop_attach(struct osiop_softc *sc)
  179 {
  180         struct osiop_acb *acb;
  181         bus_dma_segment_t seg;
  182         int nseg;
  183         int i, err;
  184 
  185         /*
  186          * Allocate and map DMA-safe memory for the script.
  187          */
  188         err = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE, 0,
  189             &seg, 1, &nseg, BUS_DMA_NOWAIT);
  190         if (err) {
  191                 aprint_error(": failed to allocate script memory, err=%d\n",
  192                     err);
  193                 return;
  194         }
  195         err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, PAGE_SIZE,
  196             (void **)&sc->sc_script, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
  197         if (err) {
  198                 aprint_error(": failed to map script memory, err=%d\n", err);
  199                 return;
  200         }
  201         err = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, 0,
  202             BUS_DMA_NOWAIT, &sc->sc_scrdma);
  203         if (err) {
  204                 aprint_error(": failed to create script map, err=%d\n", err);
  205                 return;
  206         }
  207         err = bus_dmamap_load(sc->sc_dmat, sc->sc_scrdma,
  208             sc->sc_script, PAGE_SIZE, NULL, BUS_DMA_NOWAIT);
  209         if (err) {
  210                 aprint_error(": failed to load script map, err=%d\n", err);
  211                 return;
  212         }
  213 
  214         /*
  215          * Copy and sync script
  216          */
  217         memcpy(sc->sc_script, osiop_script, sizeof(osiop_script));
  218         bus_dmamap_sync(sc->sc_dmat, sc->sc_scrdma, 0, sizeof(osiop_script),
  219             BUS_DMASYNC_PREWRITE);
  220 
  221         /*
  222          * Allocate and map DMA-safe memory for the script data structure.
  223          */
  224         err = bus_dmamem_alloc(sc->sc_dmat,
  225             sizeof(struct osiop_ds) * OSIOP_NACB, PAGE_SIZE, 0,
  226             &seg, 1, &nseg, BUS_DMA_NOWAIT);
  227         if (err) {
  228                 aprint_error(": failed to allocate ds memory, err=%d\n", err);
  229                 return;
  230         }
  231         err = bus_dmamem_map(sc->sc_dmat, &seg, nseg,
  232             sizeof(struct osiop_ds) * OSIOP_NACB, (void **)&sc->sc_ds,
  233             BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
  234         if (err) {
  235                 aprint_error(": failed to map ds memory, err=%d\n", err);
  236                 return;
  237         }
  238         err = bus_dmamap_create(sc->sc_dmat,
  239             sizeof(struct osiop_ds) * OSIOP_NACB, 1,
  240             sizeof(struct osiop_ds) * OSIOP_NACB, 0,
  241             BUS_DMA_NOWAIT, &sc->sc_dsdma);
  242         if (err) {
  243                 aprint_error(": failed to create ds map, err=%d\n", err);
  244                 return;
  245         }
  246         err = bus_dmamap_load(sc->sc_dmat, sc->sc_dsdma, sc->sc_ds,
  247             sizeof(struct osiop_ds) * OSIOP_NACB, NULL, BUS_DMA_NOWAIT);
  248         if (err) {
  249                 aprint_error(": failed to load ds map, err=%d\n", err);
  250                 return;
  251         }
  252 
  253         acb = malloc(sizeof(struct osiop_acb) * OSIOP_NACB,
  254             M_DEVBUF, M_WAITOK|M_ZERO);
  255         sc->sc_acb = acb;
  256         sc->sc_cfflags = device_cfdata(sc->sc_dev)->cf_flags;
  257         sc->sc_nexus = NULL;
  258         sc->sc_active = 0;
  259         memset(sc->sc_tinfo, 0, sizeof(sc->sc_tinfo));
  260 
  261         /* Initialize command block queue */
  262         TAILQ_INIT(&sc->ready_list);
  263         TAILQ_INIT(&sc->nexus_list);
  264         TAILQ_INIT(&sc->free_list);
  265 
  266         /* Initialize each command block */
  267         for (i = 0; i < OSIOP_NACB; i++) {
  268                 bus_addr_t dsa;
  269 
  270                 err = bus_dmamap_create(sc->sc_dmat, OSIOP_MAX_XFER, OSIOP_NSG,
  271                     OSIOP_MAX_XFER, 0, BUS_DMA_NOWAIT, &acb->datadma);
  272                 if (err) {
  273                         aprint_error(": failed to create datadma map, err=%d\n",
  274                             err);
  275                         return;
  276                 }
  277 
  278                 acb->sc = sc;
  279                 acb->ds = &sc->sc_ds[i];
  280                 acb->dsoffset = sizeof(struct osiop_ds) * i;
  281 
  282                 dsa = sc->sc_dsdma->dm_segs[0].ds_addr + acb->dsoffset;
  283                 acb->ds->id.addr = dsa + OSIOP_DSIDOFF;
  284                 acb->ds->cmd.addr = dsa + OSIOP_DSCMDOFF;
  285                 acb->ds->status.count = 1;
  286                 acb->ds->status.addr = dsa + OSIOP_DSSTATOFF;
  287                 acb->ds->msg.count = 1;
  288                 acb->ds->msg.addr = dsa + OSIOP_DSMSGOFF;
  289                 acb->ds->msgin.count = 1;
  290                 acb->ds->msgin.addr = dsa + OSIOP_DSMSGINOFF;
  291                 acb->ds->extmsg.count = 1;
  292                 acb->ds->extmsg.addr = dsa + OSIOP_DSEXTMSGOFF;
  293                 acb->ds->synmsg.count = 3;
  294                 acb->ds->synmsg.addr = dsa + OSIOP_DSSYNMSGOFF;
  295                 TAILQ_INSERT_TAIL(&sc->free_list, acb, chain);
  296 
  297                 acb++;
  298         }
  299 
  300         aprint_normal(": NCR53C710 rev %d, %dMHz, SCSI ID %d\n",
  301             osiop_read_1(sc, OSIOP_CTEST8) >> 4, sc->sc_clock_freq, sc->sc_id);
  302 
  303         /*
  304          * Initialize all
  305          */
  306         osiop_init(sc);
  307 
  308         /*
  309          * Fill in the adapter.
  310          */
  311         sc->sc_adapter.adapt_dev = sc->sc_dev;
  312         sc->sc_adapter.adapt_nchannels = 1;
  313         sc->sc_adapter.adapt_openings = OSIOP_NACB;
  314         sc->sc_adapter.adapt_max_periph = 1;
  315         sc->sc_adapter.adapt_ioctl = NULL;
  316         sc->sc_adapter.adapt_minphys = osiop_minphys;
  317         sc->sc_adapter.adapt_request = osiop_scsipi_request;
  318 
  319         /*
  320          * Fill in the channel.
  321          */
  322         sc->sc_channel.chan_adapter = &sc->sc_adapter;
  323         sc->sc_channel.chan_bustype = &scsi_bustype;
  324         sc->sc_channel.chan_channel = 0;
  325         sc->sc_channel.chan_ntargets = OSIOP_NTGT;
  326         sc->sc_channel.chan_nluns = 8;
  327         sc->sc_channel.chan_id = sc->sc_id;
  328 
  329         /*
  330          * Now try to attach all the sub devices.
  331          */
  332         config_found(sc->sc_dev, &sc->sc_channel, scsiprint, CFARGS_NONE);
  333 }
  334 
  335 /*
  336  * default minphys routine for osiop based controllers
  337  */
  338 void
  339 osiop_minphys(struct buf *bp)
  340 {
  341 
  342         if (bp->b_bcount > OSIOP_MAX_XFER)
  343                 bp->b_bcount = OSIOP_MAX_XFER;
  344         minphys(bp);
  345 }
  346 
  347 /*
  348  * used by specific osiop controller
  349  *
  350  */
  351 void
  352 osiop_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req,
  353     void *arg)
  354 {
  355         struct scsipi_xfer *xs;
  356         struct osiop_acb *acb;
  357         struct osiop_softc *sc;
  358         int err, flags, s;
  359 
  360         sc = device_private(chan->chan_adapter->adapt_dev);
  361 
  362         switch (req) {
  363         case ADAPTER_REQ_RUN_XFER:
  364                 xs = arg;
  365                 flags = xs->xs_control;
  366 
  367                 /* XXXX ?? */
  368                 if (flags & XS_CTL_DATA_UIO)
  369                         panic("osiop: scsi data uio requested");
  370 
  371                 /* XXXX ?? */
  372                 if (sc->sc_nexus && flags & XS_CTL_POLL)
  373 #if 0
  374                         panic("osiop_scsicmd: busy");
  375 #else
  376                         printf("osiop_scsicmd: busy\n");
  377 #endif
  378 
  379                 s = splbio();
  380                 acb = TAILQ_FIRST(&sc->free_list);
  381                 if (acb != NULL) {
  382                         TAILQ_REMOVE(&sc->free_list, acb, chain);
  383                 }
  384 #ifdef DIAGNOSTIC
  385                 else {
  386                         scsipi_printaddr(xs->xs_periph);
  387                         printf("unable to allocate acb\n");
  388                         panic("osiop_scsipi_request");
  389                 }
  390 #endif
  391 
  392                 acb->status = ACB_S_READY;
  393                 acb->xs = xs;
  394 
  395                 /* Setup DMA map for data buffer */
  396                 if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
  397                         err = bus_dmamap_load(sc->sc_dmat, acb->datadma,
  398                             xs->data, xs->datalen, NULL,
  399                             BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
  400                             ((xs->xs_control & XS_CTL_DATA_IN) ?
  401                              BUS_DMA_READ : BUS_DMA_WRITE));
  402                         if (err) {
  403                                 printf("%s: unable to load data DMA map: %d\n",
  404                                     device_xname(sc->sc_dev), err);
  405                                 xs->error = XS_DRIVER_STUFFUP;
  406                                 scsipi_done(xs);
  407                                 TAILQ_INSERT_TAIL(&sc->free_list, acb, chain);
  408                                 splx(s);
  409                                 return;
  410                         }
  411                 }
  412 
  413                 acb->cmdlen = xs->cmdlen;
  414                 acb->datalen = xs->datalen;
  415 #ifdef OSIOP_DEBUG
  416                 acb->data = xs->data;
  417 #endif
  418 
  419                 TAILQ_INSERT_TAIL(&sc->ready_list, acb, chain);
  420 
  421                 if (sc->sc_nexus == NULL)
  422                         osiop_sched(sc);
  423 
  424                 splx(s);
  425 
  426                 if (flags & XS_CTL_POLL || sc->sc_flags & OSIOP_NODMA)
  427                         osiop_poll(sc, acb);
  428                 return;
  429 
  430         case ADAPTER_REQ_GROW_RESOURCES:
  431                 return;
  432 
  433         case ADAPTER_REQ_SET_XFER_MODE:
  434                 {
  435                         struct osiop_tinfo *ti;
  436                         struct scsipi_xfer_mode *xm = arg;
  437 
  438                         ti = &sc->sc_tinfo[xm->xm_target];
  439 
  440                         if ((xm->xm_mode & PERIPH_CAP_SYNC) != 0 &&
  441                             (ti->flags & TI_NOSYNC) == 0)
  442                                 ti->state = NEG_INIT;
  443 
  444                         /*
  445                          * If we're not going to negotiate, send the
  446                          * notification now, since it won't happen later.
  447                          */
  448                         if (ti->state == NEG_DONE)
  449                                 osiop_update_xfer_mode(sc, xm->xm_target);
  450 
  451                         return;
  452                 }
  453         }
  454 }
  455 
  456 void
  457 osiop_poll(struct osiop_softc *sc, struct osiop_acb *acb)
  458 {
  459         struct scsipi_xfer *xs = acb->xs;
  460         int status, i, s, to;
  461         uint8_t istat, dstat, sstat0;
  462 
  463         s = splbio();
  464         to = xs->timeout / 1000;
  465         if (!TAILQ_EMPTY(&sc->nexus_list))
  466                 printf("%s: osiop_poll called with disconnected device\n",
  467                     device_xname(sc->sc_dev));
  468         for (;;) {
  469                 i = 1000;
  470                 while (((istat = osiop_read_1(sc, OSIOP_ISTAT)) &
  471                     (OSIOP_ISTAT_SIP | OSIOP_ISTAT_DIP)) == 0) {
  472                         if (i <= 0) {
  473 #ifdef OSIOP_DEBUG
  474                                 printf("waiting: tgt %d cmd %02x sbcl %02x"
  475                                     " dsp %x (+%lx) dcmd %x"
  476                                     " ds %p timeout %d\n",
  477                                     xs->xs_periph->periph_target,
  478                                     xs->cmd->opcode,
  479                                     osiop_read_1(sc, OSIOP_SBCL),
  480                                     osiop_read_4(sc, OSIOP_DSP),
  481                                     osiop_read_4(sc, OSIOP_DSP) -
  482                                         sc->sc_scrdma->dm_segs[0].ds_addr,
  483                                     osiop_read_1(sc, OSIOP_DCMD),
  484                                     acb->ds, acb->xs->timeout);
  485 #endif
  486                                 i = 1000;
  487                                 to--;
  488                                 if (to <= 0) {
  489                                         osiop_reset(sc);
  490                                         splx(s);
  491                                         return;
  492                                 }
  493                         }
  494                         delay(1000);
  495                         i--;
  496                 }
  497                 sstat0 = osiop_read_1(sc, OSIOP_SSTAT0);
  498                 delay(25);
  499                 dstat = osiop_read_1(sc, OSIOP_DSTAT);
  500                 if (osiop_checkintr(sc, istat, dstat, sstat0, &status)) {
  501                         if (acb != sc->sc_nexus)
  502                                 printf("%s: osiop_poll disconnected device"
  503                                     " completed\n", device_xname(sc->sc_dev));
  504                         else if ((sc->sc_flags & OSIOP_INTDEFER) == 0) {
  505                                 sc->sc_flags &= ~OSIOP_INTSOFF;
  506                                 osiop_write_1(sc, OSIOP_SIEN, sc->sc_sien);
  507                                 osiop_write_1(sc, OSIOP_DIEN, sc->sc_dien);
  508                         }
  509                         osiop_scsidone(sc->sc_nexus, status);
  510                 }
  511 
  512                 if (xs->xs_status & XS_STS_DONE)
  513                         break;
  514         }
  515 
  516         splx(s);
  517         return;
  518 }
  519 
  520 /*
  521  * start next command that's ready
  522  */
  523 void
  524 osiop_sched(struct osiop_softc *sc)
  525 {
  526         struct scsipi_periph *periph;
  527         struct osiop_acb *acb;
  528         int i;
  529 
  530 #ifdef OSIOP_DEBUG
  531         if (sc->sc_nexus != NULL) {
  532                 printf("%s: osiop_sched- nexus %p/%d ready %p/%d\n",
  533                     device_xname(sc->sc_dev), sc->sc_nexus,
  534                     sc->sc_nexus->xs->xs_periph->periph_target,
  535                     TAILQ_FIRST(&sc->ready_list),
  536                     TAILQ_FIRST(&sc->ready_list)->xs->xs_periph->periph_target);
  537                 return;
  538         }
  539 #endif
  540         TAILQ_FOREACH(acb, &sc->ready_list, chain) {
  541                 periph = acb->xs->xs_periph;
  542                 i = periph->periph_target;
  543                 if ((sc->sc_tinfo[i].lubusy & (1 << periph->periph_lun)) == 0) {
  544                         struct osiop_tinfo *ti;
  545 
  546                         TAILQ_REMOVE(&sc->ready_list, acb, chain);
  547                         sc->sc_nexus = acb;
  548                         ti = &sc->sc_tinfo[i];
  549                         ti->lubusy |= (1 << periph->periph_lun);
  550                         break;
  551                 }
  552         }
  553 
  554         if (acb == NULL) {
  555 #ifdef OSIOP_DEBUG
  556                 printf("%s: osiop_sched didn't find ready command\n",
  557                     device_xname(sc->sc_dev));
  558 #endif
  559                 return;
  560         }
  561 
  562         if (acb->xs->xs_control & XS_CTL_RESET)
  563                 osiop_reset(sc);
  564 
  565         sc->sc_active++;
  566         osiop_select(sc);
  567 }
  568 
  569 void
  570 osiop_scsidone(struct osiop_acb *acb, int status)
  571 {
  572         struct scsipi_xfer *xs;
  573         struct scsipi_periph *periph;
  574         struct osiop_softc *sc;
  575         int dosched = 0;
  576 
  577 #ifdef DIAGNOSTIC
  578         if (acb == NULL || acb->xs == NULL) {
  579                 printf("osiop_scsidone: NULL acb or scsipi_xfer\n");
  580 #if defined(OSIOP_DEBUG) && defined(DDB)
  581                 Debugger();
  582 #endif
  583                 return;
  584         }
  585 #endif
  586         xs = acb->xs;
  587         sc = acb->sc;
  588         periph = xs->xs_periph;
  589 
  590 #ifdef OSIOP_DEBUG
  591         if (acb->status != ACB_S_DONE)
  592                 printf("%s: acb not done (status %d)\n",
  593                     device_xname(sc->sc_dev), acb->status);
  594 #endif
  595 
  596         xs->status = status;
  597 
  598         switch (status) {
  599         case SCSI_OK:
  600                 xs->error = XS_NOERROR;
  601                 break;
  602         case SCSI_BUSY:
  603                 xs->error = XS_BUSY;
  604                 break;
  605         case SCSI_CHECK:
  606                 xs->error = XS_BUSY;
  607                 break;
  608         case SCSI_OSIOP_NOCHECK:
  609                 /*
  610                  * don't check status, xs->error is already valid
  611                  */
  612                 break;
  613         case SCSI_OSIOP_NOSTATUS:
  614                 /*
  615                  * the status byte was not updated, cmd was
  616                  * aborted
  617                  */
  618                 xs->error = XS_SELTIMEOUT;
  619                 break;
  620         default:
  621 #ifdef OSIOP_DEBUG
  622                 printf("%s: osiop_scsidone: unknown status code (0x%02x)\n",
  623                     device_xname(sc->sc_dev), status);
  624 #endif
  625                 xs->error = XS_DRIVER_STUFFUP;
  626                 break;
  627         }
  628 
  629         if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
  630                 bus_dmamap_sync(sc->sc_dmat, acb->datadma, 0, acb->datalen,
  631                     (xs->xs_control & XS_CTL_DATA_IN) ?
  632                     BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
  633                 bus_dmamap_unload(sc->sc_dmat, acb->datadma);
  634         }
  635 
  636         /*
  637          * Remove the ACB from whatever queue it's on.  We have to do a bit of
  638          * a hack to figure out which queue it's on.  Note that it is *not*
  639          * necessary to cdr down the ready queue, but we must cdr down the
  640          * nexus queue and see if it's there, so we can mark the unit as no
  641          * longer busy.  This code is sickening, but it works.
  642          */
  643         if (acb == sc->sc_nexus) {
  644                 sc->sc_nexus = NULL;
  645                 sc->sc_tinfo[periph->periph_target].lubusy &=
  646                     ~(1 << periph->periph_lun);
  647                 if (!TAILQ_EMPTY(&sc->ready_list))
  648                         dosched = 1;    /* start next command */
  649                 sc->sc_active--;
  650                 OSIOP_TRACE('d', 'a', status, 0);
  651         } else if (sc->ready_list.tqh_last == &TAILQ_NEXT(acb, chain)) {
  652                 TAILQ_REMOVE(&sc->ready_list, acb, chain);
  653                 OSIOP_TRACE('d', 'r', status, 0);
  654         } else {
  655                 struct osiop_acb *acb2;
  656                 TAILQ_FOREACH(acb2, &sc->nexus_list, chain) {
  657                         if (acb2 == acb) {
  658                                 TAILQ_REMOVE(&sc->nexus_list, acb, chain);
  659                                 sc->sc_tinfo[periph->periph_target].lubusy &=
  660                                     ~(1 << periph->periph_lun);
  661                                 sc->sc_active--;
  662                                 break;
  663                         }
  664                 }
  665                 if (acb2 == NULL) {
  666                         if (TAILQ_NEXT(acb, chain) != NULL) {
  667                                 TAILQ_REMOVE(&sc->ready_list, acb, chain);
  668                                 sc->sc_active--;
  669                         } else {
  670                                 printf("%s: can't find matching acb\n",
  671                                     device_xname(sc->sc_dev));
  672 #ifdef DDB
  673 #if 0
  674                                 Debugger();
  675 #endif
  676 #endif
  677                         }
  678                 }
  679                 OSIOP_TRACE('d', 'n', status, 0);
  680         }
  681         /* Put it on the free list. */
  682         acb->status = ACB_S_FREE;
  683         TAILQ_INSERT_TAIL(&sc->free_list, acb, chain);
  684         sc->sc_tinfo[periph->periph_target].cmds++;
  685 
  686         callout_stop(&xs->xs_callout);
  687         xs->resid = 0;
  688         scsipi_done(xs);
  689 
  690         if (dosched && sc->sc_nexus == NULL)
  691                 osiop_sched(sc);
  692 }
  693 
  694 void
  695 osiop_abort(struct osiop_softc *sc, const char *where)
  696 {
  697 
  698         printf("%s: abort %s: dstat %02x, sstat0 %02x sbcl %02x\n",
  699             device_xname(sc->sc_dev), where,
  700             osiop_read_1(sc, OSIOP_DSTAT),
  701             osiop_read_1(sc, OSIOP_SSTAT0),
  702             osiop_read_1(sc, OSIOP_SBCL));
  703 
  704         /* XXX XXX XXX */
  705         if (sc->sc_active > 0) {
  706                 sc->sc_active = 0;
  707         }
  708 }
  709 
  710 void
  711 osiop_init(struct osiop_softc *sc)
  712 {
  713         int i, inhibit_sync, inhibit_disc;
  714 
  715         sc->sc_tcp[1] = 1000 / sc->sc_clock_freq;
  716         sc->sc_tcp[2] = 1500 / sc->sc_clock_freq;
  717         sc->sc_tcp[3] = 2000 / sc->sc_clock_freq;
  718         sc->sc_minsync = sc->sc_tcp[1];         /* in 4ns units */
  719 
  720         if (sc->sc_minsync < 25)
  721                 sc->sc_minsync = 25;
  722 
  723         if (sc->sc_clock_freq <= 25) {
  724                 sc->sc_dcntl |= OSIOP_DCNTL_CF_1;       /* SCLK/1 */
  725                 sc->sc_tcp[0] = sc->sc_tcp[1];
  726         } else if (sc->sc_clock_freq <= 37) {
  727                 sc->sc_dcntl |= OSIOP_DCNTL_CF_1_5;     /* SCLK/1.5 */
  728                 sc->sc_tcp[0] = sc->sc_tcp[2];
  729         } else if (sc->sc_clock_freq <= 50) {
  730                 sc->sc_dcntl |= OSIOP_DCNTL_CF_2;       /* SCLK/2 */
  731                 sc->sc_tcp[0] = sc->sc_tcp[3];
  732         } else {
  733                 sc->sc_dcntl |= OSIOP_DCNTL_CF_3;       /* SCLK/3 */
  734                 sc->sc_tcp[0] = 3000 / sc->sc_clock_freq;
  735         }
  736 
  737         if ((sc->sc_cfflags & 0x10000) != 0) {
  738                 sc->sc_flags |= OSIOP_NODMA;
  739 #ifdef OSIOP_DEBUG
  740                 printf("%s: DMA disabled; use polling\n",
  741                     device_xname(sc->sc_dev));
  742 #endif
  743         }
  744 
  745         inhibit_sync = (sc->sc_cfflags & 0xff00) >> 8;  /* XXX */
  746         inhibit_disc =  sc->sc_cfflags & 0x00ff;        /* XXX */
  747 #ifdef OSIOP_DEBUG
  748         if (inhibit_sync != 0)
  749                 printf("%s: Inhibiting synchronous transfer: 0x%02x\n",
  750                     device_xname(sc->sc_dev), inhibit_sync);
  751         if (inhibit_disc != 0)
  752                 printf("%s: Inhibiting disconnect: 0x%02x\n",
  753                     device_xname(sc->sc_dev), inhibit_disc);
  754 #endif
  755         for (i = 0; i < OSIOP_NTGT; i++) {
  756                 if (inhibit_sync & (1 << i))
  757                         sc->sc_tinfo[i].flags |= TI_NOSYNC;
  758                 if (inhibit_disc & (1 << i))
  759                         sc->sc_tinfo[i].flags |= TI_NODISC;
  760         }
  761 
  762         osiop_resetbus(sc);
  763         osiop_reset(sc);
  764 }
  765 
  766 void
  767 osiop_reset(struct osiop_softc *sc)
  768 {
  769         struct osiop_acb *acb;
  770         int i, s;
  771         uint8_t stat;
  772 
  773 #ifdef OSIOP_DEBUG
  774         printf("%s: resetting chip\n", device_xname(sc->sc_dev));
  775 #endif
  776         if (sc->sc_flags & OSIOP_ALIVE)
  777                 osiop_abort(sc, "reset");
  778 
  779         s = splbio();
  780 
  781         /*
  782          * Reset the chip
  783          * XXX - is this really needed?
  784          */
  785 
  786         /* abort current script */
  787         osiop_write_1(sc, OSIOP_ISTAT,
  788             osiop_read_1(sc, OSIOP_ISTAT) | OSIOP_ISTAT_ABRT);
  789         /* reset chip */
  790         osiop_write_1(sc, OSIOP_ISTAT,
  791             osiop_read_1(sc, OSIOP_ISTAT) | OSIOP_ISTAT_RST);
  792         delay(100);
  793         osiop_write_1(sc, OSIOP_ISTAT,
  794             osiop_read_1(sc, OSIOP_ISTAT) & ~OSIOP_ISTAT_RST);
  795         delay(100);
  796 
  797         /*
  798          * Set up various chip parameters
  799          */
  800         osiop_write_1(sc, OSIOP_SCNTL0,
  801             OSIOP_ARB_FULL | OSIOP_SCNTL0_EPC | OSIOP_SCNTL0_EPG);
  802         osiop_write_1(sc, OSIOP_SCNTL1, OSIOP_SCNTL1_ESR);
  803         osiop_write_1(sc, OSIOP_DCNTL, sc->sc_dcntl);
  804         osiop_write_1(sc, OSIOP_DMODE, OSIOP_DMODE_BL4);
  805         /* don't enable interrupts yet */
  806         osiop_write_1(sc, OSIOP_SIEN, 0x00);
  807         osiop_write_1(sc, OSIOP_DIEN, 0x00);
  808         osiop_write_1(sc, OSIOP_SCID, OSIOP_SCID_VALUE(sc->sc_id));
  809         osiop_write_1(sc, OSIOP_DWT, 0x00);
  810         osiop_write_1(sc, OSIOP_CTEST0, osiop_read_1(sc, OSIOP_CTEST0)
  811             | OSIOP_CTEST0_BTD | OSIOP_CTEST0_EAN);
  812         osiop_write_1(sc, OSIOP_CTEST7,
  813             osiop_read_1(sc, OSIOP_CTEST7) | sc->sc_ctest7);
  814         osiop_write_1(sc, OSIOP_CTEST4,
  815             osiop_read_1(sc, OSIOP_CTEST4) | sc->sc_ctest4);
  816 
  817         /* will need to re-negotiate sync xfers */
  818         for (i = 0; i < OSIOP_NTGT; i++) {
  819                 sc->sc_tinfo[i].state = NEG_INIT;
  820                 sc->sc_tinfo[i].period = 0;
  821                 sc->sc_tinfo[i].offset = 0;
  822         }
  823 
  824         stat = osiop_read_1(sc, OSIOP_ISTAT);
  825         if (stat & OSIOP_ISTAT_SIP)
  826                 osiop_read_1(sc, OSIOP_SSTAT0);
  827         delay(25);
  828         if (stat & OSIOP_ISTAT_DIP)
  829                 osiop_read_1(sc, OSIOP_DSTAT);
  830 
  831         splx(s);
  832 
  833         delay(osiop_reset_delay * 1000);
  834 
  835         if (sc->sc_nexus != NULL) {
  836                 sc->sc_nexus->xs->error =
  837                     (sc->sc_nexus->flags & ACB_F_TIMEOUT) ?
  838                     XS_TIMEOUT : XS_RESET;
  839                 sc->sc_nexus->status = ACB_S_DONE;
  840                 sc->sc_nexus->flags = 0;
  841                 osiop_scsidone(sc->sc_nexus, SCSI_OSIOP_NOCHECK);
  842         }
  843         while ((acb = TAILQ_FIRST(&sc->nexus_list)) != NULL) {
  844                 acb->xs->error = (acb->flags & ACB_F_TIMEOUT) ?
  845                     XS_TIMEOUT : XS_RESET;
  846                 acb->status = ACB_S_DONE;
  847                 acb->flags = 0;
  848                 osiop_scsidone(acb, SCSI_OSIOP_NOCHECK);
  849         }
  850 
  851         sc->sc_flags &= ~(OSIOP_INTDEFER | OSIOP_INTSOFF);
  852         /* enable SCSI and DMA interrupts */
  853         sc->sc_sien = OSIOP_SIEN_M_A | OSIOP_SIEN_STO | /*OSIOP_SIEN_SEL |*/
  854             OSIOP_SIEN_SGE | OSIOP_SIEN_UDC | OSIOP_SIEN_RST | OSIOP_SIEN_PAR;
  855         sc->sc_dien = OSIOP_DIEN_BF | OSIOP_DIEN_ABRT | OSIOP_DIEN_SIR |
  856             /*OSIOP_DIEN_WTD |*/ OSIOP_DIEN_IID;
  857         osiop_write_1(sc, OSIOP_SIEN, sc->sc_sien);
  858         osiop_write_1(sc, OSIOP_DIEN, sc->sc_dien);
  859 }
  860 
  861 void
  862 osiop_resetbus(struct osiop_softc *sc)
  863 {
  864 
  865         osiop_write_1(sc, OSIOP_SIEN, 0);
  866         osiop_write_1(sc, OSIOP_SCNTL1,
  867             osiop_read_1(sc, OSIOP_SCNTL1) | OSIOP_SCNTL1_RST);
  868         delay(25);
  869         osiop_write_1(sc, OSIOP_SCNTL1,
  870             osiop_read_1(sc, OSIOP_SCNTL1) & ~OSIOP_SCNTL1_RST);
  871 }
  872 
  873 /*
  874  * Setup Data Storage for 53C710 and start SCRIPTS processing
  875  */
  876 
  877 void
  878 osiop_start(struct osiop_softc *sc)
  879 {
  880         struct osiop_acb *acb = sc->sc_nexus;
  881         struct osiop_ds *ds = acb->ds;
  882         struct scsipi_xfer *xs = acb->xs;
  883         bus_dmamap_t dsdma = sc->sc_dsdma, datadma = acb->datadma;
  884         struct osiop_tinfo *ti;
  885         int target = xs->xs_periph->periph_target;
  886         int lun = xs->xs_periph->periph_lun;
  887         int disconnect, i;
  888 
  889 #ifdef OSIOP_DEBUG
  890         if (osiop_debug & DEBUG_DISC &&
  891             osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) {
  892                 printf("ACK! osiop was busy: script %p dsa %p active %d\n",
  893                     sc->sc_script, acb->ds, sc->sc_active);
  894                 printf("istat %02x sfbr %02x lcrc %02x sien %02x dien %02x\n",
  895                     osiop_read_1(sc, OSIOP_ISTAT),
  896                     osiop_read_1(sc, OSIOP_SFBR),
  897                     osiop_read_1(sc, OSIOP_LCRC),
  898                     osiop_read_1(sc, OSIOP_SIEN),
  899                     osiop_read_1(sc, OSIOP_DIEN));
  900 #ifdef DDB
  901 #if 0
  902                 Debugger();
  903 #endif
  904 #endif
  905         }
  906 #endif
  907 
  908 #ifdef OSIOP_DEBUG
  909         if (acb->status != ACB_S_READY)
  910                 panic("osiop_start: non-ready cmd in acb");
  911 #endif
  912 
  913         acb->intstat = 0;
  914 
  915         /* Copy SCSI command to DMA buffer */
  916         memcpy(ds->scsipi_cmd, xs->cmd, acb->cmdlen);
  917         ds->cmd.count = acb->cmdlen;
  918 
  919         ti = &sc->sc_tinfo[target];
  920         ds->scsi_addr = ((1 << 16) << target) | (ti->sxfer << 8);
  921 
  922         disconnect = (xs->xs_control & XS_CTL_REQSENSE) == 0 &&
  923             (ti->flags & TI_NODISC) == 0;
  924 
  925         ds->msgout[0] = MSG_IDENTIFY(lun, disconnect);
  926         ds->id.count = 1;
  927         ds->stat[0] = SCSI_OSIOP_NOSTATUS;      /* set invalid status */
  928         ds->msgbuf[0] = ds->msgbuf[1] = MSG_INVALID;
  929         memset(&ds->data, 0, sizeof(ds->data));
  930 
  931         /*
  932          * Negotiate wide is the initial negotiation state;  since the 53c710
  933          * doesn't do wide transfers, just begin the synchronous transfer
  934          * negotiation here.
  935          */
  936         if (ti->state == NEG_INIT) {
  937                 if ((ti->flags & TI_NOSYNC) != 0) {
  938                         ti->state = NEG_DONE;
  939                         ti->sbcl = 0;
  940                         ti->sxfer = 0;
  941                         ti->period = 0;
  942                         ti->offset = 0;
  943                         osiop_update_xfer_mode(sc, target);
  944 #ifdef OSIOP_DEBUG
  945                         if (osiopsync_debug)
  946                                 printf("Forcing target %d asynchronous\n",
  947                                     target);
  948 #endif
  949                 } else {
  950                         ds->msgbuf[2] = MSG_INVALID;
  951                         ds->msgout[1] = MSG_EXTENDED;
  952                         ds->msgout[2] = MSG_EXT_SDTR_LEN;
  953                         ds->msgout[3] = MSG_EXT_SDTR;
  954                         ds->msgout[4] = sc->sc_minsync;
  955                         ds->msgout[5] = OSIOP_MAX_OFFSET;
  956                         ds->id.count = MSG_EXT_SDTR_LEN + 3;
  957                         ti->state = NEG_WAITS;
  958 #ifdef OSIOP_DEBUG
  959                         if (osiopsync_debug)
  960                                 printf("Sending sync request to target %d\n",
  961                                     target);
  962 #endif
  963                 }
  964         }
  965 
  966         acb->curaddr = 0;
  967         acb->curlen = 0;
  968 
  969         /*
  970          * Build physical DMA addresses for scatter/gather I/O
  971          */
  972         if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
  973                 for (i = 0; i < datadma->dm_nsegs; i++) {
  974                         ds->data[i].count = datadma->dm_segs[i].ds_len;
  975                         ds->data[i].addr  = datadma->dm_segs[i].ds_addr;
  976                 }
  977                 /* sync xfer data buffer */
  978                 bus_dmamap_sync(sc->sc_dmat, acb->datadma,
  979                     0, acb->datalen, (xs->xs_control & XS_CTL_DATA_IN) ?
  980                     BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
  981         }
  982 
  983         /* sync script data structure */
  984         bus_dmamap_sync(sc->sc_dmat, dsdma,
  985             acb->dsoffset, sizeof(struct osiop_ds),
  986             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
  987 
  988         acb->status = ACB_S_ACTIVE;
  989 
  990         /* handle timeout */
  991         if ((xs->xs_control & XS_CTL_POLL) == 0) {
  992                 int timeout = mstohz(acb->xs->timeout);
  993                 /* start expire timer */
  994                 if (timeout == 0)
  995                         timeout = 1;
  996                 callout_reset(&xs->xs_callout, timeout,
  997                     osiop_timeout, acb);
  998         }
  999 #ifdef OSIOP_DEBUG
 1000         if (osiop_debug & DEBUG_DISC &&
 1001             osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) {
 1002                 printf("ACK! osiop was busy at start: "
 1003                     "script %p dsa %p active %d\n",
 1004                     sc->sc_script, acb->ds, sc->sc_active);
 1005 #ifdef DDB
 1006 #if 0
 1007                 Debugger();
 1008 #endif
 1009 #endif
 1010         }
 1011 #endif
 1012         if (TAILQ_EMPTY(&sc->nexus_list)) {
 1013                 if (osiop_read_1(sc, OSIOP_ISTAT) & OSIOP_ISTAT_CON)
 1014                         printf("%s: osiop_select while connected?\n",
 1015                             device_xname(sc->sc_dev));
 1016                 osiop_write_4(sc, OSIOP_TEMP, 0);
 1017                 osiop_write_1(sc, OSIOP_SBCL, ti->sbcl);
 1018                 osiop_write_4(sc, OSIOP_DSA,
 1019                     dsdma->dm_segs[0].ds_addr + acb->dsoffset);
 1020                 osiop_write_4(sc, OSIOP_DSP,
 1021                     sc->sc_scrdma->dm_segs[0].ds_addr + Ent_scripts);
 1022                 OSIOP_TRACE('s', 1, 0, 0);
 1023         } else {
 1024                 if ((osiop_read_1(sc, OSIOP_ISTAT) & OSIOP_ISTAT_CON) == 0) {
 1025                         osiop_write_1(sc, OSIOP_ISTAT, OSIOP_ISTAT_SIGP);
 1026                         OSIOP_TRACE('s', 2, 0, 0);
 1027                 } else {
 1028                         OSIOP_TRACE('s', 3,
 1029                             osiop_read_1(sc, OSIOP_ISTAT), 0);
 1030                 }
 1031         }
 1032 #ifdef OSIOP_DEBUG
 1033         osiopstarts++;
 1034 #endif
 1035 }
 1036 
 1037 /*
 1038  * Process a DMA or SCSI interrupt from the 53C710 SIOP
 1039  */
 1040 
 1041 int
 1042 osiop_checkintr(struct osiop_softc *sc, uint8_t istat, uint8_t dstat,
 1043     uint8_t sstat0, int *status)
 1044 {
 1045         struct osiop_acb *acb = sc->sc_nexus;
 1046         struct osiop_ds *ds = NULL;     /* XXX */
 1047         bus_dmamap_t dsdma = sc->sc_dsdma;
 1048         bus_addr_t scraddr = sc->sc_scrdma->dm_segs[0].ds_addr;
 1049         int target = 0;
 1050         int dfifo, dbc, intcode, sstat1;
 1051 
 1052         dfifo = osiop_read_1(sc, OSIOP_DFIFO);
 1053         dbc = osiop_read_4(sc, OSIOP_DBC) & 0x00ffffff;
 1054         sstat1 = osiop_read_1(sc, OSIOP_SSTAT1);
 1055         osiop_write_1(sc, OSIOP_CTEST8,
 1056             osiop_read_1(sc, OSIOP_CTEST8) | OSIOP_CTEST8_CLF);
 1057         while ((osiop_read_1(sc, OSIOP_CTEST1) & OSIOP_CTEST1_FMT) !=
 1058             OSIOP_CTEST1_FMT)
 1059                 ;
 1060         osiop_write_1(sc, OSIOP_CTEST8,
 1061             osiop_read_1(sc, OSIOP_CTEST8) & ~OSIOP_CTEST8_CLF);
 1062         intcode = osiop_read_4(sc, OSIOP_DSPS);
 1063 #ifdef OSIOP_DEBUG
 1064         osiopints++;
 1065         if (osiop_read_4(sc, OSIOP_DSP) != 0 &&
 1066             (osiop_read_4(sc, OSIOP_DSP) < scraddr ||
 1067             osiop_read_4(sc, OSIOP_DSP) >= scraddr + sizeof(osiop_script))) {
 1068                 printf("%s: dsp not within script dsp %x scripts %lx:%lx",
 1069                     device_xname(sc->sc_dev),
 1070                     osiop_read_4(sc, OSIOP_DSP),
 1071                     scraddr, scraddr + sizeof(osiop_script));
 1072                 printf(" istat %x dstat %x sstat0 %x\n", istat, dstat, sstat0);
 1073 #ifdef DDB
 1074                 Debugger();
 1075 #endif
 1076         }
 1077 #endif
 1078         OSIOP_TRACE('i', dstat, istat, (istat & OSIOP_ISTAT_DIP) ?
 1079             intcode & 0xff : sstat0);
 1080 
 1081         if (acb != NULL) { /* XXX */
 1082                 ds = acb->ds;
 1083                 bus_dmamap_sync(sc->sc_dmat, dsdma,
 1084                     acb->dsoffset, sizeof(struct osiop_ds),
 1085                     BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 1086 #ifdef OSIOP_DEBUG
 1087                 if (acb->status != ACB_S_ACTIVE)
 1088                         printf("osiop_checkintr: acb not active (status %d)\n",
 1089                             acb->status);
 1090 #endif
 1091         }
 1092 
 1093 
 1094         if (dstat & OSIOP_DSTAT_SIR && intcode == A_ok) {
 1095                 /* Normal completion status, or check condition */
 1096                 struct osiop_tinfo *ti;
 1097 
 1098                 if (acb == NULL) {
 1099                         printf("%s: COMPLETE with no active command?\n",
 1100                             device_xname(sc->sc_dev));
 1101                         goto bad_phase;
 1102                 }
 1103 #ifdef OSIOP_DEBUG
 1104                 if (osiop_read_4(sc, OSIOP_DSA) !=
 1105                     dsdma->dm_segs[0].ds_addr + acb->dsoffset) {
 1106                         printf("osiop: invalid dsa: %x %lx\n",
 1107                             osiop_read_4(sc, OSIOP_DSA),
 1108                             dsdma->dm_segs[0].ds_addr + acb->dsoffset);
 1109                         panic("*** osiop DSA invalid ***");
 1110                 }
 1111 #endif
 1112                 target = acb->xs->xs_periph->periph_target;
 1113                 ti = &sc->sc_tinfo[target];
 1114                 if (ti->state == NEG_WAITS) {
 1115                         if (ds->msgbuf[1] == MSG_INVALID)
 1116                                 printf("%s: target %d ignored sync request\n",
 1117                                     device_xname(sc->sc_dev), target);
 1118                         else if (ds->msgbuf[1] == MSG_MESSAGE_REJECT)
 1119                                 printf("%s: target %d rejected sync request\n",
 1120                                     device_xname(sc->sc_dev), target);
 1121                         ti->period = 0;
 1122                         ti->offset = 0;
 1123                         osiop_update_xfer_mode(sc, target);
 1124                         ti->state = NEG_DONE;
 1125                 }
 1126 #ifdef OSIOP_DEBUG
 1127                 if (osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) {
 1128 #if 0
 1129                         printf("ACK! osiop was busy at end: "
 1130                             "script %p dsa %p\n", &osiop_script, ds);
 1131 #ifdef DDB
 1132                         Debugger();
 1133 #endif
 1134 #endif
 1135                 }
 1136                 if (ds->msgbuf[0] != MSG_CMDCOMPLETE)
 1137                         printf("%s: message was not COMMAND COMPLETE: %02x\n",
 1138                             device_xname(sc->sc_dev), ds->msgbuf[0]);
 1139 #endif
 1140                 if (!TAILQ_EMPTY(&sc->nexus_list))
 1141                         osiop_write_1(sc, OSIOP_DCNTL,
 1142                             osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD);
 1143                 *status = ds->stat[0];
 1144                 acb->status = ACB_S_DONE;
 1145                 return (1);
 1146         }
 1147         if (dstat & OSIOP_DSTAT_SIR && intcode == A_int_syncmsg) {
 1148                 if (acb == NULL) {
 1149                         printf("%s: sync message with no active command?\n",
 1150                             device_xname(sc->sc_dev));
 1151                         goto bad_phase;
 1152                 }
 1153                 target = acb->xs->xs_periph->periph_target;
 1154                 if (ds->msgbuf[1] == MSG_EXTENDED &&
 1155                     ds->msgbuf[2] == MSG_EXT_SDTR_LEN &&
 1156                     ds->msgbuf[3] == MSG_EXT_SDTR) {
 1157                         struct osiop_tinfo *ti = &sc->sc_tinfo[target];
 1158 #ifdef OSIOP_DEBUG
 1159                         if (osiopsync_debug)
 1160                                 printf("sync msg in: "
 1161                                     "%02x %02x %02x %02x %02x %02x\n",
 1162                                     ds->msgbuf[0], ds->msgbuf[1],
 1163                                     ds->msgbuf[2], ds->msgbuf[3],
 1164                                     ds->msgbuf[4], ds->msgbuf[5]);
 1165 #endif
 1166                         ti->period = ds->msgbuf[4];
 1167                         ti->offset = ds->msgbuf[5];
 1168                         ti->sxfer = 0;
 1169                         ti->sbcl = 0;
 1170                         if (ds->msgbuf[5] != 0)
 1171                                 scsi_period_to_osiop(sc, target);
 1172                         osiop_update_xfer_mode(sc, target);
 1173 
 1174                         bus_dmamap_sync(sc->sc_dmat, dsdma,
 1175                             acb->dsoffset, sizeof(struct osiop_ds),
 1176                             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 1177                         osiop_write_1(sc, OSIOP_SXFER, ti->sxfer);
 1178                         osiop_write_1(sc, OSIOP_SBCL, ti->sbcl);
 1179                         if (ti->state == NEG_WAITS) {
 1180                                 ti->state = NEG_DONE;
 1181                                 osiop_write_4(sc, OSIOP_DSP,
 1182                                     scraddr + Ent_clear_ack);
 1183                                 return (0);
 1184                         }
 1185                         osiop_write_1(sc, OSIOP_DCNTL,
 1186                             osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD);
 1187                         ti->state = NEG_DONE;
 1188                         return (0);
 1189                 }
 1190                 /* XXX - not SDTR message */
 1191         }
 1192         if (sstat0 & OSIOP_SSTAT0_M_A) {
 1193                 /* Phase mismatch */
 1194 #ifdef OSIOP_DEBUG
 1195                 osiopphmm++;
 1196 #endif
 1197                 if (acb == NULL) {
 1198                         printf("%s: Phase mismatch with no active command?\n",
 1199                             device_xname(sc->sc_dev));
 1200                         goto bad_phase;
 1201                 }
 1202                 if (acb->datalen > 0) {
 1203                         int adjust = (dfifo - (dbc & 0x7f)) & 0x7f;
 1204                         if (sstat1 & OSIOP_SSTAT1_ORF)
 1205                                 adjust++;
 1206                         if (sstat1 & OSIOP_SSTAT1_OLF)
 1207                                 adjust++;
 1208                         acb->curaddr = osiop_read_4(sc, OSIOP_DNAD) - adjust;
 1209                         acb->curlen = dbc + adjust;
 1210 #ifdef OSIOP_DEBUG
 1211                         if (osiop_debug & DEBUG_DISC) {
 1212                                 printf("Phase mismatch: curaddr %lx "
 1213                                     "curlen %lx dfifo %x dbc %x sstat1 %x "
 1214                                     "adjust %x sbcl %x starts %d acb %p\n",
 1215                                     acb->curaddr, acb->curlen, dfifo,
 1216                                     dbc, sstat1, adjust,
 1217                                     osiop_read_1(sc, OSIOP_SBCL),
 1218                                     osiopstarts, acb);
 1219                                 if (ds->data[1].count != 0) {
 1220                                         int i;
 1221                                         for (i = 0; ds->data[i].count != 0; i++)
 1222                                                 printf("chain[%d] "
 1223                                                     "addr %x len %x\n", i,
 1224                                                     ds->data[i].addr,
 1225                                                     ds->data[i].count);
 1226                                 }
 1227                                 bus_dmamap_sync(sc->sc_dmat, dsdma,
 1228                                     acb->dsoffset, sizeof(struct osiop_ds),
 1229                                     BUS_DMASYNC_PREREAD |
 1230                                     BUS_DMASYNC_PREWRITE);
 1231                         }
 1232 #endif
 1233                 }
 1234 #ifdef OSIOP_DEBUG
 1235                 OSIOP_TRACE('m', osiop_read_1(sc, OSIOP_SBCL),
 1236                     osiop_read_4(sc, OSIOP_DSP) >> 8,
 1237                     osiop_read_4(sc, OSIOP_DSP));
 1238                 if (osiop_debug & DEBUG_PHASE)
 1239                         printf("Phase mismatch: %x dsp +%lx dcmd %x\n",
 1240                             osiop_read_1(sc, OSIOP_SBCL),
 1241                             osiop_read_4(sc, OSIOP_DSP) - scraddr,
 1242                             osiop_read_4(sc, OSIOP_DBC));
 1243 #endif
 1244                 if ((osiop_read_1(sc, OSIOP_SBCL) & OSIOP_REQ) == 0) {
 1245                         printf("Phase mismatch: "
 1246                             "REQ not asserted! %02x dsp %x\n",
 1247                             osiop_read_1(sc, OSIOP_SBCL),
 1248                             osiop_read_4(sc, OSIOP_DSP));
 1249 #if defined(OSIOP_DEBUG) && defined(DDB)
 1250                         /*Debugger(); XXX is*/
 1251 #endif
 1252                 }
 1253                 switch (OSIOP_PHASE(osiop_read_1(sc, OSIOP_SBCL))) {
 1254                 case DATA_OUT_PHASE:
 1255                 case DATA_IN_PHASE:
 1256                 case STATUS_PHASE:
 1257                 case COMMAND_PHASE:
 1258                 case MSG_IN_PHASE:
 1259                 case MSG_OUT_PHASE:
 1260                         osiop_write_4(sc, OSIOP_DSP, scraddr + Ent_switch);
 1261                         break;
 1262                 default:
 1263                         printf("%s: invalid phase\n", device_xname(sc->sc_dev));
 1264                         goto bad_phase;
 1265                 }
 1266                 return (0);
 1267         }
 1268         if (sstat0 & OSIOP_SSTAT0_STO) {
 1269                 /* Select timed out */
 1270                 if (acb == NULL) {
 1271                         printf("%s: Select timeout with no active command?\n",
 1272                             device_xname(sc->sc_dev));
 1273                         goto bad_phase;
 1274                 }
 1275 #ifdef OSIOP_DEBUG
 1276                 if (osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) {
 1277                         printf("ACK! osiop was busy at timeout: "
 1278                             "script %p dsa %lx\n", sc->sc_script,
 1279                             dsdma->dm_segs[0].ds_addr + acb->dsoffset);
 1280                         printf(" sbcl %x sdid %x "
 1281                             "istat %x dstat %x sstat0 %x\n",
 1282                             osiop_read_1(sc, OSIOP_SBCL),
 1283                             osiop_read_1(sc, OSIOP_SDID),
 1284                             istat, dstat, sstat0);
 1285                         if ((osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) == 0) {
 1286                                 printf("Yikes, it's not busy now!\n");
 1287 #if 0
 1288                                 *status = SCSI_OSIOP_NOSTATUS;
 1289                                 if (!TAILQ_EMPTY(&sc->nexus_list))
 1290                                         osiop_write_4(sc, OSIOP_DSP,
 1291                                             scraddr + Ent_wait_reselect);
 1292                                 return (1);
 1293 #endif
 1294                         }
 1295 #if 0
 1296                         osiop_write_1(sc, OSIOP_DCNTL,
 1297                             osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD);
 1298 #endif
 1299 #ifdef DDB
 1300                         Debugger();
 1301 #endif
 1302                         return (0);
 1303                 }
 1304 #endif
 1305                 acb->status = ACB_S_DONE;
 1306                 *status = SCSI_OSIOP_NOSTATUS;
 1307                 acb->xs->error = XS_SELTIMEOUT;
 1308                 if (!TAILQ_EMPTY(&sc->nexus_list))
 1309                         osiop_write_4(sc, OSIOP_DSP,
 1310                             scraddr + Ent_wait_reselect);
 1311                 return (1);
 1312         }
 1313         if (acb != NULL)
 1314                 target = acb->xs->xs_periph->periph_target;
 1315         else
 1316                 target = sc->sc_id;
 1317         if (sstat0 & OSIOP_SSTAT0_UDC) {
 1318                 printf("%s: target %d disconnected unexpectedly",
 1319                     device_xname(sc->sc_dev), target);
 1320                 if (acb == NULL)
 1321                         printf("with no active command?");
 1322                 printf("\n");
 1323 #if 0
 1324                 osiop_abort(sc, "osiop_chkintr");
 1325 #endif
 1326                 *status = SCSI_CHECK;
 1327                 if (!TAILQ_EMPTY(&sc->nexus_list))
 1328                         osiop_write_4(sc, OSIOP_DSP,
 1329                             scraddr + Ent_wait_reselect);
 1330                 return (acb != NULL);
 1331         }
 1332         if (dstat & OSIOP_DSTAT_SIR &&
 1333             (intcode == A_int_disc || intcode == A_int_disc_wodp)) {
 1334                 /* Disconnect */
 1335                 if (acb == NULL) {
 1336                         printf("%s: Disconnect with no active command?\n",
 1337                             device_xname(sc->sc_dev));
 1338                         return (0);
 1339                 }
 1340 #ifdef OSIOP_DEBUG
 1341                 if (osiop_debug & DEBUG_DISC) {
 1342                         printf("%s: ID %02x disconnected TEMP %x (+%lx) "
 1343                             "curaddr %lx curlen %lx buf %x len %x dfifo %x "
 1344                             "dbc %x sstat1 %x starts %d acb %p\n",
 1345                             device_xname(sc->sc_dev), 1 << target,
 1346                             osiop_read_4(sc, OSIOP_TEMP),
 1347                             (osiop_read_4(sc, OSIOP_TEMP) != 0) ?
 1348                                 osiop_read_4(sc, OSIOP_TEMP) - scraddr : 0,
 1349                             acb->curaddr, acb->curlen,
 1350                             ds->data[0].addr, ds->data[0].count,
 1351                             dfifo, dbc, sstat1, osiopstarts, acb);
 1352                         bus_dmamap_sync(sc->sc_dmat, dsdma,
 1353                             acb->dsoffset, sizeof(struct osiop_ds),
 1354                             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 1355                 }
 1356 #endif
 1357                 /*
 1358                  * XXXX need to update curaddr/curlen to reflect
 1359                  * current data transferred.  If device disconnected in
 1360                  * the middle of a DMA block, they should already be set
 1361                  * by the phase change interrupt.  If the disconnect
 1362                  * occurs on a DMA block boundary, we have to figure out
 1363                  * which DMA block it was.
 1364                  */
 1365                 if (acb->datalen > 0 &&
 1366                     osiop_read_4(sc, OSIOP_TEMP) != 0) {
 1367                         long n = osiop_read_4(sc, OSIOP_TEMP) - scraddr;
 1368 
 1369                         if (acb->curlen != 0 &&
 1370                             acb->curlen != ds->data[0].count)
 1371                                 printf("%s: curaddr/curlen already set? "
 1372                                     "n %lx iob %lx/%lx chain[0] %x/%x\n",
 1373                                     device_xname(sc->sc_dev), n,
 1374                                     acb->curaddr, acb->curlen,
 1375                                     ds->data[0].addr, ds->data[0].count);
 1376                         if (n < Ent_datain)
 1377                                 n = (n - Ent_dataout) / 16;
 1378                         else
 1379                                 n = (n - Ent_datain) / 16;
 1380                         if (n < 0 || n >= OSIOP_NSG)
 1381                                 printf("TEMP invalid %ld\n", n);
 1382                         else {
 1383                                 acb->curaddr = ds->data[n].addr;
 1384                                 acb->curlen = ds->data[n].count;
 1385                         }
 1386 #ifdef OSIOP_DEBUG
 1387                         if (osiop_debug & DEBUG_DISC) {
 1388                                 printf("%s: TEMP offset %ld",
 1389                                     device_xname(sc->sc_dev), n);
 1390                                 printf(" curaddr %lx curlen %lx\n",
 1391                                     acb->curaddr, acb->curlen);
 1392                         }
 1393 #endif
 1394                 }
 1395                 /*
 1396                  * If data transfer was interrupted by disconnect, curaddr
 1397                  * and curlen should reflect the point of interruption.
 1398                  * Adjust the DMA chain so that the data transfer begins
 1399                  * at the appropriate place upon reselection.
 1400                  * XXX This should only be done on save data pointer message?
 1401                  */
 1402                 if (acb->curlen > 0) {
 1403                         int i, j;
 1404 
 1405 #ifdef OSIOP_DEBUG
 1406                         if (osiop_debug & DEBUG_DISC)
 1407                                 printf("%s: adjusting DMA chain\n",
 1408                                     device_xname(sc->sc_dev));
 1409                         if (intcode == A_int_disc_wodp)
 1410                                 printf("%s: ID %02x disconnected "
 1411                                     "without Save Data Pointers\n",
 1412                                     device_xname(sc->sc_dev), 1 << target);
 1413 #endif
 1414                         for (i = 0; i < OSIOP_NSG; i++) {
 1415                                 if (ds->data[i].count == 0)
 1416                                         break;
 1417                                 if (acb->curaddr >= ds->data[i].addr &&
 1418                                     acb->curaddr <
 1419                                     (ds->data[i].addr + ds->data[i].count))
 1420                                         break;
 1421                         }
 1422                         if (i >= OSIOP_NSG || ds->data[i].count == 0) {
 1423                                 printf("couldn't find saved data pointer: "
 1424                                     "curaddr %lx curlen %lx i %d\n",
 1425                                     acb->curaddr, acb->curlen, i);
 1426 #ifdef DDB
 1427                                 Debugger();
 1428 #endif
 1429                         }
 1430 #ifdef OSIOP_DEBUG
 1431                         if (osiop_debug & DEBUG_DISC)
 1432                                 printf(" chain[0]: %x/%x -> %lx/%lx\n",
 1433                                     ds->data[0].addr, ds->data[0].count,
 1434                                     acb->curaddr, acb->curlen);
 1435 #endif
 1436                         ds->data[0].addr = acb->curaddr;
 1437                         ds->data[0].count = acb->curlen;
 1438                         for (j = 1, i = i + 1;
 1439                             i < OSIOP_NSG && ds->data[i].count > 0;
 1440                             i++, j++) {
 1441 #ifdef OSIOP_DEBUG
 1442                                 if (osiop_debug & DEBUG_DISC)
 1443                                         printf("  chain[%d]: %x/%x -> %x/%x\n",
 1444                                             j, ds->data[j].addr,
 1445                                             ds->data[j].count,
 1446                                             ds->data[i].addr,
 1447                                             ds->data[i].count);
 1448 #endif
 1449                                 ds->data[j].addr  = ds->data[i].addr;
 1450                                 ds->data[j].count = ds->data[i].count;
 1451                         }
 1452                         if (j < OSIOP_NSG) {
 1453                                 ds->data[j].addr  = 0;
 1454                                 ds->data[j].count = 0;
 1455                         }
 1456                         bus_dmamap_sync(sc->sc_dmat, dsdma,
 1457                             acb->dsoffset, sizeof(struct osiop_ds),
 1458                             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 1459                 }
 1460                 sc->sc_tinfo[target].dconns++;
 1461                 /*
 1462                  * add nexus to waiting list
 1463                  * clear nexus
 1464                  * try to start another command for another target/lun
 1465                  */
 1466                 acb->intstat = sc->sc_flags & OSIOP_INTSOFF;
 1467                 TAILQ_INSERT_TAIL(&sc->nexus_list, acb, chain);
 1468                 sc->sc_nexus = NULL;            /* no current device */
 1469                 osiop_write_4(sc, OSIOP_DSP, scraddr + Ent_wait_reselect);
 1470                 /* XXXX start another command ? */
 1471                 if (!TAILQ_EMPTY(&sc->ready_list))
 1472                         osiop_sched(sc);
 1473                 return (0);
 1474         }
 1475         if (dstat & OSIOP_DSTAT_SIR && intcode == A_int_reconnect) {
 1476                 int reselid = ffs(osiop_read_4(sc, OSIOP_SCRATCH) & 0xff) - 1;
 1477                 int reselun = osiop_read_1(sc, OSIOP_SFBR) & 0x07;
 1478 #ifdef OSIOP_DEBUG
 1479                 uint8_t resmsg;
 1480 #endif
 1481 
 1482                 /* Reconnect */
 1483                 /* XXXX save current SBCL */
 1484                 sc->sc_sstat1 = osiop_read_1(sc, OSIOP_SBCL);
 1485 #ifdef OSIOP_DEBUG
 1486                 if (osiop_debug & DEBUG_DISC)
 1487                         printf("%s: target ID %02x reselected dsps %x\n",
 1488                             device_xname(sc->sc_dev), reselid, intcode);
 1489                 resmsg = osiop_read_1(sc, OSIOP_SFBR);
 1490                 if (!MSG_ISIDENTIFY(resmsg))
 1491                         printf("%s: Reselect message in was not identify: "
 1492                             "%02x\n", device_xname(sc->sc_dev), resmsg);
 1493 #endif
 1494                 if (sc->sc_nexus != NULL) {
 1495                         struct scsipi_periph *periph =
 1496                             sc->sc_nexus->xs->xs_periph;
 1497 #ifdef OSIOP_DEBUG
 1498                         if (osiop_debug & DEBUG_DISC)
 1499                                 printf("%s: reselect ID %02x w/active\n",
 1500                                     device_xname(sc->sc_dev), reselid);
 1501 #endif
 1502                         TAILQ_INSERT_HEAD(&sc->ready_list,
 1503                             sc->sc_nexus, chain);
 1504                         sc->sc_tinfo[periph->periph_target].lubusy
 1505                             &= ~(1 << periph->periph_lun);
 1506                         sc->sc_active--;
 1507                 }
 1508                 /*
 1509                  * locate acb of reselecting device
 1510                  * set sc->sc_nexus to acb
 1511                  */
 1512                 TAILQ_FOREACH(acb, &sc->nexus_list, chain) {
 1513                         struct scsipi_periph *periph = acb->xs->xs_periph;
 1514                         if (reselid != periph->periph_target ||
 1515                             reselun != periph->periph_lun) {
 1516                                 continue;
 1517                         }
 1518                         TAILQ_REMOVE(&sc->nexus_list, acb, chain);
 1519                         sc->sc_nexus = acb;
 1520                         sc->sc_flags |= acb->intstat;
 1521                         acb->intstat = 0;
 1522                         osiop_write_4(sc, OSIOP_DSA,
 1523                             dsdma->dm_segs[0].ds_addr + acb->dsoffset);
 1524                         osiop_write_1(sc, OSIOP_SXFER,
 1525                             sc->sc_tinfo[reselid].sxfer);
 1526                         osiop_write_1(sc, OSIOP_SBCL,
 1527                             sc->sc_tinfo[reselid].sbcl);
 1528                         break;
 1529                 }
 1530                 if (acb == NULL) {
 1531                         printf("%s: target ID %02x reselect nexus_list %p\n",
 1532                             device_xname(sc->sc_dev), reselid,
 1533                             TAILQ_FIRST(&sc->nexus_list));
 1534                         panic("unable to find reselecting device");
 1535                 }
 1536 
 1537                 osiop_write_4(sc, OSIOP_TEMP, 0);
 1538                 osiop_write_1(sc, OSIOP_DCNTL,
 1539                     osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD);
 1540                 return (0);
 1541         }
 1542         if (dstat & OSIOP_DSTAT_SIR && intcode == A_int_connect) {
 1543 #ifdef OSIOP_DEBUG
 1544                 uint8_t ctest2 = osiop_read_1(sc, OSIOP_CTEST2);
 1545 
 1546                 /* reselect was interrupted (by Sig_P or select) */
 1547                 if (osiop_debug & DEBUG_DISC ||
 1548                     (ctest2 & OSIOP_CTEST2_SIGP) == 0)
 1549                         printf("%s: reselect interrupted (Sig_P?) "
 1550                             "scntl1 %x ctest2 %x sfbr %x istat %x/%x\n",
 1551                             device_xname(sc->sc_dev),
 1552                             osiop_read_1(sc, OSIOP_SCNTL1), ctest2,
 1553                             osiop_read_1(sc, OSIOP_SFBR), istat,
 1554                             osiop_read_1(sc, OSIOP_ISTAT));
 1555 #endif
 1556                 /* XXX assumes it was not select */
 1557                 if (sc->sc_nexus == NULL) {
 1558 #ifdef OSIOP_DEBUG
 1559                         printf("%s: reselect interrupted, sc_nexus == NULL\n",
 1560                             device_xname(sc->sc_dev));
 1561 #if 0
 1562                         osiop_dump(sc);
 1563 #ifdef DDB
 1564                         Debugger();
 1565 #endif
 1566 #endif
 1567 #endif
 1568                         osiop_write_1(sc, OSIOP_DCNTL,
 1569                             osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD);
 1570                         return (0);
 1571                 }
 1572                 target = sc->sc_nexus->xs->xs_periph->periph_target;
 1573                 osiop_write_4(sc, OSIOP_TEMP, 0);
 1574                 osiop_write_4(sc, OSIOP_DSA,
 1575                     dsdma->dm_segs[0].ds_addr + sc->sc_nexus->dsoffset);
 1576                 osiop_write_1(sc, OSIOP_SXFER, sc->sc_tinfo[target].sxfer);
 1577                 osiop_write_1(sc, OSIOP_SBCL, sc->sc_tinfo[target].sbcl);
 1578                 osiop_write_4(sc, OSIOP_DSP, scraddr + Ent_scripts);
 1579                 return (0);
 1580         }
 1581         if (dstat & OSIOP_DSTAT_SIR && intcode == A_int_msgin) {
 1582                 /* Unrecognized message in byte */
 1583                 if (acb == NULL) {
 1584                         printf("%s: Bad message-in with no active command?\n",
 1585                             device_xname(sc->sc_dev));
 1586                         goto bad_phase;
 1587                 }
 1588                 printf("%s: Unrecognized message in data "
 1589                     "sfbr %x msg %x sbcl %x\n", device_xname(sc->sc_dev),
 1590                     osiop_read_1(sc, OSIOP_SFBR), ds->msgbuf[1],
 1591                     osiop_read_1(sc, OSIOP_SBCL));
 1592                 /* what should be done here? */
 1593                 osiop_write_4(sc, OSIOP_DSP, scraddr + Ent_clear_ack);
 1594                 bus_dmamap_sync(sc->sc_dmat, dsdma,
 1595                     acb->dsoffset, sizeof(struct osiop_ds),
 1596                     BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 1597                 return (0);
 1598         }
 1599         if (dstat & OSIOP_DSTAT_SIR && intcode == A_int_status) {
 1600                 /* Status phase wasn't followed by message in phase? */
 1601                 printf("%s: Status phase not followed by message in phase? "
 1602                     "sbcl %x sbdl %x\n", device_xname(sc->sc_dev),
 1603                     osiop_read_1(sc, OSIOP_SBCL),
 1604                     osiop_read_1(sc, OSIOP_SBDL));
 1605                 if (osiop_read_1(sc, OSIOP_SBCL) == 0xa7) {
 1606                         /* It is now, just continue the script? */
 1607                         osiop_write_1(sc, OSIOP_DCNTL,
 1608                             osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD);
 1609                         return (0);
 1610                 }
 1611         }
 1612         if (dstat & OSIOP_DSTAT_SIR && sstat0 == 0) {
 1613                 printf("OSIOP interrupt: %x sts %x msg %x %x sbcl %x\n",
 1614                     intcode, ds->stat[0], ds->msgbuf[0], ds->msgbuf[1],
 1615                     osiop_read_1(sc, OSIOP_SBCL));
 1616                 osiop_reset(sc);
 1617                 *status = SCSI_OSIOP_NOSTATUS;
 1618                 return (0);     /* osiop_reset has cleaned up */
 1619         }
 1620         if (sstat0 & OSIOP_SSTAT0_SGE)
 1621                 printf("%s: SCSI Gross Error\n", device_xname(sc->sc_dev));
 1622         if (sstat0 & OSIOP_SSTAT0_PAR)
 1623                 printf("%s: Parity Error\n", device_xname(sc->sc_dev));
 1624         if (dstat & OSIOP_DSTAT_IID)
 1625                 printf("%s: Invalid instruction detected\n",
 1626                     device_xname(sc->sc_dev));
 1627  bad_phase:
 1628         /*
 1629          * temporary panic for unhandled conditions
 1630          * displays various things about the 53C710 status and registers
 1631          * then panics.
 1632          * XXXX need to clean this up to print out the info, reset, and continue
 1633          */
 1634         printf("osiop_chkintr: target %x ds %p\n", target, ds);
 1635         printf("scripts %lx ds %lx dsp %x dcmd %x\n", scraddr,
 1636             acb ? sc->sc_dsdma->dm_segs[0].ds_addr + acb->dsoffset : 0,
 1637             osiop_read_4(sc, OSIOP_DSP),
 1638             osiop_read_4(sc, OSIOP_DBC));
 1639         printf("osiop_chkintr: istat %x dstat %x sstat0 %x "
 1640             "dsps %x dsa %x sbcl %x sts %x msg %x %x sfbr %x\n",
 1641             istat, dstat, sstat0, intcode,
 1642             osiop_read_4(sc, OSIOP_DSA),
 1643             osiop_read_1(sc, OSIOP_SBCL),
 1644             ds ? ds->stat[0] : 0,
 1645             ds ? ds->msgbuf[0] : 0,
 1646             ds ? ds->msgbuf[1] : 0,
 1647             osiop_read_1(sc, OSIOP_SFBR));
 1648 #ifdef OSIOP_DEBUG
 1649         if (osiop_debug & DEBUG_DMA)
 1650                 panic("osiop_chkintr: **** temp ****");
 1651 #ifdef DDB
 1652         Debugger();
 1653 #endif
 1654 #endif
 1655         osiop_reset(sc);        /* hard reset */
 1656         *status = SCSI_OSIOP_NOSTATUS;
 1657         if (acb != NULL)
 1658                 acb->status = ACB_S_DONE;
 1659         return (0);             /* osiop_reset cleaned up */
 1660 }
 1661 
 1662 void
 1663 osiop_select(struct osiop_softc *sc)
 1664 {
 1665         struct osiop_acb *acb = sc->sc_nexus;
 1666 
 1667 #ifdef OSIOP_DEBUG
 1668         if (osiop_debug & DEBUG_CMD)
 1669                 printf("%s: select ", device_xname(sc->sc_dev));
 1670 #endif
 1671 
 1672         if (acb->xs->xs_control & XS_CTL_POLL || sc->sc_flags & OSIOP_NODMA) {
 1673                 sc->sc_flags |= OSIOP_INTSOFF;
 1674                 sc->sc_flags &= ~OSIOP_INTDEFER;
 1675                 if ((osiop_read_1(sc, OSIOP_ISTAT) & OSIOP_ISTAT_CON) == 0) {
 1676                         osiop_write_1(sc, OSIOP_SIEN, 0);
 1677                         osiop_write_1(sc, OSIOP_DIEN, 0);
 1678                 }
 1679 #if 0
 1680         } else if ((sc->sc_flags & OSIOP_INTDEFER) == 0) {
 1681                 sc->sc_flags &= ~OSIOP_INTSOFF;
 1682                 if ((osiop_read_1(sc, OSIOP_ISTAT) & OSIOP_ISTAT_CON) == 0) {
 1683                         osiop_write_1(sc, OSIOP_SIEN, sc->sc_sien);
 1684                         osiop_write_1(sc, OSIOP_DIEN, sc->sc_dien);
 1685                 }
 1686 #endif
 1687         }
 1688 #ifdef OSIOP_DEBUG
 1689         if (osiop_debug & DEBUG_CMD)
 1690                 printf("osiop_select: target %x cmd %02x ds %p\n",
 1691                     acb->xs->xs_periph->periph_target,
 1692                     acb->xs->cmd->opcode, sc->sc_nexus->ds);
 1693 #endif
 1694 
 1695         osiop_start(sc);
 1696 
 1697         return;
 1698 }
 1699 
 1700 /*
 1701  * 53C710 interrupt handler
 1702  */
 1703 
 1704 void
 1705 osiop_intr(struct osiop_softc *sc)
 1706 {
 1707         int status, s;
 1708         uint8_t istat, dstat, sstat0;
 1709 
 1710         s = splbio();
 1711 
 1712         istat = sc->sc_istat;
 1713         if ((istat & (OSIOP_ISTAT_SIP | OSIOP_ISTAT_DIP)) == 0) {
 1714                 splx(s);
 1715                 return;
 1716         }
 1717 
 1718         /* Got a valid interrupt on this device; set by MD handler */
 1719         dstat = sc->sc_dstat;
 1720         sstat0 = sc->sc_sstat0;
 1721         sc->sc_istat = 0;
 1722 #ifdef OSIOP_DEBUG
 1723         if (!sc->sc_active) {
 1724                 /* XXX needs sync */
 1725                 printf("%s: spurious interrupt? "
 1726                     "istat %x dstat %x sstat0 %x nexus %p status %x\n",
 1727                     device_xname(sc->sc_dev),
 1728                     istat, dstat, sstat0, sc->sc_nexus,
 1729                     (sc->sc_nexus != NULL) ? sc->sc_nexus->ds->stat[0] : 0);
 1730         }
 1731 #endif
 1732 
 1733 #ifdef OSIOP_DEBUG
 1734         if (osiop_debug & (DEBUG_INT|DEBUG_CMD)) {
 1735                 /* XXX needs sync */
 1736                 printf("%s: intr istat %x dstat %x sstat0 %x dsps %x "
 1737                     "sbcl %x dsp %x dcmd %x sts %x msg %x\n",
 1738                     device_xname(sc->sc_dev),
 1739                     istat, dstat, sstat0,
 1740                     osiop_read_4(sc, OSIOP_DSPS),
 1741                     osiop_read_1(sc, OSIOP_SBCL),
 1742                     osiop_read_4(sc, OSIOP_DSP),
 1743                     osiop_read_4(sc, OSIOP_DBC),
 1744                     (sc->sc_nexus != NULL) ? sc->sc_nexus->ds->stat[0] : 0,
 1745                     (sc->sc_nexus != NULL) ? sc->sc_nexus->ds->msgbuf[0] : 0);
 1746         }
 1747 #endif
 1748         if (sc->sc_flags & OSIOP_INTDEFER) {
 1749                 sc->sc_flags &= ~(OSIOP_INTDEFER | OSIOP_INTSOFF);
 1750                 osiop_write_1(sc, OSIOP_SIEN, sc->sc_sien);
 1751                 osiop_write_1(sc, OSIOP_DIEN, sc->sc_dien);
 1752         }
 1753         if (osiop_checkintr(sc, istat, dstat, sstat0, &status)) {
 1754 #if 0
 1755                 if (status == SCSI_OSIOP_NOSTATUS)
 1756                         printf("osiop_intr: no valid status \n");
 1757 #endif
 1758                 if ((sc->sc_flags & (OSIOP_INTSOFF | OSIOP_INTDEFER)) !=
 1759                     OSIOP_INTSOFF) {
 1760 #if 0
 1761                         if (osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) {
 1762                                 struct scsipi_periph *periph;
 1763 
 1764                                 periph = sc->sc_nexus->xs->xs_periph;
 1765                                 printf("%s: SCSI bus busy at completion"
 1766                                     " targ %d sbcl %02x sfbr %x lcrc "
 1767                                     "%02x dsp +%x\n", device_xname(sc->sc_dev),
 1768                                     periph->periphtarget,
 1769                                     osiop_read_1(sc, OSIOP_SBCL),
 1770                                     osiop_read_1(sc, OSIOP_SFBR),
 1771                                     osiop_read_1(sc, OSIOP_LCRC),
 1772                                     osiop_read_4(sc, OSIOP_DSP) -
 1773                                         sc->sc_scrdma->dm_segs[0].ds_addr);
 1774                         }
 1775 #endif
 1776                         osiop_scsidone(sc->sc_nexus, status);
 1777                 }
 1778         }
 1779         splx(s);
 1780 }
 1781 
 1782 void
 1783 osiop_update_xfer_mode(struct osiop_softc *sc, int target)
 1784 {
 1785         struct osiop_tinfo *tinfo = &sc->sc_tinfo[target];
 1786         struct scsipi_xfer_mode xm;
 1787 
 1788         xm.xm_target = target;
 1789         xm.xm_mode = 0;
 1790         xm.xm_period = 0;
 1791         xm.xm_offset = 0;
 1792 
 1793         if (tinfo->period) {
 1794                 xm.xm_mode |= PERIPH_CAP_SYNC;
 1795                 xm.xm_period = tinfo->period;
 1796                 xm.xm_offset = tinfo->offset;
 1797         }
 1798 
 1799         scsipi_async_event(&sc->sc_channel, ASYNC_EVENT_XFER_MODE, &xm);
 1800 }
 1801 
 1802 void
 1803 scsi_period_to_osiop(struct osiop_softc *sc, int target)
 1804 {
 1805         int period, offset, sxfer, sbcl;
 1806 
 1807         period = sc->sc_tinfo[target].period;
 1808         offset = sc->sc_tinfo[target].offset;
 1809         for (sbcl = 1; sbcl < 4; sbcl++) {
 1810                 sxfer = (period * 4 - 1) / sc->sc_tcp[sbcl] - 3;
 1811                 if (sxfer >= 0 && sxfer <= 7)
 1812                         break;
 1813         }
 1814         if (sbcl > 3) {
 1815                 printf("osiop sync: unable to compute sync params "
 1816                     "for period %d ns\n", period * 4);
 1817                 /*
 1818                  * XXX need to pick a value we can do and renegotiate
 1819                  */
 1820                 sxfer = sbcl = 0;
 1821         } else {
 1822                 sxfer = (sxfer << 4) | ((offset <= OSIOP_MAX_OFFSET) ?
 1823                     offset : OSIOP_MAX_OFFSET);
 1824 #ifdef DEBUG_SYNC
 1825                 printf("osiop sync: params for period %dns: sxfer %x sbcl %x",
 1826                     period * 4, sxfer, sbcl);
 1827                 printf(" actual period %dns\n",
 1828                     sc->sc_tcp[sbcl] * ((sxfer >> 4) + 4));
 1829 #endif
 1830         }
 1831         sc->sc_tinfo[target].sxfer = sxfer;
 1832         sc->sc_tinfo[target].sbcl = sbcl;
 1833 #ifdef DEBUG_SYNC
 1834         printf("osiop sync: osiop_sxfr %02x, osiop_sbcl %02x\n", sxfer, sbcl);
 1835 #endif
 1836 }
 1837 
 1838 void
 1839 osiop_timeout(void *arg)
 1840 {
 1841         struct osiop_acb *acb = arg;
 1842         struct scsipi_xfer *xs = acb->xs;
 1843         struct osiop_softc *sc = acb->sc;
 1844         int s;
 1845 
 1846         scsipi_printaddr(xs->xs_periph);
 1847         printf("command timeout\n");
 1848 
 1849         s = splbio();
 1850         /* reset the scsi bus */
 1851         osiop_resetbus(sc);
 1852 
 1853         /* deactivate callout */
 1854         callout_stop(&xs->xs_callout);
 1855         acb->flags |= ACB_F_TIMEOUT;
 1856         osiop_reset(sc);
 1857         splx(s);
 1858         return;
 1859 }
 1860 
 1861 #ifdef OSIOP_DEBUG
 1862 
 1863 #if OSIOP_TRACE_SIZE
 1864 void
 1865 osiop_dump_trace(void)
 1866 {
 1867         int i;
 1868 
 1869         printf("osiop trace: next index %d\n", osiop_trix);
 1870         i = osiop_trix;
 1871         do {
 1872                 printf("%3d: '%c' %02x %02x %02x\n", i,
 1873                     osiop_trbuf[i], osiop_trbuf[i + 1],
 1874                     osiop_trbuf[i + 2], osiop_trbuf[i + 3]);
 1875                 i = (i + 4) & (OSIOP_TRACE_SIZE - 1);
 1876         } while (i != osiop_trix);
 1877 }
 1878 #endif
 1879 
 1880 void
 1881 osiop_dump_acb(struct osiop_acb *acb)
 1882 {
 1883         uint8_t *b;
 1884         int i;
 1885 
 1886         printf("acb@%p ", acb);
 1887         if (acb->xs == NULL) {
 1888                 printf("<unused>\n");
 1889                 return;
 1890         }
 1891 
 1892         b = (uint8_t *)&acb->xs->cmd;
 1893         printf("(%d:%d) status %2x cmdlen %2ld cmd ",
 1894             acb->xs->xs_periph->periph_target,
 1895             acb->xs->xs_periph->periph_lun, acb->status, acb->cmdlen);
 1896         for (i = acb->cmdlen; i > 0; i--)
 1897                 printf(" %02x", *b++);
 1898         printf("\n");
 1899         printf("  xs: %p data %p:%04x ", acb->xs, acb->xs->data,
 1900             acb->xs->datalen);
 1901         printf("va %p:%lx ", acb->data, acb->datalen);
 1902         printf("cur %lx:%lx\n", acb->curaddr, acb->curlen);
 1903 }
 1904 
 1905 void
 1906 osiop_dump(struct osiop_softc *sc)
 1907 {
 1908         struct osiop_acb *acb;
 1909         int i, s;
 1910 
 1911         s = splbio();
 1912 #if OSIOP_TRACE_SIZE
 1913         osiop_dump_trace();
 1914 #endif
 1915         printf("%s@%p istat %02x\n",
 1916             device_xname(sc->sc_dev), sc, osiop_read_1(sc, OSIOP_ISTAT));
 1917         if ((acb = TAILQ_FIRST(&sc->free_list)) != NULL) {
 1918                 printf("Free list:\n");
 1919                 while (acb) {
 1920                         osiop_dump_acb(acb);
 1921                         acb = TAILQ_NEXT(acb, chain);
 1922                 }
 1923         }
 1924         if ((acb = TAILQ_FIRST(&sc->ready_list)) != NULL) {
 1925                 printf("Ready list:\n");
 1926                 while (acb) {
 1927                         osiop_dump_acb(acb);
 1928                         acb = TAILQ_NEXT(acb, chain);
 1929                 }
 1930         }
 1931         if ((acb = TAILQ_FIRST(&sc->nexus_list)) != NULL) {
 1932                 printf("Nexus list:\n");
 1933                 while (acb) {
 1934                         osiop_dump_acb(acb);
 1935                         acb = TAILQ_NEXT(acb, chain);
 1936                 }
 1937         }
 1938         if (sc->sc_nexus) {
 1939                 printf("Nexus:\n");
 1940                 osiop_dump_acb(sc->sc_nexus);
 1941         }
 1942         for (i = 0; i < OSIOP_NTGT; i++) {
 1943                 if (sc->sc_tinfo[i].cmds > 2) {
 1944                         printf("tgt %d: cmds %d disc %d lubusy %x\n",
 1945                             i, sc->sc_tinfo[i].cmds,
 1946                             sc->sc_tinfo[i].dconns,
 1947                             sc->sc_tinfo[i].lubusy);
 1948                 }
 1949         }
 1950         splx(s);
 1951 }
 1952 #endif

Cache object: 5514b6b20288d49f202537cdff4ca41a


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