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