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