1 /* $OpenBSD: siop_common.c,v 1.42 2020/07/11 15:51:36 krw Exp $ */ 2 /* $NetBSD: siop_common.c,v 1.37 2005/02/27 00:27:02 perry 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 */ 28 29 /* SYM53c7/8xx PCI-SCSI I/O Processors driver */ 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/device.h> 34 #include <sys/malloc.h> 35 #include <sys/buf.h> 36 #include <sys/kernel.h> 37 #include <sys/scsiio.h> 38 #include <sys/endian.h> 39 40 #include <machine/bus.h> 41 42 #include <scsi/scsi_all.h> 43 #include <scsi/scsi_message.h> 44 #include <scsi/scsiconf.h> 45 46 #define SIOP_NEEDS_PERIOD_TABLES 47 #include <dev/ic/siopreg.h> 48 #include <dev/ic/siopvar_common.h> 49 #include <dev/ic/siopvar.h> 50 51 #undef DEBUG 52 #undef DEBUG_DR 53 #undef DEBUG_NEG 54 55 int 56 siop_common_attach(sc) 57 struct siop_common_softc *sc; 58 { 59 int error, i, buswidth; 60 bus_dma_segment_t seg; 61 int rseg; 62 63 /* 64 * Allocate DMA-safe memory for the script and map it. 65 */ 66 if ((sc->features & SF_CHIP_RAM) == 0) { 67 error = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, 68 PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT); 69 if (error) { 70 printf("%s: unable to allocate script DMA memory, " 71 "error = %d\n", sc->sc_dev.dv_xname, error); 72 return error; 73 } 74 error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, PAGE_SIZE, 75 (caddr_t *)&sc->sc_script, 76 BUS_DMA_NOWAIT|BUS_DMA_COHERENT); 77 if (error) { 78 printf("%s: unable to map script DMA memory, " 79 "error = %d\n", sc->sc_dev.dv_xname, error); 80 return error; 81 } 82 error = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, 83 PAGE_SIZE, 0, BUS_DMA_NOWAIT, &sc->sc_scriptdma); 84 if (error) { 85 printf("%s: unable to create script DMA map, " 86 "error = %d\n", sc->sc_dev.dv_xname, error); 87 return error; 88 } 89 error = bus_dmamap_load(sc->sc_dmat, sc->sc_scriptdma, 90 sc->sc_script, PAGE_SIZE, NULL, BUS_DMA_NOWAIT); 91 if (error) { 92 printf("%s: unable to load script DMA map, " 93 "error = %d\n", sc->sc_dev.dv_xname, error); 94 return error; 95 } 96 sc->sc_scriptaddr = 97 sc->sc_scriptdma->dm_segs[0].ds_addr; 98 sc->ram_size = PAGE_SIZE; 99 } 100 101 /* 102 * sc->sc_link is the template for all device sc_link's 103 * for devices attached to this adapter. It is passed to 104 * the upper layers in config_found(). 105 */ 106 buswidth = (sc->features & SF_BUS_WIDE) ? 16 : 8; 107 sc->sc_id = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCID); 108 if (sc->sc_id == 0 || sc->sc_id >= buswidth) 109 sc->sc_id = SIOP_DEFAULT_TARGET; 110 111 for (i = 0; i < 16; i++) 112 sc->targets[i] = NULL; 113 114 /* find min/max sync period for this chip */ 115 sc->st_maxsync = 0; 116 sc->dt_maxsync = 0; 117 sc->st_minsync = 255; 118 sc->dt_minsync = 255; 119 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); i++) { 120 if (sc->clock_period != scf_period[i].clock) 121 continue; 122 if (sc->st_maxsync < scf_period[i].period) 123 sc->st_maxsync = scf_period[i].period; 124 if (sc->st_minsync > scf_period[i].period) 125 sc->st_minsync = scf_period[i].period; 126 } 127 if (sc->st_maxsync == 255 || sc->st_minsync == 0) 128 panic("siop: can't find my sync parameters"); 129 for (i = 0; i < sizeof(dt_scf_period) / sizeof(dt_scf_period[0]); i++) { 130 if (sc->clock_period != dt_scf_period[i].clock) 131 continue; 132 if (sc->dt_maxsync < dt_scf_period[i].period) 133 sc->dt_maxsync = dt_scf_period[i].period; 134 if (sc->dt_minsync > dt_scf_period[i].period) 135 sc->dt_minsync = dt_scf_period[i].period; 136 } 137 if (sc->dt_maxsync == 255 || sc->dt_minsync == 0) 138 panic("siop: can't find my sync parameters"); 139 return 0; 140 } 141 142 void 143 siop_common_reset(sc) 144 struct siop_common_softc *sc; 145 { 146 u_int32_t stest3; 147 148 /* reset the chip */ 149 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SRST); 150 delay(1000); 151 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, 0); 152 153 /* init registers */ 154 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL0, 155 SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP); 156 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 0); 157 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, sc->clock_div); 158 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 0); 159 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DIEN, 0xff); 160 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN0, 161 0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL)); 162 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN1, 163 0xff & ~(SIEN1_HTH | SIEN1_GEN)); 164 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 0); 165 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, STEST3_TE); 166 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STIME0, 167 (0xb << STIME0_SEL_SHIFT)); 168 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCID, 169 sc->sc_id | SCID_RRE); 170 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_RESPID0, 171 1 << sc->sc_id); 172 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DCNTL, 173 (sc->features & SF_CHIP_PF) ? DCNTL_COM | DCNTL_PFEN : DCNTL_COM); 174 if (sc->features & SF_CHIP_AAIP) 175 bus_space_write_1(sc->sc_rt, sc->sc_rh, 176 SIOP_AIPCNTL1, AIPCNTL1_DIS); 177 178 /* enable clock doubler or quadrupler if appropriate */ 179 if (sc->features & (SF_CHIP_DBLR | SF_CHIP_QUAD)) { 180 stest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3); 181 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 182 STEST1_DBLEN); 183 if (sc->features & SF_CHIP_QUAD) { 184 /* wait for PPL to lock */ 185 while ((bus_space_read_1(sc->sc_rt, sc->sc_rh, 186 SIOP_STEST4) & STEST4_LOCK) == 0) 187 delay(10); 188 } else { 189 /* data sheet says 20us - more won't hurt */ 190 delay(100); 191 } 192 /* halt scsi clock, select doubler/quad, restart clock */ 193 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, 194 stest3 | STEST3_HSC); 195 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 196 STEST1_DBLEN | STEST1_DBLSEL); 197 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, stest3); 198 } else { 199 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 0); 200 } 201 if (sc->features & SF_CHIP_FIFO) 202 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5, 203 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5) | 204 CTEST5_DFS); 205 if (sc->features & SF_CHIP_LED0) { 206 /* Set GPIO0 as output if software LED control is required */ 207 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_GPCNTL, 208 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_GPCNTL) & 0xfe); 209 } 210 if (sc->features & SF_BUS_ULTRA3) { 211 /* reset SCNTL4 */ 212 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, 0); 213 } 214 sc->mode = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) & 215 STEST4_MODE_MASK; 216 217 /* 218 * initialise the RAM. Without this we may get scsi gross errors on 219 * the 1010 220 */ 221 if (sc->features & SF_CHIP_RAM) 222 bus_space_set_region_4(sc->sc_ramt, sc->sc_ramh, 223 0, 0, sc->ram_size / 4); 224 sc->sc_reset(sc); 225 } 226 227 /* prepare tables before sending a cmd */ 228 void 229 siop_setuptables(siop_cmd) 230 struct siop_common_cmd *siop_cmd; 231 { 232 int i; 233 struct siop_common_softc *sc = siop_cmd->siop_sc; 234 struct scsi_xfer *xs = siop_cmd->xs; 235 int target = xs->sc_link->target; 236 int lun = xs->sc_link->lun; 237 int msgoffset = 1; 238 int *targ_flags = &sc->targets[target]->flags; 239 int quirks; 240 241 siop_cmd->siop_tables->id = siop_htoc32(sc, sc->targets[target]->id); 242 memset(siop_cmd->siop_tables->msg_out, 0, 243 sizeof(siop_cmd->siop_tables->msg_out)); 244 /* request sense doesn't disconnect */ 245 if (siop_cmd->status == CMDST_SENSE) 246 siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 0); 247 else if ((sc->features & SF_CHIP_GEBUG) && 248 (sc->targets[target]->flags & TARF_ISWIDE) == 0) 249 /* 250 * 1010 bug: it seems that the 1010 has problems with reselect 251 * when not in wide mode (generate false SCSI gross error). 252 * The FreeBSD sym driver has comments about it but their 253 * workaround (disable SCSI gross error reporting) doesn't 254 * work with my adapter. So disable disconnect when not 255 * wide. 256 */ 257 siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 0); 258 else 259 siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 1); 260 siop_cmd->siop_tables->t_msgout.count = siop_htoc32(sc, msgoffset); 261 if (sc->targets[target]->status == TARST_ASYNC) { 262 *targ_flags &= TARF_DT; /* Save TARF_DT 'cuz we don't set it here */ 263 quirks = xs->sc_link->quirks; 264 265 if ((quirks & SDEV_NOTAGS) == 0) 266 *targ_flags |= TARF_TAG; 267 if (((quirks & SDEV_NOWIDE) == 0) && 268 (sc->features & SF_BUS_WIDE)) 269 *targ_flags |= TARF_WIDE; 270 if ((quirks & SDEV_NOSYNC) == 0) 271 *targ_flags |= TARF_SYNC; 272 273 if ((sc->features & SF_CHIP_GEBUG) && 274 (*targ_flags & TARF_WIDE) == 0) 275 /* 276 * 1010 workaround: can't do disconnect if not wide, 277 * so can't do tag 278 */ 279 *targ_flags &= ~TARF_TAG; 280 281 /* Safe to call siop_add_dev() multiple times */ 282 siop_add_dev((struct siop_softc *)sc, target, lun); 283 284 if ((*targ_flags & TARF_DT) && 285 (sc->mode == STEST4_MODE_LVD)) { 286 sc->targets[target]->status = TARST_PPR_NEG; 287 siop_ppr_msg(siop_cmd, msgoffset, sc->dt_minsync, 288 sc->maxoff); 289 } else if (*targ_flags & TARF_WIDE) { 290 sc->targets[target]->status = TARST_WIDE_NEG; 291 siop_wdtr_msg(siop_cmd, msgoffset, 292 MSG_EXT_WDTR_BUS_16_BIT); 293 } else if (*targ_flags & TARF_SYNC) { 294 sc->targets[target]->status = TARST_SYNC_NEG; 295 siop_sdtr_msg(siop_cmd, msgoffset, sc->st_minsync, 296 (sc->maxoff > 31) ? 31 : sc->maxoff); 297 } else { 298 sc->targets[target]->status = TARST_OK; 299 siop_update_xfer_mode(sc, target); 300 } 301 } else if (sc->targets[target]->status == TARST_OK && 302 (*targ_flags & TARF_TAG) && 303 siop_cmd->status != CMDST_SENSE) { 304 siop_cmd->flags |= CMDFL_TAG; 305 } 306 siop_cmd->siop_tables->status = 307 siop_htoc32(sc, SCSI_SIOP_NOSTATUS); /* set invalid status */ 308 309 if ((xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) || 310 siop_cmd->status == CMDST_SENSE) { 311 bzero(siop_cmd->siop_tables->data, 312 sizeof(siop_cmd->siop_tables->data)); 313 for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) { 314 siop_cmd->siop_tables->data[i].count = 315 siop_htoc32(sc, 316 siop_cmd->dmamap_data->dm_segs[i].ds_len); 317 siop_cmd->siop_tables->data[i].addr = 318 siop_htoc32(sc, 319 siop_cmd->dmamap_data->dm_segs[i].ds_addr); 320 } 321 } 322 } 323 324 int 325 siop_wdtr_neg(siop_cmd) 326 struct siop_common_cmd *siop_cmd; 327 { 328 struct siop_common_softc *sc = siop_cmd->siop_sc; 329 struct siop_common_target *siop_target = siop_cmd->siop_target; 330 int target = siop_cmd->xs->sc_link->target; 331 struct siop_common_xfer *tables = siop_cmd->siop_tables; 332 333 if (siop_target->status == TARST_WIDE_NEG) { 334 /* we initiated wide negotiation */ 335 switch (tables->msg_in[3]) { 336 case MSG_EXT_WDTR_BUS_8_BIT: 337 siop_target->flags &= ~TARF_ISWIDE; 338 sc->targets[target]->id &= ~(SCNTL3_EWS << 24); 339 break; 340 case MSG_EXT_WDTR_BUS_16_BIT: 341 if (siop_target->flags & TARF_WIDE) { 342 siop_target->flags |= TARF_ISWIDE; 343 sc->targets[target]->id |= (SCNTL3_EWS << 24); 344 break; 345 } 346 /* FALLTHROUGH */ 347 default: 348 /* 349 * hum, we got more than what we can handle, shouldn't 350 * happen. Reject, and stay async 351 */ 352 siop_target->flags &= ~TARF_ISWIDE; 353 siop_target->status = TARST_OK; 354 siop_target->offset = siop_target->period = 0; 355 siop_update_xfer_mode(sc, target); 356 printf("%s: rejecting invalid wide negotiation from " 357 "target %d (%d)\n", sc->sc_dev.dv_xname, target, 358 tables->msg_in[3]); 359 tables->t_msgout.count = siop_htoc32(sc, 1); 360 tables->msg_out[0] = MSG_MESSAGE_REJECT; 361 return SIOP_NEG_MSGOUT; 362 } 363 tables->id = siop_htoc32(sc, sc->targets[target]->id); 364 bus_space_write_1(sc->sc_rt, sc->sc_rh, 365 SIOP_SCNTL3, 366 (sc->targets[target]->id >> 24) & 0xff); 367 /* we now need to do sync */ 368 if (siop_target->flags & TARF_SYNC) { 369 siop_target->status = TARST_SYNC_NEG; 370 siop_sdtr_msg(siop_cmd, 0, sc->st_minsync, 371 (sc->maxoff > 31) ? 31 : sc->maxoff); 372 return SIOP_NEG_MSGOUT; 373 } else { 374 siop_target->status = TARST_OK; 375 siop_update_xfer_mode(sc, target); 376 return SIOP_NEG_ACK; 377 } 378 } else { 379 /* target initiated wide negotiation */ 380 if (tables->msg_in[3] >= MSG_EXT_WDTR_BUS_16_BIT 381 && (siop_target->flags & TARF_WIDE)) { 382 siop_target->flags |= TARF_ISWIDE; 383 sc->targets[target]->id |= SCNTL3_EWS << 24; 384 } else { 385 siop_target->flags &= ~TARF_ISWIDE; 386 sc->targets[target]->id &= ~(SCNTL3_EWS << 24); 387 } 388 tables->id = siop_htoc32(sc, sc->targets[target]->id); 389 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 390 (sc->targets[target]->id >> 24) & 0xff); 391 /* 392 * we did reset wide parameters, so fall back to async, 393 * but don't schedule a sync neg, target should initiate it 394 */ 395 siop_target->status = TARST_OK; 396 siop_target->offset = siop_target->period = 0; 397 siop_update_xfer_mode(sc, target); 398 siop_wdtr_msg(siop_cmd, 0, (siop_target->flags & TARF_ISWIDE) ? 399 MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT); 400 return SIOP_NEG_MSGOUT; 401 } 402 } 403 404 int 405 siop_ppr_neg(siop_cmd) 406 struct siop_common_cmd *siop_cmd; 407 { 408 struct siop_common_softc *sc = siop_cmd->siop_sc; 409 struct siop_common_target *siop_target = siop_cmd->siop_target; 410 int target = siop_cmd->xs->sc_link->target; 411 struct siop_common_xfer *tables = siop_cmd->siop_tables; 412 int sync, offset, options, scf = 0; 413 int i; 414 415 #ifdef DEBUG_NEG 416 printf("%s: answer on ppr negotiation:", sc->sc_dev.dv_xname); 417 for (i = 0; i < 8; i++) 418 printf(" 0x%x", tables->msg_in[i]); 419 printf("\n"); 420 #endif 421 422 if (siop_target->status == TARST_PPR_NEG) { 423 /* we initiated PPR negotiation */ 424 sync = tables->msg_in[3]; 425 offset = tables->msg_in[5]; 426 options = tables->msg_in[7]; 427 if (options != MSG_EXT_PPR_PROT_DT) { 428 /* should't happen */ 429 printf("%s: ppr negotiation for target %d: " 430 "no DT option\n", sc->sc_dev.dv_xname, target); 431 siop_target->status = TARST_ASYNC; 432 siop_target->flags &= ~(TARF_DT | TARF_ISDT); 433 siop_target->offset = 0; 434 siop_target->period = 0; 435 goto reject; 436 } 437 438 if (offset > sc->maxoff || sync < sc->dt_minsync || 439 sync > sc->dt_maxsync) { 440 printf("%s: ppr negotiation for target %d: " 441 "offset (%d) or sync (%d) out of range\n", 442 sc->sc_dev.dv_xname, target, offset, sync); 443 /* should not happen */ 444 siop_target->status = TARST_ASYNC; 445 siop_target->flags &= ~(TARF_DT | TARF_ISDT); 446 siop_target->offset = 0; 447 siop_target->period = 0; 448 goto reject; 449 } else { 450 for (i = 0; i < 451 sizeof(dt_scf_period) / sizeof(dt_scf_period[0]); 452 i++) { 453 if (sc->clock_period != dt_scf_period[i].clock) 454 continue; 455 if (dt_scf_period[i].period == sync) { 456 /* ok, found it. we now are sync. */ 457 siop_target->offset = offset; 458 siop_target->period = sync; 459 scf = dt_scf_period[i].scf; 460 siop_target->flags |= TARF_ISDT; 461 } 462 } 463 if ((siop_target->flags & TARF_ISDT) == 0) { 464 printf("%s: ppr negotiation for target %d: " 465 "sync (%d) incompatible with adapter\n", 466 sc->sc_dev.dv_xname, target, sync); 467 /* 468 * we didn't find it in our table, do async 469 * send reject msg, start SDTR/WDTR neg 470 */ 471 siop_target->status = TARST_ASYNC; 472 siop_target->flags &= ~(TARF_DT | TARF_ISDT); 473 siop_target->offset = 0; 474 siop_target->period = 0; 475 goto reject; 476 } 477 } 478 if (tables->msg_in[6] != 1) { 479 printf("%s: ppr negotiation for target %d: " 480 "transfer width (%d) incompatible with dt\n", 481 sc->sc_dev.dv_xname, target, tables->msg_in[6]); 482 /* DT mode can only be done with wide transfers */ 483 siop_target->status = TARST_ASYNC; 484 siop_target->flags &= ~(TARF_DT | TARF_ISDT); 485 siop_target->offset = 0; 486 siop_target->period = 0; 487 goto reject; 488 } 489 siop_target->flags |= TARF_ISWIDE; 490 sc->targets[target]->id |= (SCNTL3_EWS << 24); 491 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24); 492 sc->targets[target]->id |= scf << (24 + SCNTL3_SCF_SHIFT); 493 sc->targets[target]->id &= ~(SXFER_MO_MASK << 8); 494 sc->targets[target]->id |= 495 (siop_target->offset & SXFER_MO_MASK) << 8; 496 sc->targets[target]->id &= ~0xff; 497 sc->targets[target]->id |= SCNTL4_U3EN; 498 siop_target->status = TARST_OK; 499 siop_update_xfer_mode(sc, target); 500 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 501 (sc->targets[target]->id >> 24) & 0xff); 502 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 503 (sc->targets[target]->id >> 8) & 0xff); 504 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, 505 sc->targets[target]->id & 0xff); 506 return SIOP_NEG_ACK; 507 } else { 508 /* target initiated PPR negotiation, shouldn't happen */ 509 printf("%s: rejecting invalid PPR negotiation from " 510 "target %d\n", sc->sc_dev.dv_xname, target); 511 reject: 512 tables->t_msgout.count = siop_htoc32(sc, 1); 513 tables->msg_out[0] = MSG_MESSAGE_REJECT; 514 return SIOP_NEG_MSGOUT; 515 } 516 } 517 518 int 519 siop_sdtr_neg(siop_cmd) 520 struct siop_common_cmd *siop_cmd; 521 { 522 struct siop_common_softc *sc = siop_cmd->siop_sc; 523 struct siop_common_target *siop_target = siop_cmd->siop_target; 524 int target = siop_cmd->xs->sc_link->target; 525 int sync, maxoffset, offset, i; 526 int send_msgout = 0; 527 struct siop_common_xfer *tables = siop_cmd->siop_tables; 528 529 /* limit to Ultra/2 parameters, need PPR for Ultra/3 */ 530 maxoffset = (sc->maxoff > 31) ? 31 : sc->maxoff; 531 532 sync = tables->msg_in[3]; 533 offset = tables->msg_in[4]; 534 535 if (siop_target->status == TARST_SYNC_NEG) { 536 /* we initiated sync negotiation */ 537 siop_target->status = TARST_OK; 538 #ifdef DEBUG 539 printf("sdtr: sync %d offset %d\n", sync, offset); 540 #endif 541 if (offset > maxoffset || sync < sc->st_minsync || 542 sync > sc->st_maxsync) 543 goto reject; 544 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); 545 i++) { 546 if (sc->clock_period != scf_period[i].clock) 547 continue; 548 if (scf_period[i].period == sync) { 549 /* ok, found it. we now are sync. */ 550 siop_target->offset = offset; 551 siop_target->period = sync; 552 sc->targets[target]->id &= 553 ~(SCNTL3_SCF_MASK << 24); 554 sc->targets[target]->id |= scf_period[i].scf 555 << (24 + SCNTL3_SCF_SHIFT); 556 if (sync < 25 && /* Ultra */ 557 (sc->features & SF_BUS_ULTRA3) == 0) 558 sc->targets[target]->id |= 559 SCNTL3_ULTRA << 24; 560 else 561 sc->targets[target]->id &= 562 ~(SCNTL3_ULTRA << 24); 563 sc->targets[target]->id &= 564 ~(SXFER_MO_MASK << 8); 565 sc->targets[target]->id |= 566 (offset & SXFER_MO_MASK) << 8; 567 sc->targets[target]->id &= ~0xff; /* scntl4 */ 568 goto end; 569 } 570 } 571 /* 572 * we didn't find it in our table, do async and send reject 573 * msg 574 */ 575 reject: 576 send_msgout = 1; 577 tables->t_msgout.count = siop_htoc32(sc, 1); 578 tables->msg_out[0] = MSG_MESSAGE_REJECT; 579 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24); 580 sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24); 581 sc->targets[target]->id &= ~(SXFER_MO_MASK << 8); 582 sc->targets[target]->id &= ~0xff; /* scntl4 */ 583 siop_target->offset = siop_target->period = 0; 584 } else { /* target initiated sync neg */ 585 #ifdef DEBUG 586 printf("sdtr (target): sync %d offset %d\n", sync, offset); 587 #endif 588 if (offset == 0 || sync > sc->st_maxsync) { /* async */ 589 goto async; 590 } 591 if (offset > maxoffset) 592 offset = maxoffset; 593 if (sync < sc->st_minsync) 594 sync = sc->st_minsync; 595 /* look for sync period */ 596 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); 597 i++) { 598 if (sc->clock_period != scf_period[i].clock) 599 continue; 600 if (scf_period[i].period == sync) { 601 /* ok, found it. we now are sync. */ 602 siop_target->offset = offset; 603 siop_target->period = sync; 604 sc->targets[target]->id &= 605 ~(SCNTL3_SCF_MASK << 24); 606 sc->targets[target]->id |= scf_period[i].scf 607 << (24 + SCNTL3_SCF_SHIFT); 608 if (sync < 25 && /* Ultra */ 609 (sc->features & SF_BUS_ULTRA3) == 0) 610 sc->targets[target]->id |= 611 SCNTL3_ULTRA << 24; 612 else 613 sc->targets[target]->id &= 614 ~(SCNTL3_ULTRA << 24); 615 sc->targets[target]->id &= 616 ~(SXFER_MO_MASK << 8); 617 sc->targets[target]->id |= 618 (offset & SXFER_MO_MASK) << 8; 619 sc->targets[target]->id &= ~0xff; /* scntl4 */ 620 siop_sdtr_msg(siop_cmd, 0, sync, offset); 621 send_msgout = 1; 622 goto end; 623 } 624 } 625 async: 626 siop_target->offset = siop_target->period = 0; 627 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24); 628 sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24); 629 sc->targets[target]->id &= ~(SXFER_MO_MASK << 8); 630 sc->targets[target]->id &= ~0xff; /* scntl4 */ 631 siop_sdtr_msg(siop_cmd, 0, 0, 0); 632 send_msgout = 1; 633 } 634 end: 635 if (siop_target->status == TARST_OK) 636 siop_update_xfer_mode(sc, target); 637 #ifdef DEBUG 638 printf("id now 0x%x\n", sc->targets[target]->id); 639 #endif 640 tables->id = siop_htoc32(sc, sc->targets[target]->id); 641 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 642 (sc->targets[target]->id >> 24) & 0xff); 643 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 644 (sc->targets[target]->id >> 8) & 0xff); 645 if (send_msgout) { 646 return SIOP_NEG_MSGOUT; 647 } else { 648 return SIOP_NEG_ACK; 649 } 650 } 651 652 void 653 siop_sdtr_msg(siop_cmd, offset, ssync, soff) 654 struct siop_common_cmd *siop_cmd; 655 int offset; 656 int ssync, soff; 657 { 658 siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED; 659 siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_SDTR_LEN; 660 siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_SDTR; 661 siop_cmd->siop_tables->msg_out[offset + 3] = ssync; 662 siop_cmd->siop_tables->msg_out[offset + 4] = soff; 663 siop_cmd->siop_tables->t_msgout.count = 664 siop_htoc32(siop_cmd->siop_sc, offset + MSG_EXT_SDTR_LEN + 2); 665 } 666 667 void 668 siop_wdtr_msg(siop_cmd, offset, wide) 669 struct siop_common_cmd *siop_cmd; 670 int offset; 671 int wide; 672 { 673 siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED; 674 siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_WDTR_LEN; 675 siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_WDTR; 676 siop_cmd->siop_tables->msg_out[offset + 3] = wide; 677 siop_cmd->siop_tables->t_msgout.count = 678 siop_htoc32(siop_cmd->siop_sc, offset + MSG_EXT_WDTR_LEN + 2); 679 } 680 681 void 682 siop_ppr_msg(siop_cmd, offset, ssync, soff) 683 struct siop_common_cmd *siop_cmd; 684 int offset; 685 int ssync, soff; 686 { 687 siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED; 688 siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_PPR_LEN; 689 siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_PPR; 690 siop_cmd->siop_tables->msg_out[offset + 3] = ssync; 691 siop_cmd->siop_tables->msg_out[offset + 4] = 0; /* reserved */ 692 siop_cmd->siop_tables->msg_out[offset + 5] = soff; 693 siop_cmd->siop_tables->msg_out[offset + 6] = 1; /* wide */ 694 siop_cmd->siop_tables->msg_out[offset + 7] = MSG_EXT_PPR_PROT_DT; 695 siop_cmd->siop_tables->t_msgout.count = 696 siop_htoc32(siop_cmd->siop_sc, offset + MSG_EXT_PPR_LEN + 2); 697 } 698 699 void 700 siop_ma(siop_cmd) 701 struct siop_common_cmd *siop_cmd; 702 { 703 int offset, dbc, sstat; 704 struct siop_common_softc *sc = siop_cmd->siop_sc; 705 scr_table_t *table; /* table with partial xfer */ 706 707 /* 708 * compute how much of the current table didn't get handled when 709 * a phase mismatch occurs 710 */ 711 if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN)) 712 == 0) 713 return; /* no valid data transfer */ 714 715 offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1); 716 if (offset >= SIOP_NSG) { 717 printf("%s: bad offset in siop_sdp (%d)\n", 718 sc->sc_dev.dv_xname, offset); 719 return; 720 } 721 table = &siop_cmd->siop_tables->data[offset]; 722 #ifdef DEBUG_DR 723 printf("siop_ma: offset %d count=%d addr=0x%x ", offset, 724 table->count, table->addr); 725 #endif 726 dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff; 727 if (siop_cmd->xs->flags & SCSI_DATA_OUT) { 728 if (sc->features & SF_CHIP_DFBC) { 729 dbc += 730 bus_space_read_2(sc->sc_rt, sc->sc_rh, SIOP_DFBC); 731 } else { 732 /* need to account stale data in FIFO */ 733 int dfifo = 734 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO); 735 if (sc->features & SF_CHIP_FIFO) { 736 dfifo |= (bus_space_read_1(sc->sc_rt, sc->sc_rh, 737 SIOP_CTEST5) & CTEST5_BOMASK) << 8; 738 dbc += (dfifo - (dbc & 0x3ff)) & 0x3ff; 739 } else { 740 dbc += (dfifo - (dbc & 0x7f)) & 0x7f; 741 } 742 } 743 sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0); 744 if (sstat & SSTAT0_OLF) 745 dbc++; 746 if ((sstat & SSTAT0_ORF) && (sc->features & SF_CHIP_DFBC) == 0) 747 dbc++; 748 if (siop_cmd->siop_target->flags & TARF_ISWIDE) { 749 sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, 750 SIOP_SSTAT2); 751 if (sstat & SSTAT2_OLF1) 752 dbc++; 753 if ((sstat & SSTAT2_ORF1) && 754 (sc->features & SF_CHIP_DFBC) == 0) 755 dbc++; 756 } 757 /* clear the FIFO */ 758 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, 759 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) | 760 CTEST3_CLF); 761 } 762 siop_cmd->flags |= CMDFL_RESID; 763 siop_cmd->resid = dbc; 764 } 765 766 void 767 siop_sdp(siop_cmd, offset) 768 struct siop_common_cmd *siop_cmd; 769 int offset; 770 { 771 struct siop_common_softc *sc = siop_cmd->siop_sc; 772 scr_table_t *table; 773 774 if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN))== 0) 775 return; /* no data pointers to save */ 776 777 /* 778 * offset == SIOP_NSG may be a valid condition if we get a Save data 779 * pointer when the xfer is done. Just ignore the Save data pointer 780 * in this case 781 */ 782 if (offset == SIOP_NSG) 783 return; 784 #ifdef DIAGNOSTIC 785 if (offset > SIOP_NSG) { 786 sc_print_addr(siop_cmd->xs->sc_link); 787 printf("offset %d > %d\n", offset, SIOP_NSG); 788 panic("siop_sdp: offset"); 789 } 790 #endif 791 /* 792 * Save data pointer. We do this by adjusting the tables to point 793 * at the beginning of the data not yet transferred. 794 * offset points to the first table with untransferred data. 795 */ 796 797 /* 798 * before doing that we decrease resid from the amount of data which 799 * has been transferred. 800 */ 801 siop_update_resid(siop_cmd, offset); 802 803 /* 804 * First let see if we have a resid from a phase mismatch. If so, 805 * we have to adjst the table at offset to remove transferred data. 806 */ 807 if (siop_cmd->flags & CMDFL_RESID) { 808 siop_cmd->flags &= ~CMDFL_RESID; 809 table = &siop_cmd->siop_tables->data[offset]; 810 /* "cut" already transferred data from this table */ 811 table->addr = 812 siop_htoc32(sc, siop_ctoh32(sc, table->addr) + 813 siop_ctoh32(sc, table->count) - siop_cmd->resid); 814 table->count = siop_htoc32(sc, siop_cmd->resid); 815 } 816 817 /* 818 * now we can remove entries which have been transferred. 819 * We just move the entries with data left at the beginning of the 820 * tables 821 */ 822 bcopy(&siop_cmd->siop_tables->data[offset], 823 &siop_cmd->siop_tables->data[0], 824 (SIOP_NSG - offset) * sizeof(scr_table_t)); 825 } 826 827 void 828 siop_update_resid(siop_cmd, offset) 829 struct siop_common_cmd *siop_cmd; 830 int offset; 831 { 832 struct siop_common_softc *sc = siop_cmd->siop_sc; 833 scr_table_t *table; 834 int i; 835 836 if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN)) 837 == 0) 838 return; /* no data to transfer */ 839 840 /* 841 * update resid. First account for the table entries which have 842 * been fully completed. 843 */ 844 for (i = 0; i < offset; i++) 845 siop_cmd->xs->resid -= 846 siop_ctoh32(sc, siop_cmd->siop_tables->data[i].count); 847 /* 848 * if CMDFL_RESID is set, the last table (pointed by offset) is a 849 * partial transfers. If not, offset points to the entry folloing 850 * the last full transfer. 851 */ 852 if (siop_cmd->flags & CMDFL_RESID) { 853 table = &siop_cmd->siop_tables->data[offset]; 854 siop_cmd->xs->resid -= 855 siop_ctoh32(sc, table->count) - siop_cmd->resid; 856 } 857 } 858 859 int 860 siop_iwr(siop_cmd) 861 struct siop_common_cmd *siop_cmd; 862 { 863 int offset; 864 scr_table_t *table; /* table with IWR */ 865 struct siop_common_softc *sc = siop_cmd->siop_sc; 866 /* handle ignore wide residue messages */ 867 868 /* if target isn't wide, reject */ 869 if ((siop_cmd->siop_target->flags & TARF_ISWIDE) == 0) { 870 siop_cmd->siop_tables->t_msgout.count = siop_htoc32(sc, 1); 871 siop_cmd->siop_tables->msg_out[0] = MSG_MESSAGE_REJECT; 872 return SIOP_NEG_MSGOUT; 873 } 874 /* get index of current command in table */ 875 offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1); 876 /* 877 * if the current table did complete, we're now pointing at the 878 * next one. Go back one if we didn't see a phase mismatch. 879 */ 880 if ((siop_cmd->flags & CMDFL_RESID) == 0) 881 offset--; 882 table = &siop_cmd->siop_tables->data[offset]; 883 884 if ((siop_cmd->flags & CMDFL_RESID) == 0) { 885 if (siop_ctoh32(sc, table->count) & 1) { 886 /* we really got the number of bytes we expected */ 887 return SIOP_NEG_ACK; 888 } else { 889 /* 890 * now we really had a short xfer, by one byte. 891 * handle it just as if we had a phase mistmatch 892 * (there is a resid of one for this table). 893 * Update scratcha1 to reflect the fact that 894 * this xfer isn't complete. 895 */ 896 siop_cmd->flags |= CMDFL_RESID; 897 siop_cmd->resid = 1; 898 bus_space_write_1(sc->sc_rt, sc->sc_rh, 899 SIOP_SCRATCHA + 1, offset); 900 return SIOP_NEG_ACK; 901 } 902 } else { 903 /* 904 * we already have a short xfer for this table; it's 905 * just one byte less than we though it was 906 */ 907 siop_cmd->resid--; 908 return SIOP_NEG_ACK; 909 } 910 } 911 912 void 913 siop_clearfifo(sc) 914 struct siop_common_softc *sc; 915 { 916 int timeout = 0; 917 int ctest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3); 918 919 #ifdef DEBUG_INTR 920 printf("DMA fifo not empty !\n"); 921 #endif 922 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, 923 ctest3 | CTEST3_CLF); 924 while ((bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) & 925 CTEST3_CLF) != 0) { 926 delay(1); 927 if (++timeout > 1000) { 928 printf("clear fifo failed\n"); 929 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, 930 bus_space_read_1(sc->sc_rt, sc->sc_rh, 931 SIOP_CTEST3) & ~CTEST3_CLF); 932 return; 933 } 934 } 935 } 936 937 int 938 siop_modechange(sc) 939 struct siop_common_softc *sc; 940 { 941 int retry; 942 int sist0, sist1, stest2; 943 for (retry = 0; retry < 5; retry++) { 944 /* 945 * datasheet says to wait 100ms and re-read SIST1, 946 * to check that DIFFSENSE is stable. 947 * We may delay() 5 times for 100ms at interrupt time; 948 * hopefully this will not happen often. 949 */ 950 delay(100000); 951 sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0); 952 sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1); 953 if (sist1 & SIEN1_SBMC) 954 continue; /* we got an irq again */ 955 sc->mode = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) & 956 STEST4_MODE_MASK; 957 stest2 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2); 958 switch(sc->mode) { 959 case STEST4_MODE_DIF: 960 printf("%s: switching to differential mode\n", 961 sc->sc_dev.dv_xname); 962 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 963 stest2 | STEST2_DIF); 964 break; 965 case STEST4_MODE_SE: 966 printf("%s: switching to single-ended mode\n", 967 sc->sc_dev.dv_xname); 968 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 969 stest2 & ~STEST2_DIF); 970 break; 971 case STEST4_MODE_LVD: 972 printf("%s: switching to LVD mode\n", 973 sc->sc_dev.dv_xname); 974 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 975 stest2 & ~STEST2_DIF); 976 break; 977 default: 978 printf("%s: invalid SCSI mode 0x%x\n", 979 sc->sc_dev.dv_xname, sc->mode); 980 return 0; 981 } 982 return 1; 983 } 984 printf("%s: timeout waiting for DIFFSENSE to stabilise\n", 985 sc->sc_dev.dv_xname); 986 return 0; 987 } 988 989 void 990 siop_resetbus(sc) 991 struct siop_common_softc *sc; 992 { 993 int scntl1; 994 scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1); 995 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 996 scntl1 | SCNTL1_RST); 997 /* minimum 25 us, more time won't hurt */ 998 delay(100); 999 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1); 1000 } 1001 1002 void 1003 siop_update_xfer_mode(sc, target) 1004 struct siop_common_softc *sc; 1005 int target; 1006 { 1007 struct siop_common_target *siop_target; 1008 1009 siop_target = sc->targets[target]; 1010 1011 printf("%s: target %d now using %s%s%d bit ", 1012 sc->sc_dev.dv_xname, target, 1013 (siop_target->flags & TARF_TAG) ? "tagged " : "", 1014 (siop_target->flags & TARF_ISDT) ? "DT " : "", 1015 (siop_target->flags & TARF_ISWIDE) ? 16 : 8); 1016 1017 if (siop_target->offset == 0) 1018 printf("async "); 1019 else { 1020 switch (siop_target->period) { 1021 case 9: /* 12.5ns cycle */ 1022 printf("80.0"); 1023 break; 1024 case 10: /* 25 ns cycle */ 1025 printf("40.0"); 1026 break; 1027 case 12: /* 48 ns cycle */ 1028 printf("20.0"); 1029 break; 1030 case 18: /* 72 ns cycle */ 1031 printf("13.3"); 1032 break; 1033 case 25: /* 100 ns cycle */ 1034 printf("10.0"); 1035 break; 1036 case 37: /* 118 ns cycle */ 1037 printf("6.67"); 1038 break; 1039 case 50: /* 200 ns cycle */ 1040 printf("5.0"); 1041 break; 1042 case 75: /* 300 ns cycle */ 1043 printf("3.33"); 1044 break; 1045 default: 1046 printf("??"); 1047 break; 1048 } 1049 printf(" MHz %d REQ/ACK offset ", siop_target->offset); 1050 } 1051 1052 printf("xfers\n"); 1053 1054 if ((sc->features & SF_CHIP_GEBUG) && 1055 (siop_target->flags & TARF_ISWIDE) == 0) 1056 /* 1010 workaround: can't do disconnect if not wide, so can't do tag */ 1057 siop_target->flags &= ~TARF_TAG; 1058 } 1059