1 /* $NetBSD: siop_common.c,v 1.2 2000/05/15 15:16:59 bouyer Exp $ */ 2 3 /* 4 * Copyright (c) 2000 Manuel Bouyer. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Manuel Bouyer 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 */ 32 33 /* SYM53c7/8xx PCI-SCSI I/O Processors driver */ 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/device.h> 38 #include <sys/malloc.h> 39 #include <sys/buf.h> 40 #include <sys/kernel.h> 41 #include <sys/scsiio.h> 42 43 #include <machine/endian.h> 44 #include <machine/bus.h> 45 46 #include <vm/vm.h> 47 #include <vm/vm_param.h> 48 #include <vm/vm_kern.h> 49 50 #include <dev/scsipi/scsi_all.h> 51 #include <dev/scsipi/scsi_message.h> 52 #include <dev/scsipi/scsipi_all.h> 53 54 #include <dev/scsipi/scsiconf.h> 55 56 #include <dev/ic/siopreg.h> 57 #include <dev/ic/siopvar.h> 58 #include <dev/ic/siopvar_common.h> 59 60 #undef DEBUG 61 #undef DEBUG_DR 62 63 void 64 siop_common_reset(sc) 65 struct siop_softc *sc; 66 { 67 u_int32_t stest3; 68 69 /* reset the chip */ 70 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SRST); 71 delay(1000); 72 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, 0); 73 74 /* init registers */ 75 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL0, 76 SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP); 77 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 0); 78 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, sc->clock_div); 79 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCXFER, 0); 80 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DIEN, 0xff); 81 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN0, 82 0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL)); 83 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN1, 84 0xff & ~(SIEN1_HTH | SIEN1_GEN)); 85 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 0); 86 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, STEST3_TE); 87 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STIME0, 88 (0xb << STIME0_SEL_SHIFT)); 89 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCID, 90 sc->sc_link.scsipi_scsi.adapter_target | SCID_RRE); 91 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_RESPID0, 92 1 << sc->sc_link.scsipi_scsi.adapter_target); 93 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DCNTL, 94 (sc->features & SF_CHIP_PF) ? DCNTL_COM | DCNTL_PFEN : DCNTL_COM); 95 96 /* enable clock doubler or quadruler if appropriate */ 97 if (sc->features & (SF_CHIP_DBLR | SF_CHIP_QUAD)) { 98 stest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3); 99 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 100 STEST1_DBLEN); 101 if (sc->features & SF_CHIP_QUAD) { 102 /* wait for PPL to lock */ 103 while ((bus_space_read_1(sc->sc_rt, sc->sc_rh, 104 SIOP_STEST4) & STEST4_LOCK) == 0) 105 delay(10); 106 } else { 107 /* data sheet says 20us - more won't hurt */ 108 delay(100); 109 } 110 /* halt scsi clock, select doubler/quad, restart clock */ 111 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, 112 stest3 | STEST3_HSC); 113 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 114 STEST1_DBLEN | STEST1_DBLSEL); 115 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, stest3); 116 } else { 117 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 0); 118 } 119 if (sc->features & SF_CHIP_FIFO) 120 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5, 121 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5) | 122 CTEST5_DFS); 123 124 sc->sc_reset(sc); 125 } 126 127 int 128 siop_wdtr_neg(siop_cmd) 129 struct siop_cmd *siop_cmd; 130 { 131 struct siop_softc *sc = siop_cmd->siop_target->siop_sc; 132 struct siop_target *siop_target = siop_cmd->siop_target; 133 int target = siop_cmd->xs->sc_link->scsipi_scsi.target; 134 135 if (siop_target->status == TARST_WIDE_NEG) { 136 /* we initiated wide negotiation */ 137 switch (siop_cmd->siop_table->msg_in[3]) { 138 case MSG_EXT_WDTR_BUS_8_BIT: 139 printf("%s: target %d using 8bit transfers\n", 140 sc->sc_dev.dv_xname, target); 141 siop_target->flags &= ~SF_BUS_WIDE; 142 sc->targets[target]->id &= ~(SCNTL3_EWS << 24); 143 break; 144 case MSG_EXT_WDTR_BUS_16_BIT: 145 if (sc->features & SF_BUS_WIDE) { 146 printf("%s: target %d using 16bit transfers\n", 147 sc->sc_dev.dv_xname, target); 148 siop_target->flags |= TARF_WIDE; 149 sc->targets[target]->id |= (SCNTL3_EWS << 24); 150 break; 151 } 152 /* FALLTHROUH */ 153 default: 154 /* 155 * hum, we got more than what we can handle, shoudn't 156 * happen. Reject, and stay async 157 */ 158 siop_target->flags &= ~TARF_WIDE; 159 siop_target->status = TARST_OK; 160 printf("%s: rejecting invalid wide negotiation from " 161 "target %d (%d)\n", sc->sc_dev.dv_xname, target, 162 siop_cmd->siop_table->msg_in[3]); 163 siop_cmd->siop_table->t_msgout.count= htole32(1); 164 siop_cmd->siop_table->t_msgout.addr = 165 htole32(siop_cmd->dsa); 166 siop_cmd->siop_table->msg_out[0] = MSG_MESSAGE_REJECT; 167 return SIOP_NEG_MSGOUT; 168 } 169 siop_cmd->siop_table->id = 170 htole32(sc->targets[target]->id); 171 bus_space_write_1(sc->sc_rt, sc->sc_rh, 172 SIOP_SCNTL3, 173 (sc->targets[target]->id >> 24) & 0xff); 174 /* we now need to do sync */ 175 siop_target->status = TARST_SYNC_NEG; 176 siop_cmd->siop_table->msg_out[0] = MSG_EXTENDED; 177 siop_cmd->siop_table->msg_out[1] = MSG_EXT_SDTR_LEN; 178 siop_cmd->siop_table->msg_out[2] = MSG_EXT_SDTR; 179 siop_cmd->siop_table->msg_out[3] = sc->minsync; 180 siop_cmd->siop_table->msg_out[4] = sc->maxoff; 181 siop_cmd->siop_table->t_msgout.count = 182 htole32(MSG_EXT_SDTR_LEN + 2); 183 siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa); 184 return SIOP_NEG_MSGOUT; 185 } else { 186 /* target initiated wide negotiation */ 187 if (siop_cmd->siop_table->msg_in[3] >= MSG_EXT_WDTR_BUS_16_BIT 188 && (sc->features & SF_BUS_WIDE)) { 189 printf("%s: target %d using 16bit transfers\n", 190 sc->sc_dev.dv_xname, target); 191 siop_target->flags |= TARF_WIDE; 192 sc->targets[target]->id |= SCNTL3_EWS << 24; 193 siop_cmd->siop_table->msg_out[3] = 194 MSG_EXT_WDTR_BUS_16_BIT; 195 } else { 196 printf("%s: target %d using 8bit transfers\n", 197 sc->sc_dev.dv_xname, target); 198 siop_target->flags &= ~SF_BUS_WIDE; 199 sc->targets[target]->id &= ~(SCNTL3_EWS << 24); 200 siop_cmd->siop_table->msg_out[3] = 201 MSG_EXT_WDTR_BUS_8_BIT; 202 } 203 siop_cmd->siop_table->id = 204 htole32(sc->targets[target]->id); 205 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 206 (sc->targets[target]->id >> 24) & 0xff); 207 /* 208 * we did reset wide parameters, so fall back to async, 209 * but don't shedule a sync neg, target should initiate it 210 */ 211 siop_target->status = TARST_OK; 212 siop_cmd->siop_table->msg_out[0] = MSG_EXTENDED; 213 siop_cmd->siop_table->msg_out[1] = MSG_EXT_WDTR_LEN; 214 siop_cmd->siop_table->msg_out[2] = MSG_EXT_WDTR; 215 siop_cmd->siop_table->t_msgout.count= 216 htole32(MSG_EXT_WDTR_LEN + 2); 217 siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa); 218 return SIOP_NEG_MSGOUT; 219 } 220 } 221 222 int 223 siop_sdtr_neg(siop_cmd) 224 struct siop_cmd *siop_cmd; 225 { 226 struct siop_softc *sc = siop_cmd->siop_target->siop_sc; 227 struct siop_target *siop_target = siop_cmd->siop_target; 228 int target = siop_cmd->xs->sc_link->scsipi_scsi.target; 229 int sync, offset, i; 230 int send_msgout = 0; 231 232 sync = siop_cmd->siop_table->msg_in[3]; 233 offset = siop_cmd->siop_table->msg_in[4]; 234 235 if (siop_target->status == TARST_SYNC_NEG) { 236 /* we initiated sync negotiation */ 237 siop_target->status = TARST_OK; 238 #ifdef DEBUG 239 printf("sdtr: sync %d offset %d\n", sync, offset); 240 #endif 241 if (offset > sc->maxoff || sync < sc->minsync || 242 sync > sc->maxsync) 243 goto reject; 244 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); 245 i++) { 246 if (sc->clock_period != scf_period[i].clock) 247 continue; 248 if (scf_period[i].period == sync) { 249 /* ok, found it. we now are sync. */ 250 printf("%s: target %d now synchronous at " 251 "%sMhz, offset %d\n", sc->sc_dev.dv_xname, 252 target, scf_period[i].rate, offset); 253 sc->targets[target]->id &= 254 ~(SCNTL3_SCF_MASK << 24); 255 sc->targets[target]->id |= scf_period[i].scf 256 << (24 + SCNTL3_SCF_SHIFT); 257 if (sync < 25) /* Ultra */ 258 sc->targets[target]->id |= 259 SCNTL3_ULTRA << 24; 260 else 261 sc->targets[target]->id &= 262 ~(SCNTL3_ULTRA << 24); 263 sc->targets[target]->id &= 264 ~(SCXFER_MO_MASK << 8); 265 sc->targets[target]->id |= 266 (offset & SCXFER_MO_MASK) << 8; 267 goto end; 268 } 269 } 270 /* 271 * we didn't find it in our table, do async and send reject 272 * msg 273 */ 274 reject: 275 send_msgout = 1; 276 siop_cmd->siop_table->t_msgout.count= htole32(1); 277 siop_cmd->siop_table->msg_out[0] = MSG_MESSAGE_REJECT; 278 printf("%s: target %d asynchronous\n", sc->sc_dev.dv_xname, 279 target); 280 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24); 281 sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24); 282 sc->targets[target]->id &= ~(SCXFER_MO_MASK << 8); 283 } else { /* target initiated sync neg */ 284 #ifdef DEBUG 285 printf("sdtr (target): sync %d offset %d\n", sync, offset); 286 #endif 287 if (offset == 0 || sync > sc->maxsync) { /* async */ 288 goto async; 289 } 290 if (offset > sc->maxoff) 291 offset = sc->maxoff; 292 if (sync < sc->minsync) 293 sync = sc->minsync; 294 /* look for sync period */ 295 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); 296 i++) { 297 if (sc->clock_period != scf_period[i].clock) 298 continue; 299 if (scf_period[i].period == sync) { 300 /* ok, found it. we now are sync. */ 301 printf("%s: target %d now synchronous at " 302 "%sMhz, offset %d\n", sc->sc_dev.dv_xname, 303 target, scf_period[i].rate, offset); 304 sc->targets[target]->id &= 305 ~(SCNTL3_SCF_MASK << 24); 306 sc->targets[target]->id |= scf_period[i].scf 307 << (24 + SCNTL3_SCF_SHIFT); 308 if (sync < 25) /* Ultra */ 309 sc->targets[target]->id |= 310 SCNTL3_ULTRA << 24; 311 else 312 sc->targets[target]->id &= 313 ~(SCNTL3_ULTRA << 24); 314 sc->targets[target]->id &= 315 ~(SCXFER_MO_MASK << 8); 316 sc->targets[target]->id |= 317 (offset & SCXFER_MO_MASK) << 8; 318 siop_cmd->siop_table->msg_out[0] = MSG_EXTENDED; 319 siop_cmd->siop_table->msg_out[1] = 320 MSG_EXT_SDTR_LEN; 321 siop_cmd->siop_table->msg_out[2] = MSG_EXT_SDTR; 322 siop_cmd->siop_table->msg_out[3] = sync; 323 siop_cmd->siop_table->msg_out[4] = offset; 324 siop_cmd->siop_table->t_msgout.count= 325 htole32(MSG_EXT_SDTR_LEN + 2); 326 send_msgout = 1; 327 goto end; 328 } 329 } 330 async: 331 printf("%s: target %d asynchronous\n", 332 sc->sc_dev.dv_xname, target); 333 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24); 334 sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24); 335 sc->targets[target]->id &= ~(SCXFER_MO_MASK << 8); 336 siop_cmd->siop_table->msg_out[0] = MSG_EXTENDED; 337 siop_cmd->siop_table->msg_out[1] = MSG_EXT_SDTR_LEN; 338 siop_cmd->siop_table->msg_out[2] = MSG_EXT_SDTR; 339 siop_cmd->siop_table->msg_out[3] = 0; 340 siop_cmd->siop_table->msg_out[4] = 0; 341 siop_cmd->siop_table->t_msgout.count= 342 htole32(MSG_EXT_SDTR_LEN + 2); 343 send_msgout = 1; 344 } 345 end: 346 #ifdef DEBUG 347 printf("id now 0x%x\n", sc->targets[target]->id); 348 #endif 349 siop_cmd->siop_table->id = htole32(sc->targets[target]->id); 350 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 351 (sc->targets[target]->id >> 24) & 0xff); 352 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCXFER, 353 (sc->targets[target]->id >> 8) & 0xff); 354 if (send_msgout) { 355 siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa); 356 return SIOP_NEG_MSGOUT; 357 } else { 358 return SIOP_NEG_ACK; 359 } 360 } 361 362 void 363 siop_minphys(bp) 364 struct buf *bp; 365 { 366 minphys(bp); 367 } 368 369 int 370 siop_ioctl(link, cmd, arg, flag, p) 371 struct scsipi_link *link; 372 u_long cmd; 373 caddr_t arg; 374 int flag; 375 struct proc *p; 376 { 377 struct siop_softc *sc = link->adapter_softc; 378 u_int8_t scntl1; 379 int s; 380 381 switch (cmd) { 382 case SCBUSIORESET: 383 s = splbio(); 384 scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1); 385 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 386 scntl1 | SCNTL1_RST); 387 /* minimum 25 us, more time won't hurt */ 388 delay(100); 389 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1); 390 splx(s); 391 return (0); 392 default: 393 return (ENOTTY); 394 } 395 } 396 397 void 398 siop_sdp(siop_cmd) 399 struct siop_cmd *siop_cmd; 400 { 401 /* save data pointer. Handle async only for now */ 402 int offset, dbc, sstat; 403 struct siop_softc *sc = siop_cmd->siop_target->siop_sc; 404 scr_table_t *table; /* table to patch */ 405 406 if ((siop_cmd->xs->xs_control & (XS_CTL_DATA_OUT | XS_CTL_DATA_IN)) 407 == 0) 408 return; /* no data pointers to save */ 409 offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1); 410 if (offset >= SIOP_NSG) { 411 printf("%s: bad offset in siop_sdp (%d)\n", 412 sc->sc_dev.dv_xname, offset); 413 return; 414 } 415 table = &siop_cmd->siop_table->data[offset]; 416 #ifdef DEBUG_DR 417 printf("sdp: offset %d count=%d addr=0x%x ", offset, 418 table->count, table->addr); 419 #endif 420 dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff; 421 if (siop_cmd->xs->xs_control & XS_CTL_DATA_OUT) { 422 /* need to account stale data in FIFO */ 423 int dfifo = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO); 424 if (sc->features & SF_CHIP_FIFO) { 425 dfifo |= (bus_space_read_1(sc->sc_rt, sc->sc_rh, 426 SIOP_CTEST5) & CTEST5_BOMASK) << 8; 427 dbc += (dfifo - (dbc & 0x3ff)) & 0x3ff; 428 } else { 429 dbc += (dfifo - (dbc & 0x7f)) & 0x7f; 430 } 431 sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0); 432 if (sstat & SSTAT0_OLF) 433 dbc++; 434 if (sstat & SSTAT0_ORF) 435 dbc++; 436 if (siop_cmd->siop_target->flags & TARF_WIDE) { 437 sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, 438 SIOP_SSTAT2); 439 if (sstat & SSTAT2_OLF1) 440 dbc++; 441 if (sstat & SSTAT2_ORF1) 442 dbc++; 443 } 444 /* clear the FIFO */ 445 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, 446 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) | 447 CTEST3_CLF); 448 } 449 table->addr = 450 htole32(le32toh(table->addr) + le32toh(table->count) - dbc); 451 table->count = htole32(dbc); 452 #ifdef DEBUG_DR 453 printf("now count=%d addr=0x%x\n", table->count, table->addr); 454 #endif 455 } 456 457 void 458 siop_clearfifo(sc) 459 struct siop_softc *sc; 460 { 461 int timeout = 0; 462 int ctest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3); 463 464 #ifdef DEBUG_INTR 465 printf("DMA fifo not empty !\n"); 466 #endif 467 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, 468 ctest3 | CTEST3_CLF); 469 while ((bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) & 470 CTEST3_CLF) != 0) { 471 delay(1); 472 if (++timeout > 1000) { 473 printf("clear fifo failed\n"); 474 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, 475 bus_space_read_1(sc->sc_rt, sc->sc_rh, 476 SIOP_CTEST3) & ~CTEST3_CLF); 477 return; 478 } 479 } 480 } 481