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