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