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