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