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

Cache object: 22986b52fbf3d41144600450b67b3fb9


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