1 /* $OpenBSD: oosiop.c,v 1.12 2009/03/07 15:38:43 miod Exp $ */ 2 /* $NetBSD: oosiop.c,v 1.4 2003/10/29 17:45:55 tsutsui Exp $ */ 3 4 /* 5 * Copyright (c) 2001 Shuichiro URATA. All rights reserved. 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. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * NCR53C700 SCSI I/O processor (OOSIOP) driver 32 * 33 * TODO: 34 * - Better error handling. 35 * - Implement tagged queuing. 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/timeout.h> 41 #include <sys/kernel.h> 42 #include <sys/device.h> 43 #include <sys/buf.h> 44 #include <sys/malloc.h> 45 #include <sys/queue.h> 46 47 #include <uvm/uvm_extern.h> 48 49 #include <scsi/scsi_all.h> 50 #include <scsi/scsiconf.h> 51 #include <scsi/scsi_message.h> 52 53 #include <machine/cpu.h> 54 #include <machine/bus.h> 55 56 #include <dev/ic/oosiopreg.h> 57 #include <dev/ic/oosiopvar.h> 58 59 /* 53C700 script */ 60 #include <dev/microcode/siop/oosiop.out> 61 62 int oosiop_alloc_cb(struct oosiop_softc *, int); 63 64 static __inline void oosiop_relocate_io(struct oosiop_softc *, bus_addr_t); 65 static __inline void oosiop_relocate_tc(struct oosiop_softc *, bus_addr_t); 66 static __inline void oosiop_fixup_select(struct oosiop_softc *, bus_addr_t, 67 int); 68 static __inline void oosiop_fixup_jump(struct oosiop_softc *, bus_addr_t, 69 bus_addr_t); 70 static __inline void oosiop_fixup_move(struct oosiop_softc *, bus_addr_t, 71 bus_size_t, bus_addr_t); 72 73 void oosiop_load_script(struct oosiop_softc *); 74 void oosiop_setup_sgdma(struct oosiop_softc *, struct oosiop_cb *); 75 void oosiop_setup_dma(struct oosiop_softc *); 76 void oosiop_flush_fifo(struct oosiop_softc *); 77 void oosiop_clear_fifo(struct oosiop_softc *); 78 void oosiop_phasemismatch(struct oosiop_softc *); 79 void oosiop_setup_syncxfer(struct oosiop_softc *); 80 void oosiop_set_syncparam(struct oosiop_softc *, int, int, int); 81 void oosiop_minphys(struct buf *, struct scsi_link *); 82 int oosiop_scsicmd(struct scsi_xfer *); 83 void oosiop_done(struct oosiop_softc *, struct oosiop_cb *); 84 void oosiop_timeout(void *); 85 void oosiop_reset(struct oosiop_softc *); 86 void oosiop_reset_bus(struct oosiop_softc *); 87 void oosiop_scriptintr(struct oosiop_softc *); 88 void oosiop_msgin(struct oosiop_softc *, struct oosiop_cb *); 89 void oosiop_setup(struct oosiop_softc *, struct oosiop_cb *); 90 void oosiop_poll(struct oosiop_softc *, struct oosiop_cb *); 91 void oosiop_processintr(struct oosiop_softc *, u_int8_t); 92 93 /* Trap interrupt code for unexpected data I/O */ 94 #define DATAIN_TRAP 0xdead0001 95 #define DATAOUT_TRAP 0xdead0002 96 97 /* Possible TP and SCF conbination */ 98 static const struct { 99 u_int8_t tp; 100 u_int8_t scf; 101 } synctbl[] = { 102 {0, 1}, /* SCLK / 4.0 */ 103 {1, 1}, /* SCLK / 5.0 */ 104 {2, 1}, /* SCLK / 6.0 */ 105 {3, 1}, /* SCLK / 7.0 */ 106 {1, 2}, /* SCLK / 7.5 */ 107 {4, 1}, /* SCLK / 8.0 */ 108 {5, 1}, /* SCLK / 9.0 */ 109 {6, 1}, /* SCLK / 10.0 */ 110 {3, 2}, /* SCLK / 10.5 */ 111 {7, 1}, /* SCLK / 11.0 */ 112 {4, 2}, /* SCLK / 12.0 */ 113 {5, 2}, /* SCLK / 13.5 */ 114 {3, 3}, /* SCLK / 14.0 */ 115 {6, 2}, /* SCLK / 15.0 */ 116 {4, 3}, /* SCLK / 16.0 */ 117 {7, 2}, /* SCLK / 16.5 */ 118 {5, 3}, /* SCLK / 18.0 */ 119 {6, 3}, /* SCLK / 20.0 */ 120 {7, 3} /* SCLK / 22.0 */ 121 }; 122 #define NSYNCTBL (sizeof(synctbl) / sizeof(synctbl[0])) 123 124 #define oosiop_period(sc, tp, scf) \ 125 (((1000000000 / (sc)->sc_freq) * (tp) * (scf)) / 40) 126 127 struct cfdriver oosiop_cd = { 128 NULL, "oosiop", DV_DULL 129 }; 130 131 struct scsi_adapter oosiop_adapter = { 132 oosiop_scsicmd, 133 oosiop_minphys, 134 NULL, 135 NULL 136 }; 137 138 struct scsi_device oosiop_dev = { 139 NULL, 140 NULL, 141 NULL, 142 NULL 143 }; 144 145 void 146 oosiop_attach(struct oosiop_softc *sc) 147 { 148 struct scsibus_attach_args saa; 149 bus_size_t scrsize; 150 bus_dma_segment_t seg; 151 struct oosiop_cb *cb; 152 int err, i, nseg; 153 154 /* 155 * Allocate DMA-safe memory for the script and map it. 156 */ 157 scrsize = round_page(sizeof(oosiop_script)); 158 err = bus_dmamem_alloc(sc->sc_dmat, scrsize, PAGE_SIZE, 0, &seg, 1, 159 &nseg, BUS_DMA_NOWAIT); 160 if (err) { 161 printf(": failed to allocate script memory, err=%d\n", err); 162 return; 163 } 164 err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, scrsize, 165 (caddr_t *)&sc->sc_scr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT); 166 if (err) { 167 printf(": failed to map script memory, err=%d\n", err); 168 return; 169 } 170 err = bus_dmamap_create(sc->sc_dmat, scrsize, 1, scrsize, 0, 171 BUS_DMA_NOWAIT, &sc->sc_scrdma); 172 if (err) { 173 printf(": failed to create script map, err=%d\n", err); 174 return; 175 } 176 err = bus_dmamap_load_raw(sc->sc_dmat, sc->sc_scrdma, 177 &seg, nseg, scrsize, BUS_DMA_NOWAIT | BUS_DMA_WRITE); 178 if (err) { 179 printf(": failed to load script map, err=%d\n", err); 180 return; 181 } 182 bzero(sc->sc_scr, scrsize); 183 sc->sc_scrbase = sc->sc_scrdma->dm_segs[0].ds_addr; 184 185 /* Initialize command block array */ 186 TAILQ_INIT(&sc->sc_free_cb); 187 TAILQ_INIT(&sc->sc_cbq); 188 if (oosiop_alloc_cb(sc, OOSIOP_NCB) != 0) 189 return; 190 191 /* Use first cb to reselection msgin buffer */ 192 cb = TAILQ_FIRST(&sc->sc_free_cb); 193 sc->sc_reselbuf = cb->xferdma->dm_segs[0].ds_addr + 194 offsetof(struct oosiop_xfer, msgin[0]); 195 196 for (i = 0; i < OOSIOP_NTGT; i++) { 197 sc->sc_tgt[i].nexus = NULL; 198 sc->sc_tgt[i].flags = 0; 199 } 200 201 /* Setup asynchronous clock divisor parameters */ 202 if (sc->sc_freq <= 25000000) { 203 sc->sc_ccf = 10; 204 sc->sc_dcntl = OOSIOP_DCNTL_CF_1; 205 } else if (sc->sc_freq <= 37500000) { 206 sc->sc_ccf = 15; 207 sc->sc_dcntl = OOSIOP_DCNTL_CF_1_5; 208 } else if (sc->sc_freq <= 50000000) { 209 sc->sc_ccf = 20; 210 sc->sc_dcntl = OOSIOP_DCNTL_CF_2; 211 } else { 212 sc->sc_ccf = 30; 213 sc->sc_dcntl = OOSIOP_DCNTL_CF_3; 214 } 215 216 if (sc->sc_chip == OOSIOP_700) 217 sc->sc_minperiod = oosiop_period(sc, 4, sc->sc_ccf); 218 else 219 sc->sc_minperiod = oosiop_period(sc, 4, 10); 220 221 if (sc->sc_minperiod < 25) 222 sc->sc_minperiod = 25; /* limit to 10MB/s */ 223 224 printf(": NCR53C700%s rev %d, %dMHz\n", 225 sc->sc_chip == OOSIOP_700_66 ? "-66" : "", 226 oosiop_read_1(sc, OOSIOP_CTEST7) >> 4, 227 sc->sc_freq / 1000000); 228 /* 229 * Reset all 230 */ 231 oosiop_reset(sc); 232 oosiop_reset_bus(sc); 233 234 /* 235 * Start SCRIPTS processor 236 */ 237 oosiop_load_script(sc); 238 sc->sc_active = 0; 239 oosiop_write_4(sc, OOSIOP_DSP, sc->sc_scrbase + Ent_wait_reselect); 240 241 /* 242 * Fill in the sc_link. 243 */ 244 sc->sc_link.adapter = &oosiop_adapter; 245 sc->sc_link.adapter_softc = sc; 246 sc->sc_link.device = &oosiop_dev; 247 sc->sc_link.openings = 1; /* XXX */ 248 sc->sc_link.adapter_buswidth = OOSIOP_NTGT; 249 sc->sc_link.adapter_target = sc->sc_id; 250 sc->sc_link.quirks = ADEV_NODOORLOCK; 251 252 bzero(&saa, sizeof(saa)); 253 saa.saa_sc_link = &sc->sc_link; 254 255 /* 256 * Now try to attach all the sub devices. 257 */ 258 config_found(&sc->sc_dev, &saa, scsiprint); 259 } 260 261 int 262 oosiop_alloc_cb(struct oosiop_softc *sc, int ncb) 263 { 264 struct oosiop_cb *cb; 265 struct oosiop_xfer *xfer; 266 bus_size_t xfersize; 267 bus_dma_segment_t seg; 268 int i, s, err, nseg; 269 270 /* 271 * Allocate oosiop_cb. 272 */ 273 cb = malloc(sizeof(*cb) * ncb, M_DEVBUF, M_NOWAIT | M_ZERO); 274 if (cb == NULL) { 275 printf(": failed to allocate cb memory\n"); 276 return (ENOMEM); 277 } 278 279 /* 280 * Allocate DMA-safe memory for the oosiop_xfer and map it. 281 */ 282 xfersize = sizeof(struct oosiop_xfer) * ncb; 283 err = bus_dmamem_alloc(sc->sc_dmat, xfersize, PAGE_SIZE, 0, &seg, 1, 284 &nseg, BUS_DMA_NOWAIT); 285 if (err) { 286 printf(": failed to allocate xfer block memory, err=%d\n", err); 287 return (err); 288 } 289 err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, xfersize, 290 (caddr_t *)(void *)&xfer, BUS_DMA_NOWAIT | BUS_DMA_COHERENT); 291 if (err) { 292 printf(": failed to map xfer block memory, err=%d\n", err); 293 return (err); 294 } 295 296 /* Initialize each command block */ 297 for (i = 0; i < ncb; i++) { 298 err = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, 299 0, BUS_DMA_NOWAIT, &cb->cmddma); 300 if (err) { 301 printf(": failed to create cmddma map, err=%d\n", err); 302 return (err); 303 } 304 305 err = bus_dmamap_create(sc->sc_dmat, OOSIOP_MAX_XFER, 306 OOSIOP_NSG, OOSIOP_DBC_MAX, 0, BUS_DMA_NOWAIT, 307 &cb->datadma); 308 if (err) { 309 printf(": failed to create datadma map, err=%d\n", err); 310 return (err); 311 } 312 313 err = bus_dmamap_create(sc->sc_dmat, 314 sizeof(struct oosiop_xfer), 1, sizeof(struct oosiop_xfer), 315 0, BUS_DMA_NOWAIT, &cb->xferdma); 316 if (err) { 317 printf(": failed to create xfer block map, err=%d\n", 318 err); 319 return (err); 320 } 321 err = bus_dmamap_load(sc->sc_dmat, cb->xferdma, xfer, 322 sizeof(struct oosiop_xfer), NULL, BUS_DMA_NOWAIT); 323 if (err) { 324 printf(": failed to load xfer block, err=%d\n", err); 325 return (err); 326 } 327 328 cb->xfer = xfer; 329 330 s = splbio(); 331 TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain); 332 splx(s); 333 334 cb++; 335 xfer++; 336 } 337 338 return (0); 339 } 340 341 static __inline void 342 oosiop_relocate_io(struct oosiop_softc *sc, bus_addr_t addr) 343 { 344 u_int32_t dcmd; 345 int32_t dsps; 346 347 dcmd = letoh32(sc->sc_scr[addr / 4 + 0]); 348 dsps = letoh32(sc->sc_scr[addr / 4 + 1]); 349 350 /* convert relative to absolute */ 351 if (dcmd & 0x04000000) { 352 dcmd &= ~0x04000000; 353 #if 0 354 /* 355 * sign extension isn't needed here because 356 * ncr53cxxx.c generates 32 bit dsps. 357 */ 358 dsps <<= 8; 359 dsps >>= 8; 360 #endif 361 sc->sc_scr[addr / 4 + 0] = htole32(dcmd); 362 dsps += addr + 8; 363 } 364 365 sc->sc_scr[addr / 4 + 1] = htole32(dsps + sc->sc_scrbase); 366 } 367 368 static __inline void 369 oosiop_relocate_tc(struct oosiop_softc *sc, bus_addr_t addr) 370 { 371 u_int32_t dcmd; 372 int32_t dsps; 373 374 dcmd = letoh32(sc->sc_scr[addr / 4 + 0]); 375 dsps = letoh32(sc->sc_scr[addr / 4 + 1]); 376 377 /* convert relative to absolute */ 378 if (dcmd & 0x00800000) { 379 dcmd &= ~0x00800000; 380 sc->sc_scr[addr / 4] = htole32(dcmd); 381 #if 0 382 /* 383 * sign extension isn't needed here because 384 * ncr53cxxx.c generates 32 bit dsps. 385 */ 386 dsps <<= 8; 387 dsps >>= 8; 388 #endif 389 dsps += addr + 8; 390 } 391 392 sc->sc_scr[addr / 4 + 1] = htole32(dsps + sc->sc_scrbase); 393 } 394 395 static __inline void 396 oosiop_fixup_select(struct oosiop_softc *sc, bus_addr_t addr, int id) 397 { 398 u_int32_t dcmd; 399 400 dcmd = letoh32(sc->sc_scr[addr / 4]); 401 dcmd &= 0xff00ffff; 402 dcmd |= 0x00010000 << id; 403 sc->sc_scr[addr / 4] = htole32(dcmd); 404 } 405 406 static __inline void 407 oosiop_fixup_jump(struct oosiop_softc *sc, bus_addr_t addr, bus_addr_t dst) 408 { 409 410 sc->sc_scr[addr / 4 + 1] = htole32(dst); 411 } 412 413 static __inline void 414 oosiop_fixup_move(struct oosiop_softc *sc, bus_addr_t addr, bus_size_t dbc, 415 bus_addr_t dsps) 416 { 417 u_int32_t dcmd; 418 419 dcmd = letoh32(sc->sc_scr[addr / 4]); 420 dcmd &= 0xff000000; 421 dcmd |= dbc & 0x00ffffff; 422 sc->sc_scr[addr / 4 + 0] = htole32(dcmd); 423 sc->sc_scr[addr / 4 + 1] = htole32(dsps); 424 } 425 426 void 427 oosiop_load_script(struct oosiop_softc *sc) 428 { 429 int i; 430 431 /* load script */ 432 for (i = 0; i < sizeof(oosiop_script) / sizeof(oosiop_script[0]); i++) 433 sc->sc_scr[i] = htole32(oosiop_script[i]); 434 435 /* relocate script */ 436 for (i = 0; i < (sizeof(oosiop_script) / 8); i++) { 437 switch (oosiop_script[i * 2] >> 27) { 438 case 0x08: /* select */ 439 case 0x0a: /* wait reselect */ 440 oosiop_relocate_io(sc, i * 8); 441 break; 442 case 0x10: /* jump */ 443 case 0x11: /* call */ 444 oosiop_relocate_tc(sc, i * 8); 445 break; 446 } 447 } 448 449 oosiop_fixup_move(sc, Ent_p_resel_msgin_move, 1, sc->sc_reselbuf); 450 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE); 451 } 452 453 void 454 oosiop_setup_sgdma(struct oosiop_softc *sc, struct oosiop_cb *cb) 455 { 456 struct oosiop_xfer *xfer = cb->xfer; 457 struct scsi_xfer *xs = cb->xs; 458 int i, n, off; 459 460 OOSIOP_XFERSCR_SYNC(sc, cb, 461 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 462 463 off = cb->curdp; 464 465 if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { 466 /* Find start segment */ 467 for (i = 0; i < cb->datadma->dm_nsegs; i++) { 468 if (off < cb->datadma->dm_segs[i].ds_len) 469 break; 470 off -= cb->datadma->dm_segs[i].ds_len; 471 } 472 473 /* build MOVE block */ 474 if (xs->flags & SCSI_DATA_IN) { 475 n = 0; 476 while (i < cb->datadma->dm_nsegs) { 477 xfer->datain_scr[n * 2 + 0] = 478 htole32(0x09000000 | 479 (cb->datadma->dm_segs[i].ds_len - off)); 480 xfer->datain_scr[n * 2 + 1] = 481 htole32(cb->datadma->dm_segs[i].ds_addr + 482 off); 483 n++; 484 i++; 485 off = 0; 486 } 487 xfer->datain_scr[n * 2 + 0] = htole32(0x80080000); 488 xfer->datain_scr[n * 2 + 1] = 489 htole32(sc->sc_scrbase + Ent_phasedispatch); 490 } 491 if (xs->flags & SCSI_DATA_OUT) { 492 n = 0; 493 while (i < cb->datadma->dm_nsegs) { 494 xfer->dataout_scr[n * 2 + 0] = 495 htole32(0x08000000 | 496 (cb->datadma->dm_segs[i].ds_len - off)); 497 xfer->dataout_scr[n * 2 + 1] = 498 htole32(cb->datadma->dm_segs[i].ds_addr + 499 off); 500 n++; 501 i++; 502 off = 0; 503 } 504 xfer->dataout_scr[n * 2 + 0] = htole32(0x80080000); 505 xfer->dataout_scr[n * 2 + 1] = 506 htole32(sc->sc_scrbase + Ent_phasedispatch); 507 } 508 } 509 if ((xs->flags & SCSI_DATA_IN) == 0) { 510 xfer->datain_scr[0] = htole32(0x98080000); 511 xfer->datain_scr[1] = htole32(DATAIN_TRAP); 512 } 513 if ((xs->flags & SCSI_DATA_OUT) == 0) { 514 xfer->dataout_scr[0] = htole32(0x98080000); 515 xfer->dataout_scr[1] = htole32(DATAOUT_TRAP); 516 } 517 OOSIOP_XFERSCR_SYNC(sc, cb, 518 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 519 } 520 521 /* 522 * Setup DMA pointer into script. 523 */ 524 void 525 oosiop_setup_dma(struct oosiop_softc *sc) 526 { 527 struct oosiop_cb *cb; 528 bus_addr_t xferbase; 529 530 cb = sc->sc_curcb; 531 xferbase = cb->xferdma->dm_segs[0].ds_addr; 532 533 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE); 534 535 oosiop_fixup_select(sc, Ent_p_select, cb->id); 536 oosiop_fixup_jump(sc, Ent_p_datain_jump, xferbase + 537 offsetof(struct oosiop_xfer, datain_scr[0])); 538 oosiop_fixup_jump(sc, Ent_p_dataout_jump, xferbase + 539 offsetof(struct oosiop_xfer, dataout_scr[0])); 540 oosiop_fixup_move(sc, Ent_p_msgin_move, 1, xferbase + 541 offsetof(struct oosiop_xfer, msgin[0])); 542 oosiop_fixup_move(sc, Ent_p_extmsglen_move, 1, xferbase + 543 offsetof(struct oosiop_xfer, msgin[1])); 544 oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen, xferbase + 545 offsetof(struct oosiop_xfer, msgout[0])); 546 oosiop_fixup_move(sc, Ent_p_status_move, 1, xferbase + 547 offsetof(struct oosiop_xfer, status)); 548 oosiop_fixup_move(sc, Ent_p_cmdout_move, cb->cmdlen, 549 cb->cmddma->dm_segs[0].ds_addr); 550 551 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE); 552 } 553 554 void 555 oosiop_flush_fifo(struct oosiop_softc *sc) 556 { 557 558 oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) | 559 OOSIOP_DFIFO_FLF); 560 while ((oosiop_read_1(sc, OOSIOP_CTEST1) & OOSIOP_CTEST1_FMT) != 561 OOSIOP_CTEST1_FMT) 562 ; 563 oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) & 564 ~OOSIOP_DFIFO_FLF); 565 } 566 567 void 568 oosiop_clear_fifo(struct oosiop_softc *sc) 569 { 570 571 oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) | 572 OOSIOP_DFIFO_CLF); 573 while ((oosiop_read_1(sc, OOSIOP_CTEST1) & OOSIOP_CTEST1_FMT) != 574 OOSIOP_CTEST1_FMT) 575 ; 576 oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) & 577 ~OOSIOP_DFIFO_CLF); 578 } 579 580 void 581 oosiop_phasemismatch(struct oosiop_softc *sc) 582 { 583 struct oosiop_cb *cb; 584 u_int32_t dsp, dbc, n, i, len; 585 u_int8_t dfifo, sstat1; 586 587 cb = sc->sc_curcb; 588 if (cb == NULL) 589 return; 590 591 dsp = oosiop_read_4(sc, OOSIOP_DSP); 592 dbc = oosiop_read_4(sc, OOSIOP_DBC) & OOSIOP_DBC_MAX; 593 len = 0; 594 595 n = dsp - cb->xferdma->dm_segs[0].ds_addr - 8; 596 if (n >= offsetof(struct oosiop_xfer, datain_scr[0]) && 597 n < offsetof(struct oosiop_xfer, datain_scr[OOSIOP_NSG * 2])) { 598 n -= offsetof(struct oosiop_xfer, datain_scr[0]); 599 n >>= 3; 600 OOSIOP_DINSCR_SYNC(sc, cb, 601 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 602 for (i = 0; i <= n; i++) 603 len += letoh32(cb->xfer->datain_scr[i * 2]) & 604 0x00ffffff; 605 OOSIOP_DINSCR_SYNC(sc, cb, 606 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 607 /* All data in the chip are already flushed */ 608 } else if (n >= offsetof(struct oosiop_xfer, dataout_scr[0]) && 609 n < offsetof(struct oosiop_xfer, dataout_scr[OOSIOP_NSG * 2])) { 610 n -= offsetof(struct oosiop_xfer, dataout_scr[0]); 611 n >>= 3; 612 OOSIOP_DOUTSCR_SYNC(sc, cb, 613 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 614 for (i = 0; i <= n; i++) 615 len += letoh32(cb->xfer->dataout_scr[i * 2]) & 616 0x00ffffff; 617 OOSIOP_DOUTSCR_SYNC(sc, cb, 618 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 619 620 dfifo = oosiop_read_1(sc, OOSIOP_DFIFO); 621 dbc += ((dfifo & OOSIOP_DFIFO_BO) - (dbc & OOSIOP_DFIFO_BO)) & 622 OOSIOP_DFIFO_BO; 623 624 sstat1 = oosiop_read_1(sc, OOSIOP_SSTAT1); 625 if (sstat1 & OOSIOP_SSTAT1_OLF) 626 dbc++; 627 if ((sc->sc_tgt[cb->id].sxfer != 0) && 628 (sstat1 & OOSIOP_SSTAT1_ORF) != 0) 629 dbc++; 630 631 oosiop_clear_fifo(sc); 632 } else { 633 printf("%s: phase mismatch addr=%08x\n", sc->sc_dev.dv_xname, 634 oosiop_read_4(sc, OOSIOP_DSP) - 8); 635 oosiop_clear_fifo(sc); 636 return; 637 } 638 639 len -= dbc; 640 if (len) { 641 cb->curdp += len; 642 oosiop_setup_sgdma(sc, cb); 643 } 644 } 645 646 void 647 oosiop_setup_syncxfer(struct oosiop_softc *sc) 648 { 649 int id; 650 651 id = sc->sc_curcb->id; 652 if (sc->sc_chip != OOSIOP_700) 653 oosiop_write_1(sc, OOSIOP_SBCL, sc->sc_tgt[id].scf); 654 655 oosiop_write_1(sc, OOSIOP_SXFER, sc->sc_tgt[id].sxfer); 656 } 657 658 void 659 oosiop_set_syncparam(struct oosiop_softc *sc, int id, int period, int offset) 660 { 661 int i, p; 662 663 printf("%s: target %d now using 8 bit ", sc->sc_dev.dv_xname, id); 664 665 if (offset == 0) { 666 /* Asynchronous */ 667 sc->sc_tgt[id].scf = 0; 668 sc->sc_tgt[id].sxfer = 0; 669 printf("asynchronous"); 670 } else { 671 /* Synchronous */ 672 if (sc->sc_chip == OOSIOP_700) { 673 for (i = 4; i < 12; i++) { 674 p = oosiop_period(sc, i, sc->sc_ccf); 675 if (p >= period) 676 break; 677 } 678 if (i == 12) { 679 printf("%s: target %d period too large\n", 680 sc->sc_dev.dv_xname, id); 681 i = 11; /* XXX */ 682 } 683 sc->sc_tgt[id].scf = 0; 684 sc->sc_tgt[id].sxfer = ((i - 4) << 4) | offset; 685 } else { 686 for (i = 0; i < NSYNCTBL; i++) { 687 p = oosiop_period(sc, synctbl[i].tp + 4, 688 (synctbl[i].scf + 1) * 5); 689 if (p >= period) 690 break; 691 } 692 if (i == NSYNCTBL) { 693 printf("%s: target %d period too large\n", 694 sc->sc_dev.dv_xname, id); 695 i = NSYNCTBL - 1; /* XXX */ 696 } 697 sc->sc_tgt[id].scf = synctbl[i].scf; 698 sc->sc_tgt[id].sxfer = (synctbl[i].tp << 4) | offset; 699 } 700 /* XXX print actual ns period... */ 701 printf(" synchronous"); 702 } 703 printf(" xfers\n"); 704 } 705 706 void 707 oosiop_minphys(struct buf *bp, struct scsi_link *sl) 708 { 709 710 if (bp->b_bcount > OOSIOP_MAX_XFER) 711 bp->b_bcount = OOSIOP_MAX_XFER; 712 minphys(bp); 713 } 714 715 int 716 oosiop_scsicmd(struct scsi_xfer *xs) 717 { 718 struct oosiop_softc *sc; 719 struct oosiop_cb *cb; 720 struct oosiop_xfer *xfer; 721 int s, err; 722 int dopoll; 723 724 sc = (struct oosiop_softc *)xs->sc_link->adapter_softc; 725 726 s = splbio(); 727 cb = TAILQ_FIRST(&sc->sc_free_cb); 728 TAILQ_REMOVE(&sc->sc_free_cb, cb, chain); 729 730 cb->xs = xs; 731 cb->xsflags = xs->flags; 732 cb->cmdlen = xs->cmdlen; 733 cb->datalen = 0; 734 cb->flags = 0; 735 cb->id = xs->sc_link->target; 736 cb->lun = xs->sc_link->lun; 737 xfer = cb->xfer; 738 739 /* Setup SCSI command buffer DMA */ 740 err = bus_dmamap_load(sc->sc_dmat, cb->cmddma, xs->cmd, 741 xs->cmdlen, NULL, ((xs->flags & SCSI_NOSLEEP) ? 742 BUS_DMA_NOWAIT : BUS_DMA_WAITOK) | 743 BUS_DMA_STREAMING | BUS_DMA_WRITE); 744 if (err) { 745 printf("%s: unable to load cmd DMA map: %d", 746 sc->sc_dev.dv_xname, err); 747 xs->error = XS_DRIVER_STUFFUP; 748 scsi_done(xs); 749 TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain); 750 splx(s); 751 return (COMPLETE); 752 } 753 bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, xs->cmdlen, 754 BUS_DMASYNC_PREWRITE); 755 756 /* Setup data buffer DMA */ 757 if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { 758 cb->datalen = xs->datalen; 759 err = bus_dmamap_load(sc->sc_dmat, cb->datadma, 760 xs->data, xs->datalen, NULL, 761 ((xs->flags & SCSI_NOSLEEP) ? 762 BUS_DMA_NOWAIT : BUS_DMA_WAITOK) | 763 BUS_DMA_STREAMING | 764 ((xs->flags & SCSI_DATA_IN) ? BUS_DMA_READ : 765 BUS_DMA_WRITE)); 766 if (err) { 767 printf("%s: unable to load data DMA map: %d", 768 sc->sc_dev.dv_xname, err); 769 xs->error = XS_DRIVER_STUFFUP; 770 bus_dmamap_unload(sc->sc_dmat, cb->cmddma); 771 scsi_done(xs); 772 TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain); 773 splx(s); 774 return (COMPLETE); 775 } 776 bus_dmamap_sync(sc->sc_dmat, cb->datadma, 777 0, xs->datalen, 778 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 779 } 780 781 xfer->status = SCSI_OOSIOP_NOSTATUS; 782 783 /* 784 * Always initialize timeout so it does not contain trash 785 * that could confuse timeout_del(). 786 */ 787 timeout_set(&xs->stimeout, oosiop_timeout, cb); 788 789 if (xs->flags & SCSI_POLL) 790 dopoll = 1; 791 else { 792 dopoll = 0; 793 /* start expire timer */ 794 timeout_add_msec(&xs->stimeout, xs->timeout); 795 } 796 797 splx(s); 798 799 oosiop_setup(sc, cb); 800 801 TAILQ_INSERT_TAIL(&sc->sc_cbq, cb, chain); 802 803 if (!sc->sc_active) { 804 /* Abort script to start selection */ 805 oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT); 806 } 807 if (dopoll) 808 oosiop_poll(sc, cb); 809 810 if (xs->flags & (SCSI_POLL | ITSDONE)) 811 return (COMPLETE); 812 else 813 return (SUCCESSFULLY_QUEUED); 814 } 815 816 void 817 oosiop_poll(struct oosiop_softc *sc, struct oosiop_cb *cb) 818 { 819 struct scsi_xfer *xs = cb->xs; 820 int i, s, to; 821 u_int8_t istat; 822 823 s = splbio(); 824 to = xs->timeout / 1000; 825 for (;;) { 826 i = 1000; 827 while (((istat = oosiop_read_1(sc, OOSIOP_ISTAT)) & 828 (OOSIOP_ISTAT_SIP | OOSIOP_ISTAT_DIP)) == 0) { 829 if (i <= 0) { 830 i = 1000; 831 to--; 832 if (to <= 0) { 833 oosiop_reset(sc); 834 splx(s); 835 return; 836 } 837 } 838 delay(1000); 839 i--; 840 } 841 oosiop_processintr(sc, istat); 842 843 if (xs->flags & ITSDONE) 844 break; 845 } 846 847 splx(s); 848 } 849 850 void 851 oosiop_setup(struct oosiop_softc *sc, struct oosiop_cb *cb) 852 { 853 struct oosiop_xfer *xfer = cb->xfer; 854 855 cb->curdp = 0; 856 cb->savedp = 0; 857 858 oosiop_setup_sgdma(sc, cb); 859 860 /* Setup msgout buffer */ 861 OOSIOP_XFERMSG_SYNC(sc, cb, 862 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 863 xfer->msgout[0] = MSG_IDENTIFY(cb->lun, 864 (cb->xs->cmd->opcode != REQUEST_SENSE)); 865 cb->msgoutlen = 1; 866 867 if (sc->sc_tgt[cb->id].flags & TGTF_SYNCNEG) { 868 /* Send SDTR */ 869 xfer->msgout[1] = MSG_EXTENDED; 870 xfer->msgout[2] = MSG_EXT_SDTR_LEN; 871 xfer->msgout[3] = MSG_EXT_SDTR; 872 xfer->msgout[4] = sc->sc_minperiod; 873 xfer->msgout[5] = OOSIOP_MAX_OFFSET; 874 cb->msgoutlen = 6; 875 sc->sc_tgt[cb->id].flags &= ~TGTF_SYNCNEG; 876 sc->sc_tgt[cb->id].flags |= TGTF_WAITSDTR; 877 } 878 879 OOSIOP_XFERMSG_SYNC(sc, cb, 880 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 881 } 882 883 void 884 oosiop_done(struct oosiop_softc *sc, struct oosiop_cb *cb) 885 { 886 struct scsi_xfer *xs; 887 struct scsi_link *periph; 888 int autosense; 889 890 xs = cb->xs; 891 periph = xs->sc_link; 892 893 /* 894 * Record if this is the completion of an auto sense 895 * scsi command, and then reset the flag so we don't loop 896 * when such a command fails or times out. 897 */ 898 autosense = cb->flags & CBF_AUTOSENSE; 899 cb->flags &= ~CBF_AUTOSENSE; 900 901 bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, cb->cmdlen, 902 BUS_DMASYNC_POSTWRITE); 903 bus_dmamap_unload(sc->sc_dmat, cb->cmddma); 904 905 if (cb->xsflags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { 906 bus_dmamap_sync(sc->sc_dmat, cb->datadma, 0, cb->datalen, 907 (cb->xsflags & SCSI_DATA_IN) ? 908 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 909 bus_dmamap_unload(sc->sc_dmat, cb->datadma); 910 } 911 912 timeout_del(&xs->stimeout); 913 914 xs->status = cb->xfer->status; 915 916 if (cb->flags & CBF_SELTOUT) 917 xs->error = XS_SELTIMEOUT; 918 else if (cb->flags & CBF_TIMEOUT) 919 xs->error = XS_TIMEOUT; 920 else switch (xs->status) { 921 case SCSI_OK: 922 if (autosense == 0) 923 xs->error = XS_NOERROR; 924 else 925 xs->error = XS_SENSE; 926 break; 927 928 case SCSI_BUSY: 929 xs->error = XS_BUSY; 930 break; 931 case SCSI_CHECK: 932 #ifdef notyet 933 if (autosense == 0) 934 cb->flags |= CBF_AUTOSENSE; 935 else 936 #endif 937 xs->error = XS_DRIVER_STUFFUP; 938 break; 939 case SCSI_OOSIOP_NOSTATUS: 940 /* the status byte was not updated, cmd was aborted. */ 941 xs->error = XS_SELTIMEOUT; 942 break; 943 944 default: 945 xs->error = XS_RESET; 946 break; 947 } 948 949 if ((cb->flags & CBF_AUTOSENSE) == 0) { 950 /* Put it on the free list. */ 951 FREE: 952 xs->resid = 0; 953 xs->flags |= ITSDONE; 954 scsi_done(xs); 955 TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain); 956 957 if (cb == sc->sc_curcb) 958 sc->sc_curcb = NULL; 959 if (cb == sc->sc_lastcb) 960 sc->sc_lastcb = NULL; 961 sc->sc_tgt[cb->id].nexus = NULL; 962 } else { 963 /* Set up REQUEST_SENSE command */ 964 struct scsi_sense *cmd = (struct scsi_sense *)xs->cmd; 965 int err; 966 967 bzero(cmd, sizeof(*cmd)); 968 cmd->opcode = REQUEST_SENSE; 969 cmd->byte2 = xs->sc_link->lun << 5; 970 cb->cmdlen = cmd->length = sizeof(xs->sense); 971 972 cb->xsflags &= SCSI_POLL | SCSI_NOSLEEP; 973 cb->xsflags |= SCSI_DATA_IN; 974 cb->datalen = sizeof xs->sense; 975 976 /* Setup SCSI command buffer DMA */ 977 err = bus_dmamap_load(sc->sc_dmat, cb->cmddma, cmd, 978 cb->cmdlen, NULL, 979 BUS_DMA_NOWAIT | BUS_DMA_STREAMING | BUS_DMA_WRITE); 980 if (err) { 981 printf("%s: unable to load REQUEST_SENSE cmd DMA map: %d", 982 sc->sc_dev.dv_xname, err); 983 xs->error = XS_DRIVER_STUFFUP; 984 goto FREE; 985 } 986 bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, cb->cmdlen, 987 BUS_DMASYNC_PREWRITE); 988 989 /* Setup data buffer DMA */ 990 err = bus_dmamap_load(sc->sc_dmat, cb->datadma, 991 &xs->sense, sizeof(xs->sense), NULL, 992 BUS_DMA_NOWAIT | BUS_DMA_STREAMING | BUS_DMA_READ); 993 if (err) { 994 printf("%s: unable to load REQUEST_SENSE data DMA map: %d", 995 sc->sc_dev.dv_xname, err); 996 xs->error = XS_DRIVER_STUFFUP; 997 bus_dmamap_unload(sc->sc_dmat, cb->cmddma); 998 goto FREE; 999 } 1000 bus_dmamap_sync(sc->sc_dmat, cb->datadma, 1001 0, sizeof(xs->sense), BUS_DMASYNC_PREREAD); 1002 1003 oosiop_setup(sc, cb); 1004 1005 TAILQ_INSERT_HEAD(&sc->sc_cbq, cb, chain); 1006 if ((cb->xs->flags & SCSI_POLL) == 0) { 1007 /* start expire timer */ 1008 timeout_add_msec(&xs->stimeout, xs->timeout); 1009 } 1010 } 1011 } 1012 1013 void 1014 oosiop_timeout(void *arg) 1015 { 1016 struct oosiop_cb *cb = arg; 1017 struct scsi_xfer *xs = cb->xs; 1018 struct oosiop_softc *sc = xs->sc_link->adapter_softc; 1019 int s; 1020 1021 sc_print_addr(xs->sc_link); 1022 printf("command 0x%02x timeout on xs %p\n", xs->cmd->opcode, xs); 1023 1024 s = splbio(); 1025 1026 oosiop_reset_bus(sc); 1027 1028 cb->flags |= CBF_TIMEOUT; 1029 oosiop_done(sc, cb); 1030 1031 splx(s); 1032 } 1033 1034 void 1035 oosiop_reset(struct oosiop_softc *sc) 1036 { 1037 int i, s; 1038 1039 s = splbio(); 1040 1041 /* Stop SCRIPTS processor */ 1042 oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT); 1043 delay(100); 1044 oosiop_write_1(sc, OOSIOP_ISTAT, 0); 1045 1046 /* Reset the chip */ 1047 oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl | OOSIOP_DCNTL_RST); 1048 delay(100); 1049 oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl); 1050 delay(10000); 1051 1052 /* Set up various chip parameters */ 1053 oosiop_write_1(sc, OOSIOP_SCNTL0, OOSIOP_ARB_FULL | OOSIOP_SCNTL0_EPG); 1054 oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_ESR); 1055 oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl); 1056 oosiop_write_1(sc, OOSIOP_DMODE, OOSIOP_DMODE_BL_8); 1057 oosiop_write_1(sc, OOSIOP_SCID, OOSIOP_SCID_VALUE(sc->sc_id)); 1058 oosiop_write_1(sc, OOSIOP_DWT, 0xff); /* Enable DMA timeout */ 1059 oosiop_write_1(sc, OOSIOP_CTEST7, 0); 1060 oosiop_write_1(sc, OOSIOP_SXFER, 0); 1061 1062 /* Clear all interrupts */ 1063 (void)oosiop_read_1(sc, OOSIOP_SSTAT0); 1064 (void)oosiop_read_1(sc, OOSIOP_SSTAT1); 1065 (void)oosiop_read_1(sc, OOSIOP_DSTAT); 1066 1067 /* Enable interrupts */ 1068 oosiop_write_1(sc, OOSIOP_SIEN, 1069 OOSIOP_SIEN_M_A | OOSIOP_SIEN_STO | OOSIOP_SIEN_SGE | 1070 OOSIOP_SIEN_UDC | OOSIOP_SIEN_RST | OOSIOP_SIEN_PAR); 1071 oosiop_write_1(sc, OOSIOP_DIEN, 1072 OOSIOP_DIEN_ABRT | OOSIOP_DIEN_SSI | OOSIOP_DIEN_SIR | 1073 OOSIOP_DIEN_WTD | OOSIOP_DIEN_IID); 1074 1075 /* Set target state to asynchronous */ 1076 for (i = 0; i < OOSIOP_NTGT; i++) { 1077 sc->sc_tgt[i].flags = 0; 1078 sc->sc_tgt[i].scf = 0; 1079 sc->sc_tgt[i].sxfer = 0; 1080 } 1081 1082 splx(s); 1083 } 1084 1085 void 1086 oosiop_reset_bus(struct oosiop_softc *sc) 1087 { 1088 int s, i; 1089 1090 s = splbio(); 1091 1092 /* Assert SCSI RST */ 1093 oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_RST); 1094 delay(25); /* Reset hold time (25us) */ 1095 oosiop_write_1(sc, OOSIOP_SCNTL1, 0); 1096 1097 /* Remove all nexuses */ 1098 for (i = 0; i < OOSIOP_NTGT; i++) { 1099 if (sc->sc_tgt[i].nexus) { 1100 sc->sc_tgt[i].nexus->xfer->status = 1101 SCSI_OOSIOP_NOSTATUS; /* XXX */ 1102 oosiop_done(sc, sc->sc_tgt[i].nexus); 1103 } 1104 } 1105 1106 sc->sc_curcb = NULL; 1107 1108 delay(250000); /* Reset to selection (250ms) */ 1109 1110 splx(s); 1111 } 1112 1113 /* 1114 * interrupt handler 1115 */ 1116 int 1117 oosiop_intr(struct oosiop_softc *sc) 1118 { 1119 u_int8_t istat; 1120 1121 istat = oosiop_read_1(sc, OOSIOP_ISTAT); 1122 1123 if ((istat & (OOSIOP_ISTAT_SIP | OOSIOP_ISTAT_DIP)) == 0) 1124 return (0); 1125 1126 oosiop_processintr(sc, istat); 1127 return (1); 1128 } 1129 1130 void 1131 oosiop_processintr(struct oosiop_softc *sc, u_int8_t istat) 1132 { 1133 struct oosiop_cb *cb; 1134 u_int32_t dcmd; 1135 u_int8_t dstat, sstat0; 1136 1137 sc->sc_nextdsp = Ent_wait_reselect; 1138 1139 /* DMA interrupts */ 1140 if (istat & OOSIOP_ISTAT_DIP) { 1141 oosiop_write_1(sc, OOSIOP_ISTAT, 0); 1142 1143 dstat = oosiop_read_1(sc, OOSIOP_DSTAT); 1144 1145 if (dstat & OOSIOP_DSTAT_ABRT) { 1146 sc->sc_nextdsp = oosiop_read_4(sc, OOSIOP_DSP) - 1147 sc->sc_scrbase - 8; 1148 1149 if (sc->sc_nextdsp == Ent_p_resel_msgin_move && 1150 (oosiop_read_1(sc, OOSIOP_SBCL) & OOSIOP_ACK)) { 1151 if ((dstat & OOSIOP_DSTAT_DFE) == 0) 1152 oosiop_flush_fifo(sc); 1153 sc->sc_nextdsp += 8; 1154 } 1155 } 1156 1157 if (dstat & OOSIOP_DSTAT_SSI) { 1158 sc->sc_nextdsp = oosiop_read_4(sc, OOSIOP_DSP) - 1159 sc->sc_scrbase; 1160 printf("%s: single step %08x\n", sc->sc_dev.dv_xname, 1161 sc->sc_nextdsp); 1162 } 1163 1164 if (dstat & OOSIOP_DSTAT_SIR) { 1165 if ((dstat & OOSIOP_DSTAT_DFE) == 0) 1166 oosiop_flush_fifo(sc); 1167 oosiop_scriptintr(sc); 1168 } 1169 1170 if (dstat & OOSIOP_DSTAT_WTD) { 1171 printf("%s: DMA time out\n", sc->sc_dev.dv_xname); 1172 oosiop_reset(sc); 1173 } 1174 1175 if (dstat & OOSIOP_DSTAT_IID) { 1176 dcmd = oosiop_read_4(sc, OOSIOP_DBC); 1177 if ((dcmd & 0xf8000000) == 0x48000000) { 1178 printf("%s: REQ asserted on WAIT DISCONNECT\n", 1179 sc->sc_dev.dv_xname); 1180 sc->sc_nextdsp = Ent_phasedispatch; /* XXX */ 1181 } else { 1182 printf("%s: invalid SCRIPTS instruction " 1183 "addr=%08x dcmd=%08x dsps=%08x\n", 1184 sc->sc_dev.dv_xname, 1185 oosiop_read_4(sc, OOSIOP_DSP) - 8, dcmd, 1186 oosiop_read_4(sc, OOSIOP_DSPS)); 1187 oosiop_reset(sc); 1188 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE); 1189 oosiop_load_script(sc); 1190 } 1191 } 1192 1193 if ((dstat & OOSIOP_DSTAT_DFE) == 0) 1194 oosiop_clear_fifo(sc); 1195 } 1196 1197 /* SCSI interrupts */ 1198 if (istat & OOSIOP_ISTAT_SIP) { 1199 if (istat & OOSIOP_ISTAT_DIP) 1200 delay(1); 1201 sstat0 = oosiop_read_1(sc, OOSIOP_SSTAT0); 1202 1203 if (sstat0 & OOSIOP_SSTAT0_M_A) { 1204 /* SCSI phase mismatch during MOVE operation */ 1205 oosiop_phasemismatch(sc); 1206 sc->sc_nextdsp = Ent_phasedispatch; 1207 } 1208 1209 if (sstat0 & OOSIOP_SSTAT0_STO) { 1210 if (sc->sc_curcb) { 1211 sc->sc_curcb->flags |= CBF_SELTOUT; 1212 oosiop_done(sc, sc->sc_curcb); 1213 } 1214 } 1215 1216 if (sstat0 & OOSIOP_SSTAT0_SGE) { 1217 printf("%s: SCSI gross error\n", sc->sc_dev.dv_xname); 1218 oosiop_reset(sc); 1219 } 1220 1221 if (sstat0 & OOSIOP_SSTAT0_UDC) { 1222 /* XXX */ 1223 if (sc->sc_curcb) { 1224 printf("%s: unexpected disconnect\n", 1225 sc->sc_dev.dv_xname); 1226 oosiop_done(sc, sc->sc_curcb); 1227 } 1228 } 1229 1230 if (sstat0 & OOSIOP_SSTAT0_RST) 1231 oosiop_reset(sc); 1232 1233 if (sstat0 & OOSIOP_SSTAT0_PAR) 1234 printf("%s: parity error\n", sc->sc_dev.dv_xname); 1235 } 1236 1237 /* Start next command if available */ 1238 if (sc->sc_nextdsp == Ent_wait_reselect && TAILQ_FIRST(&sc->sc_cbq)) { 1239 cb = sc->sc_curcb = TAILQ_FIRST(&sc->sc_cbq); 1240 TAILQ_REMOVE(&sc->sc_cbq, cb, chain); 1241 sc->sc_tgt[cb->id].nexus = cb; 1242 1243 oosiop_setup_dma(sc); 1244 oosiop_setup_syncxfer(sc); 1245 sc->sc_lastcb = cb; 1246 sc->sc_nextdsp = Ent_start_select; 1247 1248 /* Schedule timeout */ 1249 if ((cb->xs->flags & SCSI_POLL) == 0) { 1250 /* start expire timer */ 1251 timeout_add_msec(&cb->xs->stimeout, cb->xs->timeout); 1252 } 1253 } 1254 1255 sc->sc_active = (sc->sc_nextdsp != Ent_wait_reselect); 1256 1257 /* Restart script */ 1258 oosiop_write_4(sc, OOSIOP_DSP, sc->sc_nextdsp + sc->sc_scrbase); 1259 } 1260 1261 void 1262 oosiop_scriptintr(struct oosiop_softc *sc) 1263 { 1264 struct oosiop_cb *cb; 1265 u_int32_t icode; 1266 u_int32_t dsp; 1267 int i; 1268 u_int8_t sfbr, resid, resmsg; 1269 1270 cb = sc->sc_curcb; 1271 icode = oosiop_read_4(sc, OOSIOP_DSPS); 1272 1273 switch (icode) { 1274 case A_int_done: 1275 if (cb) 1276 oosiop_done(sc, cb); 1277 break; 1278 1279 case A_int_msgin: 1280 if (cb) 1281 oosiop_msgin(sc, cb); 1282 break; 1283 1284 case A_int_extmsg: 1285 /* extended message in DMA setup request */ 1286 sfbr = oosiop_read_1(sc, OOSIOP_SFBR); 1287 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE); 1288 oosiop_fixup_move(sc, Ent_p_extmsgin_move, sfbr, 1289 cb->xferdma->dm_segs[0].ds_addr + 1290 offsetof(struct oosiop_xfer, msgin[2])); 1291 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE); 1292 sc->sc_nextdsp = Ent_rcv_extmsg; 1293 break; 1294 1295 case A_int_resel: 1296 /* reselected */ 1297 resid = oosiop_read_1(sc, OOSIOP_SFBR); 1298 for (i = 0; i < OOSIOP_NTGT; i++) 1299 if (resid & (1 << i)) 1300 break; 1301 if (i == OOSIOP_NTGT) { 1302 printf("%s: missing reselection target id\n", 1303 sc->sc_dev.dv_xname); 1304 break; 1305 } 1306 sc->sc_resid = i; 1307 sc->sc_nextdsp = Ent_wait_resel_identify; 1308 1309 if (cb) { 1310 /* Current command was lost arbitration */ 1311 sc->sc_tgt[cb->id].nexus = NULL; 1312 TAILQ_INSERT_HEAD(&sc->sc_cbq, cb, chain); 1313 sc->sc_curcb = NULL; 1314 } 1315 1316 break; 1317 1318 case A_int_res_id: 1319 cb = sc->sc_tgt[sc->sc_resid].nexus; 1320 resmsg = oosiop_read_1(sc, OOSIOP_SFBR); 1321 if (MSG_ISIDENTIFY(resmsg) && cb && 1322 (resmsg & MSG_IDENTIFY_LUNMASK) == cb->lun) { 1323 sc->sc_curcb = cb; 1324 if (cb != sc->sc_lastcb) { 1325 oosiop_setup_dma(sc); 1326 oosiop_setup_syncxfer(sc); 1327 sc->sc_lastcb = cb; 1328 } 1329 if (cb->curdp != cb->savedp) { 1330 cb->curdp = cb->savedp; 1331 oosiop_setup_sgdma(sc, cb); 1332 } 1333 sc->sc_nextdsp = Ent_ack_msgin; 1334 } else { 1335 /* Reselection from invalid target */ 1336 oosiop_reset_bus(sc); 1337 } 1338 break; 1339 1340 case A_int_resfail: 1341 /* reselect failed */ 1342 break; 1343 1344 case A_int_disc: 1345 /* disconnected */ 1346 sc->sc_curcb = NULL; 1347 break; 1348 1349 case A_int_err: 1350 /* generic error */ 1351 dsp = oosiop_read_4(sc, OOSIOP_DSP); 1352 printf("%s: script error at 0x%08x\n", sc->sc_dev.dv_xname, 1353 dsp - 8); 1354 sc->sc_curcb = NULL; 1355 break; 1356 1357 case DATAIN_TRAP: 1358 printf("%s: unexpected datain\n", sc->sc_dev.dv_xname); 1359 /* XXX: need to reset? */ 1360 break; 1361 1362 case DATAOUT_TRAP: 1363 printf("%s: unexpected dataout\n", sc->sc_dev.dv_xname); 1364 /* XXX: need to reset? */ 1365 break; 1366 1367 default: 1368 printf("%s: unknown intr code %08x\n", sc->sc_dev.dv_xname, 1369 icode); 1370 break; 1371 } 1372 } 1373 1374 void 1375 oosiop_msgin(struct oosiop_softc *sc, struct oosiop_cb *cb) 1376 { 1377 struct oosiop_xfer *xfer; 1378 int msgout; 1379 1380 xfer = cb->xfer; 1381 sc->sc_nextdsp = Ent_ack_msgin; 1382 msgout = 0; 1383 1384 OOSIOP_XFERMSG_SYNC(sc, cb, 1385 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1386 1387 switch (xfer->msgin[0]) { 1388 case MSG_EXTENDED: 1389 switch (xfer->msgin[2]) { 1390 case MSG_EXT_SDTR: 1391 if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) { 1392 /* Host initiated SDTR */ 1393 sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR; 1394 } else { 1395 /* Target initiated SDTR */ 1396 if (xfer->msgin[3] < sc->sc_minperiod) 1397 xfer->msgin[3] = sc->sc_minperiod; 1398 if (xfer->msgin[4] > OOSIOP_MAX_OFFSET) 1399 xfer->msgin[4] = OOSIOP_MAX_OFFSET; 1400 xfer->msgout[0] = MSG_EXTENDED; 1401 xfer->msgout[1] = MSG_EXT_SDTR_LEN; 1402 xfer->msgout[2] = MSG_EXT_SDTR; 1403 xfer->msgout[3] = xfer->msgin[3]; 1404 xfer->msgout[4] = xfer->msgin[4]; 1405 cb->msgoutlen = 5; 1406 msgout = 1; 1407 } 1408 oosiop_set_syncparam(sc, cb->id, (int)xfer->msgin[3], 1409 (int)xfer->msgin[4]); 1410 oosiop_setup_syncxfer(sc); 1411 break; 1412 1413 default: 1414 /* Reject message */ 1415 xfer->msgout[0] = MSG_MESSAGE_REJECT; 1416 cb->msgoutlen = 1; 1417 msgout = 1; 1418 break; 1419 } 1420 break; 1421 1422 case MSG_SAVEDATAPOINTER: 1423 cb->savedp = cb->curdp; 1424 break; 1425 1426 case MSG_RESTOREPOINTERS: 1427 if (cb->curdp != cb->savedp) { 1428 cb->curdp = cb->savedp; 1429 oosiop_setup_sgdma(sc, cb); 1430 } 1431 break; 1432 1433 case MSG_MESSAGE_REJECT: 1434 if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) { 1435 /* SDTR rejected */ 1436 sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR; 1437 oosiop_set_syncparam(sc, cb->id, 0, 0); 1438 oosiop_setup_syncxfer(sc); 1439 } 1440 break; 1441 1442 default: 1443 /* Reject message */ 1444 xfer->msgout[0] = MSG_MESSAGE_REJECT; 1445 cb->msgoutlen = 1; 1446 msgout = 1; 1447 } 1448 1449 OOSIOP_XFERMSG_SYNC(sc, cb, 1450 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1451 1452 if (msgout) { 1453 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE); 1454 oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen, 1455 cb->xferdma->dm_segs[0].ds_addr + 1456 offsetof(struct oosiop_xfer, msgout[0])); 1457 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE); 1458 sc->sc_nextdsp = Ent_sendmsg; 1459 } 1460 } 1461