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