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