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

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*      $OpenBSD: siop_common.c,v 1.31 2008/08/31 17:21:57 miod Exp $ */
    2 /*      $NetBSD: siop_common.c,v 1.37 2005/02/27 00:27:02 perry Exp $   */
    3 
    4 /*
    5  * Copyright (c) 2000, 2002 Manuel Bouyer.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by Manuel Bouyer.
   18  * 4. The name of the author may not be used to endorse or promote products
   19  *    derived from this software without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   31  *
   32  */
   33 
   34 /* SYM53c7/8xx PCI-SCSI I/O Processors driver */
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/device.h>
   39 #include <sys/malloc.h>
   40 #include <sys/buf.h>
   41 #include <sys/kernel.h>
   42 #include <sys/scsiio.h>
   43 
   44 #include <machine/endian.h>
   45 #include <machine/bus.h>
   46 
   47 #include <scsi/scsi_all.h>
   48 #include <scsi/scsi_message.h>
   49 #include <scsi/scsiconf.h>
   50 
   51 #define SIOP_NEEDS_PERIOD_TABLES
   52 #include <dev/ic/siopreg.h>
   53 #include <dev/ic/siopvar_common.h>
   54 #include <dev/ic/siopvar.h>
   55 
   56 #undef DEBUG
   57 #undef DEBUG_DR
   58 #undef DEBUG_NEG
   59 
   60 int
   61 siop_common_attach(sc)
   62         struct siop_common_softc *sc;
   63 {
   64         int error, i;
   65         bus_dma_segment_t seg;
   66         int rseg;
   67 
   68         /*
   69          * Allocate DMA-safe memory for the script and map it.
   70          */
   71         if ((sc->features & SF_CHIP_RAM) == 0) {
   72                 error = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE,
   73                     PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
   74                 if (error) {
   75                         printf("%s: unable to allocate script DMA memory, "
   76                             "error = %d\n", sc->sc_dev.dv_xname, error);
   77                         return error;
   78                 }
   79                 error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, PAGE_SIZE,
   80                     (caddr_t *)&sc->sc_script,
   81                     BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
   82                 if (error) {
   83                         printf("%s: unable to map script DMA memory, "
   84                             "error = %d\n", sc->sc_dev.dv_xname, error);
   85                         return error;
   86                 }
   87                 error = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1,
   88                     PAGE_SIZE, 0, BUS_DMA_NOWAIT, &sc->sc_scriptdma);
   89                 if (error) {
   90                         printf("%s: unable to create script DMA map, "
   91                             "error = %d\n", sc->sc_dev.dv_xname, error);
   92                         return error;
   93                 }
   94                 error = bus_dmamap_load(sc->sc_dmat, sc->sc_scriptdma,
   95                     sc->sc_script, PAGE_SIZE, NULL, BUS_DMA_NOWAIT);
   96                 if (error) {
   97                         printf("%s: unable to load script DMA map, "
   98                             "error = %d\n", sc->sc_dev.dv_xname, error);
   99                         return error;
  100                 }
  101                 sc->sc_scriptaddr =
  102                     sc->sc_scriptdma->dm_segs[0].ds_addr;
  103                 sc->ram_size = PAGE_SIZE;
  104         }
  105 
  106         /*
  107          * sc->sc_link is the template for all device sc_link's
  108          * for devices attached to this adapter. It is passed to
  109          * the upper layers in config_found().
  110          */
  111         sc->sc_link.adapter_softc = sc;
  112         sc->sc_link.adapter_buswidth =
  113             (sc->features & SF_BUS_WIDE) ? 16 : 8;
  114         sc->sc_link.adapter_target =
  115             bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCID);
  116         if (sc->sc_link.adapter_target == 0 ||
  117             sc->sc_link.adapter_target >=
  118             sc->sc_link.adapter_buswidth)
  119                 sc->sc_link.adapter_target = SIOP_DEFAULT_TARGET;
  120 
  121         for (i = 0; i < 16; i++)
  122                 sc->targets[i] = NULL;
  123 
  124         /* find min/max sync period for this chip */
  125         sc->st_maxsync = 0;
  126         sc->dt_maxsync = 0;
  127         sc->st_minsync = 255;
  128         sc->dt_minsync = 255;
  129         for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); i++) {
  130                 if (sc->clock_period != scf_period[i].clock)
  131                         continue;
  132                 if (sc->st_maxsync < scf_period[i].period)
  133                         sc->st_maxsync = scf_period[i].period;
  134                 if (sc->st_minsync > scf_period[i].period)
  135                         sc->st_minsync = scf_period[i].period;
  136         }
  137         if (sc->st_maxsync == 255 || sc->st_minsync == 0)
  138                 panic("siop: can't find my sync parameters");
  139         for (i = 0; i < sizeof(dt_scf_period) / sizeof(dt_scf_period[0]); i++) {
  140                 if (sc->clock_period != dt_scf_period[i].clock)
  141                         continue;
  142                 if (sc->dt_maxsync < dt_scf_period[i].period)
  143                         sc->dt_maxsync = dt_scf_period[i].period;
  144                 if (sc->dt_minsync > dt_scf_period[i].period)
  145                         sc->dt_minsync = dt_scf_period[i].period;
  146         }
  147         if (sc->dt_maxsync == 255 || sc->dt_minsync == 0)
  148                 panic("siop: can't find my sync parameters");
  149         return 0;
  150 }
  151 
  152 void
  153 siop_common_reset(sc)
  154         struct siop_common_softc *sc;
  155 {
  156         u_int32_t stest3;
  157 
  158         /* reset the chip */
  159         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SRST);
  160         delay(1000);
  161         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, 0);
  162 
  163         /* init registers */
  164         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL0,
  165             SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP);
  166         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 0);
  167         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, sc->clock_div);
  168         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 0);
  169         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DIEN, 0xff);
  170         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN0,
  171             0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL));
  172         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN1,
  173             0xff & ~(SIEN1_HTH | SIEN1_GEN));
  174         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 0);
  175         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, STEST3_TE);
  176         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STIME0,
  177             (0xb << STIME0_SEL_SHIFT));
  178         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCID,
  179             sc->sc_link.adapter_target | SCID_RRE);
  180         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_RESPID0,
  181             1 << sc->sc_link.adapter_target);
  182         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DCNTL,
  183             (sc->features & SF_CHIP_PF) ? DCNTL_COM | DCNTL_PFEN : DCNTL_COM);
  184         if (sc->features & SF_CHIP_AAIP)
  185                 bus_space_write_1(sc->sc_rt, sc->sc_rh,
  186                     SIOP_AIPCNTL1, AIPCNTL1_DIS);
  187 
  188         /* enable clock doubler or quadrupler if appropriate */
  189         if (sc->features & (SF_CHIP_DBLR | SF_CHIP_QUAD)) {
  190                 stest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3);
  191                 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1,
  192                     STEST1_DBLEN);
  193                 if (sc->features & SF_CHIP_QUAD) {
  194                         /* wait for PPL to lock */
  195                         while ((bus_space_read_1(sc->sc_rt, sc->sc_rh,
  196                             SIOP_STEST4) & STEST4_LOCK) == 0)
  197                                 delay(10);
  198                 } else {
  199                         /* data sheet says 20us - more won't hurt */
  200                         delay(100);
  201                 }
  202                 /* halt scsi clock, select doubler/quad, restart clock */
  203                 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3,
  204                     stest3 | STEST3_HSC);
  205                 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1,
  206                     STEST1_DBLEN | STEST1_DBLSEL);
  207                 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, stest3);
  208         } else {
  209                 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 0);
  210         }
  211         if (sc->features & SF_CHIP_FIFO)
  212                 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5,
  213                     bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5) |
  214                     CTEST5_DFS);
  215         if (sc->features & SF_CHIP_LED0) {
  216                 /* Set GPIO0 as output if software LED control is required */
  217                 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_GPCNTL,
  218                     bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_GPCNTL) & 0xfe);
  219         }
  220         if (sc->features & SF_BUS_ULTRA3) {
  221                 /* reset SCNTL4 */
  222                 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, 0);
  223         }
  224         sc->mode = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) &
  225             STEST4_MODE_MASK;
  226 
  227         /*
  228          * initialise the RAM. Without this we may get scsi gross errors on
  229          * the 1010
  230          */
  231         if (sc->features & SF_CHIP_RAM)
  232                 bus_space_set_region_4(sc->sc_ramt, sc->sc_ramh,
  233                         0, 0, sc->ram_size / 4);
  234         sc->sc_reset(sc);
  235 }
  236 
  237 /* prepare tables before sending a cmd */
  238 void
  239 siop_setuptables(siop_cmd)
  240         struct siop_common_cmd *siop_cmd;
  241 {
  242         int i;
  243         struct siop_common_softc *sc = siop_cmd->siop_sc;
  244         struct scsi_xfer *xs = siop_cmd->xs;
  245         int target = xs->sc_link->target;
  246         int lun = xs->sc_link->lun;
  247         int msgoffset = 1;
  248         int *targ_flags = &sc->targets[target]->flags;
  249         int quirks;
  250 
  251         siop_cmd->siop_tables->id = siop_htoc32(sc, sc->targets[target]->id);
  252         memset(siop_cmd->siop_tables->msg_out, 0,
  253             sizeof(siop_cmd->siop_tables->msg_out));
  254         /* request sense doesn't disconnect */
  255         if (siop_cmd->status == CMDST_SENSE)
  256                 siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 0);
  257         else if ((sc->features & SF_CHIP_GEBUG) &&
  258             (sc->targets[target]->flags & TARF_ISWIDE) == 0)
  259                 /*
  260                  * 1010 bug: it seems that the 1010 has problems with reselect
  261                  * when not in wide mode (generate false SCSI gross error).
  262                  * The FreeBSD sym driver has comments about it but their
  263                  * workaround (disable SCSI gross error reporting) doesn't
  264                  * work with my adapter. So disable disconnect when not
  265                  * wide.
  266                  */
  267                 siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 0);
  268         else
  269                 siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 1);
  270         siop_cmd->siop_tables->t_msgout.count = siop_htoc32(sc, msgoffset);
  271         if (sc->targets[target]->status == TARST_ASYNC) {
  272                 *targ_flags &= TARF_DT; /* Save TARF_DT 'cuz we don't set it here */
  273                 quirks = xs->sc_link->quirks;
  274 
  275                 if ((quirks & SDEV_NOTAGS) == 0)
  276                         *targ_flags |= TARF_TAG;
  277                 if (((quirks & SDEV_NOWIDE) == 0) &&
  278                     (sc->features & SF_BUS_WIDE))
  279                         *targ_flags |= TARF_WIDE;
  280                 if ((quirks & SDEV_NOSYNC) == 0)
  281                         *targ_flags |= TARF_SYNC;
  282 
  283                 if ((sc->features & SF_CHIP_GEBUG) &&
  284                     (*targ_flags & TARF_WIDE) == 0)
  285                         /* 
  286                          * 1010 workaround: can't do disconnect if not wide,
  287                          * so can't do tag
  288                          */
  289                         *targ_flags &= ~TARF_TAG;
  290 
  291                 /* Safe to call siop_add_dev() multiple times */
  292                 siop_add_dev((struct siop_softc *)sc, target, lun);
  293 
  294                 if ((*targ_flags & TARF_DT) &&
  295                     (sc->mode == STEST4_MODE_LVD)) {
  296                         sc->targets[target]->status = TARST_PPR_NEG;
  297                          siop_ppr_msg(siop_cmd, msgoffset, sc->dt_minsync,
  298                             sc->maxoff);
  299                 } else if (*targ_flags & TARF_WIDE) {
  300                         sc->targets[target]->status = TARST_WIDE_NEG;
  301                         siop_wdtr_msg(siop_cmd, msgoffset,
  302                             MSG_EXT_WDTR_BUS_16_BIT);
  303                 } else if (*targ_flags & TARF_SYNC) {
  304                         sc->targets[target]->status = TARST_SYNC_NEG;
  305                         siop_sdtr_msg(siop_cmd, msgoffset, sc->st_minsync,
  306                         (sc->maxoff > 31) ? 31 :  sc->maxoff);
  307                 } else {
  308                         sc->targets[target]->status = TARST_OK;
  309                         siop_update_xfer_mode(sc, target);
  310                 }
  311         } else if (sc->targets[target]->status == TARST_OK &&
  312             (*targ_flags & TARF_TAG) &&
  313             siop_cmd->status != CMDST_SENSE) {
  314                 siop_cmd->flags |= CMDFL_TAG;
  315         }
  316         siop_cmd->siop_tables->status =
  317             siop_htoc32(sc, SCSI_SIOP_NOSTATUS); /* set invalid status */
  318 
  319         if ((xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) ||
  320             siop_cmd->status == CMDST_SENSE) {
  321                 bzero(siop_cmd->siop_tables->data,
  322                     sizeof(siop_cmd->siop_tables->data));
  323                 for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
  324                         siop_cmd->siop_tables->data[i].count =
  325                             siop_htoc32(sc,
  326                                 siop_cmd->dmamap_data->dm_segs[i].ds_len);
  327                         siop_cmd->siop_tables->data[i].addr =
  328                             siop_htoc32(sc,
  329                                 siop_cmd->dmamap_data->dm_segs[i].ds_addr);
  330                 }
  331         }
  332 }
  333 
  334 int
  335 siop_wdtr_neg(siop_cmd)
  336         struct siop_common_cmd *siop_cmd;
  337 {
  338         struct siop_common_softc *sc = siop_cmd->siop_sc;
  339         struct siop_common_target *siop_target = siop_cmd->siop_target;
  340         int target = siop_cmd->xs->sc_link->target;
  341         struct siop_common_xfer *tables = siop_cmd->siop_tables;
  342 
  343         if (siop_target->status == TARST_WIDE_NEG) {
  344                 /* we initiated wide negotiation */
  345                 switch (tables->msg_in[3]) {
  346                 case MSG_EXT_WDTR_BUS_8_BIT:
  347                         siop_target->flags &= ~TARF_ISWIDE;
  348                         sc->targets[target]->id &= ~(SCNTL3_EWS << 24);
  349                         break;
  350                 case MSG_EXT_WDTR_BUS_16_BIT:
  351                         if (siop_target->flags & TARF_WIDE) {
  352                                 siop_target->flags |= TARF_ISWIDE;
  353                                 sc->targets[target]->id |= (SCNTL3_EWS << 24);
  354                                 break;
  355                         }
  356                 /* FALLTHROUGH */
  357                 default:
  358                         /*
  359                          * hum, we got more than what we can handle, shouldn't
  360                          * happen. Reject, and stay async
  361                          */
  362                         siop_target->flags &= ~TARF_ISWIDE;
  363                         siop_target->status = TARST_OK;
  364                         siop_target->offset = siop_target->period = 0;
  365                         siop_update_xfer_mode(sc, target);
  366                         printf("%s: rejecting invalid wide negotiation from "
  367                             "target %d (%d)\n", sc->sc_dev.dv_xname, target,
  368                             tables->msg_in[3]);
  369                         tables->t_msgout.count = siop_htoc32(sc, 1);
  370                         tables->msg_out[0] = MSG_MESSAGE_REJECT;
  371                         return SIOP_NEG_MSGOUT;
  372                 }
  373                 tables->id = siop_htoc32(sc, sc->targets[target]->id);
  374                 bus_space_write_1(sc->sc_rt, sc->sc_rh,
  375                     SIOP_SCNTL3,
  376                     (sc->targets[target]->id >> 24) & 0xff);
  377                 /* we now need to do sync */
  378                 if (siop_target->flags & TARF_SYNC) {
  379                         siop_target->status = TARST_SYNC_NEG;
  380                         siop_sdtr_msg(siop_cmd, 0, sc->st_minsync,
  381                             (sc->maxoff > 31) ? 31 : sc->maxoff);
  382                         return SIOP_NEG_MSGOUT;
  383                 } else {
  384                         siop_target->status = TARST_OK;
  385                         siop_update_xfer_mode(sc, target);
  386                         return SIOP_NEG_ACK;
  387                 }
  388         } else {
  389                 /* target initiated wide negotiation */
  390                 if (tables->msg_in[3] >= MSG_EXT_WDTR_BUS_16_BIT
  391                     && (siop_target->flags & TARF_WIDE)) {
  392                         siop_target->flags |= TARF_ISWIDE;
  393                         sc->targets[target]->id |= SCNTL3_EWS << 24;
  394                 } else {
  395                         siop_target->flags &= ~TARF_ISWIDE;
  396                         sc->targets[target]->id &= ~(SCNTL3_EWS << 24);
  397                 }
  398                 tables->id = siop_htoc32(sc, sc->targets[target]->id);
  399                 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
  400                     (sc->targets[target]->id >> 24) & 0xff);
  401                 /*
  402                  * we did reset wide parameters, so fall back to async,
  403                  * but don't schedule a sync neg, target should initiate it
  404                  */
  405                 siop_target->status = TARST_OK;
  406                 siop_target->offset = siop_target->period = 0;
  407                 siop_update_xfer_mode(sc, target);
  408                 siop_wdtr_msg(siop_cmd, 0, (siop_target->flags & TARF_ISWIDE) ?
  409                     MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT);
  410                 return SIOP_NEG_MSGOUT;
  411         }
  412 }
  413 
  414 int
  415 siop_ppr_neg(siop_cmd)
  416         struct siop_common_cmd *siop_cmd;
  417 {
  418         struct siop_common_softc *sc = siop_cmd->siop_sc;
  419         struct siop_common_target *siop_target = siop_cmd->siop_target;
  420         int target = siop_cmd->xs->sc_link->target;
  421         struct siop_common_xfer *tables = siop_cmd->siop_tables;
  422         int sync, offset, options, scf = 0;
  423         int i;
  424 
  425 #ifdef DEBUG_NEG
  426         printf("%s: answer on ppr negotiation:", sc->sc_dev.dv_xname);
  427         for (i = 0; i < 8; i++)
  428                 printf(" 0x%x", tables->msg_in[i]);
  429         printf("\n");
  430 #endif
  431 
  432         if (siop_target->status == TARST_PPR_NEG) {
  433                 /* we initiated PPR negotiation */
  434                 sync = tables->msg_in[3];
  435                 offset = tables->msg_in[5];
  436                 options = tables->msg_in[7];
  437                 if (options != MSG_EXT_PPR_PROT_DT) {
  438                         /* should't happen */
  439                         printf("%s: ppr negotiation for target %d: "
  440                             "no DT option\n", sc->sc_dev.dv_xname, target);
  441                         siop_target->status = TARST_ASYNC;
  442                         siop_target->flags &= ~(TARF_DT | TARF_ISDT);
  443                         siop_target->offset = 0;
  444                         siop_target->period = 0;
  445                         goto reject;
  446                 }
  447 
  448                 if (offset > sc->maxoff || sync < sc->dt_minsync ||
  449                     sync > sc->dt_maxsync) {
  450                         printf("%s: ppr negotiation for target %d: "
  451                             "offset (%d) or sync (%d) out of range\n",
  452                             sc->sc_dev.dv_xname, target, offset, sync);
  453                         /* should not happen */
  454                         siop_target->status = TARST_ASYNC;
  455                         siop_target->flags &= ~(TARF_DT | TARF_ISDT);
  456                         siop_target->offset = 0;
  457                         siop_target->period = 0;
  458                         goto reject;
  459                 } else {
  460                         for (i = 0; i <
  461                             sizeof(dt_scf_period) / sizeof(dt_scf_period[0]);
  462                             i++) {
  463                                 if (sc->clock_period != dt_scf_period[i].clock)
  464                                         continue;
  465                                 if (dt_scf_period[i].period == sync) {
  466                                         /* ok, found it. we now are sync. */
  467                                         siop_target->offset = offset;
  468                                         siop_target->period = sync;
  469                                         scf = dt_scf_period[i].scf;
  470                                         siop_target->flags |= TARF_ISDT;
  471                                 }
  472                         }
  473                         if ((siop_target->flags & TARF_ISDT) == 0) {
  474                                 printf("%s: ppr negotiation for target %d: "
  475                                     "sync (%d) incompatible with adapter\n",
  476                                     sc->sc_dev.dv_xname, target, sync);
  477                                 /*
  478                                  * we didn't find it in our table, do async
  479                                  * send reject msg, start SDTR/WDTR neg
  480                                  */
  481                                 siop_target->status = TARST_ASYNC;
  482                                 siop_target->flags &= ~(TARF_DT | TARF_ISDT);
  483                                 siop_target->offset = 0;
  484                                 siop_target->period = 0;
  485                                 goto reject;
  486                         }
  487                 }
  488                 if (tables->msg_in[6] != 1) {
  489                         printf("%s: ppr negotiation for target %d: "
  490                             "transfer width (%d) incompatible with dt\n",
  491                             sc->sc_dev.dv_xname, target, tables->msg_in[6]);
  492                         /* DT mode can only be done with wide transfers */
  493                         siop_target->status = TARST_ASYNC;
  494                         siop_target->flags &= ~(TARF_DT | TARF_ISDT);
  495                         siop_target->offset = 0;
  496                         siop_target->period = 0;
  497                         goto reject;
  498                 } 
  499                 siop_target->flags |= TARF_ISWIDE;
  500                 sc->targets[target]->id |= (SCNTL3_EWS << 24);
  501                 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24);
  502                 sc->targets[target]->id |= scf << (24 + SCNTL3_SCF_SHIFT);
  503                 sc->targets[target]->id &= ~(SXFER_MO_MASK << 8);
  504                 sc->targets[target]->id |=
  505                     (siop_target->offset & SXFER_MO_MASK) << 8;
  506                 sc->targets[target]->id &= ~0xff;
  507                 sc->targets[target]->id |= SCNTL4_U3EN;
  508                 siop_target->status = TARST_OK;
  509                 siop_update_xfer_mode(sc, target);
  510                 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
  511                     (sc->targets[target]->id >> 24) & 0xff);
  512                 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER,
  513                     (sc->targets[target]->id >> 8) & 0xff);
  514                 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4,
  515                     sc->targets[target]->id & 0xff);
  516                 return SIOP_NEG_ACK;
  517         } else {
  518                 /* target initiated PPR negotiation, shouldn't happen */
  519                 printf("%s: rejecting invalid PPR negotiation from "
  520                     "target %d\n", sc->sc_dev.dv_xname, target);
  521 reject:
  522                 tables->t_msgout.count = siop_htoc32(sc, 1);
  523                 tables->msg_out[0] = MSG_MESSAGE_REJECT;
  524                 return SIOP_NEG_MSGOUT;
  525         }
  526 }
  527 
  528 int
  529 siop_sdtr_neg(siop_cmd)
  530         struct siop_common_cmd *siop_cmd;
  531 {
  532         struct siop_common_softc *sc = siop_cmd->siop_sc;
  533         struct siop_common_target *siop_target = siop_cmd->siop_target;
  534         int target = siop_cmd->xs->sc_link->target;
  535         int sync, maxoffset, offset, i;
  536         int send_msgout = 0;
  537         struct siop_common_xfer *tables = siop_cmd->siop_tables;
  538 
  539         /* limit to Ultra/2 parameters, need PPR for Ultra/3 */
  540         maxoffset = (sc->maxoff > 31) ? 31 : sc->maxoff;
  541 
  542         sync = tables->msg_in[3];
  543         offset = tables->msg_in[4];
  544 
  545         if (siop_target->status == TARST_SYNC_NEG) {
  546                 /* we initiated sync negotiation */
  547                 siop_target->status = TARST_OK;
  548 #ifdef DEBUG
  549                 printf("sdtr: sync %d offset %d\n", sync, offset);
  550 #endif
  551                 if (offset > maxoffset || sync < sc->st_minsync ||
  552                         sync > sc->st_maxsync)
  553                         goto reject;
  554                 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]);
  555                     i++) {
  556                         if (sc->clock_period != scf_period[i].clock)
  557                                 continue;
  558                         if (scf_period[i].period == sync) {
  559                                 /* ok, found it. we now are sync. */
  560                                 siop_target->offset = offset;
  561                                 siop_target->period = sync;
  562                                 sc->targets[target]->id &=
  563                                     ~(SCNTL3_SCF_MASK << 24);
  564                                 sc->targets[target]->id |= scf_period[i].scf
  565                                     << (24 + SCNTL3_SCF_SHIFT);
  566                                 if (sync < 25 && /* Ultra */
  567                                     (sc->features & SF_BUS_ULTRA3) == 0)
  568                                         sc->targets[target]->id |=
  569                                             SCNTL3_ULTRA << 24;
  570                                 else
  571                                         sc->targets[target]->id &=
  572                                             ~(SCNTL3_ULTRA << 24);
  573                                 sc->targets[target]->id &=
  574                                     ~(SXFER_MO_MASK << 8);
  575                                 sc->targets[target]->id |=
  576                                     (offset & SXFER_MO_MASK) << 8;
  577                                 sc->targets[target]->id &= ~0xff; /* scntl4 */
  578                                 goto end;
  579                         }
  580                 }
  581                 /*
  582                  * we didn't find it in our table, do async and send reject
  583                  * msg
  584                  */
  585 reject:
  586                 send_msgout = 1;
  587                 tables->t_msgout.count = siop_htoc32(sc, 1);
  588                 tables->msg_out[0] = MSG_MESSAGE_REJECT;
  589                 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24);
  590                 sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24);
  591                 sc->targets[target]->id &= ~(SXFER_MO_MASK << 8);
  592                 sc->targets[target]->id &= ~0xff; /* scntl4 */
  593                 siop_target->offset = siop_target->period = 0;
  594         } else { /* target initiated sync neg */
  595 #ifdef DEBUG
  596                 printf("sdtr (target): sync %d offset %d\n", sync, offset);
  597 #endif
  598                 if (offset == 0 || sync > sc->st_maxsync) { /* async */
  599                         goto async;
  600                 }
  601                 if (offset > maxoffset)
  602                         offset = maxoffset;
  603                 if (sync < sc->st_minsync)
  604                         sync = sc->st_minsync;
  605                 /* look for sync period */
  606                 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]);
  607                     i++) {
  608                         if (sc->clock_period != scf_period[i].clock)
  609                                 continue;
  610                         if (scf_period[i].period == sync) {
  611                                 /* ok, found it. we now are sync. */
  612                                 siop_target->offset = offset;
  613                                 siop_target->period = sync;
  614                                 sc->targets[target]->id &=
  615                                     ~(SCNTL3_SCF_MASK << 24);
  616                                 sc->targets[target]->id |= scf_period[i].scf
  617                                     << (24 + SCNTL3_SCF_SHIFT);
  618                                 if (sync < 25 && /* Ultra */
  619                                     (sc->features & SF_BUS_ULTRA3) == 0)
  620                                         sc->targets[target]->id |=
  621                                             SCNTL3_ULTRA << 24;
  622                                 else
  623                                         sc->targets[target]->id &=
  624                                             ~(SCNTL3_ULTRA << 24);
  625                                 sc->targets[target]->id &=
  626                                     ~(SXFER_MO_MASK << 8);
  627                                 sc->targets[target]->id |=
  628                                     (offset & SXFER_MO_MASK) << 8;
  629                                 sc->targets[target]->id &= ~0xff; /* scntl4 */
  630                                 siop_sdtr_msg(siop_cmd, 0, sync, offset);
  631                                 send_msgout = 1;
  632                                 goto end;
  633                         }
  634                 }
  635 async:
  636                 siop_target->offset = siop_target->period = 0;
  637                 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24);
  638                 sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24);
  639                 sc->targets[target]->id &= ~(SXFER_MO_MASK << 8);
  640                 sc->targets[target]->id &= ~0xff; /* scntl4 */
  641                 siop_sdtr_msg(siop_cmd, 0, 0, 0);
  642                 send_msgout = 1;
  643         }
  644 end:
  645         if (siop_target->status == TARST_OK)
  646                 siop_update_xfer_mode(sc, target);
  647 #ifdef DEBUG
  648         printf("id now 0x%x\n", sc->targets[target]->id);
  649 #endif
  650         tables->id = siop_htoc32(sc, sc->targets[target]->id);
  651         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
  652             (sc->targets[target]->id >> 24) & 0xff);
  653         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER,
  654             (sc->targets[target]->id >> 8) & 0xff);
  655         if (send_msgout) {
  656                 return SIOP_NEG_MSGOUT;
  657         } else {
  658                 return SIOP_NEG_ACK;
  659         }
  660 }
  661 
  662 void
  663 siop_sdtr_msg(siop_cmd, offset, ssync, soff)
  664         struct siop_common_cmd *siop_cmd;
  665         int offset;
  666         int ssync, soff;
  667 {
  668         siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED;
  669         siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_SDTR_LEN;
  670         siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_SDTR;
  671         siop_cmd->siop_tables->msg_out[offset + 3] = ssync;
  672         siop_cmd->siop_tables->msg_out[offset + 4] = soff;
  673         siop_cmd->siop_tables->t_msgout.count =
  674             siop_htoc32(siop_cmd->siop_sc, offset + MSG_EXT_SDTR_LEN + 2);
  675 }
  676 
  677 void
  678 siop_wdtr_msg(siop_cmd, offset, wide)
  679         struct siop_common_cmd *siop_cmd;
  680         int offset;
  681         int wide;
  682 {
  683         siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED;
  684         siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_WDTR_LEN;
  685         siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_WDTR;
  686         siop_cmd->siop_tables->msg_out[offset + 3] = wide;
  687         siop_cmd->siop_tables->t_msgout.count =
  688             siop_htoc32(siop_cmd->siop_sc, offset + MSG_EXT_WDTR_LEN + 2);
  689 }
  690 
  691 void
  692 siop_ppr_msg(siop_cmd, offset, ssync, soff)
  693         struct siop_common_cmd *siop_cmd;
  694         int offset;
  695         int ssync, soff;
  696 {
  697         siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED;
  698         siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_PPR_LEN;
  699         siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_PPR;
  700         siop_cmd->siop_tables->msg_out[offset + 3] = ssync;
  701         siop_cmd->siop_tables->msg_out[offset + 4] = 0; /* reserved */
  702         siop_cmd->siop_tables->msg_out[offset + 5] = soff;
  703         siop_cmd->siop_tables->msg_out[offset + 6] = 1; /* wide */
  704         siop_cmd->siop_tables->msg_out[offset + 7] = MSG_EXT_PPR_PROT_DT;
  705         siop_cmd->siop_tables->t_msgout.count =
  706             siop_htoc32(siop_cmd->siop_sc, offset + MSG_EXT_PPR_LEN + 2);
  707 }
  708 
  709 void
  710 siop_minphys(bp)
  711         struct buf *bp;
  712 {
  713         if (bp->b_bcount > SIOP_MAXFER)
  714                 bp->b_bcount = SIOP_MAXFER;
  715 
  716         minphys(bp);
  717 }
  718 
  719 void
  720 siop_ma(siop_cmd)
  721         struct siop_common_cmd *siop_cmd;
  722 {
  723         int offset, dbc, sstat;
  724         struct siop_common_softc *sc = siop_cmd->siop_sc;
  725         scr_table_t *table; /* table with partial xfer */
  726 
  727         /*
  728          * compute how much of the current table didn't get handled when
  729          * a phase mismatch occurs
  730          */
  731         if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN))
  732             == 0)
  733             return; /* no valid data transfer */
  734 
  735         offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1);
  736         if (offset >= SIOP_NSG) {
  737                 printf("%s: bad offset in siop_sdp (%d)\n",
  738                     sc->sc_dev.dv_xname, offset);
  739                 return;
  740         }
  741         table = &siop_cmd->siop_tables->data[offset];
  742 #ifdef DEBUG_DR
  743         printf("siop_ma: offset %d count=%d addr=0x%x ", offset,
  744             table->count, table->addr);
  745 #endif
  746         dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff;
  747         if (siop_cmd->xs->flags & SCSI_DATA_OUT) {
  748                 if (sc->features & SF_CHIP_DFBC) {
  749                         dbc +=
  750                             bus_space_read_2(sc->sc_rt, sc->sc_rh, SIOP_DFBC);
  751                 } else {
  752                         /* need to account stale data in FIFO */
  753                         int dfifo =
  754                             bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO);
  755                         if (sc->features & SF_CHIP_FIFO) {
  756                                 dfifo |= (bus_space_read_1(sc->sc_rt, sc->sc_rh,
  757                                     SIOP_CTEST5) & CTEST5_BOMASK) << 8;
  758                                 dbc += (dfifo - (dbc & 0x3ff)) & 0x3ff;
  759                         } else {
  760                                 dbc += (dfifo - (dbc & 0x7f)) & 0x7f;
  761                         }
  762                 }
  763                 sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0);
  764                 if (sstat & SSTAT0_OLF)
  765                         dbc++;
  766                 if ((sstat & SSTAT0_ORF) && (sc->features & SF_CHIP_DFBC) == 0)
  767                         dbc++;
  768                 if (siop_cmd->siop_target->flags & TARF_ISWIDE) {
  769                         sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh,
  770                             SIOP_SSTAT2);
  771                         if (sstat & SSTAT2_OLF1)
  772                                 dbc++;
  773                         if ((sstat & SSTAT2_ORF1) &&
  774                             (sc->features & SF_CHIP_DFBC) == 0)
  775                                 dbc++;
  776                 }
  777                 /* clear the FIFO */
  778                 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
  779                     bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) |
  780                     CTEST3_CLF);
  781         }
  782         siop_cmd->flags |= CMDFL_RESID;
  783         siop_cmd->resid = dbc;
  784 }
  785 
  786 void
  787 siop_sdp(siop_cmd, offset)
  788         struct siop_common_cmd *siop_cmd;
  789         int offset;
  790 {
  791         struct siop_common_softc *sc = siop_cmd->siop_sc;
  792         scr_table_t *table;
  793         
  794         if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN))
  795             == 0)
  796             return; /* no data pointers to save */
  797 
  798         /*
  799          * offset == SIOP_NSG may be a valid condition if we get a Save data
  800          * pointer when the xfer is done. Just ignore the Save data pointer
  801          * in this case
  802          */
  803         if (offset == SIOP_NSG)
  804                 return;
  805 #ifdef DIAGNOSTIC
  806         if (offset > SIOP_NSG) {
  807                 sc_print_addr(siop_cmd->xs->sc_link);
  808                 printf("offset %d > %d\n", offset, SIOP_NSG);
  809                 panic("siop_sdp: offset");
  810         }
  811 #endif
  812         /*
  813          * Save data pointer. We do this by adjusting the tables to point
  814          * at the begginning of the data not yet transfered. 
  815          * offset points to the first table with untransfered data.
  816          */
  817 
  818         /*
  819          * before doing that we decrease resid from the amount of data which
  820          * has been transfered.
  821          */
  822         siop_update_resid(siop_cmd, offset);
  823 
  824         /*
  825          * First let see if we have a resid from a phase mismatch. If so,
  826          * we have to adjst the table at offset to remove transfered data.
  827          */
  828         if (siop_cmd->flags & CMDFL_RESID) {
  829                 siop_cmd->flags &= ~CMDFL_RESID;
  830                 table = &siop_cmd->siop_tables->data[offset];
  831                 /* "cut" already transfered data from this table */
  832                 table->addr =
  833                     siop_htoc32(sc, siop_ctoh32(sc, table->addr) +
  834                     siop_ctoh32(sc, table->count) - siop_cmd->resid);
  835                 table->count = siop_htoc32(sc, siop_cmd->resid);
  836         }
  837 
  838         /*
  839          * now we can remove entries which have been transfered.
  840          * We just move the entries with data left at the beggining of the
  841          * tables
  842          */
  843         bcopy(&siop_cmd->siop_tables->data[offset],
  844             &siop_cmd->siop_tables->data[0],
  845             (SIOP_NSG - offset) * sizeof(scr_table_t));
  846 }
  847 
  848 void
  849 siop_update_resid(siop_cmd, offset)
  850         struct siop_common_cmd *siop_cmd;
  851         int offset;
  852 {
  853         struct siop_common_softc *sc = siop_cmd->siop_sc;
  854         scr_table_t *table;
  855         int i;
  856 
  857         if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN))
  858             == 0)
  859             return; /* no data to transfer */
  860 
  861         /*
  862          * update resid. First account for the table entries which have
  863          * been fully completed.
  864          */
  865         for (i = 0; i < offset; i++)
  866                 siop_cmd->xs->resid -=
  867                     siop_ctoh32(sc, siop_cmd->siop_tables->data[i].count);
  868         /*
  869          * if CMDFL_RESID is set, the last table (pointed by offset) is a
  870          * partial transfers. If not, offset points to the entry folloing
  871          * the last full transfer.
  872          */
  873         if (siop_cmd->flags & CMDFL_RESID) {
  874                 table = &siop_cmd->siop_tables->data[offset];
  875                 siop_cmd->xs->resid -=
  876                     siop_ctoh32(sc, table->count) - siop_cmd->resid;
  877         }
  878 }
  879 
  880 int
  881 siop_iwr(siop_cmd)
  882         struct siop_common_cmd *siop_cmd;
  883 {
  884         int offset;
  885         scr_table_t *table; /* table with IWR */
  886         struct siop_common_softc *sc = siop_cmd->siop_sc;
  887         /* handle ignore wide residue messages */
  888 
  889         /* if target isn't wide, reject */
  890         if ((siop_cmd->siop_target->flags & TARF_ISWIDE) == 0) {
  891                 siop_cmd->siop_tables->t_msgout.count = siop_htoc32(sc, 1);
  892                 siop_cmd->siop_tables->msg_out[0] = MSG_MESSAGE_REJECT;
  893                 return SIOP_NEG_MSGOUT;
  894         }
  895         /* get index of current command in table */
  896         offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1);
  897         /*
  898          * if the current table did complete, we're now pointing at the
  899          * next one. Go back one if we didn't see a phase mismatch.
  900          */
  901         if ((siop_cmd->flags & CMDFL_RESID) == 0)
  902                 offset--;
  903         table = &siop_cmd->siop_tables->data[offset];
  904 
  905         if ((siop_cmd->flags & CMDFL_RESID) == 0) {
  906                 if (siop_ctoh32(sc, table->count) & 1) {
  907                         /* we really got the number of bytes we expected */
  908                         return SIOP_NEG_ACK;
  909                 } else {
  910                         /*
  911                          * now we really had a short xfer, by one byte.
  912                          * handle it just as if we had a phase mistmatch
  913                          * (there is a resid of one for this table).
  914                          * Update scratcha1 to reflect the fact that
  915                          * this xfer isn't complete.
  916                          */
  917                          siop_cmd->flags |= CMDFL_RESID;
  918                          siop_cmd->resid = 1;
  919                          bus_space_write_1(sc->sc_rt, sc->sc_rh,
  920                              SIOP_SCRATCHA + 1, offset);
  921                          return SIOP_NEG_ACK;
  922                 }
  923         } else {
  924                 /*
  925                  * we already have a short xfer for this table; it's
  926                  * just one byte less than we though it was
  927                  */
  928                 siop_cmd->resid--;
  929                 return SIOP_NEG_ACK;
  930         }
  931 }
  932 
  933 void
  934 siop_clearfifo(sc)
  935         struct siop_common_softc *sc;
  936 {
  937         int timeout = 0;
  938         int ctest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3);
  939 
  940 #ifdef DEBUG_INTR
  941         printf("DMA fifo not empty !\n");
  942 #endif
  943         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
  944             ctest3 | CTEST3_CLF);
  945         while ((bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) &
  946             CTEST3_CLF) != 0) {
  947                 delay(1);
  948                 if (++timeout > 1000) {
  949                         printf("clear fifo failed\n");
  950                         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
  951                             bus_space_read_1(sc->sc_rt, sc->sc_rh,
  952                             SIOP_CTEST3) & ~CTEST3_CLF);
  953                         return;
  954                 }
  955         }
  956 }
  957 
  958 int
  959 siop_modechange(sc)
  960         struct siop_common_softc *sc;
  961 {
  962         int retry;
  963         int sist0, sist1, stest2;
  964         for (retry = 0; retry < 5; retry++) {
  965                 /*
  966                  * datasheet says to wait 100ms and re-read SIST1,
  967                  * to check that DIFFSENSE is stable.
  968                  * We may delay() 5 times for  100ms at interrupt time;
  969                  * hopefully this will not happen often.
  970                  */
  971                 delay(100000);
  972                 sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0);
  973                 sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1);
  974                 if (sist1 & SIEN1_SBMC)
  975                         continue; /* we got an irq again */
  976                 sc->mode = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) &
  977                     STEST4_MODE_MASK;
  978                 stest2 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2);
  979                 switch(sc->mode) {
  980                 case STEST4_MODE_DIF:
  981                         printf("%s: switching to differential mode\n",
  982                             sc->sc_dev.dv_xname);
  983                         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
  984                             stest2 | STEST2_DIF);
  985                         break;
  986                 case STEST4_MODE_SE:
  987                         printf("%s: switching to single-ended mode\n",
  988                             sc->sc_dev.dv_xname);
  989                         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
  990                             stest2 & ~STEST2_DIF);
  991                         break;
  992                 case STEST4_MODE_LVD:
  993                         printf("%s: switching to LVD mode\n",
  994                             sc->sc_dev.dv_xname);
  995                         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
  996                             stest2 & ~STEST2_DIF);
  997                         break;
  998                 default:
  999                         printf("%s: invalid SCSI mode 0x%x\n",
 1000                             sc->sc_dev.dv_xname, sc->mode);
 1001                         return 0;
 1002                 }
 1003                 return 1;
 1004         }
 1005         printf("%s: timeout waiting for DIFFSENSE to stabilise\n",
 1006             sc->sc_dev.dv_xname);
 1007         return 0;
 1008 }
 1009 
 1010 void
 1011 siop_resetbus(sc)
 1012         struct siop_common_softc *sc;
 1013 {
 1014         int scntl1;
 1015         scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
 1016         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
 1017             scntl1 | SCNTL1_RST);
 1018         /* minimum 25 us, more time won't hurt */
 1019         delay(100);
 1020         bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
 1021 }
 1022 
 1023 void
 1024 siop_update_xfer_mode(sc, target)
 1025         struct siop_common_softc *sc;
 1026         int target;
 1027 {
 1028         struct siop_common_target *siop_target;
 1029 
 1030         siop_target = sc->targets[target];
 1031         
 1032         printf("%s: target %d now using %s%s%d bit ",
 1033             sc->sc_dev.dv_xname, target,
 1034             (siop_target->flags & TARF_TAG) ? "tagged " : "",
 1035             (siop_target->flags & TARF_ISDT) ? "DT " : "",
 1036             (siop_target->flags & TARF_ISWIDE) ? 16 : 8);
 1037 
 1038         if (siop_target->offset == 0)
 1039                 printf("async ");
 1040         else {
 1041                 switch (siop_target->period) {
 1042                 case 9: /*   12.5ns cycle */
 1043                         printf("80.0");
 1044                         break;
 1045                 case 10: /*  25  ns cycle */
 1046                         printf("40.0");
 1047                         break;
 1048                 case 12: /*  48  ns cycle */
 1049                         printf("20.0");
 1050                         break;
 1051                 case 18: /*  72  ns cycle */
 1052                         printf("13.3");
 1053                         break;
 1054                 case 25: /* 100  ns cycle */
 1055                         printf("10.0");
 1056                         break;
 1057                 case 37: /* 118  ns cycle */
 1058                         printf("6.67");
 1059                         break;
 1060                 case 50: /* 200  ns cycle */
 1061                         printf("5.0");
 1062                         break;
 1063                 case 75: /* 300  ns cycle */
 1064                         printf("3.33");
 1065                         break;
 1066                 default:
 1067                         printf("??");
 1068                         break;
 1069                 }
 1070                 printf(" MHz %d REQ/ACK offset ", siop_target->offset);
 1071         }
 1072         
 1073         printf("xfers\n");
 1074 
 1075         if ((sc->features & SF_CHIP_GEBUG) &&
 1076             (siop_target->flags & TARF_ISWIDE) == 0)
 1077                 /* 1010 workaround: can't do disconnect if not wide, so can't do tag */
 1078                 siop_target->flags &= ~TARF_TAG;
 1079 }

Cache object: a8f54c2686f71222ebf75caf0f061f17


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