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