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

Cache object: 5a824a6c6ee6a33158af191d51a9dadf


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