1 /* $OpenBSD: siop_common.c,v 1.9 2001/08/06 14:29:59 krw Exp $ */ 2 /* $NetBSD: siop_common.c,v 1.12 2001/02/11 18:04:50 bouyer Exp $ */ 3 4 /* 5 * Copyright (c) 2000 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 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Manuel Bouyer 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 * 32 */ 33 34 /* SYM53c7/8xx PCI-SCSI I/O Processors driver */ 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/device.h> 39 #include <sys/malloc.h> 40 #include <sys/buf.h> 41 #include <sys/kernel.h> 42 #include <sys/scsiio.h> 43 44 #include <machine/endian.h> 45 #include <machine/bus.h> 46 47 #include <scsi/scsi_all.h> 48 #include <scsi/scsi_message.h> 49 #include <scsi/scsiconf.h> 50 51 #include <dev/ic/siopreg.h> 52 #include <dev/ic/siopvar.h> 53 #include <dev/ic/siopvar_common.h> 54 55 #undef DEBUG 56 #undef DEBUG_DR 57 58 void 59 siop_common_reset(sc) 60 struct siop_softc *sc; 61 { 62 u_int32_t stest3; 63 64 /* reset the chip */ 65 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SRST); 66 delay(1000); 67 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, 0); 68 69 /* init registers */ 70 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL0, 71 SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP); 72 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 0); 73 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, sc->clock_div); 74 if (sc->features & SF_CHIP_C10) 75 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, 0); 76 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 0); 77 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DIEN, 0xff); 78 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN0, 79 0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL)); 80 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN1, 81 0xff & ~(SIEN1_HTH | SIEN1_GEN)); 82 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 0); 83 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, STEST3_TE); 84 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STIME0, 85 (0xb << STIME0_SEL_SHIFT)); 86 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCID, 87 sc->sc_link.adapter_target | SCID_RRE); 88 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_RESPID0, 89 1 << sc->sc_link.adapter_target); 90 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DCNTL, 91 (sc->features & SF_CHIP_PF) ? DCNTL_COM | DCNTL_PFEN : DCNTL_COM); 92 93 /* enable clock doubler or quadruler if appropriate */ 94 if (sc->features & (SF_CHIP_DBLR | SF_CHIP_QUAD)) { 95 stest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3); 96 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 97 STEST1_DBLEN); 98 if ((sc->features & (SF_CHIP_QUAD | SF_CHIP_C10)) == SF_CHIP_QUAD) { 99 /* wait for PPL to lock */ 100 while ((bus_space_read_1(sc->sc_rt, sc->sc_rh, 101 SIOP_STEST4) & STEST4_LOCK) == 0) 102 delay(10); 103 } else { 104 /* data sheet says 20us - more won't hurt */ 105 delay(100); 106 } 107 /* halt scsi clock, select doubler/quad, restart clock */ 108 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, 109 stest3 | STEST3_HSC); 110 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 111 STEST1_DBLEN | STEST1_DBLSEL); 112 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, stest3); 113 } else { 114 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 0); 115 } 116 if (sc->features & SF_CHIP_FIFO) 117 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5, 118 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5) | 119 CTEST5_DFS); 120 121 sc->sc_reset(sc); 122 } 123 124 /* prepare tables before sending a cmd */ 125 void 126 siop_setuptables(siop_cmd) 127 struct siop_cmd *siop_cmd; 128 { 129 int i; 130 struct siop_softc *sc = siop_cmd->siop_sc; 131 struct scsi_xfer *xs = siop_cmd->xs; 132 int target = xs->sc_link->target; 133 int lun = xs->sc_link->lun; 134 int targ_flags = sc->targets[target]->flags; 135 136 siop_cmd->siop_tables.id = htole32(sc->targets[target]->id); 137 memset(siop_cmd->siop_tables.msg_out, 0, 8); 138 if (siop_cmd->status != CMDST_SENSE) 139 siop_cmd->siop_tables.msg_out[0] = MSG_IDENTIFY(lun, 1); 140 else 141 siop_cmd->siop_tables.msg_out[0] = MSG_IDENTIFY(lun, 0); 142 siop_cmd->siop_tables.t_msgout.count= htole32(1); 143 if (sc->targets[target]->status == TARST_ASYNC) { 144 if (targ_flags & TARF_PPR) { 145 sc->targets[target]->status = TARST_PPR_NEG; 146 if (sc->min_dt_sync != 0) 147 siop_ppr_msg(siop_cmd, 1, sc->min_dt_sync, sc->maxoff); 148 else 149 siop_ppr_msg(siop_cmd, 1, sc->min_st_sync, sc->maxoff); 150 } else if (targ_flags & TARF_WIDE) { 151 sc->targets[target]->status = TARST_WIDE_NEG; 152 siop_wdtr_msg(siop_cmd, 1, MSG_EXT_WDTR_BUS_16_BIT); 153 } else if (targ_flags & TARF_SYNC) { 154 sc->targets[target]->status = TARST_SYNC_NEG; 155 siop_sdtr_msg(siop_cmd, 1, sc->min_st_sync, sc->maxoff); 156 } else { 157 sc->targets[target]->status = TARST_OK; 158 siop_print_info(sc, target); 159 } 160 } else if (sc->targets[target]->status == TARST_OK && 161 (targ_flags & TARF_TAG) && 162 siop_cmd->status != CMDST_SENSE) { 163 siop_cmd->flags |= CMDFL_TAG; 164 } 165 siop_cmd->siop_tables.status = 166 htole32(SCSI_SIOP_NOSTATUS); /* set invalid status */ 167 168 siop_cmd->siop_tables.cmd.count = 169 htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len); 170 siop_cmd->siop_tables.cmd.addr = 171 htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr); 172 if ((xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) || 173 siop_cmd->status == CMDST_SENSE) { 174 for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) { 175 siop_cmd->siop_tables.data[i].count = 176 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len); 177 siop_cmd->siop_tables.data[i].addr = 178 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr); 179 } 180 } 181 siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 182 } 183 184 int 185 siop_ppr_neg(siop_cmd) 186 struct siop_cmd *siop_cmd; 187 { 188 struct siop_softc *sc = siop_cmd->siop_sc; 189 struct siop_target *siop_target = siop_cmd->siop_target; 190 int target = siop_cmd->xs->sc_link->target; 191 struct siop_xfer_common *tables = &siop_cmd->siop_xfer->tables; 192 int offset, sync, protocol, scf; 193 194 sync = tables->msg_in[3]; 195 offset = tables->msg_in[5]; 196 protocol = tables->msg_in[7]; 197 198 #ifdef DEBUG 199 printf("%s: siop_ppr_neg: sync = %x, offset = %x, protocol = %x\n", 200 sc->sc_dev.dv_xname, sync, offset, protocol); 201 #endif 202 /* 203 * Process protocol bits first, because finding the correct scf 204 * via siop_period_factor_to_scf() requires the TARF_ISDT flag 205 * to be correctly set. 206 */ 207 if (protocol & MSG_EXT_PPR_PROT_IUS) 208 siop_target->flags |= TARF_ISIUS; 209 210 if (protocol & MSG_EXT_PPR_PROT_DT) { 211 siop_target->flags |= TARF_ISDT; 212 sc->targets[target]->id |= SCNTL4_ULTRA3; 213 } 214 215 if (protocol & MSG_EXT_PPR_PROT_QAS) 216 siop_target->flags |= TARF_ISQAS; 217 218 scf = siop_period_factor_to_scf(sc, sync, siop_target->flags); 219 220 if ((offset > sc->maxoff) || 221 (scf == 0) || 222 ((siop_target->flags & TARF_ISDT) && (offset == 1))) { 223 tables->t_msgout.count= htole32(1); 224 tables->msg_out[0] = MSG_MESSAGE_REJECT; 225 return (SIOP_NEG_MSGOUT); 226 } 227 228 siop_target->id |= scf << (24 + SCNTL3_SCF_SHIFT); 229 230 if (((sc->features & SF_CHIP_C10) == 0) && (sync < 25)) 231 siop_target->id |= SCNTL3_ULTRA << 24; 232 233 siop_target->id |= (offset & 0xff) << 8; 234 235 if (tables->msg_in[6] == MSG_EXT_WDTR_BUS_16_BIT) { 236 siop_target->flags |= TARF_ISWIDE; 237 sc->targets[target]->id |= (SCNTL3_EWS << 24); 238 } 239 240 #ifdef DEBUG 241 printf("%s: siop_ppr_neg: id now 0x%x, flags is now 0x%x\n", 242 sc->sc_dev.dv_xname, siop_target->id, siop_target->flags); 243 #endif 244 tables->id = htole32(siop_target->id); 245 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 246 (siop_target->id >> 24) & 0xff); 247 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 248 (siop_target->id >> 8) & 0xff); 249 /* Only cards with SCNTL4 can cause PPR negotiations, so ... */ 250 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, 251 (siop_target->id & 0xff)); 252 253 siop_target->status = TARST_OK; 254 siop_print_info(sc, target); 255 256 return (SIOP_NEG_ACK); 257 } 258 259 int 260 siop_wdtr_neg(siop_cmd) 261 struct siop_cmd *siop_cmd; 262 { 263 struct siop_softc *sc = siop_cmd->siop_sc; 264 struct siop_target *siop_target = siop_cmd->siop_target; 265 int target = siop_cmd->xs->sc_link->target; 266 struct siop_xfer_common *tables = &siop_cmd->siop_xfer->tables; 267 268 /* revert to narrow async until told otherwise */ 269 sc->targets[target]->id &= 0x07ff0000; /* Keep SCNTL3.CCF and id */ 270 sc->targets[target]->flags &= ~(TARF_ISWIDE | TARF_ISDT | TARF_ISQAS | TARF_ISIUS); 271 272 tables->id = htole32(sc->targets[target]->id); 273 274 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 275 (sc->targets[target]->id >> 24) & 0xff); 276 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 0); 277 if (sc->features & SF_CHIP_C10) 278 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, 0); 279 280 if (siop_target->status == TARST_WIDE_NEG) { 281 /* we initiated wide negotiation */ 282 switch (tables->msg_in[3]) { 283 case MSG_EXT_WDTR_BUS_8_BIT: 284 siop_target->flags &= ~TARF_ISWIDE; 285 sc->targets[target]->id &= ~(SCNTL3_EWS << 24); 286 break; 287 case MSG_EXT_WDTR_BUS_16_BIT: 288 if (siop_target->flags & TARF_WIDE) { 289 siop_target->flags |= TARF_ISWIDE; 290 sc->targets[target]->id |= (SCNTL3_EWS << 24); 291 break; 292 } 293 /* FALLTHROUGH */ 294 default: 295 /* 296 * We got more than we can handle, which shouldn't 297 * happen. Reject, and stay async. 298 */ 299 siop_target->flags &= ~TARF_ISWIDE; 300 siop_target->status = TARST_OK; 301 printf("%s: rejecting invalid wide negotiation from " 302 "target %d (%d)\n", sc->sc_dev.dv_xname, target, 303 tables->msg_in[3]); 304 siop_print_info(sc, target); 305 tables->t_msgout.count= htole32(1); 306 tables->msg_out[0] = MSG_MESSAGE_REJECT; 307 return SIOP_NEG_MSGOUT; 308 } 309 tables->id = htole32(sc->targets[target]->id); 310 bus_space_write_1(sc->sc_rt, sc->sc_rh, 311 SIOP_SCNTL3, 312 (sc->targets[target]->id >> 24) & 0xff); 313 /* we now need to do sync */ 314 if (siop_target->flags & TARF_SYNC) { 315 siop_target->status = TARST_SYNC_NEG; 316 siop_sdtr_msg(siop_cmd, 0, sc->min_st_sync, sc->maxoff); 317 return SIOP_NEG_MSGOUT; 318 } else { 319 siop_target->status = TARST_OK; 320 siop_print_info(sc, target); 321 return SIOP_NEG_ACK; 322 } 323 } else { 324 /* target initiated wide negotiation */ 325 if (tables->msg_in[3] >= MSG_EXT_WDTR_BUS_16_BIT 326 && (siop_target->flags & TARF_WIDE)) { 327 siop_target->flags |= TARF_ISWIDE; 328 sc->targets[target]->id |= SCNTL3_EWS << 24; 329 } else { 330 siop_target->flags &= ~TARF_ISWIDE; 331 sc->targets[target]->id &= ~(SCNTL3_EWS << 24); 332 } 333 tables->id = htole32(sc->targets[target]->id); 334 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 335 (sc->targets[target]->id >> 24) & 0xff); 336 /* 337 * Don't schedule a sync neg, target should initiate it. 338 */ 339 if (siop_target->status != TARST_PROBING) { 340 siop_target->status = TARST_OK; 341 siop_print_info(sc, target); 342 } 343 siop_wdtr_msg(siop_cmd, 0, (siop_target->flags & TARF_ISWIDE) ? 344 MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT); 345 return SIOP_NEG_MSGOUT; 346 } 347 } 348 349 int 350 siop_sdtr_neg(siop_cmd) 351 struct siop_cmd *siop_cmd; 352 { 353 struct siop_softc *sc = siop_cmd->siop_sc; 354 struct siop_target *siop_target = siop_cmd->siop_target; 355 int target = siop_cmd->xs->sc_link->target; 356 int sync, offset, scf; 357 int send_msgout = 0; 358 struct siop_xfer_common *tables = &siop_cmd->siop_xfer->tables; 359 360 sync = tables->msg_in[3]; 361 offset = tables->msg_in[4]; 362 363 /* revert to async until told otherwise */ 364 sc->targets[target]->id &= 0x0fff0000; /* Keep SCNTL3.EWS, SCNTL3.CCF and id */ 365 sc->targets[target]->flags &= ~(TARF_ISDT | TARF_ISQAS | TARF_ISIUS); 366 367 if (siop_target->status == TARST_SYNC_NEG) { 368 /* we initiated sync negotiation */ 369 #ifdef DEBUG 370 printf("%s: sdtr for target %d: sync %d offset %d\n", 371 sc->sc_dev.dv_xname, target, sync, offset); 372 #endif 373 scf = siop_period_factor_to_scf(sc, sync, sc->targets[target]->flags); 374 if (offset > sc->maxoff || scf == 0) 375 goto reject; 376 sc->targets[target]->id |= scf << (24 + SCNTL3_SCF_SHIFT); 377 if (((sc->features & SF_CHIP_C10) == 0) && (sync < 25)) 378 sc->targets[target]->id |= SCNTL3_ULTRA << 24; 379 sc->targets[target]->id |= (offset & 0xff) << 8; 380 goto end; 381 /* 382 * We didn't find it in our table, so stay async and send reject 383 * msg. 384 */ 385 reject: 386 send_msgout = 1; 387 tables->t_msgout.count= htole32(1); 388 tables->msg_out[0] = MSG_MESSAGE_REJECT; 389 } else { /* target initiated sync neg */ 390 #ifdef DEBUG 391 printf("%s: target initiated sdtr for target %d: sync %d offset %d\n", 392 sc->sc_dev.dv_xname, target, sync, offset); 393 printf("sdtr (target): sync %d offset %d\n", sync, offset); 394 #endif 395 if (sync < sc->min_st_sync) 396 sync = sc->min_st_sync; 397 scf = siop_period_factor_to_scf(sc, sync, sc->targets[target]->flags); 398 if ((sc->targets[target]->flags & TARF_SYNC) == 0 399 || offset == 0 400 || scf == 0) { 401 goto async; 402 } 403 if ((offset > 31) && ((sc->targets[target]->flags & TARF_ISDT) == 0)) 404 offset = 31; 405 if (offset > sc->maxoff) 406 offset = sc->maxoff; 407 408 sc->targets[target]->id |= scf << (24 + SCNTL3_SCF_SHIFT); 409 if (((sc->features & SF_CHIP_C10) == 0) && (sync < 25)) 410 sc->targets[target]->id |= SCNTL3_ULTRA << 24; 411 sc->targets[target]->id |= (offset & 0xff) << 8; 412 siop_sdtr_msg(siop_cmd, 0, sync, offset); 413 send_msgout = 1; 414 goto end; 415 async: 416 siop_sdtr_msg(siop_cmd, 0, 0, 0); 417 send_msgout = 1; 418 } 419 end: 420 #ifdef DEBUG 421 printf("id now 0x%x\n", sc->targets[target]->id); 422 #endif 423 tables->id = htole32(sc->targets[target]->id); 424 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 425 (sc->targets[target]->id >> 24) & 0xff); 426 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 427 (sc->targets[target]->id >> 8) & 0xff); 428 429 if (siop_target->status != TARST_PROBING) { 430 siop_target->status = TARST_OK; 431 siop_print_info(sc, target); 432 } 433 434 if (send_msgout) { 435 return SIOP_NEG_MSGOUT; 436 } else { 437 return SIOP_NEG_ACK; 438 } 439 } 440 441 void 442 siop_ppr_msg(siop_cmd, offset, ssync, soff) 443 struct siop_cmd *siop_cmd; 444 int offset, ssync, soff; 445 { 446 struct siop_softc *sc = siop_cmd->siop_sc; 447 u_int8_t protocol; 448 449 siop_cmd->siop_tables.msg_out[offset + 0] = MSG_EXTENDED; 450 siop_cmd->siop_tables.msg_out[offset + 1] = MSG_EXT_PPR_LEN; 451 siop_cmd->siop_tables.msg_out[offset + 2] = MSG_EXT_PPR; 452 siop_cmd->siop_tables.msg_out[offset + 3] = ssync; 453 siop_cmd->siop_tables.msg_out[offset + 4] = 0; /* RESERVED */ 454 siop_cmd->siop_tables.msg_out[offset + 5] = soff; 455 siop_cmd->siop_tables.msg_out[offset + 6] = MSG_EXT_WDTR_BUS_16_BIT; 456 457 protocol = 0; 458 if (sc->min_dt_sync != 0) 459 protocol |= MSG_EXT_PPR_PROT_DT; 460 461 /* XXX - need tests for chip's capability to do QAS & IUS 462 * 463 * if (test for QAS support) 464 * protocol |= MSG_EXT_PPR_PROT_QAS; 465 * if (test for IUS support) 466 * protocol |= MSG_EXT_PPR_PROT_IUS; 467 */ 468 469 siop_cmd->siop_tables.msg_out[offset + 7] = protocol; 470 471 siop_cmd->siop_tables.t_msgout.count = 472 htole32(offset + MSG_EXT_PPR_LEN + 2); 473 } 474 475 void 476 siop_sdtr_msg(siop_cmd, offset, ssync, soff) 477 struct siop_cmd *siop_cmd; 478 int offset; 479 int ssync, soff; 480 { 481 siop_cmd->siop_tables.msg_out[offset + 0] = MSG_EXTENDED; 482 siop_cmd->siop_tables.msg_out[offset + 1] = MSG_EXT_SDTR_LEN; 483 siop_cmd->siop_tables.msg_out[offset + 2] = MSG_EXT_SDTR; 484 siop_cmd->siop_tables.msg_out[offset + 3] = ssync; 485 486 if ((soff > 31) && ((siop_cmd->siop_target->flags & TARF_ISDT) == 0)) 487 soff = 31; 488 489 siop_cmd->siop_tables.msg_out[offset + 4] = soff; 490 siop_cmd->siop_tables.t_msgout.count = 491 htole32(offset + MSG_EXT_SDTR_LEN + 2); 492 } 493 494 void 495 siop_wdtr_msg(siop_cmd, offset, wide) 496 struct siop_cmd *siop_cmd; 497 int offset; 498 { 499 siop_cmd->siop_tables.msg_out[offset + 0] = MSG_EXTENDED; 500 siop_cmd->siop_tables.msg_out[offset + 1] = MSG_EXT_WDTR_LEN; 501 siop_cmd->siop_tables.msg_out[offset + 2] = MSG_EXT_WDTR; 502 siop_cmd->siop_tables.msg_out[offset + 3] = wide; 503 siop_cmd->siop_tables.t_msgout.count = 504 htole32(offset + MSG_EXT_WDTR_LEN + 2); 505 } 506 507 void 508 siop_minphys(bp) 509 struct buf *bp; 510 { 511 minphys(bp); 512 } 513 514 void 515 siop_sdp(siop_cmd) 516 struct siop_cmd *siop_cmd; 517 { 518 /* save data pointer. Handle async only for now */ 519 int offset, dbc, sstat; 520 struct siop_softc *sc = siop_cmd->siop_sc; 521 scr_table_t *table; /* table to patch */ 522 523 if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN)) 524 == 0) 525 return; /* no data pointers to save */ 526 offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1); 527 if (offset >= SIOP_NSG) { 528 printf("%s: bad offset in siop_sdp (%d)\n", 529 sc->sc_dev.dv_xname, offset); 530 return; 531 } 532 table = &siop_cmd->siop_xfer->tables.data[offset]; 533 #ifdef DEBUG_DR 534 printf("sdp: offset %d count=%d addr=0x%x ", offset, 535 table->count, table->addr); 536 #endif 537 dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff; 538 if (siop_cmd->xs->flags & SCSI_DATA_OUT) { 539 /* need to account for stale data in FIFO */ 540 if (sc->features & SF_CHIP_C10) 541 dbc += bus_space_read_2(sc->sc_rt, sc->sc_rh, SIOP_DFBC); 542 else { 543 int dfifo = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO); 544 if (sc->features & SF_CHIP_FIFO) { 545 dfifo |= (bus_space_read_1(sc->sc_rt, sc->sc_rh, 546 SIOP_CTEST5) & CTEST5_BOMASK) << 8; 547 dbc += (dfifo - (dbc & 0x3ff)) & 0x3ff; 548 } else { 549 dbc += (dfifo - (dbc & 0x7f)) & 0x7f; 550 } 551 } 552 sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0); 553 if (sstat & SSTAT0_OLF) 554 dbc++; 555 if ((sc->features & SF_CHIP_C10) == 0) 556 if (sstat & SSTAT0_ORF) 557 dbc++; 558 if (siop_cmd->siop_target->flags & TARF_ISWIDE) { 559 sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, 560 SIOP_SSTAT2); 561 if (sstat & SSTAT2_OLF1) 562 dbc++; 563 if ((sc->features & SF_CHIP_C10) == 0) 564 if (sstat & SSTAT2_ORF1) 565 dbc++; 566 } 567 /* clear the FIFO */ 568 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, 569 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) | 570 CTEST3_CLF); 571 } 572 table->addr = 573 htole32(letoh32(table->addr) + letoh32(table->count) - dbc); 574 table->count = htole32(dbc); 575 #ifdef DEBUG_DR 576 printf("now count=%d addr=0x%x\n", table->count, table->addr); 577 #endif 578 } 579 580 void 581 siop_clearfifo(sc) 582 struct siop_softc *sc; 583 { 584 int timeout = 0; 585 int ctest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3); 586 587 #ifdef SIOP_DEBUG_INTR 588 printf("DMA fifo not empty!\n"); 589 #endif 590 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, 591 ctest3 | CTEST3_CLF); 592 while ((bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) & 593 CTEST3_CLF) != 0) { 594 delay(1); 595 if (++timeout > 1000) { 596 printf("clear fifo failed\n"); 597 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, 598 bus_space_read_1(sc->sc_rt, sc->sc_rh, 599 SIOP_CTEST3) & ~CTEST3_CLF); 600 return; 601 } 602 } 603 } 604 605 int 606 siop_modechange(sc) 607 struct siop_softc *sc; 608 { 609 int retry; 610 int sist0, sist1, stest2, stest4; 611 for (retry = 0; retry < 5; retry++) { 612 /* 613 * Datasheet says to wait 100ms and re-read SIST1, 614 * to check that DIFFSENSE is stable. 615 * We may delay() 5 times for 100ms at interrupt time; 616 * hopefully this will not happen often. 617 */ 618 delay(100000); 619 sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0); 620 sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1); 621 if (sist1 & SIEN1_SBMC) 622 continue; /* we got an irq again */ 623 stest4 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) & 624 STEST4_MODE_MASK; 625 stest2 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2); 626 switch(stest4) { 627 case STEST4_MODE_DIF: 628 if (sc->features & SF_CHIP_C10) { 629 printf("%s: invalid SCSI mode 0x%x\n", 630 sc->sc_dev.dv_xname, stest4); 631 return 0; 632 } else { 633 printf("%s: switching to differential mode\n", 634 sc->sc_dev.dv_xname); 635 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 636 stest2 | STEST2_DIF); 637 } 638 break; 639 case STEST4_MODE_SE: 640 printf("%s: switching to single-ended mode\n", 641 sc->sc_dev.dv_xname); 642 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 643 stest2 & ~STEST2_DIF); 644 break; 645 case STEST4_MODE_LVD: 646 printf("%s: switching to LVD mode\n", 647 sc->sc_dev.dv_xname); 648 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 649 stest2 & ~STEST2_DIF); 650 break; 651 default: 652 printf("%s: invalid SCSI mode 0x%x\n", 653 sc->sc_dev.dv_xname, stest4); 654 return 0; 655 } 656 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST0, 657 stest4 >> 2); 658 return 1; 659 } 660 printf("%s: timeout waiting for DIFFSENSE to stabilise\n", 661 sc->sc_dev.dv_xname); 662 return 0; 663 } 664 665 void 666 siop_resetbus(sc) 667 struct siop_softc *sc; 668 { 669 int scntl1; 670 scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1); 671 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 672 scntl1 | SCNTL1_RST); 673 /* minimum 25 us, more time won't hurt */ 674 delay(100); 675 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1); 676 } 677 678 /* 679 * siop_print_info: print the current negotiated wide/sync xfer values for 680 * a particular target. This function is called whenever 681 * a wide/sync negotiation completes, i.e. whenever 682 * target->status is set to TARST_OK. 683 */ 684 void 685 siop_print_info(sc, target) 686 struct siop_softc *sc; 687 int target; 688 { 689 struct siop_target *siop_target; 690 u_int8_t scf, offset; 691 int scf_index, factors, i; 692 693 siop_target = sc->targets[target]; 694 695 printf("%s: target %d now using %s%s%s%s%d bit ", 696 sc->sc_dev.dv_xname, target, 697 (siop_target->flags & TARF_TAG) ? "tagged " : "", 698 (siop_target->flags & TARF_ISDT) ? "DT " : "", 699 (siop_target->flags & TARF_ISQAS) ? "QAS " : "", 700 (siop_target->flags & TARF_ISIUS) ? "IUS " : "", 701 (siop_target->flags & TARF_ISWIDE) ? 16 : 8); 702 703 offset = ((siop_target->id >> 8) & 0xff) >> SXFER_MO_SHIFT; 704 705 if (offset == 0) 706 printf("async "); 707 else { 708 factors = sizeof(period_factor) / sizeof(period_factor[0]); 709 710 scf = ((siop_target->id >> 24) & SCNTL3_SCF_MASK) >> SCNTL3_SCF_SHIFT; 711 scf_index = sc->scf_index; 712 713 for (i = 0; i < factors; i++) 714 if (siop_target->flags & TARF_ISDT) { 715 if (period_factor[i].scf[scf_index].dt_scf == scf) 716 break; 717 } 718 else if (period_factor[i].scf[scf_index].st_scf == scf) 719 break; 720 721 if (i >= factors) 722 printf("?? "); 723 else 724 printf("%s ", period_factor[i].rate); 725 726 printf("MHz %d REQ/ACK offset ", offset); 727 } 728 729 printf("xfers\n"); 730 } 731 732 int 733 siop_period_factor_to_scf(sc, pf, flags) 734 struct siop_softc *sc; 735 int pf, flags; 736 { 737 const int scf_index = sc->scf_index; 738 int i; 739 740 const int factors = sizeof(period_factor) / sizeof(period_factor[0]); 741 742 for (i = 0; i < factors; i++) 743 if (period_factor[i].factor == pf) { 744 if (flags & TARF_ISDT) 745 return (period_factor[i].scf[scf_index].dt_scf); 746 else 747 return (period_factor[i].scf[scf_index].st_scf); 748 } 749 750 return (0); 751 } 752