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

Cache object: ddce1af1f2b9f02e5e99a323a987e04b


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