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