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