1 /* $NetBSD: siop_common.c,v 1.15 2001/11/13 13:14:44 lukem Exp $ */ 2 3 /* 4 * Copyright (c) 2000 Manuel Bouyer. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Manuel Bouyer 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 */ 32 33 /* SYM53c7/8xx PCI-SCSI I/O Processors driver */ 34 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: siop_common.c,v 1.15 2001/11/13 13:14:44 lukem Exp $"); 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/device.h> 41 #include <sys/malloc.h> 42 #include <sys/buf.h> 43 #include <sys/kernel.h> 44 #include <sys/scsiio.h> 45 46 #include <machine/endian.h> 47 #include <machine/bus.h> 48 49 #include <dev/scsipi/scsi_all.h> 50 #include <dev/scsipi/scsi_message.h> 51 #include <dev/scsipi/scsipi_all.h> 52 53 #include <dev/scsipi/scsiconf.h> 54 55 #include <dev/ic/siopreg.h> 56 #include <dev/ic/siopvar.h> 57 #include <dev/ic/siopvar_common.h> 58 59 #undef DEBUG 60 #undef DEBUG_DR 61 62 void 63 siop_common_reset(sc) 64 struct siop_softc *sc; 65 { 66 u_int32_t stest3; 67 68 /* reset the chip */ 69 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SRST); 70 delay(1000); 71 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, 0); 72 73 /* init registers */ 74 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL0, 75 SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP); 76 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 0); 77 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, sc->clock_div); 78 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 0); 79 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DIEN, 0xff); 80 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN0, 81 0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL)); 82 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN1, 83 0xff & ~(SIEN1_HTH | SIEN1_GEN)); 84 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 0); 85 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, STEST3_TE); 86 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STIME0, 87 (0xb << STIME0_SEL_SHIFT)); 88 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCID, 89 sc->sc_chan.chan_id | SCID_RRE); 90 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_RESPID0, 91 1 << sc->sc_chan.chan_id); 92 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DCNTL, 93 (sc->features & SF_CHIP_PF) ? DCNTL_COM | DCNTL_PFEN : DCNTL_COM); 94 95 /* enable clock doubler or quadruler if appropriate */ 96 if (sc->features & (SF_CHIP_DBLR | SF_CHIP_QUAD)) { 97 stest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3); 98 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 99 STEST1_DBLEN); 100 if (sc->features & SF_CHIP_QUAD) { 101 /* wait for PPL to lock */ 102 while ((bus_space_read_1(sc->sc_rt, sc->sc_rh, 103 SIOP_STEST4) & STEST4_LOCK) == 0) 104 delay(10); 105 } else { 106 /* data sheet says 20us - more won't hurt */ 107 delay(100); 108 } 109 /* halt scsi clock, select doubler/quad, restart clock */ 110 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, 111 stest3 | STEST3_HSC); 112 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 113 STEST1_DBLEN | STEST1_DBLSEL); 114 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, stest3); 115 } else { 116 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 0); 117 } 118 if (sc->features & SF_CHIP_FIFO) 119 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5, 120 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5) | 121 CTEST5_DFS); 122 123 sc->sc_reset(sc); 124 } 125 126 /* prepare tables before sending a cmd */ 127 void 128 siop_setuptables(siop_cmd) 129 struct siop_cmd *siop_cmd; 130 { 131 int i; 132 struct siop_softc *sc = siop_cmd->siop_sc; 133 struct scsipi_xfer *xs = siop_cmd->xs; 134 int target = xs->xs_periph->periph_target; 135 int lun = xs->xs_periph->periph_lun; 136 int msgoffset = 1; 137 138 siop_cmd->siop_tables.id = htole32(sc->targets[target]->id); 139 memset(siop_cmd->siop_tables.msg_out, 0, 8); 140 /* request sense doesn't disconnect */ 141 if (xs->xs_control & XS_CTL_REQSENSE) 142 siop_cmd->siop_tables.msg_out[0] = MSG_IDENTIFY(lun, 0); 143 else 144 siop_cmd->siop_tables.msg_out[0] = MSG_IDENTIFY(lun, 1); 145 siop_cmd->siop_tables.t_msgout.count= htole32(1); 146 if (xs->xs_tag_type != 0) { 147 if ((sc->targets[target]->flags & TARF_TAG) == 0) { 148 scsipi_printaddr(xs->xs_periph); 149 printf(": tagged command type %d id %d\n", 150 siop_cmd->xs->xs_tag_type, siop_cmd->xs->xs_tag_id); 151 panic("tagged command for non-tagging device\n"); 152 } 153 siop_cmd->flags |= CMDFL_TAG; 154 siop_cmd->siop_tables.msg_out[1] = siop_cmd->xs->xs_tag_type; 155 siop_cmd->siop_tables.msg_out[2] = siop_cmd->xs->xs_tag_id + 1; 156 siop_cmd->siop_tables.t_msgout.count = htole32(3); 157 msgoffset = 3; 158 siop_cmd->tag = siop_cmd->xs->xs_tag_id + 1; 159 } else 160 siop_cmd->tag = 0; 161 if (sc->targets[target]->status == TARST_ASYNC) { 162 if (sc->targets[target]->flags & TARF_WIDE) { 163 sc->targets[target]->status = TARST_WIDE_NEG; 164 siop_wdtr_msg(siop_cmd, msgoffset, 165 MSG_EXT_WDTR_BUS_16_BIT); 166 } else if (sc->targets[target]->flags & TARF_SYNC) { 167 sc->targets[target]->status = TARST_SYNC_NEG; 168 siop_sdtr_msg(siop_cmd, msgoffset, 169 sc->minsync, sc->maxoff); 170 } else { 171 sc->targets[target]->status = TARST_OK; 172 siop_update_xfer_mode(sc, target); 173 } 174 } 175 if (xs->xs_tag_type != 0 && (siop_cmd->flags & CMDFL_TAG) == 0) 176 printf("siop_setuptables: tagged CMD type 0x%x for target %d lun %d runs untagged, status 0x%x flags 0x%x\n", xs->xs_tag_type, target, lun, sc->targets[target]->status, sc->targets[target]->flags); 177 siop_cmd->siop_tables.status = 178 htole32(SCSI_SIOP_NOSTATUS); /* set invalid status */ 179 180 siop_cmd->siop_tables.cmd.count = 181 htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len); 182 siop_cmd->siop_tables.cmd.addr = 183 htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr); 184 if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) { 185 for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) { 186 siop_cmd->siop_tables.data[i].count = 187 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len); 188 siop_cmd->siop_tables.data[i].addr = 189 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr); 190 } 191 } 192 siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 193 } 194 195 int 196 siop_wdtr_neg(siop_cmd) 197 struct siop_cmd *siop_cmd; 198 { 199 struct siop_softc *sc = siop_cmd->siop_sc; 200 struct siop_target *siop_target = siop_cmd->siop_target; 201 int target = siop_cmd->xs->xs_periph->periph_target; 202 struct siop_xfer_common *tables = &siop_cmd->siop_xfer->tables; 203 204 if (siop_target->status == TARST_WIDE_NEG) { 205 /* we initiated wide negotiation */ 206 switch (tables->msg_in[3]) { 207 case MSG_EXT_WDTR_BUS_8_BIT: 208 siop_target->flags &= ~TARF_ISWIDE; 209 sc->targets[target]->id &= ~(SCNTL3_EWS << 24); 210 break; 211 case MSG_EXT_WDTR_BUS_16_BIT: 212 if (siop_target->flags & TARF_WIDE) { 213 siop_target->flags |= TARF_ISWIDE; 214 sc->targets[target]->id |= (SCNTL3_EWS << 24); 215 break; 216 } 217 /* FALLTHROUH */ 218 default: 219 /* 220 * hum, we got more than what we can handle, shoudn't 221 * happen. Reject, and stay async 222 */ 223 siop_target->flags &= ~TARF_ISWIDE; 224 siop_target->status = TARST_OK; 225 siop_target->offset = siop_target->period = 0; 226 siop_update_xfer_mode(sc, target); 227 printf("%s: rejecting invalid wide negotiation from " 228 "target %d (%d)\n", sc->sc_dev.dv_xname, target, 229 tables->msg_in[3]); 230 tables->t_msgout.count= htole32(1); 231 tables->msg_out[0] = MSG_MESSAGE_REJECT; 232 return SIOP_NEG_MSGOUT; 233 } 234 tables->id = htole32(sc->targets[target]->id); 235 bus_space_write_1(sc->sc_rt, sc->sc_rh, 236 SIOP_SCNTL3, 237 (sc->targets[target]->id >> 24) & 0xff); 238 /* we now need to do sync */ 239 if (siop_target->flags & TARF_SYNC) { 240 siop_target->status = TARST_SYNC_NEG; 241 siop_sdtr_msg(siop_cmd, 0, sc->minsync, sc->maxoff); 242 return SIOP_NEG_MSGOUT; 243 } else { 244 siop_target->status = TARST_OK; 245 siop_update_xfer_mode(sc, target); 246 return SIOP_NEG_ACK; 247 } 248 } else { 249 /* target initiated wide negotiation */ 250 if (tables->msg_in[3] >= MSG_EXT_WDTR_BUS_16_BIT 251 && (siop_target->flags & TARF_WIDE)) { 252 siop_target->flags |= TARF_ISWIDE; 253 sc->targets[target]->id |= SCNTL3_EWS << 24; 254 } else { 255 siop_target->flags &= ~TARF_ISWIDE; 256 sc->targets[target]->id &= ~(SCNTL3_EWS << 24); 257 } 258 tables->id = htole32(sc->targets[target]->id); 259 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 260 (sc->targets[target]->id >> 24) & 0xff); 261 /* 262 * we did reset wide parameters, so fall back to async, 263 * but don't schedule a sync neg, target should initiate it 264 */ 265 siop_target->status = TARST_OK; 266 siop_target->offset = siop_target->period = 0; 267 siop_update_xfer_mode(sc, target); 268 siop_wdtr_msg(siop_cmd, 0, (siop_target->flags & TARF_ISWIDE) ? 269 MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT); 270 return SIOP_NEG_MSGOUT; 271 } 272 } 273 274 int 275 siop_sdtr_neg(siop_cmd) 276 struct siop_cmd *siop_cmd; 277 { 278 struct siop_softc *sc = siop_cmd->siop_sc; 279 struct siop_target *siop_target = siop_cmd->siop_target; 280 int target = siop_cmd->xs->xs_periph->periph_target; 281 int sync, offset, i; 282 int send_msgout = 0; 283 struct siop_xfer_common *tables = &siop_cmd->siop_xfer->tables; 284 285 sync = tables->msg_in[3]; 286 offset = tables->msg_in[4]; 287 288 if (siop_target->status == TARST_SYNC_NEG) { 289 /* we initiated sync negotiation */ 290 siop_target->status = TARST_OK; 291 #ifdef DEBUG 292 printf("sdtr: sync %d offset %d\n", sync, offset); 293 #endif 294 if (offset > sc->maxoff || sync < sc->minsync || 295 sync > sc->maxsync) 296 goto reject; 297 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); 298 i++) { 299 if (sc->clock_period != scf_period[i].clock) 300 continue; 301 if (scf_period[i].period == sync) { 302 /* ok, found it. we now are sync. */ 303 siop_target->offset = offset; 304 siop_target->period = sync; 305 sc->targets[target]->id &= 306 ~(SCNTL3_SCF_MASK << 24); 307 sc->targets[target]->id |= scf_period[i].scf 308 << (24 + SCNTL3_SCF_SHIFT); 309 if (sync < 25) /* Ultra */ 310 sc->targets[target]->id |= 311 SCNTL3_ULTRA << 24; 312 else 313 sc->targets[target]->id &= 314 ~(SCNTL3_ULTRA << 24); 315 sc->targets[target]->id &= 316 ~(SXFER_MO_MASK << 8); 317 sc->targets[target]->id |= 318 (offset & SXFER_MO_MASK) << 8; 319 goto end; 320 } 321 } 322 /* 323 * we didn't find it in our table, do async and send reject 324 * msg 325 */ 326 reject: 327 send_msgout = 1; 328 tables->t_msgout.count= htole32(1); 329 tables->msg_out[0] = MSG_MESSAGE_REJECT; 330 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24); 331 sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24); 332 sc->targets[target]->id &= ~(SXFER_MO_MASK << 8); 333 siop_target->offset = siop_target->period = 0; 334 } else { /* target initiated sync neg */ 335 #ifdef DEBUG 336 printf("sdtr (target): sync %d offset %d\n", sync, offset); 337 #endif 338 if (offset == 0 || sync > sc->maxsync) { /* async */ 339 goto async; 340 } 341 if (offset > sc->maxoff) 342 offset = sc->maxoff; 343 if (sync < sc->minsync) 344 sync = sc->minsync; 345 /* look for sync period */ 346 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); 347 i++) { 348 if (sc->clock_period != scf_period[i].clock) 349 continue; 350 if (scf_period[i].period == sync) { 351 /* ok, found it. we now are sync. */ 352 siop_target->offset = offset; 353 siop_target->period = sync; 354 sc->targets[target]->id &= 355 ~(SCNTL3_SCF_MASK << 24); 356 sc->targets[target]->id |= scf_period[i].scf 357 << (24 + SCNTL3_SCF_SHIFT); 358 if (sync < 25) /* Ultra */ 359 sc->targets[target]->id |= 360 SCNTL3_ULTRA << 24; 361 else 362 sc->targets[target]->id &= 363 ~(SCNTL3_ULTRA << 24); 364 sc->targets[target]->id &= 365 ~(SXFER_MO_MASK << 8); 366 sc->targets[target]->id |= 367 (offset & SXFER_MO_MASK) << 8; 368 siop_sdtr_msg(siop_cmd, 0, sync, offset); 369 send_msgout = 1; 370 goto end; 371 } 372 } 373 async: 374 siop_target->offset = siop_target->period = 0; 375 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24); 376 sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24); 377 sc->targets[target]->id &= ~(SXFER_MO_MASK << 8); 378 siop_sdtr_msg(siop_cmd, 0, 0, 0); 379 send_msgout = 1; 380 } 381 end: 382 if (siop_target->status == TARST_OK) 383 siop_update_xfer_mode(sc, target); 384 #ifdef DEBUG 385 printf("id now 0x%x\n", sc->targets[target]->id); 386 #endif 387 tables->id = htole32(sc->targets[target]->id); 388 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 389 (sc->targets[target]->id >> 24) & 0xff); 390 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 391 (sc->targets[target]->id >> 8) & 0xff); 392 if (send_msgout) { 393 return SIOP_NEG_MSGOUT; 394 } else { 395 return SIOP_NEG_ACK; 396 } 397 } 398 399 void 400 siop_sdtr_msg(siop_cmd, offset, ssync, soff) 401 struct siop_cmd *siop_cmd; 402 int offset; 403 int ssync, soff; 404 { 405 siop_cmd->siop_tables.msg_out[offset + 0] = MSG_EXTENDED; 406 siop_cmd->siop_tables.msg_out[offset + 1] = MSG_EXT_SDTR_LEN; 407 siop_cmd->siop_tables.msg_out[offset + 2] = MSG_EXT_SDTR; 408 siop_cmd->siop_tables.msg_out[offset + 3] = ssync; 409 siop_cmd->siop_tables.msg_out[offset + 4] = soff; 410 siop_cmd->siop_tables.t_msgout.count = 411 htole32(offset + MSG_EXT_SDTR_LEN + 2); 412 } 413 414 void 415 siop_wdtr_msg(siop_cmd, offset, wide) 416 struct siop_cmd *siop_cmd; 417 int offset; 418 { 419 siop_cmd->siop_tables.msg_out[offset + 0] = MSG_EXTENDED; 420 siop_cmd->siop_tables.msg_out[offset + 1] = MSG_EXT_WDTR_LEN; 421 siop_cmd->siop_tables.msg_out[offset + 2] = MSG_EXT_WDTR; 422 siop_cmd->siop_tables.msg_out[offset + 3] = wide; 423 siop_cmd->siop_tables.t_msgout.count = 424 htole32(offset + MSG_EXT_WDTR_LEN + 2); 425 } 426 427 void 428 siop_minphys(bp) 429 struct buf *bp; 430 { 431 minphys(bp); 432 } 433 434 int 435 siop_ioctl(chan, cmd, arg, flag, p) 436 struct scsipi_channel *chan; 437 u_long cmd; 438 caddr_t arg; 439 int flag; 440 struct proc *p; 441 { 442 struct siop_softc *sc = (void *)chan->chan_adapter->adapt_dev; 443 u_int8_t scntl1; 444 int s; 445 446 switch (cmd) { 447 case SCBUSIORESET: 448 s = splbio(); 449 scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1); 450 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 451 scntl1 | SCNTL1_RST); 452 /* minimum 25 us, more time won't hurt */ 453 delay(100); 454 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1); 455 splx(s); 456 return (0); 457 default: 458 return (ENOTTY); 459 } 460 } 461 462 void 463 siop_sdp(siop_cmd) 464 struct siop_cmd *siop_cmd; 465 { 466 /* save data pointer. Handle async only for now */ 467 int offset, dbc, sstat; 468 struct siop_softc *sc = siop_cmd->siop_sc; 469 scr_table_t *table; /* table to patch */ 470 471 if ((siop_cmd->xs->xs_control & (XS_CTL_DATA_OUT | XS_CTL_DATA_IN)) 472 == 0) 473 return; /* no data pointers to save */ 474 offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1); 475 if (offset >= SIOP_NSG) { 476 printf("%s: bad offset in siop_sdp (%d)\n", 477 sc->sc_dev.dv_xname, offset); 478 return; 479 } 480 table = &siop_cmd->siop_xfer->tables.data[offset]; 481 #ifdef DEBUG_DR 482 printf("sdp: offset %d count=%d addr=0x%x ", offset, 483 table->count, table->addr); 484 #endif 485 dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff; 486 if (siop_cmd->xs->xs_control & XS_CTL_DATA_OUT) { 487 if (sc->features & SF_CHIP_DFBC) { 488 dbc += 489 bus_space_read_2(sc->sc_rt, sc->sc_rh, SIOP_DFBC); 490 } else { 491 /* need to account stale data in FIFO */ 492 int dfifo = 493 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO); 494 if (sc->features & SF_CHIP_FIFO) { 495 dfifo |= (bus_space_read_1(sc->sc_rt, sc->sc_rh, 496 SIOP_CTEST5) & CTEST5_BOMASK) << 8; 497 dbc += (dfifo - (dbc & 0x3ff)) & 0x3ff; 498 } else { 499 dbc += (dfifo - (dbc & 0x7f)) & 0x7f; 500 } 501 } 502 sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0); 503 if (sstat & SSTAT0_OLF) 504 dbc++; 505 if ((sstat & SSTAT0_ORF) && (sc->features & SF_CHIP_DFBC) == 0) 506 dbc++; 507 if (siop_cmd->siop_target->flags & TARF_ISWIDE) { 508 sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, 509 SIOP_SSTAT2); 510 if (sstat & SSTAT2_OLF1) 511 dbc++; 512 if ((sstat & SSTAT2_ORF1) && 513 (sc->features & SF_CHIP_DFBC) == 0) 514 dbc++; 515 } 516 /* clear the FIFO */ 517 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, 518 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) | 519 CTEST3_CLF); 520 } 521 table->addr = 522 htole32(le32toh(table->addr) + le32toh(table->count) - dbc); 523 table->count = htole32(dbc); 524 #ifdef DEBUG_DR 525 printf("now count=%d addr=0x%x\n", table->count, table->addr); 526 #endif 527 } 528 529 void 530 siop_clearfifo(sc) 531 struct siop_softc *sc; 532 { 533 int timeout = 0; 534 int ctest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3); 535 536 #ifdef DEBUG_INTR 537 printf("DMA fifo not empty !\n"); 538 #endif 539 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, 540 ctest3 | CTEST3_CLF); 541 while ((bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) & 542 CTEST3_CLF) != 0) { 543 delay(1); 544 if (++timeout > 1000) { 545 printf("clear fifo failed\n"); 546 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, 547 bus_space_read_1(sc->sc_rt, sc->sc_rh, 548 SIOP_CTEST3) & ~CTEST3_CLF); 549 return; 550 } 551 } 552 } 553 554 int 555 siop_modechange(sc) 556 struct siop_softc *sc; 557 { 558 int retry; 559 int sist0, sist1, stest2, stest4; 560 for (retry = 0; retry < 5; retry++) { 561 /* 562 * datasheet says to wait 100ms and re-read SIST1, 563 * to check that DIFFSENSE is stable. 564 * We may delay() 5 times for 100ms at interrupt time; 565 * hopefully this will not happen often. 566 */ 567 delay(100000); 568 sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0); 569 sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1); 570 if (sist1 & SIEN1_SBMC) 571 continue; /* we got an irq again */ 572 stest4 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) & 573 STEST4_MODE_MASK; 574 stest2 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2); 575 switch(stest4) { 576 case STEST4_MODE_DIF: 577 printf("%s: switching to differential mode\n", 578 sc->sc_dev.dv_xname); 579 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 580 stest2 | STEST2_DIF); 581 break; 582 case STEST4_MODE_SE: 583 printf("%s: switching to single-ended mode\n", 584 sc->sc_dev.dv_xname); 585 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 586 stest2 & ~STEST2_DIF); 587 break; 588 case STEST4_MODE_LVD: 589 printf("%s: switching to LVD mode\n", 590 sc->sc_dev.dv_xname); 591 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 592 stest2 & ~STEST2_DIF); 593 break; 594 default: 595 printf("%s: invalid SCSI mode 0x%x\n", 596 sc->sc_dev.dv_xname, stest4); 597 return 0; 598 } 599 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST0, 600 stest4 >> 2); 601 return 1; 602 } 603 printf("%s: timeout waiting for DIFFSENSE to stabilise\n", 604 sc->sc_dev.dv_xname); 605 return 0; 606 } 607 608 void 609 siop_resetbus(sc) 610 struct siop_softc *sc; 611 { 612 int scntl1; 613 scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1); 614 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 615 scntl1 | SCNTL1_RST); 616 /* minimum 25 us, more time won't hurt */ 617 delay(100); 618 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1); 619 } 620