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