LCOV - code coverage report
Current view: top level - dev/ic - siop_common.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 576 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 18 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13