1 /* $NetBSD: osiop.c,v 1.13 2003/04/12 06:42:38 tsutsui Exp $ */ 2 3 /* 4 * Copyright (c) 2001 Izumi Tsutsui. 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 * Copyright (c) 1994 Michael L. Hitch 31 * Copyright (c) 1990 The Regents of the University of California. 32 * All rights reserved. 33 * 34 * This code is derived from software contributed to Berkeley by 35 * Van Jacobson of Lawrence Berkeley Laboratory. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. All advertising materials mentioning features or use of this software 46 * must display the following acknowledgement: 47 * This product includes software developed by the University of 48 * California, Berkeley and its contributors. 49 * 4. Neither the name of the University nor the names of its contributors 50 * may be used to endorse or promote products derived from this software 51 * without specific prior written permission. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 * SUCH DAMAGE. 64 * 65 * @(#)siop.c 7.5 (Berkeley) 5/4/91 66 */ 67 68 /* 69 * MI NCR53C710 scsi adaptor driver; based on arch/amiga/dev/siop.c: 70 * NetBSD: siop.c,v 1.43 1999/09/30 22:59:53 thorpej Exp 71 * 72 * bus_space/bus_dma'fied by Izumi Tsutsui <tsutsui@ceres.dti.ne.jp> 73 * 74 * The 53c710 datasheet is avaliable at: 75 * http://www.lsilogic.com/techlib/techdocs/storage_stand_prod/index.html 76 */ 77 78 #include <sys/cdefs.h> 79 __KERNEL_RCSID(0, "$NetBSD: osiop.c,v 1.13 2003/04/12 06:42:38 tsutsui Exp $"); 80 81 /* #define OSIOP_DEBUG */ 82 83 #include "opt_ddb.h" 84 85 #include <sys/param.h> 86 #include <sys/systm.h> 87 #include <sys/device.h> 88 #include <sys/malloc.h> 89 #include <sys/buf.h> 90 #include <sys/kernel.h> 91 92 #include <uvm/uvm_extern.h> 93 94 #include <dev/scsipi/scsi_all.h> 95 #include <dev/scsipi/scsipi_all.h> 96 #include <dev/scsipi/scsiconf.h> 97 #include <dev/scsipi/scsi_message.h> 98 99 #include <machine/cpu.h> 100 #include <machine/bus.h> 101 102 #include <dev/ic/osiopreg.h> 103 #include <dev/ic/osiopvar.h> 104 105 /* 53C710 script */ 106 #include <dev/microcode/siop/osiop.out> 107 108 void osiop_attach(struct osiop_softc *); 109 void osiop_minphys(struct buf *); 110 void osiop_scsipi_request(struct scsipi_channel *, scsipi_adapter_req_t, 111 void *); 112 void osiop_poll(struct osiop_softc *, struct osiop_acb *); 113 void osiop_sched(struct osiop_softc *); 114 void osiop_scsidone(struct osiop_acb *, int); 115 void osiop_abort(struct osiop_softc *, const char *); 116 void osiop_init(struct osiop_softc *); 117 void osiop_reset(struct osiop_softc *); 118 void osiop_resetbus(struct osiop_softc *); 119 void osiop_start(struct osiop_softc *); 120 int osiop_checkintr(struct osiop_softc *, u_int8_t, u_int8_t, u_int8_t, int *); 121 void osiop_select(struct osiop_softc *); 122 void osiop_update_xfer_mode(struct osiop_softc *, int); 123 void scsi_period_to_osiop(struct osiop_softc *, int); 124 void osiop_timeout(void *); 125 126 int osiop_reset_delay = 250; /* delay after reset, in milleseconds */ 127 128 #ifdef OSIOP_DEBUG 129 #define DEBUG_DMA 0x01 130 #define DEBUG_INT 0x02 131 #define DEBUG_PHASE 0x04 132 #define DEBUG_UNEXCEPT 0x08 133 #define DEBUG_DISC 0x10 134 #define DEBUG_CMD 0x20 135 #define DEBUG_ALL 0xff 136 int osiop_debug = 0; /*DEBUG_ALL;*/ 137 int osiopsync_debug = 0; 138 int osiopdma_hits = 1; 139 int osiopstarts = 0; 140 int osiopints = 0; 141 int osiopphmm = 0; 142 int osiop_trix = 0; 143 #define OSIOP_TRACE_SIZE 128 144 #define OSIOP_TRACE(a,b,c,d) do { \ 145 osiop_trbuf[osiop_trix + 0] = (a); \ 146 osiop_trbuf[osiop_trix + 1] = (b); \ 147 osiop_trbuf[osiop_trix + 2] = (c); \ 148 osiop_trbuf[osiop_trix + 3] = (d); \ 149 osiop_trix = (osiop_trix + 4) & (OSIOP_TRACE_SIZE - 1); \ 150 } while (0) 151 u_int8_t osiop_trbuf[OSIOP_TRACE_SIZE]; 152 void osiop_dump_trace(void); 153 void osiop_dump_acb(struct osiop_acb *); 154 void osiop_dump(struct osiop_softc *); 155 #else 156 #define OSIOP_TRACE(a,b,c,d) 157 #endif 158 159 void 160 osiop_attach(sc) 161 struct osiop_softc *sc; 162 { 163 struct osiop_acb *acb; 164 bus_dma_segment_t seg; 165 int nseg; 166 int i, err; 167 168 /* 169 * Allocate and map DMA-safe memory for the script. 170 */ 171 err = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE, 0, 172 &seg, 1, &nseg, BUS_DMA_NOWAIT); 173 if (err) { 174 printf(": failed to allocate script memory, err=%d\n", err); 175 return; 176 } 177 err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, PAGE_SIZE, 178 (caddr_t *)&sc->sc_script, BUS_DMA_NOWAIT | BUS_DMA_COHERENT); 179 if (err) { 180 printf(": failed to map script memory, err=%d\n", err); 181 return; 182 } 183 err = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, 0, 184 BUS_DMA_NOWAIT, &sc->sc_scrdma); 185 if (err) { 186 printf(": failed to create script map, err=%d\n", err); 187 return; 188 } 189 err = bus_dmamap_load(sc->sc_dmat, sc->sc_scrdma, 190 sc->sc_script, PAGE_SIZE, NULL, BUS_DMA_NOWAIT); 191 if (err) { 192 printf(": failed to load script map, err=%d\n", err); 193 return; 194 } 195 196 /* 197 * Copy and sync script 198 */ 199 memcpy(sc->sc_script, osiop_script, sizeof(osiop_script)); 200 bus_dmamap_sync(sc->sc_dmat, sc->sc_scrdma, 0, sizeof(osiop_script), 201 BUS_DMASYNC_PREWRITE); 202 203 /* 204 * Allocate and map DMA-safe memory for the script data structure. 205 */ 206 err = bus_dmamem_alloc(sc->sc_dmat, 207 sizeof(struct osiop_ds) * OSIOP_NACB, PAGE_SIZE, 0, 208 &seg, 1, &nseg, BUS_DMA_NOWAIT); 209 if (err) { 210 printf(": failed to allocate ds memory, err=%d\n", err); 211 return; 212 } 213 err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, 214 sizeof(struct osiop_ds) * OSIOP_NACB, (caddr_t *)&sc->sc_ds, 215 BUS_DMA_NOWAIT | BUS_DMA_COHERENT); 216 if (err) { 217 printf(": failed to map ds memory, err=%d\n", err); 218 return; 219 } 220 err = bus_dmamap_create(sc->sc_dmat, 221 sizeof(struct osiop_ds) * OSIOP_NACB, 1, 222 sizeof(struct osiop_ds) * OSIOP_NACB, 0, 223 BUS_DMA_NOWAIT, &sc->sc_dsdma); 224 if (err) { 225 printf(": failed to create ds map, err=%d\n", err); 226 return; 227 } 228 err = bus_dmamap_load(sc->sc_dmat, sc->sc_dsdma, sc->sc_ds, 229 sizeof(struct osiop_ds) * OSIOP_NACB, NULL, BUS_DMA_NOWAIT); 230 if (err) { 231 printf(": failed to load ds map, err=%d\n", err); 232 return; 233 } 234 235 acb = malloc(sizeof(struct osiop_acb) * OSIOP_NACB, 236 M_DEVBUF, M_NOWAIT|M_ZERO); 237 if (acb == NULL) { 238 printf(": can't allocate memory for acb\n"); 239 return; 240 } 241 sc->sc_acb = acb; 242 sc->sc_cfflags = sc->sc_dev.dv_cfdata->cf_flags; 243 sc->sc_nexus = NULL; 244 sc->sc_active = 0; 245 memset(sc->sc_tinfo, 0, sizeof(sc->sc_tinfo)); 246 247 /* Initialize command block queue */ 248 TAILQ_INIT(&sc->ready_list); 249 TAILQ_INIT(&sc->nexus_list); 250 TAILQ_INIT(&sc->free_list); 251 252 /* Initialize each command block */ 253 for (i = 0; i < OSIOP_NACB; i++) { 254 bus_addr_t dsa; 255 256 /* XXX How much size is required for each command block? */ 257 err = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, 258 0, BUS_DMA_NOWAIT, &acb->cmddma); 259 if (err) { 260 printf(": failed to create cmddma map, err=%d\n", err); 261 return; 262 } 263 err = bus_dmamap_create(sc->sc_dmat, OSIOP_MAX_XFER, OSIOP_NSG, 264 OSIOP_MAX_XFER, 0, BUS_DMA_NOWAIT, &acb->datadma); 265 if (err) { 266 printf(": failed to create datadma map, err=%d\n", 267 err); 268 return; 269 } 270 271 acb->sc = sc; 272 acb->ds = &sc->sc_ds[i]; 273 acb->dsoffset = sizeof(struct osiop_ds) * i; 274 275 dsa = sc->sc_dsdma->dm_segs[0].ds_addr + acb->dsoffset; 276 acb->ds->id.addr = dsa + OSIOP_DSIDOFF; 277 acb->ds->status.count = 1; 278 acb->ds->status.addr = dsa + OSIOP_DSSTATOFF; 279 acb->ds->msg.count = 1; 280 acb->ds->msg.addr = dsa + OSIOP_DSMSGOFF; 281 acb->ds->msgin.count = 1; 282 acb->ds->msgin.addr = dsa + OSIOP_DSMSGINOFF; 283 acb->ds->extmsg.count = 1; 284 acb->ds->extmsg.addr = dsa + OSIOP_DSEXTMSGOFF; 285 acb->ds->synmsg.count = 3; 286 acb->ds->synmsg.addr = dsa + OSIOP_DSSYNMSGOFF; 287 TAILQ_INSERT_TAIL(&sc->free_list, acb, chain); 288 289 acb++; 290 } 291 292 printf(": NCR53C710 rev %d, %dMHz, SCSI ID %d\n", 293 osiop_read_1(sc, OSIOP_CTEST8) >> 4, sc->sc_clock_freq, sc->sc_id); 294 295 /* 296 * Initialize all 297 */ 298 osiop_init(sc); 299 300 /* 301 * Fill in the adapter. 302 */ 303 sc->sc_adapter.adapt_dev = &sc->sc_dev; 304 sc->sc_adapter.adapt_nchannels = 1; 305 sc->sc_adapter.adapt_openings = OSIOP_NACB; 306 sc->sc_adapter.adapt_max_periph = 1; 307 sc->sc_adapter.adapt_ioctl = NULL; 308 sc->sc_adapter.adapt_minphys = osiop_minphys; 309 sc->sc_adapter.adapt_request = osiop_scsipi_request; 310 311 /* 312 * Fill in the channel. 313 */ 314 sc->sc_channel.chan_adapter = &sc->sc_adapter; 315 sc->sc_channel.chan_bustype = &scsi_bustype; 316 sc->sc_channel.chan_channel = 0; 317 sc->sc_channel.chan_ntargets = OSIOP_NTGT; 318 sc->sc_channel.chan_nluns = 8; 319 sc->sc_channel.chan_id = sc->sc_id; 320 321 /* 322 * Now try to attach all the sub devices. 323 */ 324 config_found(&sc->sc_dev, &sc->sc_channel, scsiprint); 325 } 326 327 /* 328 * default minphys routine for osiop based controllers 329 */ 330 void 331 osiop_minphys(bp) 332 struct buf *bp; 333 { 334 335 if (bp->b_bcount > OSIOP_MAX_XFER) 336 bp->b_bcount = OSIOP_MAX_XFER; 337 minphys(bp); 338 } 339 340 /* 341 * used by specific osiop controller 342 * 343 */ 344 void 345 osiop_scsipi_request(chan, req, arg) 346 struct scsipi_channel *chan; 347 scsipi_adapter_req_t req; 348 void *arg; 349 { 350 struct scsipi_xfer *xs; 351 struct scsipi_periph *periph; 352 struct osiop_acb *acb; 353 struct osiop_softc *sc; 354 int err, flags, s; 355 356 sc = (struct osiop_softc *)chan->chan_adapter->adapt_dev; 357 358 switch (req) { 359 case ADAPTER_REQ_RUN_XFER: 360 xs = arg; 361 periph = xs->xs_periph; 362 flags = xs->xs_control; 363 364 /* XXXX ?? */ 365 if (flags & XS_CTL_DATA_UIO) 366 panic("osiop: scsi data uio requested"); 367 368 /* XXXX ?? */ 369 if (sc->sc_nexus && flags & XS_CTL_POLL) 370 #if 0 371 panic("osiop_scsicmd: busy"); 372 #else 373 printf("osiop_scsicmd: busy\n"); 374 #endif 375 376 s = splbio(); 377 acb = TAILQ_FIRST(&sc->free_list); 378 if (acb != NULL) { 379 TAILQ_REMOVE(&sc->free_list, acb, chain); 380 } 381 #ifdef DIAGNOSTIC 382 else { 383 scsipi_printaddr(periph); 384 printf("unable to allocate acb\n"); 385 panic("osiop_scsipi_request"); 386 } 387 #endif 388 389 acb->status = ACB_S_READY; 390 acb->xs = xs; 391 392 /* Setup DMA map for SCSI command buffer */ 393 err = bus_dmamap_load(sc->sc_dmat, acb->cmddma, 394 xs->cmd, xs->cmdlen, NULL, BUS_DMA_NOWAIT); 395 if (err) { 396 printf("%s: unable to load cmd DMA map: %d", 397 sc->sc_dev.dv_xname, err); 398 xs->error = XS_DRIVER_STUFFUP; 399 TAILQ_INSERT_TAIL(&sc->free_list, acb, chain); 400 scsipi_done(xs); 401 splx(s); 402 return; 403 } 404 405 /* Setup DMA map for data buffer */ 406 if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) { 407 err = bus_dmamap_load(sc->sc_dmat, acb->datadma, 408 xs->data, xs->datalen, NULL, 409 BUS_DMA_NOWAIT | BUS_DMA_STREAMING | 410 ((xs->xs_control & XS_CTL_DATA_IN) ? 411 BUS_DMA_READ : BUS_DMA_WRITE)); 412 if (err) { 413 printf("%s: unable to load data DMA map: %d", 414 sc->sc_dev.dv_xname, err); 415 xs->error = XS_DRIVER_STUFFUP; 416 scsipi_done(xs); 417 bus_dmamap_unload(sc->sc_dmat, acb->cmddma); 418 TAILQ_INSERT_TAIL(&sc->free_list, acb, chain); 419 splx(s); 420 return; 421 } 422 bus_dmamap_sync(sc->sc_dmat, acb->datadma, 423 0, xs->datalen, (xs->xs_control & XS_CTL_DATA_IN) ? 424 BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 425 } 426 bus_dmamap_sync(sc->sc_dmat, acb->cmddma, 0, xs->cmdlen, 427 BUS_DMASYNC_PREWRITE); 428 429 acb->cmdlen = xs->cmdlen; 430 acb->datalen = xs->datalen; 431 #ifdef OSIOP_DEBUG 432 acb->data = xs->data; 433 #endif 434 435 TAILQ_INSERT_TAIL(&sc->ready_list, acb, chain); 436 437 if (sc->sc_nexus == NULL) 438 osiop_sched(sc); 439 440 splx(s); 441 442 if (flags & XS_CTL_POLL || sc->sc_flags & OSIOP_NODMA) 443 osiop_poll(sc, acb); 444 return; 445 446 case ADAPTER_REQ_GROW_RESOURCES: 447 return; 448 449 case ADAPTER_REQ_SET_XFER_MODE: 450 { 451 struct osiop_tinfo *ti; 452 struct scsipi_xfer_mode *xm = arg; 453 454 ti = &sc->sc_tinfo[xm->xm_target]; 455 456 if ((xm->xm_mode & PERIPH_CAP_SYNC) != 0 && 457 (ti->flags & TI_NOSYNC) == 0) 458 ti->state = NEG_INIT; 459 460 /* 461 * If we're not going to negotiate, send the 462 * notification now, since it won't happen later. 463 */ 464 if (ti->state == NEG_DONE) 465 osiop_update_xfer_mode(sc, xm->xm_target); 466 467 return; 468 } 469 } 470 } 471 472 void 473 osiop_poll(sc, acb) 474 struct osiop_softc *sc; 475 struct osiop_acb *acb; 476 { 477 struct scsipi_xfer *xs = acb->xs; 478 int status, i, s, to; 479 u_int8_t istat, dstat, sstat0; 480 481 s = splbio(); 482 to = xs->timeout / 1000; 483 if (!TAILQ_EMPTY(&sc->nexus_list)) 484 printf("%s: osiop_poll called with disconnected device\n", 485 sc->sc_dev.dv_xname); 486 for (;;) { 487 i = 1000; 488 while (((istat = osiop_read_1(sc, OSIOP_ISTAT)) & 489 (OSIOP_ISTAT_SIP | OSIOP_ISTAT_DIP)) == 0) { 490 if (i <= 0) { 491 #ifdef OSIOP_DEBUG 492 printf("waiting: tgt %d cmd %02x sbcl %02x" 493 " dsp %x (+%lx) dcmd %x" 494 " ds %p timeout %d\n", 495 xs->xs_periph->periph_target, 496 xs->cmd->opcode, 497 osiop_read_1(sc, OSIOP_SBCL), 498 osiop_read_4(sc, OSIOP_DSP), 499 osiop_read_4(sc, OSIOP_DSP) - 500 sc->sc_scrdma->dm_segs[0].ds_addr, 501 osiop_read_1(sc, OSIOP_DCMD), 502 acb->ds, acb->xs->timeout); 503 #endif 504 i = 1000; 505 to--; 506 if (to <= 0) { 507 osiop_reset(sc); 508 splx(s); 509 return; 510 } 511 } 512 delay(1000); 513 i--; 514 } 515 sstat0 = osiop_read_1(sc, OSIOP_SSTAT0); 516 delay(25); 517 dstat = osiop_read_1(sc, OSIOP_DSTAT); 518 if (osiop_checkintr(sc, istat, dstat, sstat0, &status)) { 519 if (acb != sc->sc_nexus) 520 printf("%s: osiop_poll disconnected device" 521 " completed\n", sc->sc_dev.dv_xname); 522 else if ((sc->sc_flags & OSIOP_INTDEFER) == 0) { 523 sc->sc_flags &= ~OSIOP_INTSOFF; 524 osiop_write_1(sc, OSIOP_SIEN, sc->sc_sien); 525 osiop_write_1(sc, OSIOP_DIEN, sc->sc_dien); 526 } 527 osiop_scsidone(sc->sc_nexus, status); 528 } 529 530 if (xs->xs_status & XS_STS_DONE) 531 break; 532 } 533 534 splx(s); 535 return; 536 } 537 538 /* 539 * start next command that's ready 540 */ 541 void 542 osiop_sched(sc) 543 struct osiop_softc *sc; 544 { 545 struct scsipi_periph *periph; 546 struct osiop_acb *acb; 547 int i; 548 549 #ifdef OSIOP_DEBUG 550 if (sc->sc_nexus != NULL) { 551 printf("%s: osiop_sched- nexus %p/%d ready %p/%d\n", 552 sc->sc_dev.dv_xname, sc->sc_nexus, 553 sc->sc_nexus->xs->xs_periph->periph_target, 554 sc->ready_list.tqh_first, 555 sc->ready_list.tqh_first->xs->xs_periph->periph_target); 556 return; 557 } 558 #endif 559 TAILQ_FOREACH(acb, &sc->ready_list, chain) { 560 periph = acb->xs->xs_periph; 561 i = periph->periph_target; 562 if ((sc->sc_tinfo[i].lubusy & (1 << periph->periph_lun)) == 0) { 563 struct osiop_tinfo *ti; 564 565 TAILQ_REMOVE(&sc->ready_list, acb, chain); 566 sc->sc_nexus = acb; 567 ti = &sc->sc_tinfo[i]; 568 ti->lubusy |= (1 << periph->periph_lun); 569 break; 570 } 571 } 572 573 if (acb == NULL) { 574 #ifdef OSIOP_DEBUG 575 printf("%s: osiop_sched didn't find ready command\n", 576 sc->sc_dev.dv_xname); 577 #endif 578 return; 579 } 580 581 if (acb->xs->xs_control & XS_CTL_RESET) 582 osiop_reset(sc); 583 584 sc->sc_active++; 585 osiop_select(sc); 586 } 587 588 void 589 osiop_scsidone(acb, status) 590 struct osiop_acb *acb; 591 int status; 592 { 593 struct scsipi_xfer *xs; 594 struct scsipi_periph *periph; 595 struct osiop_softc *sc; 596 int dosched = 0; 597 598 #ifdef DIAGNOSTIC 599 if (acb == NULL || acb->xs == NULL) { 600 printf("osiop_scsidone: NULL acb or scsipi_xfer\n"); 601 #if defined(OSIOP_DEBUG) && defined(DDB) 602 Debugger(); 603 #endif 604 return; 605 } 606 #endif 607 xs = acb->xs; 608 sc = acb->sc; 609 periph = xs->xs_periph; 610 611 #ifdef OSIOP_DEBUG 612 if (acb->status != ACB_S_DONE) 613 printf("%s: acb not done (status %d)\n", 614 sc->sc_dev.dv_xname, acb->status); 615 #endif 616 617 xs->status = status; 618 619 switch (status) { 620 case SCSI_OK: 621 xs->error = XS_NOERROR; 622 break; 623 case SCSI_BUSY: 624 xs->error = XS_BUSY; 625 break; 626 case SCSI_CHECK: 627 xs->error = XS_BUSY; 628 break; 629 case SCSI_OSIOP_NOCHECK: 630 /* 631 * don't check status, xs->error is already valid 632 */ 633 break; 634 case SCSI_OSIOP_NOSTATUS: 635 /* 636 * the status byte was not updated, cmd was 637 * aborted 638 */ 639 xs->error = XS_SELTIMEOUT; 640 break; 641 default: 642 #ifdef OSIOP_DEBUG 643 printf("%s: osiop_scsidone: unknown status code (0x%02x)\n", 644 sc->sc_dev.dv_xname, status); 645 #endif 646 xs->error = XS_DRIVER_STUFFUP; 647 break; 648 } 649 650 if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) { 651 bus_dmamap_sync(sc->sc_dmat, acb->datadma, 0, acb->datalen, 652 (xs->xs_control & XS_CTL_DATA_IN) ? 653 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 654 bus_dmamap_unload(sc->sc_dmat, acb->datadma); 655 } 656 657 bus_dmamap_sync(sc->sc_dmat, acb->cmddma, 0, acb->cmdlen, 658 BUS_DMASYNC_POSTWRITE); 659 bus_dmamap_unload(sc->sc_dmat, acb->cmddma); 660 661 /* 662 * Remove the ACB from whatever queue it's on. We have to do a bit of 663 * a hack to figure out which queue it's on. Note that it is *not* 664 * necessary to cdr down the ready queue, but we must cdr down the 665 * nexus queue and see if it's there, so we can mark the unit as no 666 * longer busy. This code is sickening, but it works. 667 */ 668 if (acb == sc->sc_nexus) { 669 sc->sc_nexus = NULL; 670 sc->sc_tinfo[periph->periph_target].lubusy &= 671 ~(1 << periph->periph_lun); 672 if (!TAILQ_EMPTY(&sc->ready_list)) 673 dosched = 1; /* start next command */ 674 sc->sc_active--; 675 OSIOP_TRACE('d', 'a', status, 0); 676 } else if (sc->ready_list.tqh_last == &acb->chain.tqe_next) { 677 TAILQ_REMOVE(&sc->ready_list, acb, chain); 678 OSIOP_TRACE('d', 'r', status, 0); 679 } else { 680 struct osiop_acb *acb2; 681 TAILQ_FOREACH(acb2, &sc->nexus_list, chain) { 682 if (acb2 == acb) { 683 TAILQ_REMOVE(&sc->nexus_list, acb, chain); 684 sc->sc_tinfo[periph->periph_target].lubusy &= 685 ~(1 << periph->periph_lun); 686 sc->sc_active--; 687 break; 688 } 689 } 690 if (acb2 == NULL) { 691 if (acb->chain.tqe_next != NULL) { 692 TAILQ_REMOVE(&sc->ready_list, acb, chain); 693 sc->sc_active--; 694 } else { 695 printf("%s: can't find matching acb\n", 696 sc->sc_dev.dv_xname); 697 #ifdef DDB 698 #if 0 699 Debugger(); 700 #endif 701 #endif 702 } 703 } 704 OSIOP_TRACE('d', 'n', status, 0); 705 } 706 /* Put it on the free list. */ 707 acb->status = ACB_S_FREE; 708 TAILQ_INSERT_TAIL(&sc->free_list, acb, chain); 709 sc->sc_tinfo[periph->periph_target].cmds++; 710 711 callout_stop(&xs->xs_callout); 712 xs->resid = 0; 713 scsipi_done(xs); 714 715 if (dosched && sc->sc_nexus == NULL) 716 osiop_sched(sc); 717 } 718 719 void 720 osiop_abort(sc, where) 721 struct osiop_softc *sc; 722 const char *where; 723 { 724 725 printf("%s: abort %s: dstat %02x, sstat0 %02x sbcl %02x\n", 726 sc->sc_dev.dv_xname, where, 727 osiop_read_1(sc, OSIOP_DSTAT), 728 osiop_read_1(sc, OSIOP_SSTAT0), 729 osiop_read_1(sc, OSIOP_SBCL)); 730 731 /* XXX XXX XXX */ 732 if (sc->sc_active > 0) { 733 sc->sc_active = 0; 734 } 735 } 736 737 void 738 osiop_init(sc) 739 struct osiop_softc *sc; 740 { 741 int i, inhibit_sync, inhibit_disc; 742 743 sc->sc_tcp[1] = 1000 / sc->sc_clock_freq; 744 sc->sc_tcp[2] = 1500 / sc->sc_clock_freq; 745 sc->sc_tcp[3] = 2000 / sc->sc_clock_freq; 746 sc->sc_minsync = sc->sc_tcp[1]; /* in 4ns units */ 747 748 if (sc->sc_minsync < 25) 749 sc->sc_minsync = 25; 750 751 if (sc->sc_clock_freq <= 25) { 752 sc->sc_dcntl |= OSIOP_DCNTL_CF_1; /* SCLK/1 */ 753 sc->sc_tcp[0] = sc->sc_tcp[1]; 754 } else if (sc->sc_clock_freq <= 37) { 755 sc->sc_dcntl |= OSIOP_DCNTL_CF_1_5; /* SCLK/1.5 */ 756 sc->sc_tcp[0] = sc->sc_tcp[2]; 757 } else if (sc->sc_clock_freq <= 50) { 758 sc->sc_dcntl |= OSIOP_DCNTL_CF_2; /* SCLK/2 */ 759 sc->sc_tcp[0] = sc->sc_tcp[3]; 760 } else { 761 sc->sc_dcntl |= OSIOP_DCNTL_CF_3; /* SCLK/3 */ 762 sc->sc_tcp[0] = 3000 / sc->sc_clock_freq; 763 } 764 765 if ((sc->sc_cfflags & 0x10000) != 0) { 766 sc->sc_flags |= OSIOP_NODMA; 767 #ifdef OSIOP_DEBUG 768 printf("%s: DMA disabled; use polling\n", 769 sc->sc_dev.dv_xname); 770 #endif 771 } 772 773 inhibit_sync = (sc->sc_cfflags & 0xff00) >> 8; /* XXX */ 774 inhibit_disc = sc->sc_cfflags & 0x00ff; /* XXX */ 775 #ifdef OSIOP_DEBUG 776 if (inhibit_sync != 0) 777 printf("%s: Inhibiting synchronous transfer: 0x%02x\n", 778 sc->sc_dev.dv_xname, inhibit_sync); 779 if (inhibit_disc != 0) 780 printf("%s: Inhibiting disconnect: 0x%02x\n", 781 sc->sc_dev.dv_xname, inhibit_disc); 782 #endif 783 for (i = 0; i < OSIOP_NTGT; i++) { 784 if (inhibit_sync & (1 << i)) 785 sc->sc_tinfo[i].flags |= TI_NOSYNC; 786 if (inhibit_disc & (1 << i)) 787 sc->sc_tinfo[i].flags |= TI_NODISC; 788 } 789 790 osiop_resetbus(sc); 791 osiop_reset(sc); 792 } 793 794 void 795 osiop_reset(sc) 796 struct osiop_softc *sc; 797 { 798 struct osiop_acb *acb; 799 int i, s; 800 u_int8_t stat; 801 802 #ifdef OSIOP_DEBUG 803 printf("%s: resetting chip\n", sc->sc_dev.dv_xname); 804 #endif 805 if (sc->sc_flags & OSIOP_ALIVE) 806 osiop_abort(sc, "reset"); 807 808 s = splbio(); 809 810 /* 811 * Reset the chip 812 * XXX - is this really needed? 813 */ 814 815 /* abort current script */ 816 osiop_write_1(sc, OSIOP_ISTAT, 817 osiop_read_1(sc, OSIOP_ISTAT) | OSIOP_ISTAT_ABRT); 818 /* reset chip */ 819 osiop_write_1(sc, OSIOP_ISTAT, 820 osiop_read_1(sc, OSIOP_ISTAT) | OSIOP_ISTAT_RST); 821 delay(100); 822 osiop_write_1(sc, OSIOP_ISTAT, 823 osiop_read_1(sc, OSIOP_ISTAT) & ~OSIOP_ISTAT_RST); 824 delay(100); 825 826 /* 827 * Set up various chip parameters 828 */ 829 osiop_write_1(sc, OSIOP_SCNTL0, 830 OSIOP_ARB_FULL | OSIOP_SCNTL0_EPC | OSIOP_SCNTL0_EPG); 831 osiop_write_1(sc, OSIOP_SCNTL1, OSIOP_SCNTL1_ESR); 832 osiop_write_1(sc, OSIOP_DCNTL, sc->sc_dcntl); 833 osiop_write_1(sc, OSIOP_DMODE, OSIOP_DMODE_BL4); 834 /* don't enable interrupts yet */ 835 osiop_write_1(sc, OSIOP_SIEN, 0x00); 836 osiop_write_1(sc, OSIOP_DIEN, 0x00); 837 osiop_write_1(sc, OSIOP_SCID, OSIOP_SCID_VALUE(sc->sc_id)); 838 osiop_write_1(sc, OSIOP_DWT, 0x00); 839 osiop_write_1(sc, OSIOP_CTEST0, osiop_read_1(sc, OSIOP_CTEST0) 840 | OSIOP_CTEST0_BTD | OSIOP_CTEST0_EAN); 841 osiop_write_1(sc, OSIOP_CTEST7, 842 osiop_read_1(sc, OSIOP_CTEST7) | sc->sc_ctest7); 843 844 /* will need to re-negotiate sync xfers */ 845 for (i = 0; i < OSIOP_NTGT; i++) { 846 sc->sc_tinfo[i].state = NEG_INIT; 847 sc->sc_tinfo[i].period = 0; 848 sc->sc_tinfo[i].offset = 0; 849 } 850 851 stat = osiop_read_1(sc, OSIOP_ISTAT); 852 if (stat & OSIOP_ISTAT_SIP) 853 osiop_read_1(sc, OSIOP_SSTAT0); 854 delay(25); 855 if (stat & OSIOP_ISTAT_DIP) 856 osiop_read_1(sc, OSIOP_DSTAT); 857 858 splx(s); 859 860 delay(osiop_reset_delay * 1000); 861 862 if (sc->sc_nexus != NULL) { 863 sc->sc_nexus->xs->error = 864 (sc->sc_nexus->flags & ACB_F_TIMEOUT) ? 865 XS_TIMEOUT : XS_RESET; 866 sc->sc_nexus->status = ACB_S_DONE; 867 sc->sc_nexus->flags = 0; 868 osiop_scsidone(sc->sc_nexus, SCSI_OSIOP_NOCHECK); 869 } 870 while ((acb = TAILQ_FIRST(&sc->nexus_list)) != NULL) { 871 acb->xs->error = (acb->flags & ACB_F_TIMEOUT) ? 872 XS_TIMEOUT : XS_RESET; 873 acb->status = ACB_S_DONE; 874 acb->flags = 0; 875 osiop_scsidone(acb, SCSI_OSIOP_NOCHECK); 876 } 877 878 sc->sc_flags &= ~(OSIOP_INTDEFER | OSIOP_INTSOFF); 879 /* enable SCSI and DMA interrupts */ 880 sc->sc_sien = OSIOP_SIEN_M_A | OSIOP_SIEN_STO | /*OSIOP_SIEN_SEL |*/ 881 OSIOP_SIEN_SGE | OSIOP_SIEN_UDC | OSIOP_SIEN_RST | OSIOP_SIEN_PAR; 882 sc->sc_dien = OSIOP_DIEN_BF | OSIOP_DIEN_ABRT | OSIOP_DIEN_SIR | 883 /*OSIOP_DIEN_WTD |*/ OSIOP_DIEN_IID; 884 osiop_write_1(sc, OSIOP_SIEN, sc->sc_sien); 885 osiop_write_1(sc, OSIOP_DIEN, sc->sc_dien); 886 } 887 888 void 889 osiop_resetbus(sc) 890 struct osiop_softc *sc; 891 { 892 893 osiop_write_1(sc, OSIOP_SIEN, 0); 894 osiop_write_1(sc, OSIOP_SCNTL1, 895 osiop_read_1(sc, OSIOP_SCNTL1) | OSIOP_SCNTL1_RST); 896 delay(25); 897 osiop_write_1(sc, OSIOP_SCNTL1, 898 osiop_read_1(sc, OSIOP_SCNTL1) & ~OSIOP_SCNTL1_RST); 899 } 900 901 /* 902 * Setup Data Storage for 53C710 and start SCRIPTS processing 903 */ 904 905 void 906 osiop_start(sc) 907 struct osiop_softc *sc; 908 { 909 struct osiop_acb *acb = sc->sc_nexus; 910 struct osiop_ds *ds = acb->ds; 911 struct scsipi_xfer *xs = acb->xs; 912 bus_dmamap_t dsdma = sc->sc_dsdma, datadma = acb->datadma; 913 struct osiop_tinfo *ti; 914 int target = xs->xs_periph->periph_target; 915 int lun = xs->xs_periph->periph_lun; 916 int disconnect, i; 917 918 #ifdef OSIOP_DEBUG 919 if (osiop_debug & DEBUG_DISC && 920 osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) { 921 printf("ACK! osiop was busy: script %p dsa %p active %d\n", 922 sc->sc_script, acb->ds, sc->sc_active); 923 printf("istat %02x sfbr %02x lcrc %02x sien %02x dien %02x\n", 924 osiop_read_1(sc, OSIOP_ISTAT), 925 osiop_read_1(sc, OSIOP_SFBR), 926 osiop_read_1(sc, OSIOP_LCRC), 927 osiop_read_1(sc, OSIOP_SIEN), 928 osiop_read_1(sc, OSIOP_DIEN)); 929 #ifdef DDB 930 #if 0 931 Debugger(); 932 #endif 933 #endif 934 } 935 #endif 936 937 #ifdef OSIOP_DEBUG 938 if (acb->status != ACB_S_READY) 939 panic("osiop_start: non-ready cmd in acb"); 940 #endif 941 942 acb->intstat = 0; 943 944 ds->cmd.count = acb->cmdlen; 945 ds->cmd.addr = acb->cmddma->dm_segs[0].ds_addr; 946 947 ti = &sc->sc_tinfo[target]; 948 ds->scsi_addr = ((1 << 16) << target) | (ti->sxfer << 8); 949 950 disconnect = (xs->xs_control & XS_CTL_REQSENSE) == 0 && 951 (ti->flags & TI_NODISC) == 0; 952 953 ds->msgout[0] = MSG_IDENTIFY(lun, disconnect); 954 ds->id.count = 1; 955 ds->stat[0] = SCSI_OSIOP_NOSTATUS; /* set invalid status */ 956 ds->msgbuf[0] = ds->msgbuf[1] = MSG_INVALID; 957 memset(&ds->data, 0, sizeof(ds->data)); 958 959 /* 960 * Negotiate wide is the initial negotiation state; since the 53c710 961 * doesn't do wide transfers, just begin the synchronous transfer 962 * negotation here. 963 */ 964 if (ti->state == NEG_INIT) { 965 if ((ti->flags & TI_NOSYNC) != 0) { 966 ti->state = NEG_DONE; 967 ti->sbcl = 0; 968 ti->sxfer = 0; 969 ti->period = 0; 970 ti->offset = 0; 971 osiop_update_xfer_mode(sc, target); 972 #ifdef OSIOP_DEBUG 973 if (osiopsync_debug) 974 printf("Forcing target %d asynchronous\n", 975 target); 976 #endif 977 } else { 978 ds->msgbuf[2] = MSG_INVALID; 979 ds->msgout[1] = MSG_EXTENDED; 980 ds->msgout[2] = MSG_EXT_SDTR_LEN; 981 ds->msgout[3] = MSG_EXT_SDTR; 982 ds->msgout[4] = sc->sc_minsync; 983 ds->msgout[5] = OSIOP_MAX_OFFSET; 984 ds->id.count = MSG_EXT_SDTR_LEN + 3; 985 ti->state = NEG_WAITS; 986 #ifdef OSIOP_DEBUG 987 if (osiopsync_debug) 988 printf("Sending sync request to target %d\n", 989 target); 990 #endif 991 } 992 } 993 994 acb->curaddr = 0; 995 acb->curlen = 0; 996 997 /* 998 * Build physical DMA addresses for scatter/gather I/O 999 */ 1000 if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) { 1001 for (i = 0; i < datadma->dm_nsegs; i++) { 1002 ds->data[i].count = datadma->dm_segs[i].ds_len; 1003 ds->data[i].addr = datadma->dm_segs[i].ds_addr; 1004 } 1005 } 1006 1007 /* sync script data structure */ 1008 bus_dmamap_sync(sc->sc_dmat, dsdma, 1009 acb->dsoffset, sizeof(struct osiop_ds), 1010 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1011 1012 acb->status = ACB_S_ACTIVE; 1013 1014 /* handle timeout */ 1015 if ((xs->xs_control & XS_CTL_POLL) == 0) { 1016 int timeout = mstohz(acb->xs->timeout); 1017 /* start expire timer */ 1018 if (timeout == 0) 1019 timeout = 1; 1020 callout_reset(&xs->xs_callout, timeout, 1021 osiop_timeout, acb); 1022 } 1023 #ifdef OSIOP_DEBUG 1024 if (osiop_debug & DEBUG_DISC && 1025 osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) { 1026 printf("ACK! osiop was busy at start: " 1027 "script %p dsa %p active %d\n", 1028 sc->sc_script, acb->ds, sc->sc_active); 1029 #ifdef DDB 1030 #if 0 1031 Debugger(); 1032 #endif 1033 #endif 1034 } 1035 #endif 1036 if (TAILQ_EMPTY(&sc->nexus_list)) { 1037 if (osiop_read_1(sc, OSIOP_ISTAT) & OSIOP_ISTAT_CON) 1038 printf("%s: osiop_select while connected?\n", 1039 sc->sc_dev.dv_xname); 1040 osiop_write_4(sc, OSIOP_TEMP, 0); 1041 osiop_write_1(sc, OSIOP_SBCL, ti->sbcl); 1042 osiop_write_4(sc, OSIOP_DSA, 1043 dsdma->dm_segs[0].ds_addr + acb->dsoffset); 1044 osiop_write_4(sc, OSIOP_DSP, 1045 sc->sc_scrdma->dm_segs[0].ds_addr + Ent_scripts); 1046 OSIOP_TRACE('s', 1, 0, 0); 1047 } else { 1048 if ((osiop_read_1(sc, OSIOP_ISTAT) & OSIOP_ISTAT_CON) == 0) { 1049 osiop_write_1(sc, OSIOP_ISTAT, OSIOP_ISTAT_SIGP); 1050 OSIOP_TRACE('s', 2, 0, 0); 1051 } else { 1052 OSIOP_TRACE('s', 3, 1053 osiop_read_1(sc, OSIOP_ISTAT), 0); 1054 } 1055 } 1056 #ifdef OSIOP_DEBUG 1057 osiopstarts++; 1058 #endif 1059 } 1060 1061 /* 1062 * Process a DMA or SCSI interrupt from the 53C710 SIOP 1063 */ 1064 1065 int 1066 osiop_checkintr(sc, istat, dstat, sstat0, status) 1067 struct osiop_softc *sc; 1068 u_int8_t istat; 1069 u_int8_t dstat; 1070 u_int8_t sstat0; 1071 int *status; 1072 { 1073 struct osiop_acb *acb = sc->sc_nexus; 1074 struct osiop_ds *ds; 1075 bus_dmamap_t dsdma = sc->sc_dsdma; 1076 bus_addr_t scraddr = sc->sc_scrdma->dm_segs[0].ds_addr; 1077 int target = 0; 1078 int dfifo, dbc, intcode, sstat1; 1079 1080 dfifo = osiop_read_1(sc, OSIOP_DFIFO); 1081 dbc = osiop_read_4(sc, OSIOP_DBC) & 0x00ffffff; 1082 sstat1 = osiop_read_1(sc, OSIOP_SSTAT1); 1083 osiop_write_1(sc, OSIOP_CTEST8, 1084 osiop_read_1(sc, OSIOP_CTEST8) | OSIOP_CTEST8_CLF); 1085 while ((osiop_read_1(sc, OSIOP_CTEST1) & OSIOP_CTEST1_FMT) != 1086 OSIOP_CTEST1_FMT) 1087 ; 1088 osiop_write_1(sc, OSIOP_CTEST8, 1089 osiop_read_1(sc, OSIOP_CTEST8) & ~OSIOP_CTEST8_CLF); 1090 intcode = osiop_read_4(sc, OSIOP_DSPS); 1091 #ifdef OSIOP_DEBUG 1092 osiopints++; 1093 if (osiop_read_4(sc, OSIOP_DSP) != 0 && 1094 (osiop_read_4(sc, OSIOP_DSP) < scraddr || 1095 osiop_read_4(sc, OSIOP_DSP) >= scraddr + sizeof(osiop_script))) { 1096 printf("%s: dsp not within script dsp %x scripts %lx:%lx", 1097 sc->sc_dev.dv_xname, 1098 osiop_read_4(sc, OSIOP_DSP), 1099 scraddr, scraddr + sizeof(osiop_script)); 1100 printf(" istat %x dstat %x sstat0 %x\n", istat, dstat, sstat0); 1101 #ifdef DDB 1102 Debugger(); 1103 #endif 1104 } 1105 #endif 1106 OSIOP_TRACE('i', dstat, istat, (istat & OSIOP_ISTAT_DIP) ? 1107 intcode & 0xff : sstat0); 1108 1109 if (acb != NULL) { /* XXX */ 1110 ds = acb->ds; 1111 bus_dmamap_sync(sc->sc_dmat, dsdma, 1112 acb->dsoffset, sizeof(struct osiop_ds), 1113 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1114 #ifdef OSIOP_DEBUG 1115 if (acb->status != ACB_S_ACTIVE) 1116 printf("osiop_checkintr: acb not active (status %d)\n", 1117 acb->status); 1118 #endif 1119 } 1120 1121 1122 if (dstat & OSIOP_DSTAT_SIR && intcode == A_ok) { 1123 /* Normal completion status, or check condition */ 1124 struct osiop_tinfo *ti; 1125 #ifdef OSIOP_DEBUG 1126 if (osiop_read_4(sc, OSIOP_DSA) != 1127 dsdma->dm_segs[0].ds_addr + acb->dsoffset) { 1128 printf("osiop: invalid dsa: %x %lx\n", 1129 osiop_read_4(sc, OSIOP_DSA), 1130 dsdma->dm_segs[0].ds_addr + acb->dsoffset); 1131 panic("*** osiop DSA invalid ***"); 1132 } 1133 #endif 1134 target = acb->xs->xs_periph->periph_target; 1135 ti = &sc->sc_tinfo[target]; 1136 if (ti->state == NEG_WAITS) { 1137 if (ds->msgbuf[1] == MSG_INVALID) 1138 printf("%s: target %d ignored sync request\n", 1139 sc->sc_dev.dv_xname, target); 1140 else if (ds->msgbuf[1] == MSG_MESSAGE_REJECT) 1141 printf("%s: target %d rejected sync request\n", 1142 sc->sc_dev.dv_xname, target); 1143 ti->period = 0; 1144 ti->offset = 0; 1145 osiop_update_xfer_mode(sc, target); 1146 ti->state = NEG_DONE; 1147 } 1148 #ifdef OSIOP_DEBUG 1149 if (osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) { 1150 #if 0 1151 printf("ACK! osiop was busy at end: " 1152 "script %p dsa %p\n", &osiop_script, ds); 1153 #ifdef DDB 1154 Debugger(); 1155 #endif 1156 #endif 1157 } 1158 if (ds->msgbuf[0] != MSG_CMDCOMPLETE) 1159 printf("%s: message was not COMMAND COMPLETE: %02x\n", 1160 sc->sc_dev.dv_xname, ds->msgbuf[0]); 1161 #endif 1162 if (!TAILQ_EMPTY(&sc->nexus_list)) 1163 osiop_write_1(sc, OSIOP_DCNTL, 1164 osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD); 1165 *status = ds->stat[0]; 1166 acb->status = ACB_S_DONE; 1167 return (1); 1168 } 1169 if (dstat & OSIOP_DSTAT_SIR && intcode == A_int_syncmsg) { 1170 target = acb->xs->xs_periph->periph_target; 1171 if (ds->msgbuf[1] == MSG_EXTENDED && 1172 ds->msgbuf[2] == MSG_EXT_SDTR_LEN && 1173 ds->msgbuf[3] == MSG_EXT_SDTR) { 1174 struct osiop_tinfo *ti = &sc->sc_tinfo[target]; 1175 #ifdef OSIOP_DEBUG 1176 if (osiopsync_debug) 1177 printf("sync msg in: " 1178 "%02x %02x %02x %02x %02x %02x\n", 1179 ds->msgbuf[0], ds->msgbuf[1], 1180 ds->msgbuf[2], ds->msgbuf[3], 1181 ds->msgbuf[4], ds->msgbuf[5]); 1182 #endif 1183 ti->period = ds->msgbuf[4]; 1184 ti->offset = ds->msgbuf[5]; 1185 ti->sxfer = 0; 1186 ti->sbcl = 0; 1187 if (ds->msgbuf[5] != 0) 1188 scsi_period_to_osiop(sc, target); 1189 osiop_update_xfer_mode(sc, target); 1190 1191 bus_dmamap_sync(sc->sc_dmat, dsdma, 1192 acb->dsoffset, sizeof(struct osiop_ds), 1193 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1194 osiop_write_1(sc, OSIOP_SXFER, ti->sxfer); 1195 osiop_write_1(sc, OSIOP_SBCL, ti->sbcl); 1196 if (ti->state == NEG_WAITS) { 1197 ti->state = NEG_DONE; 1198 osiop_write_4(sc, OSIOP_DSP, 1199 scraddr + Ent_clear_ack); 1200 return (0); 1201 } 1202 osiop_write_1(sc, OSIOP_DCNTL, 1203 osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD); 1204 ti->state = NEG_DONE; 1205 return (0); 1206 } 1207 /* XXX - not SDTR message */ 1208 } 1209 if (sstat0 & OSIOP_SSTAT0_M_A) { 1210 /* Phase mismatch */ 1211 #ifdef OSIOP_DEBUG 1212 osiopphmm++; 1213 if (acb == NULL) 1214 printf("%s: Phase mismatch with no active command?\n", 1215 sc->sc_dev.dv_xname); 1216 #endif 1217 if (acb->datalen > 0) { 1218 int adjust = (dfifo - (dbc & 0x7f)) & 0x7f; 1219 if (sstat1 & OSIOP_SSTAT1_ORF) 1220 adjust++; 1221 if (sstat1 & OSIOP_SSTAT1_OLF) 1222 adjust++; 1223 acb->curaddr = osiop_read_4(sc, OSIOP_DNAD) - adjust; 1224 acb->curlen = dbc + adjust; 1225 #ifdef OSIOP_DEBUG 1226 if (osiop_debug & DEBUG_DISC) { 1227 printf("Phase mismatch: curaddr %lx " 1228 "curlen %lx dfifo %x dbc %x sstat1 %x " 1229 "adjust %x sbcl %x starts %d acb %p\n", 1230 acb->curaddr, acb->curlen, dfifo, 1231 dbc, sstat1, adjust, 1232 osiop_read_1(sc, OSIOP_SBCL), 1233 osiopstarts, acb); 1234 if (ds->data[1].count != 0) { 1235 int i; 1236 for (i = 0; ds->data[i].count != 0; i++) 1237 printf("chain[%d] " 1238 "addr %x len %x\n", i, 1239 ds->data[i].addr, 1240 ds->data[i].count); 1241 } 1242 bus_dmamap_sync(sc->sc_dmat, dsdma, 1243 acb->dsoffset, sizeof(struct osiop_ds), 1244 BUS_DMASYNC_PREREAD | 1245 BUS_DMASYNC_PREWRITE); 1246 } 1247 #endif 1248 } 1249 #ifdef OSIOP_DEBUG 1250 OSIOP_TRACE('m', osiop_read_1(sc, OSIOP_SBCL), 1251 osiop_read_4(sc, OSIOP_DSP) >> 8, 1252 osiop_read_4(sc, OSIOP_DSP)); 1253 if (osiop_debug & DEBUG_PHASE) 1254 printf("Phase mismatch: %x dsp +%lx dcmd %x\n", 1255 osiop_read_1(sc, OSIOP_SBCL), 1256 osiop_read_4(sc, OSIOP_DSP) - scraddr, 1257 osiop_read_4(sc, OSIOP_DBC)); 1258 #endif 1259 if ((osiop_read_1(sc, OSIOP_SBCL) & OSIOP_REQ) == 0) { 1260 printf("Phase mismatch: " 1261 "REQ not asserted! %02x dsp %x\n", 1262 osiop_read_1(sc, OSIOP_SBCL), 1263 osiop_read_4(sc, OSIOP_DSP)); 1264 #if defined(OSIOP_DEBUG) && defined(DDB) 1265 /*Debugger(); XXX is*/ 1266 #endif 1267 } 1268 switch (OSIOP_PHASE(osiop_read_1(sc, OSIOP_SBCL))) { 1269 case DATA_OUT_PHASE: 1270 case DATA_IN_PHASE: 1271 case STATUS_PHASE: 1272 case COMMAND_PHASE: 1273 case MSG_IN_PHASE: 1274 case MSG_OUT_PHASE: 1275 osiop_write_4(sc, OSIOP_DSP, scraddr + Ent_switch); 1276 break; 1277 default: 1278 printf("%s: invalid phase\n", sc->sc_dev.dv_xname); 1279 goto bad_phase; 1280 } 1281 return (0); 1282 } 1283 if (sstat0 & OSIOP_SSTAT0_STO) { 1284 /* Select timed out */ 1285 #ifdef OSIOP_DEBUG 1286 if (acb == NULL) 1287 printf("%s: Select timeout with no active command?\n", 1288 sc->sc_dev.dv_xname); 1289 if (osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) { 1290 printf("ACK! osiop was busy at timeout: " 1291 "script %p dsa %lx\n", sc->sc_script, 1292 dsdma->dm_segs[0].ds_addr + acb->dsoffset); 1293 printf(" sbcl %x sdid %x " 1294 "istat %x dstat %x sstat0 %x\n", 1295 osiop_read_1(sc, OSIOP_SBCL), 1296 osiop_read_1(sc, OSIOP_SDID), 1297 istat, dstat, sstat0); 1298 if ((osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) == 0) { 1299 printf("Yikes, it's not busy now!\n"); 1300 #if 0 1301 *status = SCSI_OSIOP_NOSTATUS; 1302 if (!TAILQ_EMPTY(&sc->nexus_list)) 1303 osiop_write_4(sc, OSIOP_DSP, 1304 scraddr + Ent_wait_reselect); 1305 return (1); 1306 #endif 1307 } 1308 #if 0 1309 osiop_write_1(sc, OSIOP_DCNTL, 1310 osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD); 1311 #endif 1312 #ifdef DDB 1313 Debugger(); 1314 #endif 1315 return (0); 1316 } 1317 #endif 1318 acb->status = ACB_S_DONE; 1319 *status = SCSI_OSIOP_NOSTATUS; 1320 acb->xs->error = XS_SELTIMEOUT; 1321 if (!TAILQ_EMPTY(&sc->nexus_list)) 1322 osiop_write_4(sc, OSIOP_DSP, 1323 scraddr + Ent_wait_reselect); 1324 return (1); 1325 } 1326 if (acb != NULL) 1327 target = acb->xs->xs_periph->periph_target; 1328 else 1329 target = sc->sc_id; 1330 if (sstat0 & OSIOP_SSTAT0_UDC) { 1331 #ifdef OSIOP_DEBUG 1332 if (acb == NULL) 1333 printf("%s: Unexpected disconnect " 1334 "with no active command?\n", sc->sc_dev.dv_xname); 1335 printf("%s: target %d disconnected unexpectedly\n", 1336 sc->sc_dev.dv_xname, target); 1337 #endif 1338 #if 0 1339 osiop_abort(sc, "osiop_chkintr"); 1340 #endif 1341 *status = SCSI_CHECK; 1342 if (!TAILQ_EMPTY(&sc->nexus_list)) 1343 osiop_write_4(sc, OSIOP_DSP, 1344 scraddr + Ent_wait_reselect); 1345 return (acb != NULL); 1346 } 1347 if (dstat & OSIOP_DSTAT_SIR && 1348 (intcode == A_int_disc || intcode == A_int_disc_wodp)) { 1349 /* Disconnect */ 1350 if (acb == NULL) { 1351 printf("%s: Disconnect with no active command?\n", 1352 sc->sc_dev.dv_xname); 1353 return (0); 1354 } 1355 #ifdef OSIOP_DEBUG 1356 if (osiop_debug & DEBUG_DISC) { 1357 printf("%s: ID %02x disconnected TEMP %x (+%lx) " 1358 "curaddr %lx curlen %lx buf %x len %x dfifo %x " 1359 "dbc %x sstat1 %x starts %d acb %p\n", 1360 sc->sc_dev.dv_xname, 1 << target, 1361 osiop_read_4(sc, OSIOP_TEMP), 1362 (osiop_read_4(sc, OSIOP_TEMP) != 0) ? 1363 osiop_read_4(sc, OSIOP_TEMP) - scraddr : 0, 1364 acb->curaddr, acb->curlen, 1365 ds->data[0].addr, ds->data[0].count, 1366 dfifo, dbc, sstat1, osiopstarts, acb); 1367 bus_dmamap_sync(sc->sc_dmat, dsdma, 1368 acb->dsoffset, sizeof(struct osiop_ds), 1369 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1370 } 1371 #endif 1372 /* 1373 * XXXX need to update curaddr/curlen to reflect 1374 * current data transferred. If device disconnected in 1375 * the middle of a DMA block, they should already be set 1376 * by the phase change interrupt. If the disconnect 1377 * occurs on a DMA block boundary, we have to figure out 1378 * which DMA block it was. 1379 */ 1380 if (acb->datalen > 0 && 1381 osiop_read_4(sc, OSIOP_TEMP) != 0) { 1382 long n = osiop_read_4(sc, OSIOP_TEMP) - scraddr; 1383 1384 if (acb->curlen != 0 && 1385 acb->curlen != ds->data[0].count) 1386 printf("%s: curaddr/curlen already set? " 1387 "n %lx iob %lx/%lx chain[0] %x/%x\n", 1388 sc->sc_dev.dv_xname, n, 1389 acb->curaddr, acb->curlen, 1390 ds->data[0].addr, ds->data[0].count); 1391 if (n < Ent_datain) 1392 n = (n - Ent_dataout) / 16; 1393 else 1394 n = (n - Ent_datain) / 16; 1395 if (n < 0 || n >= OSIOP_NSG) 1396 printf("TEMP invalid %ld\n", n); 1397 else { 1398 acb->curaddr = ds->data[n].addr; 1399 acb->curlen = ds->data[n].count; 1400 } 1401 #ifdef OSIOP_DEBUG 1402 if (osiop_debug & DEBUG_DISC) { 1403 printf("%s: TEMP offset %ld", 1404 sc->sc_dev.dv_xname, n); 1405 printf(" curaddr %lx curlen %lx\n", 1406 acb->curaddr, acb->curlen); 1407 } 1408 #endif 1409 } 1410 /* 1411 * If data transfer was interrupted by disconnect, curaddr 1412 * and curlen should reflect the point of interruption. 1413 * Adjust the DMA chain so that the data transfer begins 1414 * at the appropriate place upon reselection. 1415 * XXX This should only be done on save data pointer message? 1416 */ 1417 if (acb->curlen > 0) { 1418 int i, j; 1419 1420 #ifdef OSIOP_DEBUG 1421 if (osiop_debug & DEBUG_DISC) 1422 printf("%s: adjusting DMA chain\n", 1423 sc->sc_dev.dv_xname); 1424 if (intcode == A_int_disc_wodp) 1425 printf("%s: ID %02x disconnected " 1426 "without Save Data Pointers\n", 1427 sc->sc_dev.dv_xname, 1 << target); 1428 #endif 1429 for (i = 0; i < OSIOP_NSG; i++) { 1430 if (ds->data[i].count == 0) 1431 break; 1432 if (acb->curaddr >= ds->data[i].addr && 1433 acb->curaddr < 1434 (ds->data[i].addr + ds->data[i].count)) 1435 break; 1436 } 1437 if (i >= OSIOP_NSG || ds->data[i].count == 0) { 1438 printf("couldn't find saved data pointer: " 1439 "curaddr %lx curlen %lx i %d\n", 1440 acb->curaddr, acb->curlen, i); 1441 #ifdef DDB 1442 Debugger(); 1443 #endif 1444 } 1445 #ifdef OSIOP_DEBUG 1446 if (osiop_debug & DEBUG_DISC) 1447 printf(" chain[0]: %x/%x -> %lx/%lx\n", 1448 ds->data[0].addr, ds->data[0].count, 1449 acb->curaddr, acb->curlen); 1450 #endif 1451 ds->data[0].addr = acb->curaddr; 1452 ds->data[0].count = acb->curlen; 1453 for (j = 1, i = i + 1; 1454 i < OSIOP_NSG && ds->data[i].count > 0; 1455 i++, j++) { 1456 #ifdef OSIOP_DEBUG 1457 if (osiop_debug & DEBUG_DISC) 1458 printf(" chain[%d]: %x/%x -> %x/%x\n", 1459 j, ds->data[j].addr, 1460 ds->data[j].count, 1461 ds->data[i].addr, 1462 ds->data[i].count); 1463 #endif 1464 ds->data[j].addr = ds->data[i].addr; 1465 ds->data[j].count = ds->data[i].count; 1466 } 1467 if (j < OSIOP_NSG) { 1468 ds->data[j].addr = 0; 1469 ds->data[j].count = 0; 1470 } 1471 bus_dmamap_sync(sc->sc_dmat, dsdma, 1472 acb->dsoffset, sizeof(struct osiop_ds), 1473 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1474 } 1475 sc->sc_tinfo[target].dconns++; 1476 /* 1477 * add nexus to waiting list 1478 * clear nexus 1479 * try to start another command for another target/lun 1480 */ 1481 acb->intstat = sc->sc_flags & OSIOP_INTSOFF; 1482 TAILQ_INSERT_TAIL(&sc->nexus_list, acb, chain); 1483 sc->sc_nexus = NULL; /* no current device */ 1484 osiop_write_4(sc, OSIOP_DSP, scraddr + Ent_wait_reselect); 1485 /* XXXX start another command ? */ 1486 if (!TAILQ_EMPTY(&sc->ready_list)) 1487 osiop_sched(sc); 1488 return (0); 1489 } 1490 if (dstat & OSIOP_DSTAT_SIR && intcode == A_int_reconnect) { 1491 int reselid = ffs(osiop_read_4(sc, OSIOP_SCRATCH) & 0xff) - 1; 1492 int reselun = osiop_read_1(sc, OSIOP_SFBR) & 0x07; 1493 #ifdef OSIOP_DEBUG 1494 u_int8_t resmsg; 1495 #endif 1496 1497 /* Reconnect */ 1498 /* XXXX save current SBCL */ 1499 sc->sc_sstat1 = osiop_read_1(sc, OSIOP_SBCL); 1500 #ifdef OSIOP_DEBUG 1501 if (osiop_debug & DEBUG_DISC) 1502 printf("%s: target ID %02x reselected dsps %x\n", 1503 sc->sc_dev.dv_xname, reselid, intcode); 1504 resmsg = osiop_read_1(sc, OSIOP_SFBR); 1505 if (!MSG_ISIDENTIFY(resmsg)) 1506 printf("%s: Reselect message in was not identify: " 1507 "%02x\n", sc->sc_dev.dv_xname, resmsg); 1508 #endif 1509 if (sc->sc_nexus != NULL) { 1510 struct scsipi_periph *periph = 1511 sc->sc_nexus->xs->xs_periph; 1512 #ifdef OSIOP_DEBUG 1513 if (osiop_debug & DEBUG_DISC) 1514 printf("%s: reselect ID %02x w/active\n", 1515 sc->sc_dev.dv_xname, reselid); 1516 #endif 1517 TAILQ_INSERT_HEAD(&sc->ready_list, 1518 sc->sc_nexus, chain); 1519 sc->sc_tinfo[periph->periph_target].lubusy 1520 &= ~(1 << periph->periph_lun); 1521 sc->sc_active--; 1522 } 1523 /* 1524 * locate acb of reselecting device 1525 * set sc->sc_nexus to acb 1526 */ 1527 TAILQ_FOREACH(acb, &sc->nexus_list, chain) { 1528 struct scsipi_periph *periph = acb->xs->xs_periph; 1529 if (reselid != periph->periph_target || 1530 reselun != periph->periph_lun) { 1531 continue; 1532 } 1533 TAILQ_REMOVE(&sc->nexus_list, acb, chain); 1534 sc->sc_nexus = acb; 1535 sc->sc_flags |= acb->intstat; 1536 acb->intstat = 0; 1537 osiop_write_4(sc, OSIOP_DSA, 1538 dsdma->dm_segs[0].ds_addr + acb->dsoffset); 1539 osiop_write_1(sc, OSIOP_SXFER, 1540 sc->sc_tinfo[reselid].sxfer); 1541 osiop_write_1(sc, OSIOP_SBCL, 1542 sc->sc_tinfo[reselid].sbcl); 1543 break; 1544 } 1545 if (acb == NULL) { 1546 printf("%s: target ID %02x reselect nexus_list %p\n", 1547 sc->sc_dev.dv_xname, reselid, 1548 TAILQ_FIRST(&sc->nexus_list)); 1549 panic("unable to find reselecting device"); 1550 } 1551 1552 osiop_write_4(sc, OSIOP_TEMP, 0); 1553 osiop_write_1(sc, OSIOP_DCNTL, 1554 osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD); 1555 return (0); 1556 } 1557 if (dstat & OSIOP_DSTAT_SIR && intcode == A_int_connect) { 1558 #ifdef OSIOP_DEBUG 1559 u_int8_t ctest2 = osiop_read_1(sc, OSIOP_CTEST2); 1560 1561 /* reselect was interrupted (by Sig_P or select) */ 1562 if (osiop_debug & DEBUG_DISC || 1563 (ctest2 & OSIOP_CTEST2_SIGP) == 0) 1564 printf("%s: reselect interrupted (Sig_P?) " 1565 "scntl1 %x ctest2 %x sfbr %x istat %x/%x\n", 1566 sc->sc_dev.dv_xname, 1567 osiop_read_1(sc, OSIOP_SCNTL1), ctest2, 1568 osiop_read_1(sc, OSIOP_SFBR), istat, 1569 osiop_read_1(sc, OSIOP_ISTAT)); 1570 #endif 1571 /* XXX assumes it was not select */ 1572 if (sc->sc_nexus == NULL) { 1573 #ifdef OSIOP_DEBUG 1574 printf("%s: reselect interrupted, sc_nexus == NULL\n", 1575 sc->sc_dev.dv_xname); 1576 #if 0 1577 osiop_dump(sc); 1578 #ifdef DDB 1579 Debugger(); 1580 #endif 1581 #endif 1582 #endif 1583 osiop_write_1(sc, OSIOP_DCNTL, 1584 osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD); 1585 return (0); 1586 } 1587 target = sc->sc_nexus->xs->xs_periph->periph_target; 1588 osiop_write_4(sc, OSIOP_TEMP, 0); 1589 osiop_write_4(sc, OSIOP_DSA, 1590 dsdma->dm_segs[0].ds_addr + sc->sc_nexus->dsoffset); 1591 osiop_write_1(sc, OSIOP_SXFER, sc->sc_tinfo[target].sxfer); 1592 osiop_write_1(sc, OSIOP_SBCL, sc->sc_tinfo[target].sbcl); 1593 osiop_write_4(sc, OSIOP_DSP, scraddr + Ent_scripts); 1594 return (0); 1595 } 1596 if (dstat & OSIOP_DSTAT_SIR && intcode == A_int_msgin) { 1597 /* Unrecognized message in byte */ 1598 if (acb == NULL) 1599 printf("%s: Bad message-in with no active command?\n", 1600 sc->sc_dev.dv_xname); 1601 printf("%s: Unrecognized message in data " 1602 "sfbr %x msg %x sbcl %x\n", sc->sc_dev.dv_xname, 1603 osiop_read_1(sc, OSIOP_SFBR), ds->msgbuf[1], 1604 osiop_read_1(sc, OSIOP_SBCL)); 1605 /* what should be done here? */ 1606 osiop_write_4(sc, OSIOP_DSP, scraddr + Ent_switch); 1607 bus_dmamap_sync(sc->sc_dmat, dsdma, 1608 acb->dsoffset, sizeof(struct osiop_ds), 1609 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1610 return (0); 1611 } 1612 if (dstat & OSIOP_DSTAT_SIR && intcode == A_int_status) { 1613 /* Status phase wasn't followed by message in phase? */ 1614 printf("%s: Status phase not followed by message in phase? " 1615 "sbcl %x sbdl %x\n", sc->sc_dev.dv_xname, 1616 osiop_read_1(sc, OSIOP_SBCL), 1617 osiop_read_1(sc, OSIOP_SBDL)); 1618 if (osiop_read_1(sc, OSIOP_SBCL) == 0xa7) { 1619 /* It is now, just continue the script? */ 1620 osiop_write_1(sc, OSIOP_DCNTL, 1621 osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD); 1622 return (0); 1623 } 1624 } 1625 if (dstat & OSIOP_DSTAT_SIR && sstat0 == 0) { 1626 printf("OSIOP interrupt: %x sts %x msg %x %x sbcl %x\n", 1627 intcode, ds->stat[0], ds->msgbuf[0], ds->msgbuf[1], 1628 osiop_read_1(sc, OSIOP_SBCL)); 1629 osiop_reset(sc); 1630 *status = SCSI_OSIOP_NOSTATUS; 1631 return (0); /* osiop_reset has cleaned up */ 1632 } 1633 if (sstat0 & OSIOP_SSTAT0_SGE) 1634 printf("%s: SCSI Gross Error\n", sc->sc_dev.dv_xname); 1635 if (sstat0 & OSIOP_SSTAT0_PAR) 1636 printf("%s: Parity Error\n", sc->sc_dev.dv_xname); 1637 if (dstat & OSIOP_DSTAT_IID) 1638 printf("%s: Invalid instruction detected\n", 1639 sc->sc_dev.dv_xname); 1640 bad_phase: 1641 /* 1642 * temporary panic for unhandled conditions 1643 * displays various things about the 53C710 status and registers 1644 * then panics. 1645 * XXXX need to clean this up to print out the info, reset, and continue 1646 */ 1647 printf("osiop_chkintr: target %x ds %p\n", target, ds); 1648 printf("scripts %lx ds %lx dsp %x dcmd %x\n", scraddr, 1649 sc->sc_dsdma->dm_segs[0].ds_addr + acb->dsoffset, 1650 osiop_read_4(sc, OSIOP_DSP), 1651 osiop_read_4(sc, OSIOP_DBC)); 1652 printf("osiop_chkintr: istat %x dstat %x sstat0 %x " 1653 "dsps %x dsa %x sbcl %x sts %x msg %x %x sfbr %x\n", 1654 istat, dstat, sstat0, intcode, 1655 osiop_read_4(sc, OSIOP_DSA), 1656 osiop_read_1(sc, OSIOP_SBCL), 1657 ds->stat[0], ds->msgbuf[0], ds->msgbuf[1], 1658 osiop_read_1(sc, OSIOP_SFBR)); 1659 #ifdef OSIOP_DEBUG 1660 if (osiop_debug & DEBUG_DMA) 1661 panic("osiop_chkintr: **** temp ****"); 1662 #endif 1663 #ifdef DDB 1664 Debugger(); 1665 #endif 1666 osiop_reset(sc); /* hard reset */ 1667 *status = SCSI_OSIOP_NOSTATUS; 1668 acb->status = ACB_S_DONE; 1669 return (0); /* osiop_reset cleaned up */ 1670 } 1671 1672 void 1673 osiop_select(sc) 1674 struct osiop_softc *sc; 1675 { 1676 struct osiop_acb *acb = sc->sc_nexus; 1677 1678 #ifdef OSIOP_DEBUG 1679 if (osiop_debug & DEBUG_CMD) 1680 printf("%s: select ", sc->sc_dev.dv_xname); 1681 #endif 1682 1683 if (acb->xs->xs_control & XS_CTL_POLL || sc->sc_flags & OSIOP_NODMA) { 1684 sc->sc_flags |= OSIOP_INTSOFF; 1685 sc->sc_flags &= ~OSIOP_INTDEFER; 1686 if ((osiop_read_1(sc, OSIOP_ISTAT) & OSIOP_ISTAT_CON) == 0) { 1687 osiop_write_1(sc, OSIOP_SIEN, 0); 1688 osiop_write_1(sc, OSIOP_DIEN, 0); 1689 } 1690 #if 0 1691 } else if ((sc->sc_flags & OSIOP_INTDEFER) == 0) { 1692 sc->sc_flags &= ~OSIOP_INTSOFF; 1693 if ((osiop_read_1(sc, OSIOP_ISTAT) & OSIOP_ISTAT_CON) == 0) { 1694 osiop_write_1(sc, OSIOP_SIEN, sc->sc_sien); 1695 osiop_write_1(sc, OSIOP_DIEN, sc->sc_dien); 1696 } 1697 #endif 1698 } 1699 #ifdef OSIOP_DEBUG 1700 if (osiop_debug & DEBUG_CMD) 1701 printf("osiop_select: target %x cmd %02x ds %p\n", 1702 acb->xs->xs_periph->periph_target, 1703 acb->xs->cmd->opcode, sc->sc_nexus->ds); 1704 #endif 1705 1706 osiop_start(sc); 1707 1708 return; 1709 } 1710 1711 /* 1712 * 53C710 interrupt handler 1713 */ 1714 1715 void 1716 osiop_intr(sc) 1717 struct osiop_softc *sc; 1718 { 1719 int status, s; 1720 u_int8_t istat, dstat, sstat0; 1721 1722 s = splbio(); 1723 1724 istat = sc->sc_istat; 1725 if ((istat & (OSIOP_ISTAT_SIP | OSIOP_ISTAT_DIP)) == 0) { 1726 splx(s); 1727 return; 1728 } 1729 1730 /* Got a valid interrupt on this device; set by MD handler */ 1731 dstat = sc->sc_dstat; 1732 sstat0 = sc->sc_sstat0; 1733 sc->sc_istat = 0; 1734 #ifdef OSIOP_DEBUG 1735 if (!sc->sc_active) { 1736 /* XXX needs sync */ 1737 printf("%s: spurious interrupt? " 1738 "istat %x dstat %x sstat0 %x nexus %p status %x\n", 1739 sc->sc_dev.dv_xname, istat, dstat, sstat0, sc->sc_nexus, 1740 (sc->sc_nexus != NULL) ? sc->sc_nexus->ds->stat[0] : 0); 1741 } 1742 #endif 1743 1744 #ifdef OSIOP_DEBUG 1745 if (osiop_debug & (DEBUG_INT|DEBUG_CMD)) { 1746 /* XXX needs sync */ 1747 printf("%s: intr istat %x dstat %x sstat0 %x dsps %x " 1748 "sbcl %x dsp %x dcmd %x sts %x msg %x\n", 1749 sc->sc_dev.dv_xname, 1750 istat, dstat, sstat0, 1751 osiop_read_4(sc, OSIOP_DSPS), 1752 osiop_read_1(sc, OSIOP_SBCL), 1753 osiop_read_4(sc, OSIOP_DSP), 1754 osiop_read_4(sc, OSIOP_DBC), 1755 (sc->sc_nexus != NULL) ? sc->sc_nexus->ds->stat[0] : 0, 1756 (sc->sc_nexus != NULL) ? sc->sc_nexus->ds->msgbuf[0] : 0); 1757 } 1758 #endif 1759 if (sc->sc_flags & OSIOP_INTDEFER) { 1760 sc->sc_flags &= ~(OSIOP_INTDEFER | OSIOP_INTSOFF); 1761 osiop_write_1(sc, OSIOP_SIEN, sc->sc_sien); 1762 osiop_write_1(sc, OSIOP_DIEN, sc->sc_dien); 1763 } 1764 if (osiop_checkintr(sc, istat, dstat, sstat0, &status)) { 1765 #if 0 1766 if (status == SCSI_OSIOP_NOSTATUS) 1767 printf("osiop_intr: no valid status \n"); 1768 #endif 1769 if ((sc->sc_flags & (OSIOP_INTSOFF | OSIOP_INTDEFER)) != 1770 OSIOP_INTSOFF) { 1771 #if 0 1772 if (osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) { 1773 struct scsipi_periph *periph; 1774 1775 periph = sc->sc_nexus->xs->xs_periph; 1776 printf("%s: SCSI bus busy at completion" 1777 " targ %d sbcl %02x sfbr %x lcrc " 1778 "%02x dsp +%x\n", sc->sc_dev.dv_xname, 1779 periph->periphtarget, 1780 osiop_read_1(sc, OSIOP_SBCL), 1781 osiop_read_1(sc, OSIOP_SFBR), 1782 osiop_read_1(sc, OSIOP_LCRC), 1783 osiop_read_4(sc, OSIOP_DSP) - 1784 sc->sc_scrdma->dm_segs[0].ds_addr); 1785 } 1786 #endif 1787 osiop_scsidone(sc->sc_nexus, status); 1788 } 1789 } 1790 splx(s); 1791 } 1792 1793 void 1794 osiop_update_xfer_mode(sc, target) 1795 struct osiop_softc *sc; 1796 int target; 1797 { 1798 struct osiop_tinfo *tinfo = &sc->sc_tinfo[target]; 1799 struct scsipi_xfer_mode xm; 1800 1801 xm.xm_target = target; 1802 xm.xm_mode = 0; 1803 xm.xm_period = 0; 1804 xm.xm_offset = 0; 1805 1806 if (tinfo->period) { 1807 xm.xm_mode |= PERIPH_CAP_SYNC; 1808 xm.xm_period = tinfo->period; 1809 xm.xm_offset = tinfo->offset; 1810 } 1811 1812 scsipi_async_event(&sc->sc_channel, ASYNC_EVENT_XFER_MODE, &xm); 1813 } 1814 1815 void 1816 scsi_period_to_osiop(sc, target) 1817 struct osiop_softc *sc; 1818 int target; 1819 { 1820 int period, offset, sxfer, sbcl; 1821 1822 period = sc->sc_tinfo[target].period; 1823 offset = sc->sc_tinfo[target].offset; 1824 for (sbcl = 1; sbcl < 4; sbcl++) { 1825 sxfer = (period * 4 - 1) / sc->sc_tcp[sbcl] - 3; 1826 if (sxfer >= 0 && sxfer <= 7) 1827 break; 1828 } 1829 if (sbcl > 3) { 1830 printf("osiop sync: unable to compute sync params " 1831 "for period %d ns\n", period * 4); 1832 /* 1833 * XXX need to pick a value we can do and renegotiate 1834 */ 1835 sxfer = sbcl = 0; 1836 } else { 1837 sxfer = (sxfer << 4) | ((offset <= OSIOP_MAX_OFFSET) ? 1838 offset : OSIOP_MAX_OFFSET); 1839 #ifdef DEBUG_SYNC 1840 printf("osiop sync: params for period %dns: sxfer %x sbcl %x", 1841 period * 4, sxfer, sbcl); 1842 printf(" actual period %dns\n", 1843 sc->sc_tcp[sbcl] * ((sxfer >> 4) + 4)); 1844 #endif 1845 } 1846 sc->sc_tinfo[target].sxfer = sxfer; 1847 sc->sc_tinfo[target].sbcl = sbcl; 1848 #ifdef DEBUG_SYNC 1849 printf("osiop sync: osiop_sxfr %02x, osiop_sbcl %02x\n", sxfer, sbcl); 1850 #endif 1851 } 1852 1853 void 1854 osiop_timeout(arg) 1855 void *arg; 1856 { 1857 struct osiop_acb *acb = arg; 1858 struct scsipi_xfer *xs = acb->xs; 1859 struct osiop_softc *sc = acb->sc; 1860 int s; 1861 1862 scsipi_printaddr(xs->xs_periph); 1863 printf("command timeout\n"); 1864 1865 s = splbio(); 1866 /* reset the scsi bus */ 1867 osiop_resetbus(sc); 1868 1869 /* deactivate callout */ 1870 callout_stop(&xs->xs_callout); 1871 acb->flags |= ACB_F_TIMEOUT; 1872 osiop_reset(sc); 1873 splx(s); 1874 return; 1875 } 1876 1877 #ifdef OSIOP_DEBUG 1878 1879 #if OSIOP_TRACE_SIZE 1880 void 1881 osiop_dump_trace() 1882 { 1883 int i; 1884 1885 printf("osiop trace: next index %d\n", osiop_trix); 1886 i = osiop_trix; 1887 do { 1888 printf("%3d: '%c' %02x %02x %02x\n", i, 1889 osiop_trbuf[i], osiop_trbuf[i + 1], 1890 osiop_trbuf[i + 2], osiop_trbuf[i + 3]); 1891 i = (i + 4) & (OSIOP_TRACE_SIZE - 1); 1892 } while (i != osiop_trix); 1893 } 1894 #endif 1895 1896 void 1897 osiop_dump_acb(acb) 1898 struct osiop_acb *acb; 1899 { 1900 u_int8_t *b; 1901 int i; 1902 1903 printf("acb@%p ", acb); 1904 if (acb->xs == NULL) { 1905 printf("<unused>\n"); 1906 return; 1907 } 1908 1909 b = (u_int8_t *)&acb->xs->cmd; 1910 printf("(%d:%d) status %2x cmdlen %2ld cmd ", 1911 acb->xs->xs_periph->periph_target, 1912 acb->xs->xs_periph->periph_lun, acb->status, acb->cmdlen); 1913 for (i = acb->cmdlen; i > 0; i--) 1914 printf(" %02x", *b++); 1915 printf("\n"); 1916 printf(" xs: %p data %p:%04x ", acb->xs, acb->xs->data, 1917 acb->xs->datalen); 1918 printf("va %p:%lx ", acb->data, acb->datalen); 1919 printf("cur %lx:%lx\n", acb->curaddr, acb->curlen); 1920 } 1921 1922 void 1923 osiop_dump(sc) 1924 struct osiop_softc *sc; 1925 { 1926 struct osiop_acb *acb; 1927 int i, s; 1928 1929 s = splbio(); 1930 #if OSIOP_TRACE_SIZE 1931 osiop_dump_trace(); 1932 #endif 1933 printf("%s@%p istat %02x\n", 1934 sc->sc_dev.dv_xname, sc, osiop_read_1(sc, OSIOP_ISTAT)); 1935 if ((acb = TAILQ_FIRST(&sc->free_list)) != NULL) { 1936 printf("Free list:\n"); 1937 while (acb) { 1938 osiop_dump_acb(acb); 1939 acb = TAILQ_NEXT(acb, chain); 1940 } 1941 } 1942 if ((acb = TAILQ_FIRST(&sc->ready_list)) != NULL) { 1943 printf("Ready list:\n"); 1944 while (acb) { 1945 osiop_dump_acb(acb); 1946 acb = TAILQ_NEXT(acb, chain); 1947 } 1948 } 1949 if ((acb = TAILQ_FIRST(&sc->nexus_list)) != NULL) { 1950 printf("Nexus list:\n"); 1951 while (acb) { 1952 osiop_dump_acb(acb); 1953 acb = TAILQ_NEXT(acb, chain); 1954 } 1955 } 1956 if (sc->sc_nexus) { 1957 printf("Nexus:\n"); 1958 osiop_dump_acb(sc->sc_nexus); 1959 } 1960 for (i = 0; i < OSIOP_NTGT; i++) { 1961 if (sc->sc_tinfo[i].cmds > 2) { 1962 printf("tgt %d: cmds %d disc %d lubusy %x\n", 1963 i, sc->sc_tinfo[i].cmds, 1964 sc->sc_tinfo[i].dconns, 1965 sc->sc_tinfo[i].lubusy); 1966 } 1967 } 1968 splx(s); 1969 } 1970 #endif 1971