1 /* $OpenBSD: siop_common.c,v 1.18 2003/10/27 03:07:39 mickey 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 #ifndef __hppa__ 272 if ((quirks & SDEV_NOTAGS) == 0) 273 *targ_flags |= TARF_TAG; 274 #endif 275 if (((quirks & SDEV_NOWIDE) == 0) && 276 (sc->features & SF_BUS_WIDE)) 277 *targ_flags |= TARF_WIDE; 278 if ((quirks & SDEV_NOSYNC) == 0) 279 *targ_flags |= TARF_SYNC; 280 281 if ((sc->features & SF_CHIP_GEBUG) && 282 (*targ_flags & TARF_WIDE) == 0) 283 /* 284 * 1010 workaround: can't do disconnect if not wide, 285 * so can't do tag 286 */ 287 *targ_flags &= ~TARF_TAG; 288 289 /* Safe to call siop_add_dev() multiple times */ 290 siop_add_dev((struct siop_softc *)sc, target, lun); 291 292 if ((*targ_flags & TARF_DT) && 293 (sc->mode == STEST4_MODE_LVD)) { 294 sc->targets[target]->status = TARST_PPR_NEG; 295 siop_ppr_msg(siop_cmd, msgoffset, sc->dt_minsync, 296 sc->maxoff); 297 } else if (*targ_flags & TARF_WIDE) { 298 sc->targets[target]->status = TARST_WIDE_NEG; 299 siop_wdtr_msg(siop_cmd, msgoffset, 300 MSG_EXT_WDTR_BUS_16_BIT); 301 } else if (*targ_flags & TARF_SYNC) { 302 sc->targets[target]->status = TARST_SYNC_NEG; 303 siop_sdtr_msg(siop_cmd, msgoffset, sc->st_minsync, 304 (sc->maxoff > 31) ? 31 : sc->maxoff); 305 } else { 306 sc->targets[target]->status = TARST_OK; 307 siop_update_xfer_mode(sc, target); 308 } 309 } else if (sc->targets[target]->status == TARST_OK && 310 (*targ_flags & TARF_TAG) && 311 siop_cmd->status != CMDST_SENSE) { 312 siop_cmd->flags |= CMDFL_TAG; 313 } 314 siop_cmd->siop_tables->status = 315 htole32(SCSI_SIOP_NOSTATUS); /* set invalid status */ 316 317 if ((xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) || 318 siop_cmd->status == CMDST_SENSE) { 319 bzero(siop_cmd->siop_tables->data, 320 sizeof(siop_cmd->siop_tables->data)); 321 for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) { 322 siop_cmd->siop_tables->data[i].count = 323 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len); 324 siop_cmd->siop_tables->data[i].addr = 325 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr); 326 } 327 } 328 } 329 330 int 331 siop_wdtr_neg(siop_cmd) 332 struct siop_common_cmd *siop_cmd; 333 { 334 struct siop_common_softc *sc = siop_cmd->siop_sc; 335 struct siop_common_target *siop_target = siop_cmd->siop_target; 336 int target = siop_cmd->xs->sc_link->target; 337 struct siop_common_xfer *tables = siop_cmd->siop_tables; 338 339 if (siop_target->status == TARST_WIDE_NEG) { 340 /* we initiated wide negotiation */ 341 switch (tables->msg_in[3]) { 342 case MSG_EXT_WDTR_BUS_8_BIT: 343 siop_target->flags &= ~TARF_ISWIDE; 344 sc->targets[target]->id &= ~(SCNTL3_EWS << 24); 345 break; 346 case MSG_EXT_WDTR_BUS_16_BIT: 347 if (siop_target->flags & TARF_WIDE) { 348 siop_target->flags |= TARF_ISWIDE; 349 sc->targets[target]->id |= (SCNTL3_EWS << 24); 350 break; 351 } 352 /* FALLTHROUH */ 353 default: 354 /* 355 * hum, we got more than what we can handle, shouldn't 356 * happen. Reject, and stay async 357 */ 358 siop_target->flags &= ~TARF_ISWIDE; 359 siop_target->status = TARST_OK; 360 siop_target->offset = siop_target->period = 0; 361 siop_update_xfer_mode(sc, target); 362 printf("%s: rejecting invalid wide negotiation from " 363 "target %d (%d)\n", sc->sc_dev.dv_xname, target, 364 tables->msg_in[3]); 365 tables->t_msgout.count= htole32(1); 366 tables->msg_out[0] = MSG_MESSAGE_REJECT; 367 return SIOP_NEG_MSGOUT; 368 } 369 tables->id = htole32(sc->targets[target]->id); 370 bus_space_write_1(sc->sc_rt, sc->sc_rh, 371 SIOP_SCNTL3, 372 (sc->targets[target]->id >> 24) & 0xff); 373 /* we now need to do sync */ 374 if (siop_target->flags & TARF_SYNC) { 375 siop_target->status = TARST_SYNC_NEG; 376 siop_sdtr_msg(siop_cmd, 0, sc->st_minsync, 377 (sc->maxoff > 31) ? 31 : sc->maxoff); 378 return SIOP_NEG_MSGOUT; 379 } else { 380 siop_target->status = TARST_OK; 381 siop_update_xfer_mode(sc, target); 382 return SIOP_NEG_ACK; 383 } 384 } else { 385 /* target initiated wide negotiation */ 386 if (tables->msg_in[3] >= MSG_EXT_WDTR_BUS_16_BIT 387 && (siop_target->flags & TARF_WIDE)) { 388 siop_target->flags |= TARF_ISWIDE; 389 sc->targets[target]->id |= SCNTL3_EWS << 24; 390 } else { 391 siop_target->flags &= ~TARF_ISWIDE; 392 sc->targets[target]->id &= ~(SCNTL3_EWS << 24); 393 } 394 tables->id = htole32(sc->targets[target]->id); 395 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 396 (sc->targets[target]->id >> 24) & 0xff); 397 /* 398 * we did reset wide parameters, so fall back to async, 399 * but don't schedule a sync neg, target should initiate it 400 */ 401 siop_target->status = TARST_OK; 402 siop_target->offset = siop_target->period = 0; 403 siop_update_xfer_mode(sc, target); 404 siop_wdtr_msg(siop_cmd, 0, (siop_target->flags & TARF_ISWIDE) ? 405 MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT); 406 return SIOP_NEG_MSGOUT; 407 } 408 } 409 410 int 411 siop_ppr_neg(siop_cmd) 412 struct siop_common_cmd *siop_cmd; 413 { 414 struct siop_common_softc *sc = siop_cmd->siop_sc; 415 struct siop_common_target *siop_target = siop_cmd->siop_target; 416 int target = siop_cmd->xs->sc_link->target; 417 struct siop_common_xfer *tables = siop_cmd->siop_tables; 418 int sync, offset, options, scf = 0; 419 int i; 420 421 #ifdef DEBUG_NEG 422 printf("%s: answer on ppr negotiation:", sc->sc_dev.dv_xname); 423 for (i = 0; i < 8; i++) 424 printf(" 0x%x", tables->msg_in[i]); 425 printf("\n"); 426 #endif 427 428 if (siop_target->status == TARST_PPR_NEG) { 429 /* we initiated PPR negotiation */ 430 sync = tables->msg_in[3]; 431 offset = tables->msg_in[5]; 432 options = tables->msg_in[7]; 433 if (options != MSG_EXT_PPR_PROT_DT) { 434 /* should't happen */ 435 printf("%s: ppr negotiation for target %d: " 436 "no DT option\n", sc->sc_dev.dv_xname, target); 437 siop_target->status = TARST_ASYNC; 438 siop_target->flags &= ~(TARF_DT | TARF_ISDT); 439 siop_target->offset = 0; 440 siop_target->period = 0; 441 goto reject; 442 } 443 444 if (offset > sc->maxoff || sync < sc->dt_minsync || 445 sync > sc->dt_maxsync) { 446 printf("%s: ppr negotiation for target %d: " 447 "offset (%d) or sync (%d) out of range\n", 448 sc->sc_dev.dv_xname, target, offset, sync); 449 /* should not happen */ 450 siop_target->status = TARST_ASYNC; 451 siop_target->flags &= ~(TARF_DT | TARF_ISDT); 452 siop_target->offset = 0; 453 siop_target->period = 0; 454 goto reject; 455 } else { 456 for (i = 0; i < 457 sizeof(dt_scf_period) / sizeof(dt_scf_period[0]); 458 i++) { 459 if (sc->clock_period != dt_scf_period[i].clock) 460 continue; 461 if (dt_scf_period[i].period == sync) { 462 /* ok, found it. we now are sync. */ 463 siop_target->offset = offset; 464 siop_target->period = sync; 465 scf = dt_scf_period[i].scf; 466 siop_target->flags |= TARF_ISDT; 467 } 468 } 469 if ((siop_target->flags & TARF_ISDT) == 0) { 470 printf("%s: ppr negotiation for target %d: " 471 "sync (%d) incompatible with adapter\n", 472 sc->sc_dev.dv_xname, target, sync); 473 /* 474 * we didn't find it in our table, do async 475 * send reject msg, start SDTR/WDTR neg 476 */ 477 siop_target->status = TARST_ASYNC; 478 siop_target->flags &= ~(TARF_DT | TARF_ISDT); 479 siop_target->offset = 0; 480 siop_target->period = 0; 481 goto reject; 482 } 483 } 484 if (tables->msg_in[6] != 1) { 485 printf("%s: ppr negotiation for target %d: " 486 "transfer width (%d) incompatible with dt\n", 487 sc->sc_dev.dv_xname, target, tables->msg_in[6]); 488 /* DT mode can only be done with wide transfers */ 489 siop_target->status = TARST_ASYNC; 490 siop_target->flags &= ~(TARF_DT | TARF_ISDT); 491 siop_target->offset = 0; 492 siop_target->period = 0; 493 goto reject; 494 } 495 siop_target->flags |= TARF_ISWIDE; 496 sc->targets[target]->id |= (SCNTL3_EWS << 24); 497 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24); 498 sc->targets[target]->id |= scf << (24 + SCNTL3_SCF_SHIFT); 499 sc->targets[target]->id &= ~(SXFER_MO_MASK << 8); 500 sc->targets[target]->id |= 501 (siop_target->offset & SXFER_MO_MASK) << 8; 502 sc->targets[target]->id &= ~0xff; 503 sc->targets[target]->id |= SCNTL4_U3EN; 504 siop_target->status = TARST_OK; 505 siop_update_xfer_mode(sc, target); 506 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 507 (sc->targets[target]->id >> 24) & 0xff); 508 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 509 (sc->targets[target]->id >> 8) & 0xff); 510 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, 511 sc->targets[target]->id & 0xff); 512 return SIOP_NEG_ACK; 513 } else { 514 /* target initiated PPR negotiation, shouldn't happen */ 515 printf("%s: rejecting invalid PPR negotiation from " 516 "target %d\n", sc->sc_dev.dv_xname, target); 517 reject: 518 tables->t_msgout.count= htole32(1); 519 tables->msg_out[0] = MSG_MESSAGE_REJECT; 520 return SIOP_NEG_MSGOUT; 521 } 522 } 523 524 int 525 siop_sdtr_neg(siop_cmd) 526 struct siop_common_cmd *siop_cmd; 527 { 528 struct siop_common_softc *sc = siop_cmd->siop_sc; 529 struct siop_common_target *siop_target = siop_cmd->siop_target; 530 int target = siop_cmd->xs->sc_link->target; 531 int sync, maxoffset, offset, i; 532 int send_msgout = 0; 533 struct siop_common_xfer *tables = siop_cmd->siop_tables; 534 535 /* limit to Ultra/2 parameters, need PPR for Ultra/3 */ 536 maxoffset = (sc->maxoff > 31) ? 31 : sc->maxoff; 537 538 sync = tables->msg_in[3]; 539 offset = tables->msg_in[4]; 540 541 if (siop_target->status == TARST_SYNC_NEG) { 542 /* we initiated sync negotiation */ 543 siop_target->status = TARST_OK; 544 #ifdef DEBUG 545 printf("sdtr: sync %d offset %d\n", sync, offset); 546 #endif 547 if (offset > maxoffset || sync < sc->st_minsync || 548 sync > sc->st_maxsync) 549 goto reject; 550 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); 551 i++) { 552 if (sc->clock_period != scf_period[i].clock) 553 continue; 554 if (scf_period[i].period == sync) { 555 /* ok, found it. we now are sync. */ 556 siop_target->offset = offset; 557 siop_target->period = sync; 558 sc->targets[target]->id &= 559 ~(SCNTL3_SCF_MASK << 24); 560 sc->targets[target]->id |= scf_period[i].scf 561 << (24 + SCNTL3_SCF_SHIFT); 562 if (sync < 25 && /* Ultra */ 563 (sc->features & SF_BUS_ULTRA3) == 0) 564 sc->targets[target]->id |= 565 SCNTL3_ULTRA << 24; 566 else 567 sc->targets[target]->id &= 568 ~(SCNTL3_ULTRA << 24); 569 sc->targets[target]->id &= 570 ~(SXFER_MO_MASK << 8); 571 sc->targets[target]->id |= 572 (offset & SXFER_MO_MASK) << 8; 573 sc->targets[target]->id &= ~0xff; /* scntl4 */ 574 goto end; 575 } 576 } 577 /* 578 * we didn't find it in our table, do async and send reject 579 * msg 580 */ 581 reject: 582 send_msgout = 1; 583 tables->t_msgout.count= htole32(1); 584 tables->msg_out[0] = MSG_MESSAGE_REJECT; 585 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24); 586 sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24); 587 sc->targets[target]->id &= ~(SXFER_MO_MASK << 8); 588 sc->targets[target]->id &= ~0xff; /* scntl4 */ 589 siop_target->offset = siop_target->period = 0; 590 } else { /* target initiated sync neg */ 591 #ifdef DEBUG 592 printf("sdtr (target): sync %d offset %d\n", sync, offset); 593 #endif 594 if (offset == 0 || sync > sc->st_maxsync) { /* async */ 595 goto async; 596 } 597 if (offset > maxoffset) 598 offset = maxoffset; 599 if (sync < sc->st_minsync) 600 sync = sc->st_minsync; 601 /* look for sync period */ 602 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); 603 i++) { 604 if (sc->clock_period != scf_period[i].clock) 605 continue; 606 if (scf_period[i].period == sync) { 607 /* ok, found it. we now are sync. */ 608 siop_target->offset = offset; 609 siop_target->period = sync; 610 sc->targets[target]->id &= 611 ~(SCNTL3_SCF_MASK << 24); 612 sc->targets[target]->id |= scf_period[i].scf 613 << (24 + SCNTL3_SCF_SHIFT); 614 if (sync < 25 && /* Ultra */ 615 (sc->features & SF_BUS_ULTRA3) == 0) 616 sc->targets[target]->id |= 617 SCNTL3_ULTRA << 24; 618 else 619 sc->targets[target]->id &= 620 ~(SCNTL3_ULTRA << 24); 621 sc->targets[target]->id &= 622 ~(SXFER_MO_MASK << 8); 623 sc->targets[target]->id |= 624 (offset & SXFER_MO_MASK) << 8; 625 sc->targets[target]->id &= ~0xff; /* scntl4 */ 626 siop_sdtr_msg(siop_cmd, 0, sync, offset); 627 send_msgout = 1; 628 goto end; 629 } 630 } 631 async: 632 siop_target->offset = siop_target->period = 0; 633 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24); 634 sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24); 635 sc->targets[target]->id &= ~(SXFER_MO_MASK << 8); 636 sc->targets[target]->id &= ~0xff; /* scntl4 */ 637 siop_sdtr_msg(siop_cmd, 0, 0, 0); 638 send_msgout = 1; 639 } 640 end: 641 if (siop_target->status == TARST_OK) 642 siop_update_xfer_mode(sc, target); 643 #ifdef DEBUG 644 printf("id now 0x%x\n", sc->targets[target]->id); 645 #endif 646 tables->id = htole32(sc->targets[target]->id); 647 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 648 (sc->targets[target]->id >> 24) & 0xff); 649 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 650 (sc->targets[target]->id >> 8) & 0xff); 651 if (send_msgout) { 652 return SIOP_NEG_MSGOUT; 653 } else { 654 return SIOP_NEG_ACK; 655 } 656 } 657 658 void 659 siop_sdtr_msg(siop_cmd, offset, ssync, soff) 660 struct siop_common_cmd *siop_cmd; 661 int offset; 662 int ssync, soff; 663 { 664 siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED; 665 siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_SDTR_LEN; 666 siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_SDTR; 667 siop_cmd->siop_tables->msg_out[offset + 3] = ssync; 668 siop_cmd->siop_tables->msg_out[offset + 4] = soff; 669 siop_cmd->siop_tables->t_msgout.count = 670 htole32(offset + MSG_EXT_SDTR_LEN + 2); 671 } 672 673 void 674 siop_wdtr_msg(siop_cmd, offset, wide) 675 struct siop_common_cmd *siop_cmd; 676 int offset; 677 { 678 siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED; 679 siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_WDTR_LEN; 680 siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_WDTR; 681 siop_cmd->siop_tables->msg_out[offset + 3] = wide; 682 siop_cmd->siop_tables->t_msgout.count = 683 htole32(offset + MSG_EXT_WDTR_LEN + 2); 684 } 685 686 void 687 siop_ppr_msg(siop_cmd, offset, ssync, soff) 688 struct siop_common_cmd *siop_cmd; 689 int offset; 690 int ssync, soff; 691 { 692 siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED; 693 siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_PPR_LEN; 694 siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_PPR; 695 siop_cmd->siop_tables->msg_out[offset + 3] = ssync; 696 siop_cmd->siop_tables->msg_out[offset + 4] = 0; /* reserved */ 697 siop_cmd->siop_tables->msg_out[offset + 5] = soff; 698 siop_cmd->siop_tables->msg_out[offset + 6] = 1; /* wide */ 699 siop_cmd->siop_tables->msg_out[offset + 7] = MSG_EXT_PPR_PROT_DT; 700 siop_cmd->siop_tables->t_msgout.count = 701 htole32(offset + MSG_EXT_PPR_LEN + 2); 702 } 703 704 void 705 siop_minphys(bp) 706 struct buf *bp; 707 { 708 minphys(bp); 709 } 710 711 void 712 siop_sdp(siop_cmd) 713 struct siop_common_cmd *siop_cmd; 714 { 715 /* save data pointer. Handle async only for now */ 716 int offset, dbc, sstat; 717 struct siop_common_softc *sc = siop_cmd->siop_sc; 718 scr_table_t *table; /* table to patch */ 719 720 if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN)) 721 == 0) 722 return; /* no data pointers to save */ 723 offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1); 724 if (offset >= SIOP_NSG) { 725 printf("%s: bad offset in siop_sdp (%d)\n", 726 sc->sc_dev.dv_xname, offset); 727 return; 728 } 729 table = &siop_cmd->siop_tables->data[offset]; 730 #ifdef DEBUG_DR 731 printf("sdp: offset %d count=%d addr=0x%x ", offset, 732 letoh32(table->count), letoh32(table->addr)); 733 #endif 734 dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff; 735 if (siop_cmd->xs->flags & SCSI_DATA_OUT) { 736 if (sc->features & SF_CHIP_DFBC) { 737 dbc += 738 bus_space_read_2(sc->sc_rt, sc->sc_rh, SIOP_DFBC); 739 } else { 740 /* need to account stale data in FIFO */ 741 int dfifo = 742 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO); 743 if (sc->features & SF_CHIP_FIFO) { 744 dfifo |= (bus_space_read_1(sc->sc_rt, sc->sc_rh, 745 SIOP_CTEST5) & CTEST5_BOMASK) << 8; 746 dbc += (dfifo - (dbc & 0x3ff)) & 0x3ff; 747 } else { 748 dbc += (dfifo - (dbc & 0x7f)) & 0x7f; 749 } 750 } 751 sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0); 752 if (sstat & SSTAT0_OLF) 753 dbc++; 754 if ((sstat & SSTAT0_ORF) && (sc->features & SF_CHIP_DFBC) == 0) 755 dbc++; 756 if (siop_cmd->siop_target->flags & TARF_ISWIDE) { 757 sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, 758 SIOP_SSTAT2); 759 if (sstat & SSTAT2_OLF1) 760 dbc++; 761 if ((sstat & SSTAT2_ORF1) && 762 (sc->features & SF_CHIP_DFBC) == 0) 763 dbc++; 764 } 765 /* clear the FIFO */ 766 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, 767 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) | 768 CTEST3_CLF); 769 } 770 table->addr = 771 htole32(letoh32(table->addr) + letoh32(table->count) - dbc); 772 table->count = htole32(dbc); 773 #ifdef DEBUG_DR 774 printf("now count=%d addr=0x%x\n", 775 letoh32(table->count), letoh32(table->addr)); 776 #endif 777 } 778 779 void 780 siop_clearfifo(sc) 781 struct siop_common_softc *sc; 782 { 783 int timeout = 0; 784 int ctest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3); 785 786 #ifdef DEBUG_INTR 787 printf("DMA fifo not empty !\n"); 788 #endif 789 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, 790 ctest3 | CTEST3_CLF); 791 while ((bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) & 792 CTEST3_CLF) != 0) { 793 delay(1); 794 if (++timeout > 1000) { 795 printf("clear fifo failed\n"); 796 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, 797 bus_space_read_1(sc->sc_rt, sc->sc_rh, 798 SIOP_CTEST3) & ~CTEST3_CLF); 799 return; 800 } 801 } 802 } 803 804 int 805 siop_modechange(sc) 806 struct siop_common_softc *sc; 807 { 808 int retry; 809 int sist0, sist1, stest2; 810 for (retry = 0; retry < 5; retry++) { 811 /* 812 * datasheet says to wait 100ms and re-read SIST1, 813 * to check that DIFFSENSE is stable. 814 * We may delay() 5 times for 100ms at interrupt time; 815 * hopefully this will not happen often. 816 */ 817 delay(100000); 818 sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0); 819 sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1); 820 if (sist1 & SIEN1_SBMC) 821 continue; /* we got an irq again */ 822 sc->mode = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) & 823 STEST4_MODE_MASK; 824 stest2 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2); 825 switch(sc->mode) { 826 case STEST4_MODE_DIF: 827 printf("%s: switching to differential mode\n", 828 sc->sc_dev.dv_xname); 829 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 830 stest2 | STEST2_DIF); 831 break; 832 case STEST4_MODE_SE: 833 printf("%s: switching to single-ended mode\n", 834 sc->sc_dev.dv_xname); 835 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 836 stest2 & ~STEST2_DIF); 837 break; 838 case STEST4_MODE_LVD: 839 printf("%s: switching to LVD mode\n", 840 sc->sc_dev.dv_xname); 841 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 842 stest2 & ~STEST2_DIF); 843 break; 844 default: 845 printf("%s: invalid SCSI mode 0x%x\n", 846 sc->sc_dev.dv_xname, sc->mode); 847 return 0; 848 } 849 return 1; 850 } 851 printf("%s: timeout waiting for DIFFSENSE to stabilise\n", 852 sc->sc_dev.dv_xname); 853 return 0; 854 } 855 856 void 857 siop_resetbus(sc) 858 struct siop_common_softc *sc; 859 { 860 int scntl1; 861 scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1); 862 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 863 scntl1 | SCNTL1_RST); 864 /* minimum 25 us, more time won't hurt */ 865 delay(100); 866 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1); 867 } 868 869 void 870 siop_update_xfer_mode(sc, target) 871 struct siop_common_softc *sc; 872 int target; 873 { 874 struct siop_common_target *siop_target; 875 876 siop_target = sc->targets[target]; 877 878 printf("%s: target %d now using %s%s%d bit ", 879 sc->sc_dev.dv_xname, target, 880 (siop_target->flags & TARF_TAG) ? "tagged " : "", 881 (siop_target->flags & TARF_ISDT) ? "DT " : "", 882 (siop_target->flags & TARF_ISWIDE) ? 16 : 8); 883 884 if (siop_target->offset == 0) 885 printf("async "); 886 else { 887 switch (siop_target->period) { 888 case 9: /* 12.5ns cycle */ 889 printf("80.0"); 890 break; 891 case 10: /* 25 ns cycle */ 892 printf("40.0"); 893 break; 894 case 12: /* 48 ns cycle */ 895 printf("20.0"); 896 break; 897 case 18: /* 72 ns cycle */ 898 printf("13.3"); 899 break; 900 case 25: /* 100 ns cycle */ 901 printf("10.0"); 902 break; 903 case 37: /* 118 ns cycle */ 904 printf("6.67"); 905 break; 906 case 50: /* 200 ns cycle */ 907 printf("5.0"); 908 break; 909 case 75: /* 300 ns cycle */ 910 printf("3.33"); 911 break; 912 default: 913 printf("??"); 914 break; 915 } 916 printf(" MHz %d REQ/ACK offset ", siop_target->offset); 917 } 918 919 printf("xfers\n"); 920 921 if ((sc->features & SF_CHIP_GEBUG) && 922 (siop_target->flags & TARF_ISWIDE) == 0) 923 /* 1010 workaround: can't do disconnect if not wide, so can't do tag */ 924 siop_target->flags &= ~TARF_TAG; 925 } 926