1 /* $OpenBSD: siop_common.c,v 1.16 2003/07/01 17:15:06 krw Exp $ */ 2 /* $NetBSD: siop_common.c,v 1.31 2002/09/27 15:37:18 provos Exp $ */ 3 4 /* 5 * Copyright (c) 2000, 2002 Manuel Bouyer. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 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_common.h> 53 #include <dev/ic/siopvar.h> 54 55 #undef DEBUG 56 #undef DEBUG_DR 57 #undef DEBUG_NEG 58 59 int 60 siop_common_attach(sc) 61 struct siop_common_softc *sc; 62 { 63 int error, i; 64 bus_dma_segment_t seg; 65 int rseg; 66 67 /* 68 * Allocate DMA-safe memory for the script and map it. 69 */ 70 if ((sc->features & SF_CHIP_RAM) == 0) { 71 error = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, 72 PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT); 73 if (error) { 74 printf("%s: unable to allocate script DMA memory, " 75 "error = %d\n", sc->sc_dev.dv_xname, error); 76 return error; 77 } 78 error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, PAGE_SIZE, 79 (caddr_t *)&sc->sc_script, 80 BUS_DMA_NOWAIT|BUS_DMA_COHERENT); 81 if (error) { 82 printf("%s: unable to map script DMA memory, " 83 "error = %d\n", sc->sc_dev.dv_xname, error); 84 return error; 85 } 86 error = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, 87 PAGE_SIZE, 0, BUS_DMA_NOWAIT, &sc->sc_scriptdma); 88 if (error) { 89 printf("%s: unable to create script DMA map, " 90 "error = %d\n", sc->sc_dev.dv_xname, error); 91 return error; 92 } 93 error = bus_dmamap_load(sc->sc_dmat, sc->sc_scriptdma, 94 sc->sc_script, PAGE_SIZE, NULL, BUS_DMA_NOWAIT); 95 if (error) { 96 printf("%s: unable to load script DMA map, " 97 "error = %d\n", sc->sc_dev.dv_xname, error); 98 return error; 99 } 100 sc->sc_scriptaddr = 101 sc->sc_scriptdma->dm_segs[0].ds_addr; 102 sc->ram_size = PAGE_SIZE; 103 } 104 105 /* 106 * sc->sc_link is the template for all device sc_link's 107 * for devices attached to this adapter. It is passed to 108 * the upper layers in config_found(). 109 */ 110 sc->sc_link.adapter_softc = sc; 111 sc->sc_link.adapter_buswidth = 112 (sc->features & SF_BUS_WIDE) ? 16 : 8; 113 sc->sc_link.adapter_target = 114 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCID); 115 if (sc->sc_link.adapter_target == 0 || 116 sc->sc_link.adapter_target >= 117 sc->sc_link.adapter_buswidth) 118 sc->sc_link.adapter_target = SIOP_DEFAULT_TARGET; 119 120 for (i = 0; i < 16; i++) 121 sc->targets[i] = NULL; 122 123 /* find min/max sync period for this chip */ 124 sc->st_maxsync = 0; 125 sc->dt_maxsync = 0; 126 sc->st_minsync = 255; 127 sc->dt_minsync = 255; 128 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); i++) { 129 if (sc->clock_period != scf_period[i].clock) 130 continue; 131 if (sc->st_maxsync < scf_period[i].period) 132 sc->st_maxsync = scf_period[i].period; 133 if (sc->st_minsync > scf_period[i].period) 134 sc->st_minsync = scf_period[i].period; 135 } 136 if (sc->st_maxsync == 255 || sc->st_minsync == 0) 137 panic("siop: can't find my sync parameters"); 138 for (i = 0; i < sizeof(dt_scf_period) / sizeof(dt_scf_period[0]); i++) { 139 if (sc->clock_period != dt_scf_period[i].clock) 140 continue; 141 if (sc->dt_maxsync < dt_scf_period[i].period) 142 sc->dt_maxsync = dt_scf_period[i].period; 143 if (sc->dt_minsync > dt_scf_period[i].period) 144 sc->dt_minsync = dt_scf_period[i].period; 145 } 146 if (sc->dt_maxsync == 255 || sc->dt_minsync == 0) 147 panic("siop: can't find my sync parameters"); 148 return 0; 149 } 150 151 void 152 siop_common_reset(sc) 153 struct siop_common_softc *sc; 154 { 155 u_int32_t stest3; 156 157 /* reset the chip */ 158 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SRST); 159 delay(1000); 160 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, 0); 161 162 /* init registers */ 163 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL0, 164 SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP); 165 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 0); 166 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, sc->clock_div); 167 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 0); 168 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DIEN, 0xff); 169 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN0, 170 0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL)); 171 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN1, 172 0xff & ~(SIEN1_HTH | SIEN1_GEN)); 173 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 0); 174 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, STEST3_TE); 175 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STIME0, 176 (0xb << STIME0_SEL_SHIFT)); 177 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCID, 178 sc->sc_link.adapter_target | SCID_RRE); 179 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_RESPID0, 180 1 << sc->sc_link.adapter_target); 181 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DCNTL, 182 (sc->features & SF_CHIP_PF) ? DCNTL_COM | DCNTL_PFEN : DCNTL_COM); 183 184 /* enable clock doubler or quadruler if appropriate */ 185 if (sc->features & (SF_CHIP_DBLR | SF_CHIP_QUAD)) { 186 stest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3); 187 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 188 STEST1_DBLEN); 189 if (sc->features & SF_CHIP_QUAD) { 190 /* wait for PPL to lock */ 191 while ((bus_space_read_1(sc->sc_rt, sc->sc_rh, 192 SIOP_STEST4) & STEST4_LOCK) == 0) 193 delay(10); 194 } else { 195 /* data sheet says 20us - more won't hurt */ 196 delay(100); 197 } 198 /* halt scsi clock, select doubler/quad, restart clock */ 199 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, 200 stest3 | STEST3_HSC); 201 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 202 STEST1_DBLEN | STEST1_DBLSEL); 203 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, stest3); 204 } else { 205 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 0); 206 } 207 if (sc->features & SF_CHIP_FIFO) 208 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5, 209 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5) | 210 CTEST5_DFS); 211 if (sc->features & SF_CHIP_LED0) { 212 /* Set GPIO0 as output if software LED control is required */ 213 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_GPCNTL, 214 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_GPCNTL) & 0xfe); 215 } 216 if (sc->features & SF_BUS_ULTRA3) { 217 /* reset SCNTL4 */ 218 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, 0); 219 } 220 sc->mode = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) & 221 STEST4_MODE_MASK; 222 223 /* 224 * initialise the RAM. Without this we may get scsi gross errors on 225 * the 1010 226 */ 227 if (sc->features & SF_CHIP_RAM) 228 bus_space_set_region_4(sc->sc_ramt, sc->sc_ramh, 229 0, 0, sc->ram_size / 4); 230 sc->sc_reset(sc); 231 } 232 233 /* prepare tables before sending a cmd */ 234 void 235 siop_setuptables(siop_cmd) 236 struct siop_common_cmd *siop_cmd; 237 { 238 int i; 239 struct siop_common_softc *sc = siop_cmd->siop_sc; 240 struct scsi_xfer *xs = siop_cmd->xs; 241 int target = xs->sc_link->target; 242 int lun = xs->sc_link->lun; 243 int msgoffset = 1; 244 int *targ_flags = &sc->targets[target]->flags; 245 int quirks; 246 247 siop_cmd->siop_tables->id = htole32(sc->targets[target]->id); 248 memset(siop_cmd->siop_tables->msg_out, 0, 249 sizeof(siop_cmd->siop_tables->msg_out)); 250 /* request sense doesn't disconnect */ 251 if (siop_cmd->status == CMDST_SENSE) 252 siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 0); 253 else if ((sc->features & SF_CHIP_GEBUG) && 254 (sc->targets[target]->flags & TARF_ISWIDE) == 0) 255 /* 256 * 1010 bug: it seems that the 1010 has problems with reselect 257 * when not in wide mode (generate false SCSI gross error). 258 * The FreeBSD sym driver has comments about it but their 259 * workaround (disable SCSI gross error reporting) doesn't 260 * work with my adapter. So disable disconnect when not 261 * wide. 262 */ 263 siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 0); 264 else 265 siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 1); 266 siop_cmd->siop_tables->t_msgout.count= htole32(msgoffset); 267 if (sc->targets[target]->status == TARST_ASYNC) { 268 *targ_flags &= TARF_DT; /* Save TARF_DT 'cuz we don't set it here */ 269 quirks = xs->sc_link->quirks; 270 271 if ((quirks & SDEV_NOTAGS) == 0) 272 *targ_flags |= TARF_TAG; 273 if (((quirks & SDEV_NOWIDE) == 0) && 274 (sc->features & SF_BUS_WIDE)) 275 *targ_flags |= TARF_WIDE; 276 if ((quirks & SDEV_NOSYNC) == 0) 277 *targ_flags |= TARF_SYNC; 278 279 if ((sc->features & SF_CHIP_GEBUG) && 280 (*targ_flags & TARF_WIDE) == 0) 281 /* 282 * 1010 workaround: can't do disconnect if not wide, 283 * so can't do tag 284 */ 285 *targ_flags &= ~TARF_TAG; 286 287 /* Safe to call siop_add_dev() multiple times */ 288 siop_add_dev((struct siop_softc *)sc, target, lun); 289 290 if ((*targ_flags & TARF_DT) && 291 (sc->mode == STEST4_MODE_LVD)) { 292 sc->targets[target]->status = TARST_PPR_NEG; 293 siop_ppr_msg(siop_cmd, msgoffset, sc->dt_minsync, 294 sc->maxoff); 295 } else if (*targ_flags & TARF_WIDE) { 296 sc->targets[target]->status = TARST_WIDE_NEG; 297 siop_wdtr_msg(siop_cmd, msgoffset, 298 MSG_EXT_WDTR_BUS_16_BIT); 299 } else if (*targ_flags & TARF_SYNC) { 300 sc->targets[target]->status = TARST_SYNC_NEG; 301 siop_sdtr_msg(siop_cmd, msgoffset, sc->st_minsync, 302 (sc->maxoff > 31) ? 31 : sc->maxoff); 303 } else { 304 sc->targets[target]->status = TARST_OK; 305 siop_update_xfer_mode(sc, target); 306 } 307 } else if (sc->targets[target]->status == TARST_OK && 308 (*targ_flags & TARF_TAG) && 309 siop_cmd->status != CMDST_SENSE) { 310 siop_cmd->flags |= CMDFL_TAG; 311 } 312 siop_cmd->siop_tables->status = 313 htole32(SCSI_SIOP_NOSTATUS); /* set invalid status */ 314 315 if ((xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) || 316 siop_cmd->status == CMDST_SENSE) { 317 for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) { 318 siop_cmd->siop_tables->data[i].count = 319 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len); 320 siop_cmd->siop_tables->data[i].addr = 321 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr); 322 } 323 } 324 } 325 326 int 327 siop_wdtr_neg(siop_cmd) 328 struct siop_common_cmd *siop_cmd; 329 { 330 struct siop_common_softc *sc = siop_cmd->siop_sc; 331 struct siop_common_target *siop_target = siop_cmd->siop_target; 332 int target = siop_cmd->xs->sc_link->target; 333 struct siop_common_xfer *tables = siop_cmd->siop_tables; 334 335 if (siop_target->status == TARST_WIDE_NEG) { 336 /* we initiated wide negotiation */ 337 switch (tables->msg_in[3]) { 338 case MSG_EXT_WDTR_BUS_8_BIT: 339 siop_target->flags &= ~TARF_ISWIDE; 340 sc->targets[target]->id &= ~(SCNTL3_EWS << 24); 341 break; 342 case MSG_EXT_WDTR_BUS_16_BIT: 343 if (siop_target->flags & TARF_WIDE) { 344 siop_target->flags |= TARF_ISWIDE; 345 sc->targets[target]->id |= (SCNTL3_EWS << 24); 346 break; 347 } 348 /* FALLTHROUH */ 349 default: 350 /* 351 * hum, we got more than what we can handle, shouldn't 352 * happen. Reject, and stay async 353 */ 354 siop_target->flags &= ~TARF_ISWIDE; 355 siop_target->status = TARST_OK; 356 siop_target->offset = siop_target->period = 0; 357 siop_update_xfer_mode(sc, target); 358 printf("%s: rejecting invalid wide negotiation from " 359 "target %d (%d)\n", sc->sc_dev.dv_xname, target, 360 tables->msg_in[3]); 361 tables->t_msgout.count= htole32(1); 362 tables->msg_out[0] = MSG_MESSAGE_REJECT; 363 return SIOP_NEG_MSGOUT; 364 } 365 tables->id = htole32(sc->targets[target]->id); 366 bus_space_write_1(sc->sc_rt, sc->sc_rh, 367 SIOP_SCNTL3, 368 (sc->targets[target]->id >> 24) & 0xff); 369 /* we now need to do sync */ 370 if (siop_target->flags & TARF_SYNC) { 371 siop_target->status = TARST_SYNC_NEG; 372 siop_sdtr_msg(siop_cmd, 0, sc->st_minsync, 373 (sc->maxoff > 31) ? 31 : sc->maxoff); 374 return SIOP_NEG_MSGOUT; 375 } else { 376 siop_target->status = TARST_OK; 377 siop_update_xfer_mode(sc, target); 378 return SIOP_NEG_ACK; 379 } 380 } else { 381 /* target initiated wide negotiation */ 382 if (tables->msg_in[3] >= MSG_EXT_WDTR_BUS_16_BIT 383 && (siop_target->flags & TARF_WIDE)) { 384 siop_target->flags |= TARF_ISWIDE; 385 sc->targets[target]->id |= SCNTL3_EWS << 24; 386 } else { 387 siop_target->flags &= ~TARF_ISWIDE; 388 sc->targets[target]->id &= ~(SCNTL3_EWS << 24); 389 } 390 tables->id = htole32(sc->targets[target]->id); 391 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 392 (sc->targets[target]->id >> 24) & 0xff); 393 /* 394 * we did reset wide parameters, so fall back to async, 395 * but don't schedule a sync neg, target should initiate it 396 */ 397 siop_target->status = TARST_OK; 398 siop_target->offset = siop_target->period = 0; 399 siop_update_xfer_mode(sc, target); 400 siop_wdtr_msg(siop_cmd, 0, (siop_target->flags & TARF_ISWIDE) ? 401 MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT); 402 return SIOP_NEG_MSGOUT; 403 } 404 } 405 406 int 407 siop_ppr_neg(siop_cmd) 408 struct siop_common_cmd *siop_cmd; 409 { 410 struct siop_common_softc *sc = siop_cmd->siop_sc; 411 struct siop_common_target *siop_target = siop_cmd->siop_target; 412 int target = siop_cmd->xs->sc_link->target; 413 struct siop_common_xfer *tables = siop_cmd->siop_tables; 414 int sync, offset, options, scf = 0; 415 int i; 416 417 #ifdef DEBUG_NEG 418 printf("%s: answer on ppr negotiation:", sc->sc_dev.dv_xname); 419 for (i = 0; i < 8; i++) 420 printf(" 0x%x", tables->msg_in[i]); 421 printf("\n"); 422 #endif 423 424 if (siop_target->status == TARST_PPR_NEG) { 425 /* we initiated PPR negotiation */ 426 sync = tables->msg_in[3]; 427 offset = tables->msg_in[5]; 428 options = tables->msg_in[7]; 429 if (options != MSG_EXT_PPR_PROT_DT) { 430 /* should't happen */ 431 printf("%s: ppr negotiation for target %d: " 432 "no DT option\n", sc->sc_dev.dv_xname, target); 433 siop_target->status = TARST_ASYNC; 434 siop_target->flags &= ~(TARF_DT | TARF_ISDT); 435 siop_target->offset = 0; 436 siop_target->period = 0; 437 goto reject; 438 } 439 440 if (offset > sc->maxoff || sync < sc->dt_minsync || 441 sync > sc->dt_maxsync) { 442 printf("%s: ppr negotiation for target %d: " 443 "offset (%d) or sync (%d) out of range\n", 444 sc->sc_dev.dv_xname, target, offset, sync); 445 /* should not happen */ 446 siop_target->status = TARST_ASYNC; 447 siop_target->flags &= ~(TARF_DT | TARF_ISDT); 448 siop_target->offset = 0; 449 siop_target->period = 0; 450 goto reject; 451 } else { 452 for (i = 0; i < 453 sizeof(dt_scf_period) / sizeof(dt_scf_period[0]); 454 i++) { 455 if (sc->clock_period != dt_scf_period[i].clock) 456 continue; 457 if (dt_scf_period[i].period == sync) { 458 /* ok, found it. we now are sync. */ 459 siop_target->offset = offset; 460 siop_target->period = sync; 461 scf = dt_scf_period[i].scf; 462 siop_target->flags |= TARF_ISDT; 463 } 464 } 465 if ((siop_target->flags & TARF_ISDT) == 0) { 466 printf("%s: ppr negotiation for target %d: " 467 "sync (%d) incompatible with adapter\n", 468 sc->sc_dev.dv_xname, target, sync); 469 /* 470 * we didn't find it in our table, do async 471 * send reject msg, start SDTR/WDTR neg 472 */ 473 siop_target->status = TARST_ASYNC; 474 siop_target->flags &= ~(TARF_DT | TARF_ISDT); 475 siop_target->offset = 0; 476 siop_target->period = 0; 477 goto reject; 478 } 479 } 480 if (tables->msg_in[6] != 1) { 481 printf("%s: ppr negotiation for target %d: " 482 "transfer width (%d) incompatible with dt\n", 483 sc->sc_dev.dv_xname, target, tables->msg_in[6]); 484 /* DT mode can only be done with wide transfers */ 485 siop_target->status = TARST_ASYNC; 486 siop_target->flags &= ~(TARF_DT | TARF_ISDT); 487 siop_target->offset = 0; 488 siop_target->period = 0; 489 goto reject; 490 } 491 siop_target->flags |= TARF_ISWIDE; 492 sc->targets[target]->id |= (SCNTL3_EWS << 24); 493 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24); 494 sc->targets[target]->id |= scf << (24 + SCNTL3_SCF_SHIFT); 495 sc->targets[target]->id &= ~(SXFER_MO_MASK << 8); 496 sc->targets[target]->id |= 497 (siop_target->offset & SXFER_MO_MASK) << 8; 498 sc->targets[target]->id &= ~0xff; 499 sc->targets[target]->id |= SCNTL4_U3EN; 500 siop_target->status = TARST_OK; 501 siop_update_xfer_mode(sc, target); 502 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 503 (sc->targets[target]->id >> 24) & 0xff); 504 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 505 (sc->targets[target]->id >> 8) & 0xff); 506 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, 507 sc->targets[target]->id & 0xff); 508 return SIOP_NEG_ACK; 509 } else { 510 /* target initiated PPR negotiation, shouldn't happen */ 511 printf("%s: rejecting invalid PPR negotiation from " 512 "target %d\n", sc->sc_dev.dv_xname, target); 513 reject: 514 tables->t_msgout.count= htole32(1); 515 tables->msg_out[0] = MSG_MESSAGE_REJECT; 516 return SIOP_NEG_MSGOUT; 517 } 518 } 519 520 int 521 siop_sdtr_neg(siop_cmd) 522 struct siop_common_cmd *siop_cmd; 523 { 524 struct siop_common_softc *sc = siop_cmd->siop_sc; 525 struct siop_common_target *siop_target = siop_cmd->siop_target; 526 int target = siop_cmd->xs->sc_link->target; 527 int sync, maxoffset, offset, i; 528 int send_msgout = 0; 529 struct siop_common_xfer *tables = siop_cmd->siop_tables; 530 531 /* limit to Ultra/2 parameters, need PPR for Ultra/3 */ 532 maxoffset = (sc->maxoff > 31) ? 31 : sc->maxoff; 533 534 sync = tables->msg_in[3]; 535 offset = tables->msg_in[4]; 536 537 if (siop_target->status == TARST_SYNC_NEG) { 538 /* we initiated sync negotiation */ 539 siop_target->status = TARST_OK; 540 #ifdef DEBUG 541 printf("sdtr: sync %d offset %d\n", sync, offset); 542 #endif 543 if (offset > maxoffset || sync < sc->st_minsync || 544 sync > sc->st_maxsync) 545 goto reject; 546 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); 547 i++) { 548 if (sc->clock_period != scf_period[i].clock) 549 continue; 550 if (scf_period[i].period == sync) { 551 /* ok, found it. we now are sync. */ 552 siop_target->offset = offset; 553 siop_target->period = sync; 554 sc->targets[target]->id &= 555 ~(SCNTL3_SCF_MASK << 24); 556 sc->targets[target]->id |= scf_period[i].scf 557 << (24 + SCNTL3_SCF_SHIFT); 558 if (sync < 25 && /* Ultra */ 559 (sc->features & SF_BUS_ULTRA3) == 0) 560 sc->targets[target]->id |= 561 SCNTL3_ULTRA << 24; 562 else 563 sc->targets[target]->id &= 564 ~(SCNTL3_ULTRA << 24); 565 sc->targets[target]->id &= 566 ~(SXFER_MO_MASK << 8); 567 sc->targets[target]->id |= 568 (offset & SXFER_MO_MASK) << 8; 569 sc->targets[target]->id &= ~0xff; /* scntl4 */ 570 goto end; 571 } 572 } 573 /* 574 * we didn't find it in our table, do async and send reject 575 * msg 576 */ 577 reject: 578 send_msgout = 1; 579 tables->t_msgout.count= htole32(1); 580 tables->msg_out[0] = MSG_MESSAGE_REJECT; 581 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24); 582 sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24); 583 sc->targets[target]->id &= ~(SXFER_MO_MASK << 8); 584 sc->targets[target]->id &= ~0xff; /* scntl4 */ 585 siop_target->offset = siop_target->period = 0; 586 } else { /* target initiated sync neg */ 587 #ifdef DEBUG 588 printf("sdtr (target): sync %d offset %d\n", sync, offset); 589 #endif 590 if (offset == 0 || sync > sc->st_maxsync) { /* async */ 591 goto async; 592 } 593 if (offset > maxoffset) 594 offset = maxoffset; 595 if (sync < sc->st_minsync) 596 sync = sc->st_minsync; 597 /* look for sync period */ 598 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); 599 i++) { 600 if (sc->clock_period != scf_period[i].clock) 601 continue; 602 if (scf_period[i].period == sync) { 603 /* ok, found it. we now are sync. */ 604 siop_target->offset = offset; 605 siop_target->period = sync; 606 sc->targets[target]->id &= 607 ~(SCNTL3_SCF_MASK << 24); 608 sc->targets[target]->id |= scf_period[i].scf 609 << (24 + SCNTL3_SCF_SHIFT); 610 if (sync < 25 && /* Ultra */ 611 (sc->features & SF_BUS_ULTRA3) == 0) 612 sc->targets[target]->id |= 613 SCNTL3_ULTRA << 24; 614 else 615 sc->targets[target]->id &= 616 ~(SCNTL3_ULTRA << 24); 617 sc->targets[target]->id &= 618 ~(SXFER_MO_MASK << 8); 619 sc->targets[target]->id |= 620 (offset & SXFER_MO_MASK) << 8; 621 sc->targets[target]->id &= ~0xff; /* scntl4 */ 622 siop_sdtr_msg(siop_cmd, 0, sync, offset); 623 send_msgout = 1; 624 goto end; 625 } 626 } 627 async: 628 siop_target->offset = siop_target->period = 0; 629 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24); 630 sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24); 631 sc->targets[target]->id &= ~(SXFER_MO_MASK << 8); 632 sc->targets[target]->id &= ~0xff; /* scntl4 */ 633 siop_sdtr_msg(siop_cmd, 0, 0, 0); 634 send_msgout = 1; 635 } 636 end: 637 if (siop_target->status == TARST_OK) 638 siop_update_xfer_mode(sc, target); 639 #ifdef DEBUG 640 printf("id now 0x%x\n", sc->targets[target]->id); 641 #endif 642 tables->id = htole32(sc->targets[target]->id); 643 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 644 (sc->targets[target]->id >> 24) & 0xff); 645 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 646 (sc->targets[target]->id >> 8) & 0xff); 647 if (send_msgout) { 648 return SIOP_NEG_MSGOUT; 649 } else { 650 return SIOP_NEG_ACK; 651 } 652 } 653 654 void 655 siop_sdtr_msg(siop_cmd, offset, ssync, soff) 656 struct siop_common_cmd *siop_cmd; 657 int offset; 658 int ssync, soff; 659 { 660 siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED; 661 siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_SDTR_LEN; 662 siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_SDTR; 663 siop_cmd->siop_tables->msg_out[offset + 3] = ssync; 664 siop_cmd->siop_tables->msg_out[offset + 4] = soff; 665 siop_cmd->siop_tables->t_msgout.count = 666 htole32(offset + MSG_EXT_SDTR_LEN + 2); 667 } 668 669 void 670 siop_wdtr_msg(siop_cmd, offset, wide) 671 struct siop_common_cmd *siop_cmd; 672 int offset; 673 { 674 siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED; 675 siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_WDTR_LEN; 676 siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_WDTR; 677 siop_cmd->siop_tables->msg_out[offset + 3] = wide; 678 siop_cmd->siop_tables->t_msgout.count = 679 htole32(offset + MSG_EXT_WDTR_LEN + 2); 680 } 681 682 void 683 siop_ppr_msg(siop_cmd, offset, ssync, soff) 684 struct siop_common_cmd *siop_cmd; 685 int offset; 686 int ssync, soff; 687 { 688 siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED; 689 siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_PPR_LEN; 690 siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_PPR; 691 siop_cmd->siop_tables->msg_out[offset + 3] = ssync; 692 siop_cmd->siop_tables->msg_out[offset + 4] = 0; /* reserved */ 693 siop_cmd->siop_tables->msg_out[offset + 5] = soff; 694 siop_cmd->siop_tables->msg_out[offset + 6] = 1; /* wide */ 695 siop_cmd->siop_tables->msg_out[offset + 7] = MSG_EXT_PPR_PROT_DT; 696 siop_cmd->siop_tables->t_msgout.count = 697 htole32(offset + MSG_EXT_PPR_LEN + 2); 698 } 699 700 void 701 siop_minphys(bp) 702 struct buf *bp; 703 { 704 minphys(bp); 705 } 706 707 void 708 siop_sdp(siop_cmd) 709 struct siop_common_cmd *siop_cmd; 710 { 711 /* save data pointer. Handle async only for now */ 712 int offset, dbc, sstat; 713 struct siop_common_softc *sc = siop_cmd->siop_sc; 714 scr_table_t *table; /* table to patch */ 715 716 if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN)) 717 == 0) 718 return; /* no data pointers to save */ 719 offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1); 720 if (offset >= SIOP_NSG) { 721 printf("%s: bad offset in siop_sdp (%d)\n", 722 sc->sc_dev.dv_xname, offset); 723 return; 724 } 725 table = &siop_cmd->siop_tables->data[offset]; 726 #ifdef DEBUG_DR 727 printf("sdp: offset %d count=%d addr=0x%x ", offset, 728 letoh32(table->count), letoh32(table->addr)); 729 #endif 730 dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff; 731 if (siop_cmd->xs->flags & SCSI_DATA_OUT) { 732 if (sc->features & SF_CHIP_DFBC) { 733 dbc += 734 bus_space_read_2(sc->sc_rt, sc->sc_rh, SIOP_DFBC); 735 } else { 736 /* need to account stale data in FIFO */ 737 int dfifo = 738 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO); 739 if (sc->features & SF_CHIP_FIFO) { 740 dfifo |= (bus_space_read_1(sc->sc_rt, sc->sc_rh, 741 SIOP_CTEST5) & CTEST5_BOMASK) << 8; 742 dbc += (dfifo - (dbc & 0x3ff)) & 0x3ff; 743 } else { 744 dbc += (dfifo - (dbc & 0x7f)) & 0x7f; 745 } 746 } 747 sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0); 748 if (sstat & SSTAT0_OLF) 749 dbc++; 750 if ((sstat & SSTAT0_ORF) && (sc->features & SF_CHIP_DFBC) == 0) 751 dbc++; 752 if (siop_cmd->siop_target->flags & TARF_ISWIDE) { 753 sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, 754 SIOP_SSTAT2); 755 if (sstat & SSTAT2_OLF1) 756 dbc++; 757 if ((sstat & SSTAT2_ORF1) && 758 (sc->features & SF_CHIP_DFBC) == 0) 759 dbc++; 760 } 761 /* clear the FIFO */ 762 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, 763 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) | 764 CTEST3_CLF); 765 } 766 table->addr = 767 htole32(letoh32(table->addr) + letoh32(table->count) - dbc); 768 table->count = htole32(dbc); 769 #ifdef DEBUG_DR 770 printf("now count=%d addr=0x%x\n", 771 letoh32(table->count), letoh32(table->addr)); 772 #endif 773 } 774 775 void 776 siop_clearfifo(sc) 777 struct siop_common_softc *sc; 778 { 779 int timeout = 0; 780 int ctest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3); 781 782 #ifdef DEBUG_INTR 783 printf("DMA fifo not empty !\n"); 784 #endif 785 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, 786 ctest3 | CTEST3_CLF); 787 while ((bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) & 788 CTEST3_CLF) != 0) { 789 delay(1); 790 if (++timeout > 1000) { 791 printf("clear fifo failed\n"); 792 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, 793 bus_space_read_1(sc->sc_rt, sc->sc_rh, 794 SIOP_CTEST3) & ~CTEST3_CLF); 795 return; 796 } 797 } 798 } 799 800 int 801 siop_modechange(sc) 802 struct siop_common_softc *sc; 803 { 804 int retry; 805 int sist0, sist1, stest2; 806 for (retry = 0; retry < 5; retry++) { 807 /* 808 * datasheet says to wait 100ms and re-read SIST1, 809 * to check that DIFFSENSE is stable. 810 * We may delay() 5 times for 100ms at interrupt time; 811 * hopefully this will not happen often. 812 */ 813 delay(100000); 814 sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0); 815 sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1); 816 if (sist1 & SIEN1_SBMC) 817 continue; /* we got an irq again */ 818 sc->mode = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) & 819 STEST4_MODE_MASK; 820 stest2 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2); 821 switch(sc->mode) { 822 case STEST4_MODE_DIF: 823 printf("%s: switching to differential mode\n", 824 sc->sc_dev.dv_xname); 825 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 826 stest2 | STEST2_DIF); 827 break; 828 case STEST4_MODE_SE: 829 printf("%s: switching to single-ended mode\n", 830 sc->sc_dev.dv_xname); 831 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 832 stest2 & ~STEST2_DIF); 833 break; 834 case STEST4_MODE_LVD: 835 printf("%s: switching to LVD mode\n", 836 sc->sc_dev.dv_xname); 837 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 838 stest2 & ~STEST2_DIF); 839 break; 840 default: 841 printf("%s: invalid SCSI mode 0x%x\n", 842 sc->sc_dev.dv_xname, sc->mode); 843 return 0; 844 } 845 return 1; 846 } 847 printf("%s: timeout waiting for DIFFSENSE to stabilise\n", 848 sc->sc_dev.dv_xname); 849 return 0; 850 } 851 852 void 853 siop_resetbus(sc) 854 struct siop_common_softc *sc; 855 { 856 int scntl1; 857 scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1); 858 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 859 scntl1 | SCNTL1_RST); 860 /* minimum 25 us, more time won't hurt */ 861 delay(100); 862 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1); 863 } 864 865 void 866 siop_update_xfer_mode(sc, target) 867 struct siop_common_softc *sc; 868 int target; 869 { 870 struct siop_common_target *siop_target; 871 872 siop_target = sc->targets[target]; 873 874 printf("%s: target %d now using %s%s%d bit ", 875 sc->sc_dev.dv_xname, target, 876 (siop_target->flags & TARF_TAG) ? "tagged " : "", 877 (siop_target->flags & TARF_ISDT) ? "DT " : "", 878 (siop_target->flags & TARF_ISWIDE) ? 16 : 8); 879 880 if (siop_target->offset == 0) 881 printf("async "); 882 else { 883 switch (siop_target->period) { 884 case 9: /* 12.5ns cycle */ 885 printf("80.0"); 886 break; 887 case 10: /* 25 ns cycle */ 888 printf("40.0"); 889 break; 890 case 12: /* 48 ns cycle */ 891 printf("20.0"); 892 break; 893 case 18: /* 72 ns cycle */ 894 printf("13.3"); 895 break; 896 case 25: /* 100 ns cycle */ 897 printf("10.0"); 898 break; 899 case 37: /* 118 ns cycle */ 900 printf("6.67"); 901 break; 902 case 50: /* 200 ns cycle */ 903 printf("5.0"); 904 break; 905 case 75: /* 300 ns cycle */ 906 printf("3.33"); 907 break; 908 default: 909 printf("??"); 910 break; 911 } 912 printf(" MHz %d REQ/ACK offset ", siop_target->offset); 913 } 914 915 printf("xfers\n"); 916 917 if ((sc->features & SF_CHIP_GEBUG) && 918 (siop_target->flags & TARF_ISWIDE) == 0) 919 /* 1010 workaround: can't do disconnect if not wide, so can't do tag */ 920 siop_target->flags &= ~TARF_TAG; 921 } 922