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