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

Cache object: 37cd52b6c70e63a2c9fc854c95dee1b8


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