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