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/esiop.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: esiop.c,v 1.27 2004/03/16 19:10:43 bouyer Exp $        */
    2 
    3 /*
    4  * Copyright (c) 2002 Manuel Bouyer.
    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. All advertising materials mentioning features or use of this software
   15  *    must display the following acknowledgement:
   16  *      This product includes software developed by Manuel Bouyer.
   17  * 4. The name of the author may not be used to endorse or promote products
   18  *    derived from this software without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   30  *
   31  */
   32 
   33 /* SYM53c7/8xx PCI-SCSI I/O Processors driver */
   34 
   35 #include <sys/cdefs.h>
   36 __KERNEL_RCSID(0, "$NetBSD: esiop.c,v 1.27 2004/03/16 19:10:43 bouyer Exp $");
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/device.h>
   41 #include <sys/malloc.h>
   42 #include <sys/buf.h>
   43 #include <sys/kernel.h>
   44 
   45 #include <uvm/uvm_extern.h>
   46 
   47 #include <machine/endian.h>
   48 #include <machine/bus.h>
   49 
   50 #include <dev/microcode/siop/esiop.out>
   51 
   52 #include <dev/scsipi/scsi_all.h>
   53 #include <dev/scsipi/scsi_message.h>
   54 #include <dev/scsipi/scsipi_all.h>
   55 
   56 #include <dev/scsipi/scsiconf.h>
   57 
   58 #include <dev/ic/siopreg.h>
   59 #include <dev/ic/siopvar_common.h>
   60 #include <dev/ic/esiopvar.h>
   61 
   62 #include "opt_siop.h"
   63 
   64 #ifndef DEBUG
   65 #undef DEBUG
   66 #endif
   67 #undef SIOP_DEBUG
   68 #undef SIOP_DEBUG_DR
   69 #undef SIOP_DEBUG_INTR
   70 #undef SIOP_DEBUG_SCHED
   71 #undef DUMP_SCRIPT
   72 
   73 #define SIOP_STATS
   74 
   75 #ifndef SIOP_DEFAULT_TARGET
   76 #define SIOP_DEFAULT_TARGET 7
   77 #endif
   78 
   79 /* number of cmd descriptors per block */
   80 #define SIOP_NCMDPB (PAGE_SIZE / sizeof(struct esiop_xfer))
   81 
   82 void    esiop_reset __P((struct esiop_softc *));
   83 void    esiop_checkdone __P((struct esiop_softc *));
   84 void    esiop_handle_reset __P((struct esiop_softc *));
   85 void    esiop_scsicmd_end __P((struct esiop_cmd *));
   86 void    esiop_unqueue __P((struct esiop_softc *, int, int));
   87 int     esiop_handle_qtag_reject __P((struct esiop_cmd *));
   88 static void     esiop_start __P((struct esiop_softc *, struct esiop_cmd *));
   89 void    esiop_timeout __P((void *));
   90 void    esiop_scsipi_request __P((struct scsipi_channel *,
   91                         scsipi_adapter_req_t, void *));
   92 void    esiop_dump_script __P((struct esiop_softc *));
   93 void    esiop_morecbd __P((struct esiop_softc *));
   94 void    esiop_moretagtbl __P((struct esiop_softc *));
   95 void    siop_add_reselsw __P((struct esiop_softc *, int));
   96 void    esiop_target_register __P((struct esiop_softc *, u_int32_t));
   97 
   98 void    esiop_update_scntl3 __P((struct esiop_softc *,
   99                         struct siop_common_target *));
  100 
  101 #ifdef SIOP_STATS
  102 static int esiop_stat_intr = 0;
  103 static int esiop_stat_intr_shortxfer = 0;
  104 static int esiop_stat_intr_sdp = 0;
  105 static int esiop_stat_intr_done = 0;
  106 static int esiop_stat_intr_xferdisc = 0;
  107 static int esiop_stat_intr_lunresel = 0;
  108 static int esiop_stat_intr_qfull = 0;
  109 void esiop_printstats __P((void));
  110 #define INCSTAT(x) x++
  111 #else
  112 #define INCSTAT(x)
  113 #endif
  114 
  115 static __inline__ void esiop_script_sync __P((struct esiop_softc *, int));
  116 static __inline__ void
  117 esiop_script_sync(sc, ops)
  118         struct esiop_softc *sc;
  119         int ops;
  120 {
  121         if ((sc->sc_c.features & SF_CHIP_RAM) == 0)
  122                 bus_dmamap_sync(sc->sc_c.sc_dmat, sc->sc_c.sc_scriptdma, 0,
  123                     PAGE_SIZE, ops);
  124 }
  125 
  126 static __inline__ u_int32_t esiop_script_read __P((struct esiop_softc *, u_int));
  127 static __inline__ u_int32_t
  128 esiop_script_read(sc, offset)
  129         struct esiop_softc *sc;
  130         u_int offset;
  131 {
  132         if (sc->sc_c.features & SF_CHIP_RAM) {
  133                 return bus_space_read_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh,
  134                     offset * 4);
  135         } else {
  136                 return le32toh(sc->sc_c.sc_script[offset]);
  137         }
  138 }
  139 
  140 static __inline__ void esiop_script_write __P((struct esiop_softc *, u_int,
  141         u_int32_t));
  142 static __inline__ void
  143 esiop_script_write(sc, offset, val)
  144         struct esiop_softc *sc;
  145         u_int offset;
  146         u_int32_t val;
  147 {
  148         if (sc->sc_c.features & SF_CHIP_RAM) {
  149                 bus_space_write_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh,
  150                     offset * 4, val);
  151         } else {
  152                 sc->sc_c.sc_script[offset] = htole32(val);
  153         }
  154 }
  155 
  156 void
  157 esiop_attach(sc)
  158         struct esiop_softc *sc;
  159 {
  160         struct esiop_dsatbl *tagtbl_donering;
  161 
  162         if (siop_common_attach(&sc->sc_c) != 0 )
  163                 return;
  164 
  165         TAILQ_INIT(&sc->free_list);
  166         TAILQ_INIT(&sc->cmds);
  167         TAILQ_INIT(&sc->free_tagtbl);
  168         TAILQ_INIT(&sc->tag_tblblk);
  169         sc->sc_currschedslot = 0;
  170 #ifdef SIOP_DEBUG
  171         aprint_debug("%s: script size = %d, PHY addr=0x%x, VIRT=%p\n",
  172             sc->sc_c.sc_dev.dv_xname, (int)sizeof(esiop_script),
  173             (u_int32_t)sc->sc_c.sc_scriptaddr, sc->sc_c.sc_script);
  174 #endif
  175 
  176         sc->sc_c.sc_adapt.adapt_max_periph = ESIOP_NTAG;
  177         sc->sc_c.sc_adapt.adapt_request = esiop_scsipi_request;
  178 
  179         /*
  180          * get space for the CMD done slot. For this we use a tag table entry.
  181          * It's the same size and allows us to not waste 3/4 of a page
  182          */
  183 #ifdef DIAGNOSTIC
  184         if (ESIOP_NTAG != A_ndone_slots) {
  185                 aprint_error("%s: size of tag DSA table different from the done"
  186                     " ring\n", sc->sc_c.sc_dev.dv_xname);
  187                 return;
  188         }
  189 #endif
  190         esiop_moretagtbl(sc);
  191         tagtbl_donering = TAILQ_FIRST(&sc->free_tagtbl);
  192         if (tagtbl_donering == NULL) {
  193                 aprint_error("%s: no memory for command done ring\n",
  194                     sc->sc_c.sc_dev.dv_xname);
  195                 return;
  196         }
  197         TAILQ_REMOVE(&sc->free_tagtbl, tagtbl_donering, next);
  198         sc->sc_done_map = tagtbl_donering->tblblk->blkmap;
  199         sc->sc_done_offset = tagtbl_donering->tbl_offset;
  200         sc->sc_done_slot = &tagtbl_donering->tbl[0];
  201 
  202         /* Do a bus reset, so that devices fall back to narrow/async */
  203         siop_resetbus(&sc->sc_c);
  204         /*
  205          * siop_reset() will reset the chip, thus clearing pending interrupts
  206          */
  207         esiop_reset(sc);
  208 #ifdef DUMP_SCRIPT
  209         esiop_dump_script(sc);
  210 #endif
  211 
  212         config_found((struct device*)sc, &sc->sc_c.sc_chan, scsiprint);
  213 }
  214 
  215 void
  216 esiop_reset(sc)
  217         struct esiop_softc *sc;
  218 {
  219         int i, j;
  220         u_int32_t addr;
  221         u_int32_t msgin_addr, sem_addr;
  222 
  223         siop_common_reset(&sc->sc_c);
  224 
  225         /*
  226          * we copy the script at the beggining of RAM. Then there is 4 bytes
  227          * for messages in, and 4 bytes for semaphore
  228          */
  229         sc->sc_free_offset = sizeof(esiop_script) / sizeof(esiop_script[0]);
  230         msgin_addr =
  231             sc->sc_free_offset * sizeof(u_int32_t) + sc->sc_c.sc_scriptaddr;
  232         sc->sc_free_offset += 1;
  233         sc->sc_semoffset = sc->sc_free_offset;
  234         sem_addr =
  235             sc->sc_semoffset * sizeof(u_int32_t) + sc->sc_c.sc_scriptaddr;
  236         sc->sc_free_offset += 1;
  237         /* then we have the scheduler ring */
  238         sc->sc_shedoffset = sc->sc_free_offset;
  239         sc->sc_free_offset += A_ncmd_slots * CMD_SLOTSIZE;
  240         /* then the targets DSA table */
  241         sc->sc_target_table_offset = sc->sc_free_offset;
  242         sc->sc_free_offset += sc->sc_c.sc_chan.chan_ntargets;
  243         /* copy and patch the script */
  244         if (sc->sc_c.features & SF_CHIP_RAM) {
  245                 bus_space_write_region_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh, 0,
  246                     esiop_script,
  247                     sizeof(esiop_script) / sizeof(esiop_script[0]));
  248                 for (j = 0; j <
  249                     (sizeof(E_tlq_offset_Used) / sizeof(E_tlq_offset_Used[0]));
  250                     j++) {
  251                         bus_space_write_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh,
  252                             E_tlq_offset_Used[j] * 4,
  253                             sizeof(struct siop_common_xfer));
  254                 }
  255                 for (j = 0; j <
  256                     (sizeof(E_abs_msgin2_Used) / sizeof(E_abs_msgin2_Used[0]));
  257                     j++) {
  258                         bus_space_write_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh,
  259                             E_abs_msgin2_Used[j] * 4, msgin_addr);
  260                 }
  261                 for (j = 0; j <
  262                     (sizeof(E_abs_sem_Used) / sizeof(E_abs_sem_Used[0]));
  263                     j++) {
  264                         bus_space_write_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh,
  265                             E_abs_sem_Used[j] * 4, sem_addr);
  266                 }
  267 
  268                 if (sc->sc_c.features & SF_CHIP_LED0) {
  269                         bus_space_write_region_4(sc->sc_c.sc_ramt,
  270                             sc->sc_c.sc_ramh,
  271                             Ent_led_on1, esiop_led_on,
  272                             sizeof(esiop_led_on) / sizeof(esiop_led_on[0]));
  273                         bus_space_write_region_4(sc->sc_c.sc_ramt,
  274                             sc->sc_c.sc_ramh,
  275                             Ent_led_on2, esiop_led_on,
  276                             sizeof(esiop_led_on) / sizeof(esiop_led_on[0]));
  277                         bus_space_write_region_4(sc->sc_c.sc_ramt,
  278                             sc->sc_c.sc_ramh,
  279                             Ent_led_off, esiop_led_off,
  280                             sizeof(esiop_led_off) / sizeof(esiop_led_off[0]));
  281                 }
  282         } else {
  283                 for (j = 0;
  284                     j < (sizeof(esiop_script) / sizeof(esiop_script[0])); j++) {
  285                         sc->sc_c.sc_script[j] = htole32(esiop_script[j]);
  286                 }
  287                 for (j = 0; j <
  288                     (sizeof(E_tlq_offset_Used) / sizeof(E_tlq_offset_Used[0]));
  289                     j++) {
  290                         sc->sc_c.sc_script[E_tlq_offset_Used[j]] =
  291                             htole32(sizeof(struct siop_common_xfer));
  292                 }
  293                 for (j = 0; j <
  294                     (sizeof(E_abs_msgin2_Used) / sizeof(E_abs_msgin2_Used[0]));
  295                     j++) {
  296                         sc->sc_c.sc_script[E_abs_msgin2_Used[j]] =
  297                             htole32(msgin_addr);
  298                 }
  299                 for (j = 0; j <
  300                     (sizeof(E_abs_sem_Used) / sizeof(E_abs_sem_Used[0]));
  301                     j++) {
  302                         sc->sc_c.sc_script[E_abs_sem_Used[j]] =
  303                             htole32(sem_addr);
  304                 }
  305 
  306                 if (sc->sc_c.features & SF_CHIP_LED0) {
  307                         for (j = 0; j < (sizeof(esiop_led_on) /
  308                             sizeof(esiop_led_on[0])); j++)
  309                                 sc->sc_c.sc_script[
  310                                     Ent_led_on1 / sizeof(esiop_led_on[0]) + j
  311                                     ] = htole32(esiop_led_on[j]);
  312                         for (j = 0; j < (sizeof(esiop_led_on) /
  313                             sizeof(esiop_led_on[0])); j++)
  314                                 sc->sc_c.sc_script[
  315                                     Ent_led_on2 / sizeof(esiop_led_on[0]) + j
  316                                     ] = htole32(esiop_led_on[j]);
  317                         for (j = 0; j < (sizeof(esiop_led_off) /
  318                             sizeof(esiop_led_off[0])); j++)
  319                                 sc->sc_c.sc_script[
  320                                    Ent_led_off / sizeof(esiop_led_off[0]) + j
  321                                    ] = htole32(esiop_led_off[j]);
  322                 }
  323         }
  324         /* get base of scheduler ring */
  325         addr = sc->sc_c.sc_scriptaddr + sc->sc_shedoffset * sizeof(u_int32_t);
  326         /* init scheduler */
  327         for (i = 0; i < A_ncmd_slots; i++) {
  328                 esiop_script_write(sc,
  329                     sc->sc_shedoffset + i * CMD_SLOTSIZE, A_f_cmd_free);
  330         }
  331         sc->sc_currschedslot = 0;
  332         bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_SCRATCHE, 0);
  333         bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_SCRATCHD, addr);
  334         /*
  335          * 0x78000000 is a 'move data8 to reg'. data8 is the second
  336          * octet, reg offset is the third.
  337          */
  338         esiop_script_write(sc, Ent_cmdr0 / 4,
  339             0x78640000 | ((addr & 0x000000ff) <<  8));
  340         esiop_script_write(sc, Ent_cmdr1 / 4,
  341             0x78650000 | ((addr & 0x0000ff00)      ));
  342         esiop_script_write(sc, Ent_cmdr2 / 4,
  343             0x78660000 | ((addr & 0x00ff0000) >>  8));
  344         esiop_script_write(sc, Ent_cmdr3 / 4,
  345             0x78670000 | ((addr & 0xff000000) >> 16));
  346         /* done ring */
  347         for (i = 0; i < A_ndone_slots; i++)
  348                 sc->sc_done_slot[i] = 0;
  349         bus_dmamap_sync(sc->sc_c.sc_dmat, sc->sc_done_map,
  350             sc->sc_done_offset, A_ndone_slots * sizeof(u_int32_t),
  351             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
  352         addr = sc->sc_done_map->dm_segs[0].ds_addr + sc->sc_done_offset;
  353         sc->sc_currdoneslot = 0;
  354         bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_SCRATCHE + 2, 0);
  355         bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_SCRATCHF, addr);
  356         esiop_script_write(sc, Ent_doner0 / 4,
  357             0x786c0000 | ((addr & 0x000000ff) <<  8));
  358         esiop_script_write(sc, Ent_doner1 / 4,
  359             0x786d0000 | ((addr & 0x0000ff00)      ));
  360         esiop_script_write(sc, Ent_doner2 / 4,
  361             0x786e0000 | ((addr & 0x00ff0000) >>  8));
  362         esiop_script_write(sc, Ent_doner3 / 4,
  363             0x786f0000 | ((addr & 0xff000000) >> 16));
  364 
  365         /* set flags */
  366         bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_SCRATCHC, 0);
  367         /* write pointer of base of target DSA table */
  368         addr = (sc->sc_target_table_offset * sizeof(u_int32_t)) +
  369             sc->sc_c.sc_scriptaddr;
  370         esiop_script_write(sc, (Ent_load_targtable / 4) + 0,
  371             esiop_script_read(sc,(Ent_load_targtable / 4) + 0) |
  372             ((addr & 0x000000ff) <<  8));
  373         esiop_script_write(sc, (Ent_load_targtable / 4) + 2,
  374             esiop_script_read(sc,(Ent_load_targtable / 4) + 2) |
  375             ((addr & 0x0000ff00)      ));
  376         esiop_script_write(sc, (Ent_load_targtable / 4) + 4,
  377             esiop_script_read(sc,(Ent_load_targtable / 4) + 4) |
  378             ((addr & 0x00ff0000) >>  8));
  379         esiop_script_write(sc, (Ent_load_targtable / 4) + 6,
  380             esiop_script_read(sc,(Ent_load_targtable / 4) + 6) |
  381             ((addr & 0xff000000) >> 16));
  382 #ifdef SIOP_DEBUG
  383         printf("%s: target table offset %d free offset %d\n",
  384             sc->sc_c.sc_dev.dv_xname, sc->sc_target_table_offset,
  385             sc->sc_free_offset);
  386 #endif
  387 
  388         /* register existing targets */
  389         for (i = 0; i < sc->sc_c.sc_chan.chan_ntargets; i++) {
  390                 if (sc->sc_c.targets[i])
  391                         esiop_target_register(sc, i);
  392         }
  393         /* start script */
  394         if ((sc->sc_c.features & SF_CHIP_RAM) == 0) {
  395                 bus_dmamap_sync(sc->sc_c.sc_dmat, sc->sc_c.sc_scriptdma, 0,
  396                     PAGE_SIZE, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
  397         }
  398         bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSP,
  399             sc->sc_c.sc_scriptaddr + Ent_reselect);
  400 }
  401 
  402 #if 0
  403 #define CALL_SCRIPT(ent) do {\
  404         printf ("start script DSA 0x%lx DSP 0x%lx\n", \
  405             esiop_cmd->cmd_c.dsa, \
  406             sc->sc_c.sc_scriptaddr + ent); \
  407 bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSP, sc->sc_c.sc_scriptaddr + ent); \
  408 } while (0)
  409 #else
  410 #define CALL_SCRIPT(ent) do {\
  411 bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSP, sc->sc_c.sc_scriptaddr + ent); \
  412 } while (0)
  413 #endif
  414 
  415 int
  416 esiop_intr(v)
  417         void *v;
  418 {
  419         struct esiop_softc *sc = v;
  420         struct esiop_target *esiop_target;
  421         struct esiop_cmd *esiop_cmd;
  422         struct esiop_lun *esiop_lun;
  423         struct scsipi_xfer *xs;
  424         int istat, sist, sstat1, dstat = 0; /* XXX: gcc */
  425         u_int32_t irqcode;
  426         int need_reset = 0;
  427         int offset, target, lun, tag;
  428         u_int32_t tflags;
  429         u_int32_t addr;
  430         int freetarget = 0;
  431         int slot;
  432         int retval = 0;
  433 
  434 again:
  435         istat = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_ISTAT);
  436         if ((istat & (ISTAT_INTF | ISTAT_DIP | ISTAT_SIP)) == 0) {
  437                 return retval;
  438         }
  439         retval = 1;
  440         INCSTAT(esiop_stat_intr);
  441         esiop_checkdone(sc);
  442         if (istat & ISTAT_INTF) {
  443                 bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
  444                     SIOP_ISTAT, ISTAT_INTF);
  445                 goto again;
  446         }
  447 
  448         if ((istat &(ISTAT_DIP | ISTAT_SIP | ISTAT_ABRT)) ==
  449             (ISTAT_DIP | ISTAT_ABRT)) {
  450                 /* clear abort */
  451                 bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
  452                     SIOP_ISTAT, 0);
  453         }
  454 
  455         /* get CMD from T/L/Q */
  456         tflags = bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
  457             SIOP_SCRATCHC);
  458 #ifdef SIOP_DEBUG_INTR
  459                 printf("interrupt, istat=0x%x tflags=0x%x "
  460                     "DSA=0x%x DSP=0x%lx\n", istat, tflags,
  461                     bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA),
  462                     (u_long)(bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
  463                         SIOP_DSP) -
  464                     sc->sc_c.sc_scriptaddr));
  465 #endif
  466         target = (tflags & A_f_c_target) ? ((tflags >> 8) & 0xff) : -1;
  467         if (target > sc->sc_c.sc_chan.chan_ntargets) target = -1;
  468         lun = (tflags & A_f_c_lun) ? ((tflags >> 16) & 0xff) : -1;
  469         if (lun > sc->sc_c.sc_chan.chan_nluns) lun = -1;
  470         tag = (tflags & A_f_c_tag) ? ((tflags >> 24) & 0xff) : -1;
  471 
  472         if (target >= 0 && lun >= 0) {
  473                 esiop_target = (struct esiop_target *)sc->sc_c.targets[target];
  474                 if (esiop_target == NULL) {
  475                         printf("esiop_target (target %d) not valid\n", target);
  476                         goto none;
  477                 }
  478                 esiop_lun = esiop_target->esiop_lun[lun];
  479                 if (esiop_lun == NULL) {
  480                         printf("esiop_lun (target %d lun %d) not valid\n",
  481                             target, lun);
  482                         goto none;
  483                 }
  484                 esiop_cmd =
  485                     (tag >= 0) ? esiop_lun->tactive[tag] : esiop_lun->active;
  486                 if (esiop_cmd == NULL) {
  487                         printf("esiop_cmd (target %d lun %d tag %d) not valid\n",
  488                             target, lun, tag);
  489                         goto none;
  490                 }
  491                 xs = esiop_cmd->cmd_c.xs;
  492 #ifdef DIAGNOSTIC
  493                 if (esiop_cmd->cmd_c.status != CMDST_ACTIVE) {
  494                         printf("esiop_cmd (target %d lun %d) "
  495                             "not active (%d)\n", target, lun,
  496                             esiop_cmd->cmd_c.status);
  497                         goto none;
  498                 }
  499 #endif
  500                 esiop_table_sync(esiop_cmd,
  501                     BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
  502         } else {
  503 none:
  504                 xs = NULL;
  505                 esiop_target = NULL;
  506                 esiop_lun = NULL;
  507                 esiop_cmd = NULL;
  508         }
  509         if (istat & ISTAT_DIP) {
  510                 dstat = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
  511                     SIOP_DSTAT);
  512                 if (dstat & DSTAT_ABRT) {
  513                         /* was probably generated by a bus reset IOCTL */
  514                         if ((dstat & DSTAT_DFE) == 0)
  515                                 siop_clearfifo(&sc->sc_c);
  516                         goto reset;
  517                 }
  518                 if (dstat & DSTAT_SSI) {
  519                         printf("single step dsp 0x%08x dsa 0x08%x\n",
  520                             (int)(bus_space_read_4(sc->sc_c.sc_rt,
  521                             sc->sc_c.sc_rh, SIOP_DSP) -
  522                             sc->sc_c.sc_scriptaddr),
  523                             bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
  524                                 SIOP_DSA));
  525                         if ((dstat & ~(DSTAT_DFE | DSTAT_SSI)) == 0 &&
  526                             (istat & ISTAT_SIP) == 0) {
  527                                 bus_space_write_1(sc->sc_c.sc_rt,
  528                                     sc->sc_c.sc_rh, SIOP_DCNTL,
  529                                     bus_space_read_1(sc->sc_c.sc_rt,
  530                                     sc->sc_c.sc_rh, SIOP_DCNTL) | DCNTL_STD);
  531                         }
  532                         return 1;
  533                 }
  534 
  535                 if (dstat & ~(DSTAT_SIR | DSTAT_DFE | DSTAT_SSI)) {
  536                 printf("%s: DMA IRQ:", sc->sc_c.sc_dev.dv_xname);
  537                 if (dstat & DSTAT_IID)
  538                         printf(" Illegal instruction");
  539                 if (dstat & DSTAT_BF)
  540                         printf(" bus fault");
  541                 if (dstat & DSTAT_MDPE)
  542                         printf(" parity");
  543                 if (dstat & DSTAT_DFE)
  544                         printf(" DMA fifo empty");
  545                 else
  546                         siop_clearfifo(&sc->sc_c);
  547                 printf(", DSP=0x%x DSA=0x%x: ",
  548                     (int)(bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
  549                         SIOP_DSP) - sc->sc_c.sc_scriptaddr),
  550                     bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA));
  551                 if (esiop_cmd)
  552                         printf("T/L/Q=%d/%d/%d last msg_in=0x%x status=0x%x\n",
  553                             target, lun, tag, esiop_cmd->cmd_tables->msg_in[0],
  554                             le32toh(esiop_cmd->cmd_tables->status));
  555                 else
  556                         printf(" current T/L/Q invalid\n");
  557                 need_reset = 1;
  558                 }
  559         }
  560         if (istat & ISTAT_SIP) {
  561                 if (istat & ISTAT_DIP)
  562                         delay(10);
  563                 /*
  564                  * Can't read sist0 & sist1 independently, or we have to
  565                  * insert delay
  566                  */
  567                 sist = bus_space_read_2(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
  568                     SIOP_SIST0);
  569                 sstat1 = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
  570                     SIOP_SSTAT1);
  571 #ifdef SIOP_DEBUG_INTR
  572                 printf("scsi interrupt, sist=0x%x sstat1=0x%x "
  573                     "DSA=0x%x DSP=0x%lx\n", sist, sstat1,
  574                     bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA),
  575                     (u_long)(bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
  576                         SIOP_DSP) -
  577                     sc->sc_c.sc_scriptaddr));
  578 #endif
  579                 if (sist & SIST0_RST) {
  580                         esiop_handle_reset(sc);
  581                         /* no table to flush here */
  582                         return 1;
  583                 }
  584                 if (sist & SIST0_SGE) {
  585                         if (esiop_cmd)
  586                                 scsipi_printaddr(xs->xs_periph);
  587                         else
  588                                 printf("%s:", sc->sc_c.sc_dev.dv_xname);
  589                         printf("scsi gross error\n");
  590                         if (esiop_target)
  591                                 esiop_target->target_c.flags &= ~TARF_DT;
  592 #ifdef DEBUG
  593                         printf("DSA=0x%x DSP=0x%lx\n",
  594                             bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA),
  595                             (u_long)(bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
  596                                 SIOP_DSP) -
  597                             sc->sc_c.sc_scriptaddr));
  598                         printf("SDID 0x%x SCNTL3 0x%x SXFER 0x%x SCNTL4 0x%x\n",
  599                             bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_SDID),
  600                              bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_SCNTL3),
  601                              bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_SXFER),
  602                              bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_SCNTL4));
  603 
  604 #endif
  605                         goto reset;
  606                 }
  607                 if ((sist & SIST0_MA) && need_reset == 0) {
  608                         if (esiop_cmd) {
  609                                 int scratchc0;
  610                                 dstat = bus_space_read_1(sc->sc_c.sc_rt,
  611                                     sc->sc_c.sc_rh, SIOP_DSTAT);
  612                                 /*
  613                                  * first restore DSA, in case we were in a S/G
  614                                  * operation.
  615                                  */
  616                                 bus_space_write_4(sc->sc_c.sc_rt,
  617                                     sc->sc_c.sc_rh,
  618                                     SIOP_DSA, esiop_cmd->cmd_c.dsa);
  619                                 scratchc0 = bus_space_read_1(sc->sc_c.sc_rt,
  620                                     sc->sc_c.sc_rh, SIOP_SCRATCHC);
  621                                 switch (sstat1 & SSTAT1_PHASE_MASK) {
  622                                 case SSTAT1_PHASE_STATUS:
  623                                 /*
  624                                  * previous phase may be aborted for any reason
  625                                  * ( for example, the target has less data to
  626                                  * transfer than requested). Just go to status
  627                                  * and the command should terminate.
  628                                  */
  629                                         INCSTAT(esiop_stat_intr_shortxfer);
  630                                         if ((dstat & DSTAT_DFE) == 0)
  631                                                 siop_clearfifo(&sc->sc_c);
  632                                         /* no table to flush here */
  633                                         CALL_SCRIPT(Ent_status);
  634                                         return 1;
  635                                 case SSTAT1_PHASE_MSGIN:
  636                                         /*
  637                                          * target may be ready to disconnect
  638                                          * Save data pointers just in case.
  639                                          */
  640                                         INCSTAT(esiop_stat_intr_xferdisc);
  641                                         if (scratchc0 & A_f_c_data)
  642                                                 siop_sdp(&esiop_cmd->cmd_c);
  643                                         else if ((dstat & DSTAT_DFE) == 0)
  644                                                 siop_clearfifo(&sc->sc_c);
  645                                         bus_space_write_1(sc->sc_c.sc_rt,
  646                                             sc->sc_c.sc_rh, SIOP_SCRATCHC,
  647                                             scratchc0 & ~A_f_c_data);
  648                                         esiop_table_sync(esiop_cmd,
  649                                             BUS_DMASYNC_PREREAD |
  650                                             BUS_DMASYNC_PREWRITE);
  651                                         CALL_SCRIPT(Ent_msgin);
  652                                         return 1;
  653                                 }
  654                                 printf("%s: unexpected phase mismatch %d\n",
  655                                     sc->sc_c.sc_dev.dv_xname,
  656                                     sstat1 & SSTAT1_PHASE_MASK);
  657                         } else {
  658                                 printf("%s: phase mismatch without command\n",
  659                                     sc->sc_c.sc_dev.dv_xname);
  660                         }
  661                         need_reset = 1;
  662                 }
  663                 if (sist & SIST0_PAR) {
  664                         /* parity error, reset */
  665                         if (esiop_cmd)
  666                                 scsipi_printaddr(xs->xs_periph);
  667                         else
  668                                 printf("%s:", sc->sc_c.sc_dev.dv_xname);
  669                         printf("parity error\n");
  670                         if (esiop_target)
  671                                 esiop_target->target_c.flags &= ~TARF_DT;
  672                         goto reset;
  673                 }
  674                 if ((sist & (SIST1_STO << 8)) && need_reset == 0) {
  675                         /*
  676                          * selection time out, assume there's no device here
  677                          * We also have to update the ring pointer ourselve
  678                          */
  679                         slot = bus_space_read_1(sc->sc_c.sc_rt,
  680                             sc->sc_c.sc_rh, SIOP_SCRATCHE);
  681                         esiop_script_sync(sc,
  682                             BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
  683 #ifdef SIOP_DEBUG_SCHED
  684                         printf("sel timeout target %d, slot %d\n", target, slot);
  685 #endif
  686                         /*
  687                          * mark this slot as free, and advance to next slot
  688                          */
  689                         esiop_script_write(sc,
  690                             sc->sc_shedoffset + slot * CMD_SLOTSIZE,
  691                             A_f_cmd_free);
  692                         addr = bus_space_read_4(sc->sc_c.sc_rt,
  693                                     sc->sc_c.sc_rh, SIOP_SCRATCHD);
  694                         if (slot < (A_ncmd_slots - 1)) {
  695                                 bus_space_write_1(sc->sc_c.sc_rt,
  696                                     sc->sc_c.sc_rh, SIOP_SCRATCHE, slot + 1);
  697                                 addr = addr + sizeof(struct esiop_slot);
  698                         } else {
  699                                 bus_space_write_1(sc->sc_c.sc_rt,
  700                                     sc->sc_c.sc_rh, SIOP_SCRATCHE, 0);
  701                                 addr = sc->sc_c.sc_scriptaddr +
  702                                     sc->sc_shedoffset * sizeof(u_int32_t);
  703                         }
  704                         bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
  705                             SIOP_SCRATCHD, addr);
  706                         esiop_script_sync(sc,
  707                             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
  708                         if (esiop_cmd) {
  709                                 esiop_cmd->cmd_c.status = CMDST_DONE;
  710                                 xs->error = XS_SELTIMEOUT;
  711                                 freetarget = 1;
  712                                 goto end;
  713                         } else {
  714                                 printf("%s: selection timeout without "
  715                                     "command, target %d (sdid 0x%x), "
  716                                     "slot %d\n",
  717                                     sc->sc_c.sc_dev.dv_xname, target,
  718                                     bus_space_read_1(sc->sc_c.sc_rt,
  719                                     sc->sc_c.sc_rh, SIOP_SDID), slot);
  720                                 need_reset = 1;
  721                         }
  722                 }
  723                 if (sist & SIST0_UDC) {
  724                         /*
  725                          * unexpected disconnect. Usually the target signals
  726                          * a fatal condition this way. Attempt to get sense.
  727                          */
  728                          if (esiop_cmd) {
  729                                 esiop_cmd->cmd_tables->status =
  730                                     htole32(SCSI_CHECK);
  731                                 goto end;
  732                         }
  733                         printf("%s: unexpected disconnect without "
  734                             "command\n", sc->sc_c.sc_dev.dv_xname);
  735                         goto reset;
  736                 }
  737                 if (sist & (SIST1_SBMC << 8)) {
  738                         /* SCSI bus mode change */
  739                         if (siop_modechange(&sc->sc_c) == 0 || need_reset == 1)
  740                                 goto reset;
  741                         if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) {
  742                                 /*
  743                                  * we have a script interrupt, it will
  744                                  * restart the script.
  745                                  */
  746                                 goto scintr;
  747                         }
  748                         /*
  749                          * else we have to restart it ourselve, at the
  750                          * interrupted instruction.
  751                          */
  752                         bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
  753                             SIOP_DSP,
  754                             bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
  755                             SIOP_DSP) - 8);
  756                         return 1;
  757                 }
  758                 /* Else it's an unhandled exception (for now). */
  759                 printf("%s: unhandled scsi interrupt, sist=0x%x sstat1=0x%x "
  760                     "DSA=0x%x DSP=0x%x\n", sc->sc_c.sc_dev.dv_xname, sist,
  761                     bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
  762                         SIOP_SSTAT1),
  763                     bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA),
  764                     (int)(bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
  765                         SIOP_DSP) - sc->sc_c.sc_scriptaddr));
  766                 if (esiop_cmd) {
  767                         esiop_cmd->cmd_c.status = CMDST_DONE;
  768                         xs->error = XS_SELTIMEOUT;
  769                         goto end;
  770                 }
  771                 need_reset = 1;
  772         }
  773         if (need_reset) {
  774 reset:
  775                 /* fatal error, reset the bus */
  776                 siop_resetbus(&sc->sc_c);
  777                 /* no table to flush here */
  778                 return 1;
  779         }
  780 
  781 scintr:
  782         if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */
  783                 irqcode = bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
  784                     SIOP_DSPS);
  785 #ifdef SIOP_DEBUG_INTR
  786                 printf("script interrupt 0x%x\n", irqcode);
  787 #endif
  788                 /*
  789                  * no command, or an inactive command is only valid for a
  790                  * reselect interrupt
  791                  */
  792                 if ((irqcode & 0x80) == 0) {
  793                         if (esiop_cmd == NULL) {
  794                                 printf(
  795                         "%s: script interrupt (0x%x) with invalid DSA !!!\n",
  796                                     sc->sc_c.sc_dev.dv_xname, irqcode);
  797                                 goto reset;
  798                         }
  799                         if (esiop_cmd->cmd_c.status != CMDST_ACTIVE) {
  800                                 printf("%s: command with invalid status "
  801                                     "(IRQ code 0x%x current status %d) !\n",
  802                                     sc->sc_c.sc_dev.dv_xname,
  803                                     irqcode, esiop_cmd->cmd_c.status);
  804                                 xs = NULL;
  805                         }
  806                 }
  807                 switch(irqcode) {
  808                 case A_int_err:
  809                         printf("error, DSP=0x%x\n",
  810                             (int)(bus_space_read_4(sc->sc_c.sc_rt,
  811                             sc->sc_c.sc_rh, SIOP_DSP) - sc->sc_c.sc_scriptaddr));
  812                         if (xs) {
  813                                 xs->error = XS_SELTIMEOUT;
  814                                 goto end;
  815                         } else {
  816                                 goto reset;
  817                         }
  818                 case A_int_msgin:
  819                 {
  820                         int msgin = bus_space_read_1(sc->sc_c.sc_rt,
  821                             sc->sc_c.sc_rh, SIOP_SFBR);
  822                         if (msgin == MSG_MESSAGE_REJECT) {
  823                                 int msg, extmsg;
  824                                 if (esiop_cmd->cmd_tables->msg_out[0] & 0x80) {
  825                                         /*
  826                                          * message was part of a identify +
  827                                          * something else. Identify shouldn't
  828                                          * have been rejected.
  829                                          */
  830                                         msg =
  831                                             esiop_cmd->cmd_tables->msg_out[1];
  832                                         extmsg =
  833                                             esiop_cmd->cmd_tables->msg_out[3];
  834                                 } else {
  835                                         msg =
  836                                             esiop_cmd->cmd_tables->msg_out[0];
  837                                         extmsg =
  838                                             esiop_cmd->cmd_tables->msg_out[2];
  839                                 }
  840                                 if (msg == MSG_MESSAGE_REJECT) {
  841                                         /* MSG_REJECT  for a MSG_REJECT  !*/
  842                                         if (xs)
  843                                                 scsipi_printaddr(xs->xs_periph);
  844                                         else
  845                                                 printf("%s: ",
  846                                                    sc->sc_c.sc_dev.dv_xname);
  847                                         printf("our reject message was "
  848                                             "rejected\n");
  849                                         goto reset;
  850                                 }
  851                                 if (msg == MSG_EXTENDED &&
  852                                     extmsg == MSG_EXT_WDTR) {
  853                                         /* WDTR rejected, initiate sync */
  854                                         if ((esiop_target->target_c.flags &
  855                                            TARF_SYNC) == 0) {
  856                                                 esiop_target->target_c.status =
  857                                                     TARST_OK;
  858                                                 siop_update_xfer_mode(&sc->sc_c,
  859                                                     target);
  860                                                 /* no table to flush here */
  861                                                 CALL_SCRIPT(Ent_msgin_ack);
  862                                                 return 1;
  863                                         }
  864                                         esiop_target->target_c.status =
  865                                             TARST_SYNC_NEG;
  866                                         siop_sdtr_msg(&esiop_cmd->cmd_c, 0,
  867                                             sc->sc_c.st_minsync,
  868                                             sc->sc_c.maxoff);
  869                                         esiop_table_sync(esiop_cmd,
  870                                             BUS_DMASYNC_PREREAD |
  871                                             BUS_DMASYNC_PREWRITE);
  872                                         CALL_SCRIPT(Ent_send_msgout);
  873                                         return 1;
  874                                 } else if (msg == MSG_EXTENDED &&
  875                                     extmsg == MSG_EXT_SDTR) {
  876                                         /* sync rejected */
  877                                         esiop_target->target_c.offset = 0;
  878                                         esiop_target->target_c.period = 0;
  879                                         esiop_target->target_c.status =
  880                                             TARST_OK;
  881                                         siop_update_xfer_mode(&sc->sc_c,
  882                                             target);
  883                                         /* no table to flush here */
  884                                         CALL_SCRIPT(Ent_msgin_ack);
  885                                         return 1;
  886                                 } else if (msg == MSG_EXTENDED &&
  887                                     extmsg == MSG_EXT_PPR) {
  888                                         /* PPR rejected */
  889                                         esiop_target->target_c.offset = 0;
  890                                         esiop_target->target_c.period = 0;
  891                                         esiop_target->target_c.status =
  892                                             TARST_OK;
  893                                         siop_update_xfer_mode(&sc->sc_c,
  894                                             target);
  895                                         /* no table to flush here */
  896                                         CALL_SCRIPT(Ent_msgin_ack);
  897                                         return 1;
  898                                 } else if (msg == MSG_SIMPLE_Q_TAG ||
  899                                     msg == MSG_HEAD_OF_Q_TAG ||
  900                                     msg == MSG_ORDERED_Q_TAG) {
  901                                         if (esiop_handle_qtag_reject(
  902                                             esiop_cmd) == -1)
  903                                                 goto reset;
  904                                         CALL_SCRIPT(Ent_msgin_ack);
  905                                         return 1;
  906                                 }
  907                                 if (xs)
  908                                         scsipi_printaddr(xs->xs_periph);
  909                                 else
  910                                         printf("%s: ",
  911                                             sc->sc_c.sc_dev.dv_xname);
  912                                 if (msg == MSG_EXTENDED) {
  913                                         printf("scsi message reject, extended "
  914                                             "message sent was 0x%x\n", extmsg);
  915                                 } else {
  916                                         printf("scsi message reject, message "
  917                                             "sent was 0x%x\n", msg);
  918                                 }
  919                                 /* no table to flush here */
  920                                 CALL_SCRIPT(Ent_msgin_ack);
  921                                 return 1;
  922                         }
  923                         if (xs)
  924                                 scsipi_printaddr(xs->xs_periph);
  925                         else
  926                                 printf("%s: ", sc->sc_c.sc_dev.dv_xname);
  927                         printf("unhandled message 0x%x\n", msgin);
  928                         esiop_cmd->cmd_tables->msg_out[0] = MSG_MESSAGE_REJECT;
  929                         esiop_cmd->cmd_tables->t_msgout.count= htole32(1);
  930                         esiop_table_sync(esiop_cmd,
  931                             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
  932                         CALL_SCRIPT(Ent_send_msgout);
  933                         return 1;
  934                 }
  935                 case A_int_extmsgin:
  936 #ifdef SIOP_DEBUG_INTR
  937                         printf("extended message: msg 0x%x len %d\n",
  938                             esiop_cmd->cmd_tables->msg_in[2],
  939                             esiop_cmd->cmd_tables->msg_in[1]);
  940 #endif
  941                         if (esiop_cmd->cmd_tables->msg_in[1] >
  942                             sizeof(esiop_cmd->cmd_tables->msg_in) - 2)
  943                                 printf("%s: extended message too big (%d)\n",
  944                                     sc->sc_c.sc_dev.dv_xname,
  945                                     esiop_cmd->cmd_tables->msg_in[1]);
  946                         esiop_cmd->cmd_tables->t_extmsgdata.count =
  947                             htole32(esiop_cmd->cmd_tables->msg_in[1] - 1);
  948                         esiop_table_sync(esiop_cmd,
  949                             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
  950                         CALL_SCRIPT(Ent_get_extmsgdata);
  951                         return 1;
  952                 case A_int_extmsgdata:
  953 #ifdef SIOP_DEBUG_INTR
  954                         {
  955                         int i;
  956                         printf("extended message: 0x%x, data:",
  957                             esiop_cmd->cmd_tables->msg_in[2]);
  958                         for (i = 3; i < 2 + esiop_cmd->cmd_tables->msg_in[1];
  959                             i++)
  960                                 printf(" 0x%x",
  961                                     esiop_cmd->cmd_tables->msg_in[i]);
  962                         printf("\n");
  963                         }
  964 #endif
  965                         if (esiop_cmd->cmd_tables->msg_in[2] == MSG_EXT_PPR) {
  966                                 switch (siop_ppr_neg(&esiop_cmd->cmd_c)) {
  967                                 case SIOP_NEG_MSGOUT:
  968                                         esiop_update_scntl3(sc,
  969                                             esiop_cmd->cmd_c.siop_target);
  970                                         esiop_table_sync(esiop_cmd,
  971                                             BUS_DMASYNC_PREREAD |
  972                                             BUS_DMASYNC_PREWRITE);
  973                                         CALL_SCRIPT(Ent_send_msgout);
  974                                         return 1;
  975                                 case SIOP_NEG_ACK:
  976                                         esiop_update_scntl3(sc,
  977                                             esiop_cmd->cmd_c.siop_target);
  978                                         CALL_SCRIPT(Ent_msgin_ack);
  979                                         return 1;
  980                                 default:
  981                                         panic("invalid retval from "
  982                                             "siop_wdtr_neg()");
  983                                 }
  984                                 return 1;
  985                         }
  986                         if (esiop_cmd->cmd_tables->msg_in[2] == MSG_EXT_WDTR) {
  987                                 switch (siop_wdtr_neg(&esiop_cmd->cmd_c)) {
  988                                 case SIOP_NEG_MSGOUT:
  989                                         esiop_update_scntl3(sc,
  990                                             esiop_cmd->cmd_c.siop_target);
  991                                         esiop_table_sync(esiop_cmd,
  992                                             BUS_DMASYNC_PREREAD |
  993                                             BUS_DMASYNC_PREWRITE);
  994                                         CALL_SCRIPT(Ent_send_msgout);
  995                                         return 1;
  996                                 case SIOP_NEG_ACK:
  997                                         esiop_update_scntl3(sc,
  998                                             esiop_cmd->cmd_c.siop_target);
  999                                         CALL_SCRIPT(Ent_msgin_ack);
 1000                                         return 1;
 1001                                 default:
 1002                                         panic("invalid retval from "
 1003                                             "siop_wdtr_neg()");
 1004                                 }
 1005                                 return 1;
 1006                         }
 1007                         if (esiop_cmd->cmd_tables->msg_in[2] == MSG_EXT_SDTR) {
 1008                                 switch (siop_sdtr_neg(&esiop_cmd->cmd_c)) {
 1009                                 case SIOP_NEG_MSGOUT:
 1010                                         esiop_update_scntl3(sc,
 1011                                             esiop_cmd->cmd_c.siop_target);
 1012                                         esiop_table_sync(esiop_cmd,
 1013                                             BUS_DMASYNC_PREREAD |
 1014                                             BUS_DMASYNC_PREWRITE);
 1015                                         CALL_SCRIPT(Ent_send_msgout);
 1016                                         return 1;
 1017                                 case SIOP_NEG_ACK:
 1018                                         esiop_update_scntl3(sc,
 1019                                             esiop_cmd->cmd_c.siop_target);
 1020                                         CALL_SCRIPT(Ent_msgin_ack);
 1021                                         return 1;
 1022                                 default:
 1023                                         panic("invalid retval from "
 1024                                             "siop_wdtr_neg()");
 1025                                 }
 1026                                 return 1;
 1027                         }
 1028                         /* send a message reject */
 1029                         esiop_cmd->cmd_tables->msg_out[0] = MSG_MESSAGE_REJECT;
 1030                         esiop_cmd->cmd_tables->t_msgout.count = htole32(1);
 1031                         esiop_table_sync(esiop_cmd,
 1032                             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 1033                         CALL_SCRIPT(Ent_send_msgout);
 1034                         return 1;
 1035                 case A_int_disc:
 1036                         INCSTAT(esiop_stat_intr_sdp);
 1037                         offset = bus_space_read_1(sc->sc_c.sc_rt,
 1038                             sc->sc_c.sc_rh, SIOP_SCRATCHA + 1);
 1039 #ifdef SIOP_DEBUG_DR
 1040                         printf("disconnect offset %d\n", offset);
 1041 #endif
 1042                         if (offset > SIOP_NSG) {
 1043                                 printf("%s: bad offset for disconnect (%d)\n",
 1044                                     sc->sc_c.sc_dev.dv_xname, offset);
 1045                                 goto reset;
 1046                         }
 1047                         /*
 1048                          * offset == SIOP_NSG may be a valid condition if
 1049                          * we get a sdp when the xfer is done.
 1050                          * Don't call memmove in this case.
 1051                          */
 1052                         if (offset < SIOP_NSG) {
 1053                                 memmove(&esiop_cmd->cmd_tables->data[0],
 1054                                     &esiop_cmd->cmd_tables->data[offset],
 1055                                     (SIOP_NSG - offset) * sizeof(scr_table_t));
 1056                                 esiop_table_sync(esiop_cmd,
 1057                                     BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 1058                         }
 1059                         CALL_SCRIPT(Ent_script_sched);
 1060                         return 1;
 1061                 case A_int_resfail:
 1062                         printf("reselect failed\n");
 1063                         CALL_SCRIPT(Ent_script_sched);
 1064                         return 1;
 1065                 case A_int_done:
 1066                         if (xs == NULL) {
 1067                                 printf("%s: done without command\n",
 1068                                     sc->sc_c.sc_dev.dv_xname);
 1069                                 CALL_SCRIPT(Ent_script_sched);
 1070                                 return 1;
 1071                         }
 1072 #ifdef SIOP_DEBUG_INTR
 1073                         printf("done, DSA=0x%lx target id 0x%x last msg "
 1074                             "in=0x%x status=0x%x\n", (u_long)esiop_cmd->cmd_c.dsa,
 1075                             le32toh(esiop_cmd->cmd_tables->id),
 1076                             esiop_cmd->cmd_tables->msg_in[0],
 1077                             le32toh(esiop_cmd->cmd_tables->status));
 1078 #endif
 1079                         INCSTAT(esiop_stat_intr_done);
 1080                         esiop_cmd->cmd_c.status = CMDST_DONE;
 1081                         goto end;
 1082                 default:
 1083                         printf("unknown irqcode %x\n", irqcode);
 1084                         if (xs) {
 1085                                 xs->error = XS_SELTIMEOUT;
 1086                                 goto end;
 1087                         }
 1088                         goto reset;
 1089                 }
 1090                 return 1;
 1091         }
 1092         /* We just should't get there */
 1093         panic("siop_intr: I shouldn't be there !");
 1094 
 1095 end:
 1096         /*
 1097          * restart the script now if command completed properly
 1098          * Otherwise wait for siop_scsicmd_end(), we may need to cleanup the
 1099          * queue
 1100          */
 1101         xs->status = le32toh(esiop_cmd->cmd_tables->status);
 1102 #ifdef SIOP_DEBUG_INTR
 1103         printf("esiop_intr end: status %d\n", xs->status);
 1104 #endif
 1105         if (tag >= 0)
 1106                 esiop_lun->tactive[tag] = NULL;
 1107         else
 1108                 esiop_lun->active = NULL;
 1109         esiop_scsicmd_end(esiop_cmd);
 1110         if (freetarget && esiop_target->target_c.status == TARST_PROBING)
 1111                 esiop_del_dev(sc, target, lun);
 1112         CALL_SCRIPT(Ent_script_sched);
 1113         return 1;
 1114 }
 1115 
 1116 void
 1117 esiop_scsicmd_end(esiop_cmd)
 1118         struct esiop_cmd *esiop_cmd;
 1119 {
 1120         struct scsipi_xfer *xs = esiop_cmd->cmd_c.xs;
 1121         struct esiop_softc *sc = (struct esiop_softc *)esiop_cmd->cmd_c.siop_sc;
 1122 
 1123         switch(xs->status) {
 1124         case SCSI_OK:
 1125                 xs->error = XS_NOERROR;
 1126                 break;
 1127         case SCSI_BUSY:
 1128                 xs->error = XS_BUSY;
 1129                 break;
 1130         case SCSI_CHECK:
 1131                 xs->error = XS_BUSY;
 1132                 /* remove commands in the queue and scheduler */
 1133                 esiop_unqueue(sc, xs->xs_periph->periph_target,
 1134                     xs->xs_periph->periph_lun);
 1135                 break;
 1136         case SCSI_QUEUE_FULL:
 1137                 INCSTAT(esiop_stat_intr_qfull);
 1138 #ifdef SIOP_DEBUG
 1139                 printf("%s:%d:%d: queue full (tag %d)\n",
 1140                     sc->sc_c.sc_dev.dv_xname,
 1141                     xs->xs_periph->periph_target,
 1142                     xs->xs_periph->periph_lun, esiop_cmd->cmd_c.tag);
 1143 #endif
 1144                 xs->error = XS_BUSY;
 1145                 break;
 1146         case SCSI_SIOP_NOCHECK:
 1147                 /*
 1148                  * don't check status, xs->error is already valid
 1149                  */
 1150                 break;
 1151         case SCSI_SIOP_NOSTATUS:
 1152                 /*
 1153                  * the status byte was not updated, cmd was
 1154                  * aborted
 1155                  */
 1156                 xs->error = XS_SELTIMEOUT;
 1157                 break;
 1158         default:
 1159                 scsipi_printaddr(xs->xs_periph);
 1160                 printf("invalid status code %d\n", xs->status);
 1161                 xs->error = XS_DRIVER_STUFFUP;
 1162         }
 1163         if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
 1164                 bus_dmamap_sync(sc->sc_c.sc_dmat,
 1165                     esiop_cmd->cmd_c.dmamap_data, 0,
 1166                     esiop_cmd->cmd_c.dmamap_data->dm_mapsize,
 1167                     (xs->xs_control & XS_CTL_DATA_IN) ?
 1168                     BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
 1169                 bus_dmamap_unload(sc->sc_c.sc_dmat,
 1170                     esiop_cmd->cmd_c.dmamap_data);
 1171         }
 1172         bus_dmamap_unload(sc->sc_c.sc_dmat, esiop_cmd->cmd_c.dmamap_cmd);
 1173         callout_stop(&esiop_cmd->cmd_c.xs->xs_callout);
 1174         esiop_cmd->cmd_c.status = CMDST_FREE;
 1175         TAILQ_INSERT_TAIL(&sc->free_list, esiop_cmd, next);
 1176         xs->resid = 0;
 1177         scsipi_done (xs);
 1178 }
 1179 
 1180 void
 1181 esiop_checkdone(sc)
 1182         struct esiop_softc *sc;
 1183 {
 1184         int target, lun, tag;
 1185         struct esiop_target *esiop_target;
 1186         struct esiop_lun *esiop_lun;
 1187         struct esiop_cmd *esiop_cmd;
 1188         u_int32_t slot;
 1189         int needsync = 0;
 1190         int status;
 1191         u_int32_t sem;
 1192 
 1193         esiop_script_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 1194         sem = esiop_script_read(sc, sc->sc_semoffset);
 1195         esiop_script_write(sc, sc->sc_semoffset, sem & ~A_sem_done);
 1196         if ((sc->sc_flags & SCF_CHAN_NOSLOT) && (sem & A_sem_start)) {
 1197                 /*
 1198                  * at last one command have been started,
 1199                  * so we should have free slots now
 1200                  */
 1201                 sc->sc_flags &= ~SCF_CHAN_NOSLOT;
 1202                 scsipi_channel_thaw(&sc->sc_c.sc_chan, 1);
 1203         }
 1204         esiop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 1205 
 1206         if ((sem & A_sem_done) == 0) {
 1207                 /* no pending done command */
 1208                 return;
 1209         }
 1210 
 1211         bus_dmamap_sync(sc->sc_c.sc_dmat, sc->sc_done_map,
 1212             sc->sc_done_offset, A_ndone_slots * sizeof(u_int32_t),
 1213             BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 1214 next:
 1215         if (sc->sc_done_slot[sc->sc_currdoneslot] == 0) {
 1216                 if (needsync)
 1217                         bus_dmamap_sync(sc->sc_c.sc_dmat, sc->sc_done_map,
 1218                             sc->sc_done_offset,
 1219                             A_ndone_slots * sizeof(u_int32_t),
 1220                             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 1221                 return;
 1222         }
 1223 
 1224         needsync = 1;
 1225 
 1226         slot = htole32(sc->sc_done_slot[sc->sc_currdoneslot]);
 1227         sc->sc_done_slot[sc->sc_currdoneslot] = 0;
 1228         sc->sc_currdoneslot += 1;
 1229         if (sc->sc_currdoneslot == A_ndone_slots)
 1230                 sc->sc_currdoneslot = 0;
 1231 
 1232         target =  (slot & A_f_c_target) ? (slot >> 8) & 0xff : -1;
 1233         lun =  (slot & A_f_c_lun) ? (slot >> 16) & 0xff : -1;
 1234         tag =  (slot & A_f_c_tag) ? (slot >> 24) & 0xff : -1;
 1235 
 1236         esiop_target = (target >= 0) ?
 1237             (struct esiop_target *)sc->sc_c.targets[target] : NULL;
 1238         if (esiop_target == NULL) {
 1239                 printf("esiop_target (target %d) not valid\n", target);
 1240                 goto next;
 1241         }
 1242         esiop_lun = (lun >= 0) ? esiop_target->esiop_lun[lun] : NULL;
 1243         if (esiop_lun == NULL) {
 1244                 printf("esiop_lun (target %d lun %d) not valid\n",
 1245                     target, lun);
 1246                 goto next;
 1247         }
 1248         esiop_cmd = (tag >= 0) ? esiop_lun->tactive[tag] : esiop_lun->active;
 1249         if (esiop_cmd == NULL) {
 1250                 printf("esiop_cmd (target %d lun %d tag %d) not valid\n",
 1251                     target, lun, tag);
 1252                         goto next;
 1253         }
 1254 
 1255         esiop_table_sync(esiop_cmd,
 1256                     BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 1257         status = le32toh(esiop_cmd->cmd_tables->status);
 1258 #ifdef DIAGNOSTIC
 1259         if (status != SCSI_OK) {
 1260                 printf("command for T/L/Q %d/%d/%d status %d\n",
 1261                     target, lun, tag, status);
 1262                 goto next;
 1263         }
 1264 
 1265 #endif
 1266         /* Ok, this command has been handled */
 1267         esiop_cmd->cmd_c.xs->status = status;
 1268         if (tag >= 0)
 1269                 esiop_lun->tactive[tag] = NULL;
 1270         else
 1271                 esiop_lun->active = NULL;
 1272         esiop_scsicmd_end(esiop_cmd);
 1273         goto next;
 1274 }
 1275 
 1276 void
 1277 esiop_unqueue(sc, target, lun)
 1278         struct esiop_softc *sc;
 1279         int target;
 1280         int lun;
 1281 {
 1282         int slot, tag;
 1283         u_int32_t slotdsa;
 1284         struct esiop_cmd *esiop_cmd;
 1285         struct esiop_lun *esiop_lun =
 1286             ((struct esiop_target *)sc->sc_c.targets[target])->esiop_lun[lun];
 1287 
 1288         /* first make sure to read valid data */
 1289         esiop_script_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 1290 
 1291         for (tag = 0; tag < ESIOP_NTAG; tag++) {
 1292                 /* look for commands in the scheduler, not yet started */
 1293                 if (esiop_lun->tactive[tag] == NULL)
 1294                         continue;
 1295                 esiop_cmd = esiop_lun->tactive[tag];
 1296                 for (slot = 0; slot < A_ncmd_slots; slot++) {
 1297                         slotdsa = esiop_script_read(sc,
 1298                             sc->sc_shedoffset + slot * CMD_SLOTSIZE);
 1299                         /* if the slot has any flag, it won't match the DSA */
 1300                         if (slotdsa == esiop_cmd->cmd_c.dsa) { /* found it */
 1301                                 /* Mark this slot as ignore */
 1302                                 esiop_script_write(sc,
 1303                                     sc->sc_shedoffset + slot * CMD_SLOTSIZE,
 1304                                     esiop_cmd->cmd_c.dsa | A_f_cmd_ignore);
 1305                                 /* ask to requeue */
 1306                                 esiop_cmd->cmd_c.xs->error = XS_REQUEUE;
 1307                                 esiop_cmd->cmd_c.xs->status = SCSI_SIOP_NOCHECK;
 1308                                 esiop_lun->tactive[tag] = NULL;
 1309                                 esiop_scsicmd_end(esiop_cmd);
 1310                                 break;
 1311                         }
 1312                 }
 1313         }
 1314         esiop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 1315 }
 1316 
 1317 /*
 1318  * handle a rejected queue tag message: the command will run untagged,
 1319  * has to adjust the reselect script.
 1320  */
 1321 
 1322 
 1323 int
 1324 esiop_handle_qtag_reject(esiop_cmd)
 1325         struct esiop_cmd *esiop_cmd;
 1326 {
 1327         struct esiop_softc *sc = (struct esiop_softc *)esiop_cmd->cmd_c.siop_sc;
 1328         int target = esiop_cmd->cmd_c.xs->xs_periph->periph_target;
 1329         int lun = esiop_cmd->cmd_c.xs->xs_periph->periph_lun;
 1330         int tag = esiop_cmd->cmd_tables->msg_out[2];
 1331         struct esiop_target *esiop_target =
 1332             (struct esiop_target*)sc->sc_c.targets[target];
 1333         struct esiop_lun *esiop_lun = esiop_target->esiop_lun[lun];
 1334 
 1335 #ifdef SIOP_DEBUG
 1336         printf("%s:%d:%d: tag message %d (%d) rejected (status %d)\n",
 1337             sc->sc_c.sc_dev.dv_xname, target, lun, tag, esiop_cmd->cmd_c.tag,
 1338             esiop_cmd->cmd_c.status);
 1339 #endif
 1340 
 1341         if (esiop_lun->active != NULL) {
 1342                 printf("%s: untagged command already running for target %d "
 1343                     "lun %d (status %d)\n", sc->sc_c.sc_dev.dv_xname,
 1344                     target, lun, esiop_lun->active->cmd_c.status);
 1345                 return -1;
 1346         }
 1347         /* clear tag slot */
 1348         esiop_lun->tactive[tag] = NULL;
 1349         /* add command to non-tagged slot */
 1350         esiop_lun->active = esiop_cmd;
 1351         esiop_cmd->cmd_c.flags &= ~CMDFL_TAG;
 1352         esiop_cmd->cmd_c.tag = -1;
 1353         /* update DSA table */
 1354         esiop_script_write(sc, esiop_target->lun_table_offset +
 1355             lun * 2 + A_target_luntbl / sizeof(u_int32_t),
 1356             esiop_cmd->cmd_c.dsa);
 1357         esiop_script_sync(sc, BUS_DMASYNC_PREREAD |  BUS_DMASYNC_PREWRITE);
 1358         return 0;
 1359 }
 1360 
 1361 /*
 1362  * handle a bus reset: reset chip, unqueue all active commands, free all
 1363  * target struct and report lossage to upper layer.
 1364  * As the upper layer may requeue immediatly we have to first store
 1365  * all active commands in a temporary queue.
 1366  */
 1367 void
 1368 esiop_handle_reset(sc)
 1369         struct esiop_softc *sc;
 1370 {
 1371         struct esiop_cmd *esiop_cmd;
 1372         struct esiop_lun *esiop_lun;
 1373         int target, lun, tag;
 1374         /*
 1375          * scsi bus reset. reset the chip and restart
 1376          * the queue. Need to clean up all active commands
 1377          */
 1378         printf("%s: scsi bus reset\n", sc->sc_c.sc_dev.dv_xname);
 1379         /* stop, reset and restart the chip */
 1380         esiop_reset(sc);
 1381 
 1382         if (sc->sc_flags & SCF_CHAN_NOSLOT) {
 1383                 /* chip has been reset, all slots are free now */
 1384                 sc->sc_flags &= ~SCF_CHAN_NOSLOT;
 1385                 scsipi_channel_thaw(&sc->sc_c.sc_chan, 1);
 1386         }
 1387         /*
 1388          * Process all commands: first commands completes, then commands
 1389          * being executed
 1390          */
 1391         esiop_checkdone(sc);
 1392         for (target = 0; target < sc->sc_c.sc_chan.chan_ntargets;
 1393             target++) {
 1394                 struct esiop_target *esiop_target =
 1395                     (struct esiop_target *)sc->sc_c.targets[target];
 1396                 if (esiop_target == NULL)
 1397                         continue;
 1398                 for (lun = 0; lun < 8; lun++) {
 1399                         esiop_lun = esiop_target->esiop_lun[lun];
 1400                         if (esiop_lun == NULL)
 1401                                 continue;
 1402                         for (tag = -1; tag <
 1403                             ((sc->sc_c.targets[target]->flags & TARF_TAG) ?
 1404                             ESIOP_NTAG : 0);
 1405                             tag++) {
 1406                                 if (tag >= 0)
 1407                                         esiop_cmd = esiop_lun->tactive[tag];
 1408                                 else
 1409                                         esiop_cmd = esiop_lun->active;
 1410                                 if (esiop_cmd == NULL)
 1411                                         continue;
 1412                                 scsipi_printaddr(esiop_cmd->cmd_c.xs->xs_periph);
 1413                                 printf("command with tag id %d reset\n", tag);
 1414                                 esiop_cmd->cmd_c.xs->error =
 1415                                     (esiop_cmd->cmd_c.flags & CMDFL_TIMEOUT) ?
 1416                                     XS_TIMEOUT : XS_RESET;
 1417                                 esiop_cmd->cmd_c.xs->status = SCSI_SIOP_NOCHECK;
 1418                                 if (tag >= 0)
 1419                                         esiop_lun->tactive[tag] = NULL;
 1420                                 else
 1421                                         esiop_lun->active = NULL;
 1422                                 esiop_cmd->cmd_c.status = CMDST_DONE;
 1423                                 esiop_scsicmd_end(esiop_cmd);
 1424                         }
 1425                 }
 1426                 sc->sc_c.targets[target]->status = TARST_ASYNC;
 1427                 sc->sc_c.targets[target]->flags &= ~(TARF_ISWIDE | TARF_ISDT);
 1428                 sc->sc_c.targets[target]->period =
 1429                     sc->sc_c.targets[target]->offset = 0;
 1430                 siop_update_xfer_mode(&sc->sc_c, target);
 1431         }
 1432 
 1433         scsipi_async_event(&sc->sc_c.sc_chan, ASYNC_EVENT_RESET, NULL);
 1434 }
 1435 
 1436 void
 1437 esiop_scsipi_request(chan, req, arg)
 1438         struct scsipi_channel *chan;
 1439         scsipi_adapter_req_t req;
 1440         void *arg;
 1441 {
 1442         struct scsipi_xfer *xs;
 1443         struct scsipi_periph *periph;
 1444         struct esiop_softc *sc = (void *)chan->chan_adapter->adapt_dev;
 1445         struct esiop_cmd *esiop_cmd;
 1446         struct esiop_target *esiop_target;
 1447         int s, error, i;
 1448         int target;
 1449         int lun;
 1450 
 1451         switch (req) {
 1452         case ADAPTER_REQ_RUN_XFER:
 1453                 xs = arg;
 1454                 periph = xs->xs_periph;
 1455                 target = periph->periph_target;
 1456                 lun = periph->periph_lun;
 1457 
 1458                 s = splbio();
 1459                 /*
 1460                  * first check if there are pending complete commands.
 1461                  * this can free us some resources (in the rings for example).
 1462                  * we have to lock it to avoid recursion.
 1463                  */
 1464                 if ((sc->sc_flags & SCF_CHAN_ADAPTREQ) == 0) {
 1465                         sc->sc_flags |= SCF_CHAN_ADAPTREQ;
 1466                         esiop_checkdone(sc);
 1467                         sc->sc_flags &= ~SCF_CHAN_ADAPTREQ;
 1468                 }
 1469 #ifdef SIOP_DEBUG_SCHED
 1470                 printf("starting cmd for %d:%d tag %d(%d)\n", target, lun,
 1471                     xs->xs_tag_type, xs->xs_tag_id);
 1472 #endif
 1473                 esiop_cmd = TAILQ_FIRST(&sc->free_list);
 1474                 if (esiop_cmd == NULL) {
 1475                         xs->error = XS_RESOURCE_SHORTAGE;
 1476                         scsipi_done(xs);
 1477                         splx(s);
 1478                         return;
 1479                 }
 1480                 TAILQ_REMOVE(&sc->free_list, esiop_cmd, next);
 1481 #ifdef DIAGNOSTIC
 1482                 if (esiop_cmd->cmd_c.status != CMDST_FREE)
 1483                         panic("siop_scsicmd: new cmd not free");
 1484 #endif
 1485                 esiop_target = (struct esiop_target*)sc->sc_c.targets[target];
 1486                 if (esiop_target == NULL) {
 1487 #ifdef SIOP_DEBUG
 1488                         printf("%s: alloc siop_target for target %d\n",
 1489                                 sc->sc_c.sc_dev.dv_xname, target);
 1490 #endif
 1491                         sc->sc_c.targets[target] =
 1492                             malloc(sizeof(struct esiop_target),
 1493                                 M_DEVBUF, M_NOWAIT | M_ZERO);
 1494                         if (sc->sc_c.targets[target] == NULL) {
 1495                                 printf("%s: can't malloc memory for "
 1496                                     "target %d\n", sc->sc_c.sc_dev.dv_xname,
 1497                                     target);
 1498                                 xs->error = XS_RESOURCE_SHORTAGE;
 1499                                 scsipi_done(xs);
 1500                                 splx(s);
 1501                                 return;
 1502                         }
 1503                         esiop_target =
 1504                             (struct esiop_target*)sc->sc_c.targets[target];
 1505                         esiop_target->target_c.status = TARST_PROBING;
 1506                         esiop_target->target_c.flags = 0;
 1507                         esiop_target->target_c.id =
 1508                             sc->sc_c.clock_div << 24; /* scntl3 */
 1509                         esiop_target->target_c.id |=  target << 16; /* id */
 1510                         /* esiop_target->target_c.id |= 0x0 << 8; scxfer is 0 */
 1511 
 1512                         for (i=0; i < 8; i++)
 1513                                 esiop_target->esiop_lun[i] = NULL;
 1514                         esiop_target_register(sc, target);
 1515                 }
 1516                 if (esiop_target->esiop_lun[lun] == NULL) {
 1517                         esiop_target->esiop_lun[lun] =
 1518                             malloc(sizeof(struct esiop_lun), M_DEVBUF,
 1519                             M_NOWAIT|M_ZERO);
 1520                         if (esiop_target->esiop_lun[lun] == NULL) {
 1521                                 printf("%s: can't alloc esiop_lun for "
 1522                                     "target %d lun %d\n",
 1523                                     sc->sc_c.sc_dev.dv_xname, target, lun);
 1524                                 xs->error = XS_RESOURCE_SHORTAGE;
 1525                                 scsipi_done(xs);
 1526                                 splx(s);
 1527                                 return;
 1528                         }
 1529                 }
 1530                 esiop_cmd->cmd_c.siop_target = sc->sc_c.targets[target];
 1531                 esiop_cmd->cmd_c.xs = xs;
 1532                 esiop_cmd->cmd_c.flags = 0;
 1533                 esiop_cmd->cmd_c.status = CMDST_READY;
 1534 
 1535                 /* load the DMA maps */
 1536                 error = bus_dmamap_load(sc->sc_c.sc_dmat,
 1537                     esiop_cmd->cmd_c.dmamap_cmd,
 1538                     xs->cmd, xs->cmdlen, NULL, BUS_DMA_NOWAIT);
 1539                 if (error) {
 1540                         printf("%s: unable to load cmd DMA map: %d\n",
 1541                             sc->sc_c.sc_dev.dv_xname, error);
 1542                         xs->error = XS_DRIVER_STUFFUP;
 1543                         scsipi_done(xs);
 1544                         splx(s);
 1545                         return;
 1546                 }
 1547                 if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
 1548                         error = bus_dmamap_load(sc->sc_c.sc_dmat,
 1549                             esiop_cmd->cmd_c.dmamap_data, xs->data, xs->datalen,
 1550                             NULL, BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
 1551                             ((xs->xs_control & XS_CTL_DATA_IN) ?
 1552                              BUS_DMA_READ : BUS_DMA_WRITE));
 1553                         if (error) {
 1554                                 printf("%s: unable to load cmd DMA map: %d",
 1555                                     sc->sc_c.sc_dev.dv_xname, error);
 1556                                 xs->error = XS_DRIVER_STUFFUP;
 1557                                 scsipi_done(xs);
 1558                                 bus_dmamap_unload(sc->sc_c.sc_dmat,
 1559                                     esiop_cmd->cmd_c.dmamap_cmd);
 1560                                 splx(s);
 1561                                 return;
 1562                         }
 1563                         bus_dmamap_sync(sc->sc_c.sc_dmat,
 1564                             esiop_cmd->cmd_c.dmamap_data, 0,
 1565                             esiop_cmd->cmd_c.dmamap_data->dm_mapsize,
 1566                             (xs->xs_control & XS_CTL_DATA_IN) ?
 1567                             BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
 1568                 }
 1569                 bus_dmamap_sync(sc->sc_c.sc_dmat, esiop_cmd->cmd_c.dmamap_cmd,
 1570                     0, esiop_cmd->cmd_c.dmamap_cmd->dm_mapsize,
 1571                     BUS_DMASYNC_PREWRITE);
 1572 
 1573                 if (xs->xs_tag_type)
 1574                         esiop_cmd->cmd_c.tag = xs->xs_tag_id;
 1575                 else
 1576                         esiop_cmd->cmd_c.tag = -1;
 1577                 siop_setuptables(&esiop_cmd->cmd_c);
 1578                 ((struct esiop_xfer *)esiop_cmd->cmd_tables)->tlq =
 1579                     htole32(A_f_c_target | A_f_c_lun);
 1580                 ((struct esiop_xfer *)esiop_cmd->cmd_tables)->tlq |=
 1581                     htole32((target << 8) | (lun << 16));
 1582                 if (esiop_cmd->cmd_c.flags & CMDFL_TAG) {
 1583                         ((struct esiop_xfer *)esiop_cmd->cmd_tables)->tlq |=
 1584                             htole32(A_f_c_tag);
 1585                         ((struct esiop_xfer *)esiop_cmd->cmd_tables)->tlq |=
 1586                             htole32(esiop_cmd->cmd_c.tag << 24);
 1587                 }
 1588 
 1589                 esiop_table_sync(esiop_cmd,
 1590                     BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 1591                 esiop_start(sc, esiop_cmd);
 1592                 if (xs->xs_control & XS_CTL_POLL) {
 1593                         /* poll for command completion */
 1594                         while ((xs->xs_status & XS_STS_DONE) == 0) {
 1595                                 delay(1000);
 1596                                 esiop_intr(sc);
 1597                         }
 1598                 }
 1599                 splx(s);
 1600                 return;
 1601 
 1602         case ADAPTER_REQ_GROW_RESOURCES:
 1603 #ifdef SIOP_DEBUG
 1604                 printf("%s grow resources (%d)\n", sc->sc_c.sc_dev.dv_xname,
 1605                     sc->sc_c.sc_adapt.adapt_openings);
 1606 #endif
 1607                 esiop_morecbd(sc);
 1608                 return;
 1609 
 1610         case ADAPTER_REQ_SET_XFER_MODE:
 1611         {
 1612                 struct scsipi_xfer_mode *xm = arg;
 1613                 if (sc->sc_c.targets[xm->xm_target] == NULL)
 1614                         return;
 1615                 s = splbio();
 1616                 if ((xm->xm_mode & PERIPH_CAP_TQING) &&
 1617                     (sc->sc_c.targets[xm->xm_target]->flags & TARF_TAG) == 0) {
 1618                         sc->sc_c.targets[xm->xm_target]->flags |= TARF_TAG;
 1619                         /* allocate tag tables for this device */
 1620                         for (lun = 0;
 1621                             lun < sc->sc_c.sc_chan.chan_nluns; lun++) {
 1622                                 if (scsipi_lookup_periph(chan,
 1623                                     xm->xm_target, lun) != NULL)
 1624                                         esiop_add_dev(sc, xm->xm_target, lun);
 1625                         }
 1626                 }
 1627                 if ((xm->xm_mode & PERIPH_CAP_WIDE16) &&
 1628                     (sc->sc_c.features & SF_BUS_WIDE))
 1629                         sc->sc_c.targets[xm->xm_target]->flags |= TARF_WIDE;
 1630                 if (xm->xm_mode & PERIPH_CAP_SYNC)
 1631                         sc->sc_c.targets[xm->xm_target]->flags |= TARF_SYNC;
 1632                 if ((xm->xm_mode & PERIPH_CAP_DT) &&
 1633                     (sc->sc_c.features & SF_CHIP_DT))
 1634                         sc->sc_c.targets[xm->xm_target]->flags |= TARF_DT;
 1635                 if ((xm->xm_mode &
 1636                     (PERIPH_CAP_SYNC | PERIPH_CAP_WIDE16 | PERIPH_CAP_DT)) ||
 1637                     sc->sc_c.targets[xm->xm_target]->status == TARST_PROBING)
 1638                         sc->sc_c.targets[xm->xm_target]->status = TARST_ASYNC;
 1639 
 1640                 splx(s);
 1641         }
 1642         }
 1643 }
 1644 
 1645 static void
 1646 esiop_start(sc, esiop_cmd)
 1647         struct esiop_softc *sc;
 1648         struct esiop_cmd *esiop_cmd;
 1649 {
 1650         struct esiop_lun *esiop_lun;
 1651         struct esiop_target *esiop_target;
 1652         int timeout;
 1653         int target, lun, slot;
 1654 
 1655         /*
 1656          * first make sure to read valid data
 1657          */
 1658         esiop_script_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 1659 
 1660         /*
 1661          * We use a circular queue here. sc->sc_currschedslot points to a
 1662          * free slot, unless we have filled the queue. Check this.
 1663          */
 1664         slot = sc->sc_currschedslot;
 1665         if ((esiop_script_read(sc, sc->sc_shedoffset + slot * CMD_SLOTSIZE) &
 1666             A_f_cmd_free) == 0) {
 1667                 /*
 1668                  * no more free slot, no need to continue. freeze the queue
 1669                  * and requeue this command.
 1670                  */
 1671                 scsipi_channel_freeze(&sc->sc_c.sc_chan, 1);
 1672                 sc->sc_flags |= SCF_CHAN_NOSLOT;
 1673                 esiop_script_sync(sc,
 1674                     BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 1675                 esiop_script_write(sc, sc->sc_semoffset,
 1676                     esiop_script_read(sc, sc->sc_semoffset) & ~A_sem_start);
 1677                 esiop_script_sync(sc,
 1678                     BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 1679                 esiop_cmd->cmd_c.xs->error = XS_REQUEUE;
 1680                 esiop_cmd->cmd_c.xs->status = SCSI_SIOP_NOCHECK;
 1681                 esiop_scsicmd_end(esiop_cmd);
 1682                 return;
 1683         }
 1684         /* OK, we can use this slot */
 1685 
 1686         target = esiop_cmd->cmd_c.xs->xs_periph->periph_target;
 1687         lun = esiop_cmd->cmd_c.xs->xs_periph->periph_lun;
 1688         esiop_target = (struct esiop_target*)sc->sc_c.targets[target];
 1689         esiop_lun = esiop_target->esiop_lun[lun];
 1690         /* if non-tagged command active, panic: this shouldn't happen */
 1691         if (esiop_lun->active != NULL) {
 1692                 panic("esiop_start: tagged cmd while untagged running");
 1693         }
 1694 #ifdef DIAGNOSTIC
 1695         /* sanity check the tag if needed */
 1696         if (esiop_cmd->cmd_c.flags & CMDFL_TAG) {
 1697                 if (esiop_lun->tactive[esiop_cmd->cmd_c.tag] != NULL)
 1698                         panic("esiop_start: tag not free");
 1699                 if (esiop_cmd->cmd_c.tag >= ESIOP_NTAG ||
 1700                     esiop_cmd->cmd_c.tag < 0) {
 1701                         scsipi_printaddr(esiop_cmd->cmd_c.xs->xs_periph);
 1702                         printf(": tag id %d\n", esiop_cmd->cmd_c.tag);
 1703                         panic("esiop_start: invalid tag id");
 1704                 }
 1705         }
 1706 #endif
 1707 #ifdef SIOP_DEBUG_SCHED
 1708         printf("using slot %d for DSA 0x%lx\n", slot,
 1709             (u_long)esiop_cmd->cmd_c.dsa);
 1710 #endif
 1711         /* mark command as active */
 1712         if (esiop_cmd->cmd_c.status == CMDST_READY)
 1713                 esiop_cmd->cmd_c.status = CMDST_ACTIVE;
 1714         else
 1715                 panic("esiop_start: bad status");
 1716         /* DSA table for reselect */
 1717         if (esiop_cmd->cmd_c.flags & CMDFL_TAG) {
 1718                 esiop_lun->tactive[esiop_cmd->cmd_c.tag] = esiop_cmd;
 1719                 /* DSA table for reselect */
 1720                 esiop_lun->lun_tagtbl->tbl[esiop_cmd->cmd_c.tag] =
 1721                     htole32(esiop_cmd->cmd_c.dsa);
 1722                 bus_dmamap_sync(sc->sc_c.sc_dmat,
 1723                     esiop_lun->lun_tagtbl->tblblk->blkmap,
 1724                     esiop_lun->lun_tagtbl->tbl_offset,
 1725                     sizeof(u_int32_t) * ESIOP_NTAG, BUS_DMASYNC_PREWRITE);
 1726         } else {
 1727                 esiop_lun->active = esiop_cmd;
 1728                 esiop_script_write(sc,
 1729                     esiop_target->lun_table_offset +
 1730                     lun * 2 + A_target_luntbl / sizeof(u_int32_t),
 1731                     esiop_cmd->cmd_c.dsa);
 1732         }
 1733         /* scheduler slot: DSA */
 1734         esiop_script_write(sc, sc->sc_shedoffset + slot * CMD_SLOTSIZE,
 1735             esiop_cmd->cmd_c.dsa);
 1736         /* make sure SCRIPT processor will read valid data */
 1737         esiop_script_sync(sc, BUS_DMASYNC_PREREAD |  BUS_DMASYNC_PREWRITE);
 1738         /* handle timeout */
 1739         if ((esiop_cmd->cmd_c.xs->xs_control & XS_CTL_POLL) == 0) {
 1740                 /* start exire timer */
 1741                 timeout = mstohz(esiop_cmd->cmd_c.xs->timeout);
 1742                 if (timeout == 0)
 1743                         timeout = 1;
 1744                 callout_reset( &esiop_cmd->cmd_c.xs->xs_callout,
 1745                     timeout, esiop_timeout, esiop_cmd);
 1746         }
 1747         /* Signal script it has some work to do */
 1748         bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
 1749             SIOP_ISTAT, ISTAT_SIGP);
 1750         /* update the current slot, and wait for IRQ */
 1751         sc->sc_currschedslot++;
 1752         if (sc->sc_currschedslot >= A_ncmd_slots)
 1753                 sc->sc_currschedslot = 0;
 1754         return;
 1755 }
 1756 
 1757 void
 1758 esiop_timeout(v)
 1759         void *v;
 1760 {
 1761         struct esiop_cmd *esiop_cmd = v;
 1762         struct esiop_softc *sc =
 1763             (struct esiop_softc *)esiop_cmd->cmd_c.siop_sc;
 1764         int s;
 1765 #ifdef SIOP_DEBUG
 1766         int slot, slotdsa;
 1767 #endif
 1768 
 1769         s = splbio();
 1770         esiop_table_sync(esiop_cmd,
 1771             BUS_DMASYNC_POSTREAD |
 1772             BUS_DMASYNC_POSTWRITE);
 1773         scsipi_printaddr(esiop_cmd->cmd_c.xs->xs_periph);
 1774 #ifdef SIOP_DEBUG
 1775         printf("command timeout (status %d)\n", le32toh(esiop_cmd->cmd_tables->status));
 1776 
 1777         esiop_script_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 1778         for (slot = 0; slot < A_ncmd_slots; slot++) {
 1779                 slotdsa = esiop_script_read(sc,
 1780                     sc->sc_shedoffset + slot * CMD_SLOTSIZE);
 1781                 if ((slotdsa & 0x01) == 0)
 1782                         printf("slot %d not free (0x%x)\n", slot, slotdsa);
 1783         }
 1784         printf("istat 0x%x ", bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_ISTAT));
 1785         printf("DSP 0x%lx DSA 0x%x\n",
 1786             (u_long)(bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSP) - sc->sc_c.sc_scriptaddr),
 1787             bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA));
 1788         bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_CTEST2);
 1789         printf("istat 0x%x\n", bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_ISTAT));
 1790 #else
 1791         printf("command timeout, CDB: ");
 1792         scsipi_print_cdb(esiop_cmd->cmd_c.xs->cmd);
 1793         printf("\n");
 1794 #endif
 1795         /* reset the scsi bus */
 1796         siop_resetbus(&sc->sc_c);
 1797 
 1798         /* deactivate callout */
 1799         callout_stop(&esiop_cmd->cmd_c.xs->xs_callout);
 1800         /*
 1801          * mark command has being timed out and just return;
 1802          * the bus reset will generate an interrupt,
 1803          * it will be handled in siop_intr()
 1804          */
 1805         esiop_cmd->cmd_c.flags |= CMDFL_TIMEOUT;
 1806         splx(s);
 1807         return;
 1808 
 1809 }
 1810 
 1811 void
 1812 esiop_dump_script(sc)
 1813         struct esiop_softc *sc;
 1814 {
 1815         int i;
 1816         for (i = 0; i < PAGE_SIZE / 4; i += 2) {
 1817                 printf("0x%04x: 0x%08x 0x%08x", i * 4,
 1818                     le32toh(sc->sc_c.sc_script[i]),
 1819                     le32toh(sc->sc_c.sc_script[i+1]));
 1820                 if ((le32toh(sc->sc_c.sc_script[i]) & 0xe0000000) ==
 1821                     0xc0000000) {
 1822                         i++;
 1823                         printf(" 0x%08x", le32toh(sc->sc_c.sc_script[i+1]));
 1824                 }
 1825                 printf("\n");
 1826         }
 1827 }
 1828 
 1829 void
 1830 esiop_morecbd(sc)
 1831         struct esiop_softc *sc;
 1832 {
 1833         int error, i, s;
 1834         bus_dma_segment_t seg;
 1835         int rseg;
 1836         struct esiop_cbd *newcbd;
 1837         struct esiop_xfer *xfer;
 1838         bus_addr_t dsa;
 1839 
 1840         /* allocate a new list head */
 1841         newcbd = malloc(sizeof(struct esiop_cbd), M_DEVBUF, M_NOWAIT|M_ZERO);
 1842         if (newcbd == NULL) {
 1843                 printf("%s: can't allocate memory for command descriptors "
 1844                     "head\n", sc->sc_c.sc_dev.dv_xname);
 1845                 return;
 1846         }
 1847 
 1848         /* allocate cmd list */
 1849         newcbd->cmds = malloc(sizeof(struct esiop_cmd) * SIOP_NCMDPB,
 1850             M_DEVBUF, M_NOWAIT|M_ZERO);
 1851         if (newcbd->cmds == NULL) {
 1852                 printf("%s: can't allocate memory for command descriptors\n",
 1853                     sc->sc_c.sc_dev.dv_xname);
 1854                 goto bad3;
 1855         }
 1856         error = bus_dmamem_alloc(sc->sc_c.sc_dmat, PAGE_SIZE, PAGE_SIZE, 0,
 1857             &seg, 1, &rseg, BUS_DMA_NOWAIT);
 1858         if (error) {
 1859                 printf("%s: unable to allocate cbd DMA memory, error = %d\n",
 1860                     sc->sc_c.sc_dev.dv_xname, error);
 1861                 goto bad2;
 1862         }
 1863         error = bus_dmamem_map(sc->sc_c.sc_dmat, &seg, rseg, PAGE_SIZE,
 1864             (caddr_t *)&newcbd->xfers, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
 1865         if (error) {
 1866                 printf("%s: unable to map cbd DMA memory, error = %d\n",
 1867                     sc->sc_c.sc_dev.dv_xname, error);
 1868                 goto bad2;
 1869         }
 1870         error = bus_dmamap_create(sc->sc_c.sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, 0,
 1871             BUS_DMA_NOWAIT, &newcbd->xferdma);
 1872         if (error) {
 1873                 printf("%s: unable to create cbd DMA map, error = %d\n",
 1874                     sc->sc_c.sc_dev.dv_xname, error);
 1875                 goto bad1;
 1876         }
 1877         error = bus_dmamap_load(sc->sc_c.sc_dmat, newcbd->xferdma,
 1878             newcbd->xfers, PAGE_SIZE, NULL, BUS_DMA_NOWAIT);
 1879         if (error) {
 1880                 printf("%s: unable to load cbd DMA map, error = %d\n",
 1881                     sc->sc_c.sc_dev.dv_xname, error);
 1882                 goto bad0;
 1883         }
 1884 #ifdef DEBUG
 1885         printf("%s: alloc newcdb at PHY addr 0x%lx\n", sc->sc_c.sc_dev.dv_xname,
 1886             (unsigned long)newcbd->xferdma->dm_segs[0].ds_addr);
 1887 #endif
 1888         for (i = 0; i < SIOP_NCMDPB; i++) {
 1889                 error = bus_dmamap_create(sc->sc_c.sc_dmat, MAXPHYS, SIOP_NSG,
 1890                     MAXPHYS, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
 1891                     &newcbd->cmds[i].cmd_c.dmamap_data);
 1892                 if (error) {
 1893                         printf("%s: unable to create data DMA map for cbd: "
 1894                             "error %d\n",
 1895                             sc->sc_c.sc_dev.dv_xname, error);
 1896                         goto bad0;
 1897                 }
 1898                 error = bus_dmamap_create(sc->sc_c.sc_dmat,
 1899                     sizeof(struct scsipi_generic), 1,
 1900                     sizeof(struct scsipi_generic), 0,
 1901                     BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
 1902                     &newcbd->cmds[i].cmd_c.dmamap_cmd);
 1903                 if (error) {
 1904                         printf("%s: unable to create cmd DMA map for cbd %d\n",
 1905                             sc->sc_c.sc_dev.dv_xname, error);
 1906                         goto bad0;
 1907                 }
 1908                 newcbd->cmds[i].cmd_c.siop_sc = &sc->sc_c;
 1909                 newcbd->cmds[i].esiop_cbdp = newcbd;
 1910                 xfer = &newcbd->xfers[i];
 1911                 newcbd->cmds[i].cmd_tables = (struct siop_common_xfer *)xfer;
 1912                 memset(newcbd->cmds[i].cmd_tables, 0,
 1913                     sizeof(struct esiop_xfer));
 1914                 dsa = newcbd->xferdma->dm_segs[0].ds_addr +
 1915                     i * sizeof(struct esiop_xfer);
 1916                 newcbd->cmds[i].cmd_c.dsa = dsa;
 1917                 newcbd->cmds[i].cmd_c.status = CMDST_FREE;
 1918                 xfer->siop_tables.t_msgout.count= htole32(1);
 1919                 xfer->siop_tables.t_msgout.addr = htole32(dsa);
 1920                 xfer->siop_tables.t_msgin.count= htole32(1);
 1921                 xfer->siop_tables.t_msgin.addr = htole32(dsa +
 1922                         offsetof(struct siop_common_xfer, msg_in));
 1923                 xfer->siop_tables.t_extmsgin.count= htole32(2);
 1924                 xfer->siop_tables.t_extmsgin.addr = htole32(dsa +
 1925                         offsetof(struct siop_common_xfer, msg_in) + 1);
 1926                 xfer->siop_tables.t_extmsgdata.addr = htole32(dsa +
 1927                         offsetof(struct siop_common_xfer, msg_in) + 3);
 1928                 xfer->siop_tables.t_status.count= htole32(1);
 1929                 xfer->siop_tables.t_status.addr = htole32(dsa +
 1930                         offsetof(struct siop_common_xfer, status));
 1931 
 1932                 s = splbio();
 1933                 TAILQ_INSERT_TAIL(&sc->free_list, &newcbd->cmds[i], next);
 1934                 splx(s);
 1935 #ifdef SIOP_DEBUG
 1936                 printf("tables[%d]: in=0x%x out=0x%x status=0x%x\n", i,
 1937                     le32toh(newcbd->cmds[i].cmd_tables->t_msgin.addr),
 1938                     le32toh(newcbd->cmds[i].cmd_tables->t_msgout.addr),
 1939                     le32toh(newcbd->cmds[i].cmd_tables->t_status.addr));
 1940 #endif
 1941         }
 1942         s = splbio();
 1943         TAILQ_INSERT_TAIL(&sc->cmds, newcbd, next);
 1944         sc->sc_c.sc_adapt.adapt_openings += SIOP_NCMDPB;
 1945         splx(s);
 1946         return;
 1947 bad0:
 1948         bus_dmamap_unload(sc->sc_c.sc_dmat, newcbd->xferdma);
 1949         bus_dmamap_destroy(sc->sc_c.sc_dmat, newcbd->xferdma);
 1950 bad1:
 1951         bus_dmamem_free(sc->sc_c.sc_dmat, &seg, rseg);
 1952 bad2:
 1953         free(newcbd->cmds, M_DEVBUF);
 1954 bad3:
 1955         free(newcbd, M_DEVBUF);
 1956         return;
 1957 }
 1958 
 1959 void
 1960 esiop_moretagtbl(sc)
 1961         struct esiop_softc *sc;
 1962 {
 1963         int error, i, j, s;
 1964         bus_dma_segment_t seg;
 1965         int rseg;
 1966         struct esiop_dsatblblk *newtblblk;
 1967         struct esiop_dsatbl *newtbls;
 1968         u_int32_t *tbls;
 1969 
 1970         /* allocate a new list head */
 1971         newtblblk = malloc(sizeof(struct esiop_dsatblblk),
 1972             M_DEVBUF, M_NOWAIT|M_ZERO);
 1973         if (newtblblk == NULL) {
 1974                 printf("%s: can't allocate memory for tag DSA table block\n",
 1975                     sc->sc_c.sc_dev.dv_xname);
 1976                 return;
 1977         }
 1978 
 1979         /* allocate tbl list */
 1980         newtbls = malloc(sizeof(struct esiop_dsatbl) * ESIOP_NTPB,
 1981             M_DEVBUF, M_NOWAIT|M_ZERO);
 1982         if (newtbls == NULL) {
 1983                 printf("%s: can't allocate memory for command descriptors\n",
 1984                     sc->sc_c.sc_dev.dv_xname);
 1985                 goto bad3;
 1986         }
 1987         error = bus_dmamem_alloc(sc->sc_c.sc_dmat, PAGE_SIZE, PAGE_SIZE, 0,
 1988             &seg, 1, &rseg, BUS_DMA_NOWAIT);
 1989         if (error) {
 1990                 printf("%s: unable to allocate tbl DMA memory, error = %d\n",
 1991                     sc->sc_c.sc_dev.dv_xname, error);
 1992                 goto bad2;
 1993         }
 1994         error = bus_dmamem_map(sc->sc_c.sc_dmat, &seg, rseg, PAGE_SIZE,
 1995             (void *)&tbls, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
 1996         if (error) {
 1997                 printf("%s: unable to map tbls DMA memory, error = %d\n",
 1998                     sc->sc_c.sc_dev.dv_xname, error);
 1999                 goto bad2;
 2000         }
 2001         error = bus_dmamap_create(sc->sc_c.sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, 0,
 2002             BUS_DMA_NOWAIT, &newtblblk->blkmap);
 2003         if (error) {
 2004                 printf("%s: unable to create tbl DMA map, error = %d\n",
 2005                     sc->sc_c.sc_dev.dv_xname, error);
 2006                 goto bad1;
 2007         }
 2008         error = bus_dmamap_load(sc->sc_c.sc_dmat, newtblblk->blkmap,
 2009             tbls, PAGE_SIZE, NULL, BUS_DMA_NOWAIT);
 2010         if (error) {
 2011                 printf("%s: unable to load tbl DMA map, error = %d\n",
 2012                     sc->sc_c.sc_dev.dv_xname, error);
 2013                 goto bad0;
 2014         }
 2015 #ifdef DEBUG
 2016         printf("%s: alloc new tag DSA table at PHY addr 0x%lx\n",
 2017             sc->sc_c.sc_dev.dv_xname,
 2018             (unsigned long)newtblblk->blkmap->dm_segs[0].ds_addr);
 2019 #endif
 2020         for (i = 0; i < ESIOP_NTPB; i++) {
 2021                 newtbls[i].tblblk = newtblblk;
 2022                 newtbls[i].tbl = &tbls[i * ESIOP_NTAG];
 2023                 newtbls[i].tbl_offset = i * ESIOP_NTAG * sizeof(u_int32_t);
 2024                 newtbls[i].tbl_dsa = newtblblk->blkmap->dm_segs[0].ds_addr +
 2025                     newtbls[i].tbl_offset;
 2026                 for (j = 0; j < ESIOP_NTAG; j++)
 2027                         newtbls[i].tbl[j] = j;
 2028                 s = splbio();
 2029                 TAILQ_INSERT_TAIL(&sc->free_tagtbl, &newtbls[i], next);
 2030                 splx(s);
 2031         }
 2032         s = splbio();
 2033         TAILQ_INSERT_TAIL(&sc->tag_tblblk, newtblblk, next);
 2034         splx(s);
 2035         return;
 2036 bad0:
 2037         bus_dmamap_unload(sc->sc_c.sc_dmat, newtblblk->blkmap);
 2038         bus_dmamap_destroy(sc->sc_c.sc_dmat, newtblblk->blkmap);
 2039 bad1:
 2040         bus_dmamem_free(sc->sc_c.sc_dmat, &seg, rseg);
 2041 bad2:
 2042         free(newtbls, M_DEVBUF);
 2043 bad3:
 2044         free(newtblblk, M_DEVBUF);
 2045         return;
 2046 }
 2047 
 2048 void
 2049 esiop_update_scntl3(sc, _siop_target)
 2050         struct esiop_softc *sc;
 2051         struct siop_common_target *_siop_target;
 2052 {
 2053         struct esiop_target *esiop_target = (struct esiop_target *)_siop_target;
 2054         esiop_script_write(sc, esiop_target->lun_table_offset,
 2055             esiop_target->target_c.id);
 2056         esiop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 2057 }
 2058 
 2059 void
 2060 esiop_add_dev(sc, target, lun)
 2061         struct esiop_softc *sc;
 2062         int target;
 2063         int lun;
 2064 {
 2065         struct esiop_target *esiop_target =
 2066             (struct esiop_target *)sc->sc_c.targets[target];
 2067         struct esiop_lun *esiop_lun = esiop_target->esiop_lun[lun];
 2068 
 2069         /* we need a tag DSA table */
 2070         esiop_lun->lun_tagtbl= TAILQ_FIRST(&sc->free_tagtbl);
 2071         if (esiop_lun->lun_tagtbl == NULL) {
 2072                 esiop_moretagtbl(sc);
 2073                 esiop_lun->lun_tagtbl= TAILQ_FIRST(&sc->free_tagtbl);
 2074                 if (esiop_lun->lun_tagtbl == NULL) {
 2075                         /* no resources, run untagged */
 2076                         esiop_target->target_c.flags &= ~TARF_TAG;
 2077                         return;
 2078                 }
 2079         }
 2080         TAILQ_REMOVE(&sc->free_tagtbl, esiop_lun->lun_tagtbl, next);
 2081         /* Update LUN DSA table */
 2082         esiop_script_write(sc, esiop_target->lun_table_offset +
 2083            lun * 2 + A_target_luntbl_tag / sizeof(u_int32_t),
 2084             esiop_lun->lun_tagtbl->tbl_dsa);
 2085         esiop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 2086 }
 2087 
 2088 void
 2089 esiop_del_dev(sc, target, lun)
 2090         struct esiop_softc *sc;
 2091         int target;
 2092         int lun;
 2093 {
 2094         struct esiop_target *esiop_target;
 2095 #ifdef SIOP_DEBUG
 2096                 printf("%s:%d:%d: free lun sw entry\n",
 2097                     sc->sc_c.sc_dev.dv_xname, target, lun);
 2098 #endif
 2099         if (sc->sc_c.targets[target] == NULL)
 2100                 return;
 2101         esiop_target = (struct esiop_target *)sc->sc_c.targets[target];
 2102         free(esiop_target->esiop_lun[lun], M_DEVBUF);
 2103         esiop_target->esiop_lun[lun] = NULL;
 2104 }
 2105 
 2106 void
 2107 esiop_target_register(sc, target)
 2108         struct esiop_softc *sc;
 2109         u_int32_t target;
 2110 {
 2111         struct esiop_target *esiop_target =
 2112             (struct esiop_target *)sc->sc_c.targets[target];
 2113         struct esiop_lun *esiop_lun;
 2114         int lun;
 2115 
 2116         /* get a DSA table for this target */
 2117         esiop_target->lun_table_offset = sc->sc_free_offset;
 2118         sc->sc_free_offset += sc->sc_c.sc_chan.chan_nluns * 2 + 2;
 2119 #ifdef SIOP_DEBUG
 2120         printf("%s: lun table for target %d offset %d free offset %d\n",
 2121             sc->sc_c.sc_dev.dv_xname, target, esiop_target->lun_table_offset,
 2122             sc->sc_free_offset);
 2123 #endif
 2124         /* first 32 bytes are ID (for select) */
 2125         esiop_script_write(sc, esiop_target->lun_table_offset,
 2126             esiop_target->target_c.id);
 2127         /* Record this table in the target DSA table */
 2128         esiop_script_write(sc,
 2129             sc->sc_target_table_offset + target,
 2130             (esiop_target->lun_table_offset * sizeof(u_int32_t)) +
 2131             sc->sc_c.sc_scriptaddr);
 2132         /* if we have a tag table, register it */
 2133         for (lun = 0; lun < sc->sc_c.sc_chan.chan_nluns; lun++) {
 2134                 esiop_lun = esiop_target->esiop_lun[lun];
 2135                 if (esiop_lun == NULL)
 2136                         continue;
 2137                 if (esiop_lun->lun_tagtbl)
 2138                         esiop_script_write(sc, esiop_target->lun_table_offset +
 2139                            lun * 2 + A_target_luntbl_tag / sizeof(u_int32_t),
 2140                             esiop_lun->lun_tagtbl->tbl_dsa);
 2141         }
 2142         esiop_script_sync(sc,
 2143             BUS_DMASYNC_PREREAD |  BUS_DMASYNC_PREWRITE);
 2144 }
 2145 
 2146 #ifdef SIOP_STATS
 2147 void
 2148 esiop_printstats()
 2149 {
 2150         printf("esiop_stat_intr %d\n", esiop_stat_intr);
 2151         printf("esiop_stat_intr_shortxfer %d\n", esiop_stat_intr_shortxfer);
 2152         printf("esiop_stat_intr_xferdisc %d\n", esiop_stat_intr_xferdisc);
 2153         printf("esiop_stat_intr_sdp %d\n", esiop_stat_intr_sdp);
 2154         printf("esiop_stat_intr_done %d\n", esiop_stat_intr_done);
 2155         printf("esiop_stat_intr_lunresel %d\n", esiop_stat_intr_lunresel);
 2156         printf("esiop_stat_intr_qfull %d\n", esiop_stat_intr_qfull);
 2157 }
 2158 #endif

Cache object: 96cfd5b7d2fb60599f0fd9ca1771fb47


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