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