1 /* $NetBSD: siop.c,v 1.43 1999/09/30 22:59:53 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1994 Michael L. Hitch 5 * Copyright (c) 1990 The Regents of the University of California. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Van Jacobson of Lawrence Berkeley Laboratory. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * @(#)siop.c 7.5 (Berkeley) 5/4/91 40 */ 41 42 /* 43 * AMIGA 53C710 scsi adaptor driver 44 */ 45 46 #include "opt_ddb.h" 47 48 #include <sys/param.h> 49 #include <sys/systm.h> 50 #include <sys/device.h> 51 #include <sys/disklabel.h> 52 #include <sys/dkstat.h> 53 #include <sys/buf.h> 54 #include <sys/malloc.h> 55 #include <dev/scsipi/scsi_all.h> 56 #include <dev/scsipi/scsipi_all.h> 57 #include <dev/scsipi/scsiconf.h> 58 #include <machine/cpu.h> 59 #ifdef __m68k__ 60 #include <m68k/cacheops.h> 61 #endif 62 #include <amiga/amiga/custom.h> 63 #include <amiga/amiga/isr.h> 64 #include <amiga/dev/siopreg.h> 65 #include <amiga/dev/siopvar.h> 66 67 /* 68 * SCSI delays 69 * In u-seconds, primarily for state changes on the SPC. 70 */ 71 #define SCSI_CMD_WAIT 500000 /* wait per step of 'immediate' cmds */ 72 #define SCSI_DATA_WAIT 500000 /* wait per data in/out step */ 73 #define SCSI_INIT_WAIT 500000 /* wait per step (both) during init */ 74 75 void siop_select __P((struct siop_softc *)); 76 void siopabort __P((struct siop_softc *, siop_regmap_p, char *)); 77 void sioperror __P((struct siop_softc *, siop_regmap_p, u_char)); 78 void siopstart __P((struct siop_softc *)); 79 int siop_checkintr __P((struct siop_softc *, u_char, u_char, u_char, int *)); 80 void siopreset __P((struct siop_softc *)); 81 void siopsetdelay __P((int)); 82 void siop_scsidone __P((struct siop_acb *, int)); 83 void siop_sched __P((struct siop_softc *)); 84 int siop_poll __P((struct siop_softc *, struct siop_acb *)); 85 void siopintr __P((struct siop_softc *)); 86 void scsi_period_to_siop __P((struct siop_softc *, int)); 87 void siop_start __P((struct siop_softc *, int, int, u_char *, int, u_char *, int)); 88 void siop_dump_acb __P((struct siop_acb *)); 89 90 /* 53C710 script */ 91 const 92 #include <amiga/dev/siop_script.out> 93 94 /* default to not inhibit sync negotiation on any drive */ 95 u_char siop_inhibit_sync[8] = { 0, 0, 0, 0, 0, 0, 0 }; /* initialize, so patchable */ 96 u_char siop_allow_disc[8] = {3, 3, 3, 3, 3, 3, 3, 3}; 97 int siop_no_dma = 0; 98 99 int siop_reset_delay = 250; /* delay after reset, in milleseconds */ 100 101 int siop_cmd_wait = SCSI_CMD_WAIT; 102 int siop_data_wait = SCSI_DATA_WAIT; 103 int siop_init_wait = SCSI_INIT_WAIT; 104 105 #ifdef DEBUG_SYNC 106 /* 107 * sync period transfer lookup - only valid for 66Mhz clock 108 */ 109 static struct { 110 unsigned char p; /* period from sync request message */ 111 unsigned char r; /* siop_period << 4 | sbcl */ 112 } sync_tab[] = { 113 { 60/4, 0<<4 | 1}, 114 { 76/4, 1<<4 | 1}, 115 { 92/4, 2<<4 | 1}, 116 { 92/4, 0<<4 | 2}, 117 {108/4, 3<<4 | 1}, 118 {116/4, 1<<4 | 2}, 119 {120/4, 4<<4 | 1}, 120 {120/4, 0<<4 | 3}, 121 {136/4, 5<<4 | 1}, 122 {140/4, 2<<4 | 2}, 123 {152/4, 6<<4 | 1}, 124 {152/4, 1<<4 | 3}, 125 {164/4, 3<<4 | 2}, 126 {168/4, 7<<4 | 1}, 127 {180/4, 2<<4 | 3}, 128 {184/4, 4<<4 | 2}, 129 {208/4, 5<<4 | 2}, 130 {212/4, 3<<4 | 3}, 131 {232/4, 6<<4 | 2}, 132 {240/4, 4<<4 | 3}, 133 {256/4, 7<<4 | 2}, 134 {272/4, 5<<4 | 3}, 135 {300/4, 6<<4 | 3}, 136 {332/4, 7<<4 | 3} 137 }; 138 #endif 139 140 #ifdef DEBUG 141 /* 142 * 0x01 - full debug 143 * 0x02 - DMA chaining 144 * 0x04 - siopintr 145 * 0x08 - phase mismatch 146 * 0x10 - <not used> 147 * 0x20 - panic on unhandled exceptions 148 * 0x100 - disconnect/reselect 149 */ 150 int siop_debug = 0; 151 int siopsync_debug = 0; 152 int siopdma_hits = 0; 153 int siopdma_misses = 0; 154 int siopchain_ints = 0; 155 int siopstarts = 0; 156 int siopints = 0; 157 int siopphmm = 0; 158 #define SIOP_TRACE_SIZE 128 159 #define SIOP_TRACE(a,b,c,d) \ 160 siop_trbuf[siop_trix] = (a); \ 161 siop_trbuf[siop_trix+1] = (b); \ 162 siop_trbuf[siop_trix+2] = (c); \ 163 siop_trbuf[siop_trix+3] = (d); \ 164 siop_trix = (siop_trix + 4) & (SIOP_TRACE_SIZE - 1); 165 u_char siop_trbuf[SIOP_TRACE_SIZE]; 166 int siop_trix; 167 void siop_dump __P((struct siop_softc *)); 168 void siop_dump_trace __P((void)); 169 #else 170 #define SIOP_TRACE(a,b,c,d) 171 #endif 172 173 174 /* 175 * default minphys routine for siop based controllers 176 */ 177 void 178 siop_minphys(bp) 179 struct buf *bp; 180 { 181 182 /* 183 * No max transfer at this level. 184 */ 185 minphys(bp); 186 } 187 188 /* 189 * used by specific siop controller 190 * 191 */ 192 int 193 siop_scsicmd(xs) 194 struct scsipi_xfer *xs; 195 { 196 struct siop_acb *acb; 197 struct siop_softc *sc; 198 struct scsipi_link *slp; 199 int flags, s; 200 201 slp = xs->sc_link; 202 sc = slp->adapter_softc; 203 flags = xs->xs_control; 204 205 /* XXXX ?? */ 206 if (flags & XS_CTL_DATA_UIO) 207 panic("siop: scsi data uio requested"); 208 209 /* XXXX ?? */ 210 if (sc->sc_nexus && flags & XS_CTL_POLL) 211 /* panic("siop_scsicmd: busy");*/ 212 printf("siop_scsicmd: busy\n"); 213 214 s = splbio(); 215 acb = sc->free_list.tqh_first; 216 if (acb) { 217 TAILQ_REMOVE(&sc->free_list, acb, chain); 218 } 219 splx(s); 220 221 if (acb == NULL) { 222 xs->error = XS_DRIVER_STUFFUP; 223 return(TRY_AGAIN_LATER); 224 } 225 226 acb->flags = ACB_ACTIVE; 227 acb->xs = xs; 228 bcopy(xs->cmd, &acb->cmd, xs->cmdlen); 229 acb->clen = xs->cmdlen; 230 acb->daddr = xs->data; 231 acb->dleft = xs->datalen; 232 233 s = splbio(); 234 TAILQ_INSERT_TAIL(&sc->ready_list, acb, chain); 235 236 if (sc->sc_nexus == NULL) 237 siop_sched(sc); 238 239 splx(s); 240 241 if (flags & XS_CTL_POLL || siop_no_dma) 242 return(siop_poll(sc, acb)); 243 return(SUCCESSFULLY_QUEUED); 244 } 245 246 int 247 siop_poll(sc, acb) 248 struct siop_softc *sc; 249 struct siop_acb *acb; 250 { 251 siop_regmap_p rp = sc->sc_siopp; 252 struct scsipi_xfer *xs = acb->xs; 253 int i; 254 int status; 255 u_char istat; 256 u_char dstat; 257 u_char sstat0; 258 int s; 259 int to; 260 261 s = splbio(); 262 to = xs->timeout / 1000; 263 if (sc->nexus_list.tqh_first) 264 printf("%s: siop_poll called with disconnected device\n", 265 sc->sc_dev.dv_xname); 266 for (;;) { 267 /* use cmd_wait values? */ 268 i = 50000; 269 /* XXX spl0(); */ 270 while (((istat = rp->siop_istat) & 271 (SIOP_ISTAT_SIP | SIOP_ISTAT_DIP)) == 0) { 272 if (--i <= 0) { 273 #ifdef DEBUG 274 printf ("waiting: tgt %d cmd %02x sbcl %02x dsp %lx (+%lx) dcmd %lx ds %p timeout %d\n", 275 xs->sc_link->scsipi_scsi.target, acb->cmd.opcode, 276 rp->siop_sbcl, rp->siop_dsp, 277 rp->siop_dsp - sc->sc_scriptspa, 278 *((long *)&rp->siop_dcmd), &acb->ds, acb->xs->timeout); 279 #endif 280 i = 50000; 281 --to; 282 if (to <= 0) { 283 siopreset(sc); 284 return(COMPLETE); 285 } 286 } 287 delay(20); 288 } 289 sstat0 = rp->siop_sstat0; 290 dstat = rp->siop_dstat; 291 if (siop_checkintr(sc, istat, dstat, sstat0, &status)) { 292 if (acb != sc->sc_nexus) 293 printf("%s: siop_poll disconnected device completed\n", 294 sc->sc_dev.dv_xname); 295 else if ((sc->sc_flags & SIOP_INTDEFER) == 0) { 296 sc->sc_flags &= ~SIOP_INTSOFF; 297 rp->siop_sien = sc->sc_sien; 298 rp->siop_dien = sc->sc_dien; 299 } 300 siop_scsidone(sc->sc_nexus, status); 301 } 302 303 if (xs->xs_status & XS_STS_DONE) 304 break; 305 } 306 splx(s); 307 return (COMPLETE); 308 } 309 310 /* 311 * start next command that's ready 312 */ 313 void 314 siop_sched(sc) 315 struct siop_softc *sc; 316 { 317 struct scsipi_link *slp; 318 struct siop_acb *acb; 319 int i; 320 321 #ifdef DEBUG 322 if (sc->sc_nexus) { 323 printf("%s: siop_sched- nexus %p/%d ready %p/%d\n", 324 sc->sc_dev.dv_xname, sc->sc_nexus, 325 sc->sc_nexus->xs->sc_link->scsipi_scsi.target, 326 sc->ready_list.tqh_first, 327 sc->ready_list.tqh_first->xs->sc_link->scsipi_scsi.target); 328 return; 329 } 330 #endif 331 for (acb = sc->ready_list.tqh_first; acb; acb = acb->chain.tqe_next) { 332 slp = acb->xs->sc_link; 333 i = slp->scsipi_scsi.target; 334 if(!(sc->sc_tinfo[i].lubusy & (1 << slp->scsipi_scsi.lun))) { 335 struct siop_tinfo *ti = &sc->sc_tinfo[i]; 336 337 TAILQ_REMOVE(&sc->ready_list, acb, chain); 338 sc->sc_nexus = acb; 339 slp = acb->xs->sc_link; 340 ti = &sc->sc_tinfo[slp->scsipi_scsi.target]; 341 ti->lubusy |= (1 << slp->scsipi_scsi.lun); 342 break; 343 } 344 } 345 346 if (acb == NULL) { 347 #ifdef DEBUGXXX 348 printf("%s: siop_sched didn't find ready command\n", 349 sc->sc_dev.dv_xname); 350 #endif 351 return; 352 } 353 354 if (acb->xs->xs_control & XS_CTL_RESET) 355 siopreset(sc); 356 357 #if 0 358 acb->cmd.bytes[0] |= slp->scsipi_scsi.lun << 5; /* XXXX */ 359 #endif 360 ++sc->sc_active; 361 siop_select(sc); 362 } 363 364 void 365 siop_scsidone(acb, stat) 366 struct siop_acb *acb; 367 int stat; 368 { 369 struct scsipi_xfer *xs; 370 struct scsipi_link *slp; 371 struct siop_softc *sc; 372 int dosched = 0; 373 374 if (acb == NULL || (xs = acb->xs) == NULL) { 375 #ifdef DIAGNOSTIC 376 printf("siop_scsidone: NULL acb or scsipi_xfer\n"); 377 #if defined(DEBUG) && defined(DDB) 378 Debugger(); 379 #endif 380 #endif 381 return; 382 } 383 slp = xs->sc_link; 384 sc = slp->adapter_softc; 385 /* 386 * is this right? 387 */ 388 xs->status = stat; 389 390 if (xs->error == XS_NOERROR && !(acb->flags & ACB_CHKSENSE)) { 391 if (stat == SCSI_CHECK) { 392 struct scsipi_sense *ss = (void *)&acb->cmd; 393 bzero(ss, sizeof(*ss)); 394 ss->opcode = REQUEST_SENSE; 395 ss->byte2 = slp->scsipi_scsi.lun << 5; 396 ss->length = sizeof(struct scsipi_sense_data); 397 acb->clen = sizeof(*ss); 398 acb->daddr = (char *)&xs->sense.scsi_sense; 399 acb->dleft = sizeof(struct scsipi_sense_data); 400 acb->flags = ACB_ACTIVE | ACB_CHKSENSE; 401 TAILQ_INSERT_HEAD(&sc->ready_list, acb, chain); 402 --sc->sc_active; 403 sc->sc_tinfo[slp->scsipi_scsi.target].lubusy &= 404 ~(1 << slp->scsipi_scsi.lun); 405 sc->sc_tinfo[slp->scsipi_scsi.target].senses++; 406 if (sc->sc_nexus == acb) { 407 sc->sc_nexus = NULL; 408 siop_sched(sc); 409 } 410 SIOP_TRACE('d','s',0,0) 411 return; 412 } 413 } 414 if (xs->error == XS_NOERROR && (acb->flags & ACB_CHKSENSE)) { 415 xs->error = XS_SENSE; 416 } else { 417 xs->resid = 0; /* XXXX */ 418 } 419 #if whataboutthisone 420 case SCSI_BUSY: 421 xs->error = XS_BUSY; 422 break; 423 #endif 424 xs->xs_status |= XS_STS_DONE; 425 426 /* 427 * Remove the ACB from whatever queue it's on. We have to do a bit of 428 * a hack to figure out which queue it's on. Note that it is *not* 429 * necessary to cdr down the ready queue, but we must cdr down the 430 * nexus queue and see if it's there, so we can mark the unit as no 431 * longer busy. This code is sickening, but it works. 432 */ 433 if (acb == sc->sc_nexus) { 434 sc->sc_nexus = NULL; 435 sc->sc_tinfo[slp->scsipi_scsi.target].lubusy &= 436 ~(1<<slp->scsipi_scsi.lun); 437 if (sc->ready_list.tqh_first) 438 dosched = 1; /* start next command */ 439 --sc->sc_active; 440 SIOP_TRACE('d','a',stat,0) 441 } else if (sc->ready_list.tqh_last == &acb->chain.tqe_next) { 442 TAILQ_REMOVE(&sc->ready_list, acb, chain); 443 SIOP_TRACE('d','r',stat,0) 444 } else { 445 register struct siop_acb *acb2; 446 for (acb2 = sc->nexus_list.tqh_first; acb2; 447 acb2 = acb2->chain.tqe_next) 448 if (acb2 == acb) { 449 TAILQ_REMOVE(&sc->nexus_list, acb, chain); 450 sc->sc_tinfo[slp->scsipi_scsi.target].lubusy 451 &= ~(1<<slp->scsipi_scsi.lun); 452 --sc->sc_active; 453 break; 454 } 455 if (acb2) 456 ; 457 else if (acb->chain.tqe_next) { 458 TAILQ_REMOVE(&sc->ready_list, acb, chain); 459 --sc->sc_active; 460 } else { 461 printf("%s: can't find matching acb\n", 462 sc->sc_dev.dv_xname); 463 #ifdef DDB 464 /* Debugger(); */ 465 #endif 466 } 467 SIOP_TRACE('d','n',stat,0); 468 } 469 /* Put it on the free list. */ 470 acb->flags = ACB_FREE; 471 TAILQ_INSERT_HEAD(&sc->free_list, acb, chain); 472 473 sc->sc_tinfo[slp->scsipi_scsi.target].cmds++; 474 475 scsipi_done(xs); 476 477 if (dosched && sc->sc_nexus == NULL) 478 siop_sched(sc); 479 } 480 481 void 482 siopabort(sc, rp, where) 483 register struct siop_softc *sc; 484 siop_regmap_p rp; 485 char *where; 486 { 487 #ifdef fix_this 488 int i; 489 #endif 490 491 printf ("%s: abort %s: dstat %02x, sstat0 %02x sbcl %02x\n", 492 sc->sc_dev.dv_xname, 493 where, rp->siop_dstat, rp->siop_sstat0, rp->siop_sbcl); 494 495 if (sc->sc_active > 0) { 496 #ifdef TODO 497 SET_SBIC_cmd (rp, SBIC_CMD_ABORT); 498 WAIT_CIP (rp); 499 500 GET_SBIC_asr (rp, asr); 501 if (asr & (SBIC_ASR_BSY|SBIC_ASR_LCI)) 502 { 503 /* ok, get more drastic.. */ 504 505 SET_SBIC_cmd (rp, SBIC_CMD_RESET); 506 delay(25); 507 SBIC_WAIT(rp, SBIC_ASR_INT, 0); 508 GET_SBIC_csr (rp, csr); /* clears interrupt also */ 509 510 return; 511 } 512 513 do 514 { 515 SBIC_WAIT (rp, SBIC_ASR_INT, 0); 516 GET_SBIC_csr (rp, csr); 517 } 518 while ((csr != SBIC_CSR_DISC) && (csr != SBIC_CSR_DISC_1) 519 && (csr != SBIC_CSR_CMD_INVALID)); 520 #endif 521 522 /* lets just hope it worked.. */ 523 #ifdef fix_this 524 for (i = 0; i < 2; ++i) { 525 if (sc->sc_iob[i].sc_xs && &sc->sc_iob[i] != 526 sc->sc_cur) { 527 printf ("siopabort: cleanup!\n"); 528 sc->sc_iob[i].sc_xs = NULL; 529 } 530 } 531 #endif /* fix_this */ 532 /* sc->sc_active = 0; */ 533 } 534 } 535 536 void 537 siopinitialize(sc) 538 struct siop_softc *sc; 539 { 540 int i; 541 u_int inhibit_sync; 542 extern u_long scsi_nosync; 543 extern int shift_nosync; 544 545 /* 546 * Need to check that scripts is on a long word boundary 547 * Also should verify that dev doesn't span non-contiguous 548 * physical pages. 549 */ 550 sc->sc_scriptspa = kvtop((caddr_t)scripts); 551 552 /* 553 * malloc sc_acb to ensure that DS is on a long word boundary. 554 */ 555 556 MALLOC(sc->sc_acb, struct siop_acb *, 557 sizeof(struct siop_acb) * SIOP_NACB, M_DEVBUF, M_NOWAIT); 558 if (sc->sc_acb == NULL) 559 panic("siopinitialize: ACB malloc failed!"); 560 561 sc->sc_tcp[1] = 1000 / sc->sc_clock_freq; 562 sc->sc_tcp[2] = 1500 / sc->sc_clock_freq; 563 sc->sc_tcp[3] = 2000 / sc->sc_clock_freq; 564 sc->sc_minsync = sc->sc_tcp[1]; /* in 4ns units */ 565 if (sc->sc_minsync < 25) 566 sc->sc_minsync = 25; 567 if (sc->sc_clock_freq <= 25) { 568 sc->sc_dcntl |= 0x80; /* SCLK/1 */ 569 sc->sc_tcp[0] = sc->sc_tcp[1]; 570 } else if (sc->sc_clock_freq <= 37) { 571 sc->sc_dcntl |= 0x40; /* SCLK/1.5 */ 572 sc->sc_tcp[0] = sc->sc_tcp[2]; 573 } else if (sc->sc_clock_freq <= 50) { 574 sc->sc_dcntl |= 0x00; /* SCLK/2 */ 575 sc->sc_tcp[0] = sc->sc_tcp[3]; 576 } else { 577 sc->sc_dcntl |= 0xc0; /* SCLK/3 */ 578 sc->sc_tcp[0] = 3000 / sc->sc_clock_freq; 579 } 580 581 if (scsi_nosync) { 582 inhibit_sync = (scsi_nosync >> shift_nosync) & 0xff; 583 shift_nosync += 8; 584 #ifdef DEBUG 585 if (inhibit_sync) 586 printf("%s: Inhibiting synchronous transfer %02x\n", 587 sc->sc_dev.dv_xname, inhibit_sync); 588 #endif 589 for (i = 0; i < 8; ++i) 590 if (inhibit_sync & (1 << i)) 591 siop_inhibit_sync[i] = 1; 592 } 593 594 siopreset (sc); 595 } 596 597 void 598 siopreset(sc) 599 struct siop_softc *sc; 600 { 601 siop_regmap_p rp; 602 u_int i, s; 603 u_char dummy; 604 struct siop_acb *acb; 605 606 rp = sc->sc_siopp; 607 608 if (sc->sc_flags & SIOP_ALIVE) 609 siopabort(sc, rp, "reset"); 610 611 printf("%s: ", sc->sc_dev.dv_xname); /* XXXX */ 612 613 s = splbio(); 614 615 /* 616 * Reset the chip 617 * XXX - is this really needed? 618 */ 619 rp->siop_istat |= SIOP_ISTAT_ABRT; /* abort current script */ 620 rp->siop_istat |= SIOP_ISTAT_RST; /* reset chip */ 621 rp->siop_istat &= ~SIOP_ISTAT_RST; 622 /* 623 * Reset SCSI bus (do we really want this?) 624 */ 625 rp->siop_sien = 0; 626 rp->siop_scntl1 |= SIOP_SCNTL1_RST; 627 delay(1); 628 rp->siop_scntl1 &= ~SIOP_SCNTL1_RST; 629 630 /* 631 * Set up various chip parameters 632 */ 633 rp->siop_scntl0 = SIOP_ARB_FULL | SIOP_SCNTL0_EPC | SIOP_SCNTL0_EPG; 634 rp->siop_scntl1 = SIOP_SCNTL1_ESR; 635 rp->siop_dcntl = sc->sc_dcntl; 636 rp->siop_dmode = 0x80; /* burst length = 4 */ 637 rp->siop_sien = 0x00; /* don't enable interrupts yet */ 638 rp->siop_dien = 0x00; /* don't enable interrupts yet */ 639 rp->siop_scid = 1 << sc->sc_link.scsipi_scsi.adapter_target; 640 rp->siop_dwt = 0x00; 641 rp->siop_ctest0 |= SIOP_CTEST0_BTD | SIOP_CTEST0_EAN; 642 rp->siop_ctest7 |= sc->sc_ctest7; 643 644 /* will need to re-negotiate sync xfers */ 645 bzero(&sc->sc_sync, sizeof (sc->sc_sync)); 646 647 i = rp->siop_istat; 648 if (i & SIOP_ISTAT_SIP) 649 dummy = rp->siop_sstat0; 650 if (i & SIOP_ISTAT_DIP) 651 dummy = rp->siop_dstat; 652 653 splx (s); 654 655 delay (siop_reset_delay * 1000); 656 printf("siop id %d reset V%d\n", sc->sc_link.scsipi_scsi.adapter_target, 657 rp->siop_ctest8 >> 4); 658 659 if ((sc->sc_flags & SIOP_ALIVE) == 0) { 660 TAILQ_INIT(&sc->ready_list); 661 TAILQ_INIT(&sc->nexus_list); 662 TAILQ_INIT(&sc->free_list); 663 sc->sc_nexus = NULL; 664 acb = sc->sc_acb; 665 bzero(acb, sizeof(struct siop_acb) * SIOP_NACB); 666 for (i = 0; i < SIOP_NACB; i++) { 667 TAILQ_INSERT_TAIL(&sc->free_list, acb, chain); 668 acb++; 669 } 670 bzero(sc->sc_tinfo, sizeof(sc->sc_tinfo)); 671 } else { 672 if (sc->sc_nexus != NULL) { 673 sc->sc_nexus->xs->error = XS_DRIVER_STUFFUP; 674 siop_scsidone(sc->sc_nexus, sc->sc_nexus->stat[0]); 675 } 676 while ((acb = sc->nexus_list.tqh_first) > 0) { 677 acb->xs->error = XS_DRIVER_STUFFUP; 678 siop_scsidone(acb, acb->stat[0]); 679 } 680 } 681 682 sc->sc_flags |= SIOP_ALIVE; 683 sc->sc_flags &= ~(SIOP_INTDEFER|SIOP_INTSOFF); 684 /* enable SCSI and DMA interrupts */ 685 sc->sc_sien = SIOP_SIEN_M_A | SIOP_SIEN_STO | /*SIOP_SIEN_SEL |*/ SIOP_SIEN_SGE | 686 SIOP_SIEN_UDC | SIOP_SIEN_RST | SIOP_SIEN_PAR; 687 sc->sc_dien = SIOP_DIEN_BF | SIOP_DIEN_ABRT | SIOP_DIEN_SIR | 688 /*SIOP_DIEN_WTD |*/ SIOP_DIEN_IID; 689 rp->siop_sien = sc->sc_sien; 690 rp->siop_dien = sc->sc_dien; 691 } 692 693 /* 694 * Setup Data Storage for 53C710 and start SCRIPTS processing 695 */ 696 697 void 698 siop_start (sc, target, lun, cbuf, clen, buf, len) 699 struct siop_softc *sc; 700 int target; 701 int lun; 702 u_char *cbuf; 703 int clen; 704 u_char *buf; 705 int len; 706 { 707 siop_regmap_p rp = sc->sc_siopp; 708 int nchain; 709 int count, tcount; 710 char *addr, *dmaend; 711 struct siop_acb *acb = sc->sc_nexus; 712 #ifdef DEBUG 713 int i; 714 #endif 715 716 #ifdef DEBUG 717 if (siop_debug & 0x100 && rp->siop_sbcl & SIOP_BSY) { 718 printf ("ACK! siop was busy: rp %p script %p dsa %p active %ld\n", 719 rp, &scripts, &acb->ds, sc->sc_active); 720 printf ("istat %02x sfbr %02x lcrc %02x sien %02x dien %02x\n", 721 rp->siop_istat, rp->siop_sfbr, rp->siop_lcrc, 722 rp->siop_sien, rp->siop_dien); 723 #ifdef DDB 724 /*Debugger();*/ 725 #endif 726 } 727 #endif 728 acb->msgout[0] = MSG_IDENTIFY | lun; 729 if (siop_allow_disc[target] & 2 || 730 (siop_allow_disc[target] && len == 0)) 731 acb->msgout[0] = MSG_IDENTIFY_DR | lun; 732 acb->status = 0; 733 acb->stat[0] = -1; 734 acb->msg[0] = -1; 735 acb->ds.scsi_addr = (0x10000 << target) | (sc->sc_sync[target].sxfer << 8); 736 acb->ds.idlen = 1; 737 acb->ds.idbuf = (char *) kvtop(&acb->msgout[0]); 738 acb->ds.cmdlen = clen; 739 acb->ds.cmdbuf = (char *) kvtop(cbuf); 740 acb->ds.stslen = 1; 741 acb->ds.stsbuf = (char *) kvtop(&acb->stat[0]); 742 acb->ds.msglen = 1; 743 acb->ds.msgbuf = (char *) kvtop(&acb->msg[0]); 744 acb->msg[1] = -1; 745 acb->ds.msginlen = 1; 746 acb->ds.extmsglen = 1; 747 acb->ds.synmsglen = 3; 748 acb->ds.msginbuf = (char *) kvtop(&acb->msg[1]); 749 acb->ds.extmsgbuf = (char *) kvtop(&acb->msg[2]); 750 acb->ds.synmsgbuf = (char *) kvtop(&acb->msg[3]); 751 bzero(&acb->ds.chain, sizeof (acb->ds.chain)); 752 753 /* 754 * Negotiate wide is the initial negotiation state; since the 53c710 755 * doesn't do wide transfers, just begin the synchronous transfer 756 * negotation here. 757 */ 758 if (sc->sc_sync[target].state == NEG_WIDE) { 759 if (siop_inhibit_sync[target]) { 760 sc->sc_sync[target].state = NEG_DONE; 761 sc->sc_sync[target].sbcl = 0; 762 sc->sc_sync[target].sxfer = 0; 763 #ifdef DEBUG 764 if (siopsync_debug) 765 printf ("Forcing target %d asynchronous\n", target); 766 #endif 767 } 768 else { 769 acb->msg[2] = -1; 770 acb->msgout[1] = MSG_EXT_MESSAGE; 771 acb->msgout[2] = 3; 772 acb->msgout[3] = MSG_SYNC_REQ; 773 #ifdef MAXTOR_SYNC_KLUDGE 774 acb->msgout[4] = 50 / 4; /* ask for ridiculous period */ 775 #else 776 acb->msgout[4] = sc->sc_minsync; 777 #endif 778 acb->msgout[5] = SIOP_MAX_OFFSET; 779 acb->ds.idlen = 6; 780 sc->sc_sync[target].state = NEG_WAITS; 781 #ifdef DEBUG 782 if (siopsync_debug) 783 printf ("Sending sync request to target %d\n", target); 784 #endif 785 } 786 } 787 788 /* 789 * Build physical DMA addresses for scatter/gather I/O 790 */ 791 acb->iob_buf = buf; 792 acb->iob_len = len; 793 acb->iob_curbuf = acb->iob_curlen = 0; 794 nchain = 0; 795 count = len; 796 addr = buf; 797 dmaend = NULL; 798 while (count > 0) { 799 acb->ds.chain[nchain].databuf = (char *) kvtop (addr); 800 if (count < (tcount = NBPG - ((int) addr & PGOFSET))) 801 tcount = count; 802 acb->ds.chain[nchain].datalen = tcount; 803 addr += tcount; 804 count -= tcount; 805 if (acb->ds.chain[nchain].databuf == dmaend) { 806 dmaend += acb->ds.chain[nchain].datalen; 807 acb->ds.chain[nchain].datalen = 0; 808 acb->ds.chain[--nchain].datalen += tcount; 809 #ifdef DEBUG 810 ++siopdma_hits; 811 #endif 812 } 813 else { 814 dmaend = acb->ds.chain[nchain].databuf + 815 acb->ds.chain[nchain].datalen; 816 acb->ds.chain[nchain].datalen = tcount; 817 #ifdef DEBUG 818 if (nchain) /* Don't count miss on first one */ 819 ++siopdma_misses; 820 #endif 821 } 822 ++nchain; 823 } 824 #ifdef DEBUG 825 if (nchain != 1 && len != 0 && siop_debug & 3) { 826 printf ("DMA chaining set: %d\n", nchain); 827 for (i = 0; i < nchain; ++i) { 828 printf (" [%d] %8p %lx\n", i, acb->ds.chain[i].databuf, 829 acb->ds.chain[i].datalen); 830 } 831 } 832 #endif 833 834 /* push data cache for all data the 53c710 needs to access */ 835 dma_cachectl ((caddr_t)acb, sizeof (struct siop_acb)); 836 dma_cachectl (cbuf, clen); 837 if (buf != NULL && len != 0) 838 dma_cachectl (buf, len); 839 #ifdef DEBUG 840 if (siop_debug & 0x100 && rp->siop_sbcl & SIOP_BSY) { 841 printf ("ACK! siop was busy at start: rp %p script %p dsa %p active %ld\n", 842 rp, &scripts, &acb->ds, sc->sc_active); 843 #ifdef DDB 844 /*Debugger();*/ 845 #endif 846 } 847 #endif 848 if (sc->nexus_list.tqh_first == NULL) { 849 if (rp->siop_istat & SIOP_ISTAT_CON) 850 printf("%s: siop_select while connected?\n", 851 sc->sc_dev.dv_xname); 852 rp->siop_temp = 0; 853 rp->siop_sbcl = sc->sc_sync[target].sbcl; 854 rp->siop_dsa = kvtop((caddr_t)&acb->ds); 855 rp->siop_dsp = sc->sc_scriptspa; 856 SIOP_TRACE('s',1,0,0) 857 } else { 858 if ((rp->siop_istat & SIOP_ISTAT_CON) == 0) { 859 rp->siop_istat = SIOP_ISTAT_SIGP; 860 SIOP_TRACE('s',2,0,0); 861 } 862 else { 863 SIOP_TRACE('s',3,rp->siop_istat,0); 864 } 865 } 866 #ifdef DEBUG 867 ++siopstarts; 868 #endif 869 } 870 871 /* 872 * Process a DMA or SCSI interrupt from the 53C710 SIOP 873 */ 874 875 int 876 siop_checkintr(sc, istat, dstat, sstat0, status) 877 struct siop_softc *sc; 878 u_char istat; 879 u_char dstat; 880 u_char sstat0; 881 int *status; 882 { 883 siop_regmap_p rp = sc->sc_siopp; 884 struct siop_acb *acb = sc->sc_nexus; 885 int target = 0; 886 int dfifo, dbc, sstat1; 887 888 dfifo = rp->siop_dfifo; 889 dbc = rp->siop_dbc0; 890 sstat1 = rp->siop_sstat1; 891 rp->siop_ctest8 |= SIOP_CTEST8_CLF; 892 while ((rp->siop_ctest1 & SIOP_CTEST1_FMT) != SIOP_CTEST1_FMT) 893 ; 894 rp->siop_ctest8 &= ~SIOP_CTEST8_CLF; 895 #ifdef DEBUG 896 ++siopints; 897 #if 0 898 if (siop_debug & 0x100) { 899 DCIAS(&acb->stat[0]); /* XXX */ 900 printf ("siopchkintr: istat %x dstat %x sstat0 %x dsps %x sbcl %x sts %x msg %x\n", 901 istat, dstat, sstat0, rp->siop_dsps, rp->siop_sbcl, acb->stat[0], acb->msg[0]); 902 printf ("sync msg in: %02x %02x %02x %02x %02x %02x\n", 903 acb->msg[0], acb->msg[1], acb->msg[2], 904 acb->msg[3], acb->msg[4], acb->msg[5]); 905 } 906 #endif 907 if (rp->siop_dsp && (rp->siop_dsp < sc->sc_scriptspa || 908 rp->siop_dsp >= sc->sc_scriptspa + sizeof(scripts))) { 909 printf ("%s: dsp not within script dsp %lx scripts %lx:%lx", 910 sc->sc_dev.dv_xname, rp->siop_dsp, sc->sc_scriptspa, 911 sc->sc_scriptspa + sizeof(scripts)); 912 printf(" istat %x dstat %x sstat0 %x\n", 913 istat, dstat, sstat0); 914 #ifdef DDB 915 Debugger(); 916 #endif 917 } 918 #endif 919 SIOP_TRACE('i',dstat,istat,(istat&SIOP_ISTAT_DIP)?rp->siop_dsps&0xff:sstat0); 920 if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff00) { 921 /* Normal completion status, or check condition */ 922 #ifdef DEBUG 923 if (rp->siop_dsa != kvtop((caddr_t)&acb->ds)) { 924 printf ("siop: invalid dsa: %lx %x\n", rp->siop_dsa, 925 kvtop((caddr_t)&acb->ds)); 926 panic("*** siop DSA invalid ***"); 927 } 928 #endif 929 target = acb->xs->sc_link->scsipi_scsi.target; 930 if (sc->sc_sync[target].state == NEG_WAITS) { 931 if (acb->msg[1] == 0xff) 932 printf ("%s: target %d ignored sync request\n", 933 sc->sc_dev.dv_xname, target); 934 else if (acb->msg[1] == MSG_REJECT) 935 printf ("%s: target %d rejected sync request\n", 936 sc->sc_dev.dv_xname, target); 937 else 938 /* XXX - need to set sync transfer parameters */ 939 printf("%s: target %d (sync) %02x %02x %02x\n", 940 sc->sc_dev.dv_xname, target, acb->msg[1], 941 acb->msg[2], acb->msg[3]); 942 sc->sc_sync[target].state = NEG_DONE; 943 } 944 dma_cachectl(&acb->stat[0], 1); 945 *status = acb->stat[0]; 946 #ifdef DEBUG 947 if (rp->siop_sbcl & SIOP_BSY) { 948 /*printf ("ACK! siop was busy at end: rp %x script %x dsa %x\n", 949 rp, &scripts, &acb->ds);*/ 950 #ifdef DDB 951 /*Debugger();*/ 952 #endif 953 } 954 if (acb->msg[0] != 0x00) 955 printf("%s: message was not COMMAND COMPLETE: %x\n", 956 sc->sc_dev.dv_xname, acb->msg[0]); 957 #endif 958 if (sc->nexus_list.tqh_first) 959 rp->siop_dcntl |= SIOP_DCNTL_STD; 960 return 1; 961 } 962 if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff0b) { 963 target = acb->xs->sc_link->scsipi_scsi.target; 964 if (acb->msg[1] == MSG_EXT_MESSAGE && acb->msg[2] == 3 && 965 acb->msg[3] == MSG_SYNC_REQ) { 966 #ifdef DEBUG 967 if (siopsync_debug) 968 printf ("sync msg in: %02x %02x %02x %02x %02x %02x\n", 969 acb->msg[0], acb->msg[1], acb->msg[2], 970 acb->msg[3], acb->msg[4], acb->msg[5]); 971 #endif 972 sc->sc_sync[target].sxfer = 0; 973 sc->sc_sync[target].sbcl = 0; 974 if (acb->msg[2] == 3 && 975 acb->msg[3] == MSG_SYNC_REQ && 976 acb->msg[5] != 0) { 977 #ifdef MAXTOR_KLUDGE 978 /* 979 * Kludge for my Maxtor XT8580S 980 * It accepts whatever we request, even 981 * though it won't work. So we ask for 982 * a short period than we can handle. If 983 * the device says it can do it, use 208ns. 984 * If the device says it can do less than 985 * 100ns, then we limit it to 100ns. 986 */ 987 if (acb->msg[4] && acb->msg[4] < 100 / 4) { 988 #ifdef DEBUG 989 printf ("%d: target %d wanted %dns period\n", 990 sc->sc_dev.dv_xname, target, 991 acb->msg[4] * 4); 992 #endif 993 if (acb->msg[4] == 50 / 4) 994 acb->msg[4] = 208 / 4; 995 else 996 acb->msg[4] = 100 / 4; 997 } 998 #endif /* MAXTOR_KLUDGE */ 999 printf ("%s: target %d now synchronous, period=%dns, offset=%d\n", 1000 sc->sc_dev.dv_xname, target, 1001 acb->msg[4] * 4, acb->msg[5]); 1002 scsi_period_to_siop (sc, target); 1003 } 1004 rp->siop_sxfer = sc->sc_sync[target].sxfer; 1005 rp->siop_sbcl = sc->sc_sync[target].sbcl; 1006 if (sc->sc_sync[target].state == NEG_WAITS) { 1007 sc->sc_sync[target].state = NEG_DONE; 1008 rp->siop_dsp = sc->sc_scriptspa + Ent_clear_ack; 1009 return(0); 1010 } 1011 rp->siop_dcntl |= SIOP_DCNTL_STD; 1012 sc->sc_sync[target].state = NEG_DONE; 1013 return (0); 1014 } 1015 /* XXX - not SDTR message */ 1016 } 1017 if (sstat0 & SIOP_SSTAT0_M_A) { /* Phase mismatch */ 1018 #ifdef DEBUG 1019 ++siopphmm; 1020 if (acb == NULL) 1021 printf("%s: Phase mismatch with no active command?\n", 1022 sc->sc_dev.dv_xname); 1023 #endif 1024 if (acb->iob_len) { 1025 int adjust; 1026 adjust = ((dfifo - (dbc & 0x7f)) & 0x7f); 1027 if (sstat1 & SIOP_SSTAT1_ORF) 1028 ++adjust; 1029 if (sstat1 & SIOP_SSTAT1_OLF) 1030 ++adjust; 1031 acb->iob_curlen = *((long *)&rp->siop_dcmd) & 0xffffff; 1032 acb->iob_curlen += adjust; 1033 acb->iob_curbuf = *((long *)&rp->siop_dnad) - adjust; 1034 #ifdef DEBUG 1035 if (siop_debug & 0x100) { 1036 int i; 1037 printf ("Phase mismatch: curbuf %lx curlen %lx dfifo %x dbc %x sstat1 %x adjust %x sbcl %x starts %d acb %p\n", 1038 acb->iob_curbuf, acb->iob_curlen, dfifo, 1039 dbc, sstat1, adjust, rp->siop_sbcl, siopstarts, acb); 1040 if (acb->ds.chain[1].datalen) { 1041 for (i = 0; acb->ds.chain[i].datalen; ++i) 1042 printf("chain[%d] addr %p len %lx\n", 1043 i, acb->ds.chain[i].databuf, 1044 acb->ds.chain[i].datalen); 1045 } 1046 } 1047 #endif 1048 dma_cachectl ((caddr_t)acb, sizeof(*acb)); 1049 } 1050 #ifdef DEBUG 1051 SIOP_TRACE('m',rp->siop_sbcl,(rp->siop_dsp>>8),rp->siop_dsp); 1052 if (siop_debug & 9) 1053 printf ("Phase mismatch: %x dsp +%lx dcmd %lx\n", 1054 rp->siop_sbcl, 1055 rp->siop_dsp - sc->sc_scriptspa, 1056 *((long *)&rp->siop_dcmd)); 1057 #endif 1058 if ((rp->siop_sbcl & SIOP_REQ) == 0) { 1059 printf ("Phase mismatch: REQ not asserted! %02x dsp %lx\n", 1060 rp->siop_sbcl, rp->siop_dsp); 1061 #if defined(DEBUG) && defined(DDB) 1062 /*Debugger(); XXX is*/ 1063 #endif 1064 } 1065 switch (rp->siop_sbcl & 7) { 1066 case 0: /* data out */ 1067 case 1: /* data in */ 1068 case 2: /* status */ 1069 case 3: /* command */ 1070 case 6: /* message in */ 1071 case 7: /* message out */ 1072 rp->siop_dsp = sc->sc_scriptspa + Ent_switch; 1073 break; 1074 default: 1075 goto bad_phase; 1076 } 1077 return 0; 1078 } 1079 if (sstat0 & SIOP_SSTAT0_STO) { /* Select timed out */ 1080 #ifdef DEBUG 1081 if (acb == NULL) 1082 printf("%s: Select timeout with no active command?\n", 1083 sc->sc_dev.dv_xname); 1084 if (rp->siop_sbcl & SIOP_BSY) { 1085 printf ("ACK! siop was busy at timeout: rp %p script %p dsa %p\n", 1086 rp, &scripts, &acb->ds); 1087 printf(" sbcl %x sdid %x istat %x dstat %x sstat0 %x\n", 1088 rp->siop_sbcl, rp->siop_sdid, istat, dstat, sstat0); 1089 if (!(rp->siop_sbcl & SIOP_BSY)) { 1090 printf ("Yikes, it's not busy now!\n"); 1091 #if 0 1092 *status = -1; 1093 if (sc->nexus_list.tqh_first) 1094 rp->siop_dsp = sc->sc_scriptspa + Ent_wait_reselect; 1095 return 1; 1096 #endif 1097 } 1098 /* rp->siop_dcntl |= SIOP_DCNTL_STD;*/ 1099 return (0); 1100 #ifdef DDB 1101 Debugger(); 1102 #endif 1103 } 1104 #endif 1105 *status = -1; 1106 acb->xs->error = XS_SELTIMEOUT; 1107 if (sc->nexus_list.tqh_first) 1108 rp->siop_dsp = sc->sc_scriptspa + Ent_wait_reselect; 1109 return 1; 1110 } 1111 if (acb) 1112 target = acb->xs->sc_link->scsipi_scsi.target; 1113 else 1114 target = 7; 1115 if (sstat0 & SIOP_SSTAT0_UDC) { 1116 #ifdef DEBUG 1117 if (acb == NULL) 1118 printf("%s: Unexpected disconnect with no active command?\n", 1119 sc->sc_dev.dv_xname); 1120 printf ("%s: target %d disconnected unexpectedly\n", 1121 sc->sc_dev.dv_xname, target); 1122 #endif 1123 #if 0 1124 siopabort (sc, rp, "siopchkintr"); 1125 #endif 1126 *status = STS_BUSY; 1127 if (sc->nexus_list.tqh_first) 1128 rp->siop_dsp = sc->sc_scriptspa + Ent_wait_reselect; 1129 return (acb != NULL); 1130 } 1131 if (dstat & SIOP_DSTAT_SIR && (rp->siop_dsps == 0xff01 || 1132 rp->siop_dsps == 0xff02)) { 1133 #ifdef DEBUG 1134 if (siop_debug & 0x100) 1135 printf ("%s: ID %02x disconnected TEMP %lx (+%lx) curbuf %lx curlen %lx buf %p len %lx dfifo %x dbc %x sstat1 %x starts %d acb %p\n", 1136 sc->sc_dev.dv_xname, 1 << target, rp->siop_temp, 1137 rp->siop_temp ? rp->siop_temp - sc->sc_scriptspa : 0, 1138 acb->iob_curbuf, acb->iob_curlen, 1139 acb->ds.chain[0].databuf, acb->ds.chain[0].datalen, dfifo, dbc, sstat1, siopstarts, acb); 1140 #endif 1141 if (acb == NULL) { 1142 printf("%s: Disconnect with no active command?\n", 1143 sc->sc_dev.dv_xname); 1144 return (0); 1145 } 1146 /* 1147 * XXXX need to update iob_curbuf/iob_curlen to reflect 1148 * current data transferred. If device disconnected in 1149 * the middle of a DMA block, they should already be set 1150 * by the phase change interrupt. If the disconnect 1151 * occurs on a DMA block boundary, we have to figure out 1152 * which DMA block it was. 1153 */ 1154 if (acb->iob_len && rp->siop_temp) { 1155 int n = rp->siop_temp - sc->sc_scriptspa; 1156 1157 if (acb->iob_curlen && acb->iob_curlen != acb->ds.chain[0].datalen) 1158 printf("%s: iob_curbuf/len already set? n %x iob %lx/%lx chain[0] %p/%lx\n", 1159 sc->sc_dev.dv_xname, n, acb->iob_curbuf, acb->iob_curlen, 1160 acb->ds.chain[0].databuf, acb->ds.chain[0].datalen); 1161 if (n < Ent_datain) 1162 n = (n - Ent_dataout) / 16; 1163 else 1164 n = (n - Ent_datain) / 16; 1165 if (n <= 0 && n > DMAMAXIO) 1166 printf("TEMP invalid %d\n", n); 1167 else { 1168 acb->iob_curbuf = (u_long)acb->ds.chain[n].databuf; 1169 acb->iob_curlen = acb->ds.chain[n].datalen; 1170 } 1171 #ifdef DEBUG 1172 if (siop_debug & 0x100) { 1173 printf("%s: TEMP offset %d", sc->sc_dev.dv_xname, n); 1174 printf(" curbuf %lx curlen %lx\n", acb->iob_curbuf, 1175 acb->iob_curlen); 1176 } 1177 #endif 1178 } 1179 /* 1180 * If data transfer was interrupted by disconnect, iob_curbuf 1181 * and iob_curlen should reflect the point of interruption. 1182 * Adjust the DMA chain so that the data transfer begins 1183 * at the appropriate place upon reselection. 1184 * XXX This should only be done on save data pointer message? 1185 */ 1186 if (acb->iob_curlen) { 1187 int i, j; 1188 1189 #ifdef DEBUG 1190 if (siop_debug & 0x100) 1191 printf ("%s: adjusting DMA chain\n", 1192 sc->sc_dev.dv_xname); 1193 if (rp->siop_dsps == 0xff02) 1194 printf ("%s: ID %02x disconnected without Save Data Pointers\n", 1195 sc->sc_dev.dv_xname, 1 << target); 1196 #endif 1197 for (i = 0; i < DMAMAXIO; ++i) { 1198 if (acb->ds.chain[i].datalen == 0) 1199 break; 1200 if (acb->iob_curbuf >= (long)acb->ds.chain[i].databuf && 1201 acb->iob_curbuf < (long)(acb->ds.chain[i].databuf + 1202 acb->ds.chain[i].datalen)) 1203 break; 1204 } 1205 if (i >= DMAMAXIO || acb->ds.chain[i].datalen == 0) { 1206 printf("couldn't find saved data pointer: "); 1207 printf("curbuf %lx curlen %lx i %d\n", 1208 acb->iob_curbuf, acb->iob_curlen, i); 1209 #ifdef DDB 1210 Debugger(); 1211 #endif 1212 } 1213 #ifdef DEBUG 1214 if (siop_debug & 0x100) 1215 printf(" chain[0]: %p/%lx -> %lx/%lx\n", 1216 acb->ds.chain[0].databuf, 1217 acb->ds.chain[0].datalen, 1218 acb->iob_curbuf, 1219 acb->iob_curlen); 1220 #endif 1221 acb->ds.chain[0].databuf = (char *)acb->iob_curbuf; 1222 acb->ds.chain[0].datalen = acb->iob_curlen; 1223 for (j = 1, ++i; i < DMAMAXIO && acb->ds.chain[i].datalen; ++i, ++j) { 1224 #ifdef DEBUG 1225 if (siop_debug & 0x100) 1226 printf(" chain[%d]: %p/%lx -> %p/%lx\n", j, 1227 acb->ds.chain[j].databuf, 1228 acb->ds.chain[j].datalen, 1229 acb->ds.chain[i].databuf, 1230 acb->ds.chain[i].datalen); 1231 #endif 1232 acb->ds.chain[j].databuf = acb->ds.chain[i].databuf; 1233 acb->ds.chain[j].datalen = acb->ds.chain[i].datalen; 1234 } 1235 if (j < DMAMAXIO) 1236 acb->ds.chain[j].datalen = 0; 1237 DCIAS(kvtop((caddr_t)&acb->ds.chain)); 1238 } 1239 ++sc->sc_tinfo[target].dconns; 1240 /* 1241 * add nexus to waiting list 1242 * clear nexus 1243 * try to start another command for another target/lun 1244 */ 1245 acb->status = sc->sc_flags & SIOP_INTSOFF; 1246 TAILQ_INSERT_HEAD(&sc->nexus_list, acb, chain); 1247 sc->sc_nexus = NULL; /* no current device */ 1248 /* start script to wait for reselect */ 1249 if (sc->sc_nexus == NULL) 1250 rp->siop_dsp = sc->sc_scriptspa + Ent_wait_reselect; 1251 /* XXXX start another command ? */ 1252 if (sc->ready_list.tqh_first) 1253 siop_sched(sc); 1254 return (0); 1255 } 1256 if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff03) { 1257 int reselid = rp->siop_scratch & 0x7f; 1258 int reselun = rp->siop_sfbr & 0x07; 1259 1260 sc->sc_sstat1 = rp->siop_sbcl; /* XXXX save current SBCL */ 1261 #ifdef DEBUG 1262 if (siop_debug & 0x100) 1263 printf ("%s: target ID %02x reselected dsps %lx\n", 1264 sc->sc_dev.dv_xname, reselid, 1265 rp->siop_dsps); 1266 if ((rp->siop_sfbr & 0x80) == 0) 1267 printf("%s: Reselect message in was not identify: %x\n", 1268 sc->sc_dev.dv_xname, rp->siop_sfbr); 1269 #endif 1270 if (sc->sc_nexus) { 1271 #ifdef DEBUG 1272 if (siop_debug & 0x100) 1273 printf ("%s: reselect ID %02x w/active\n", 1274 sc->sc_dev.dv_xname, reselid); 1275 #endif 1276 TAILQ_INSERT_HEAD(&sc->ready_list, sc->sc_nexus, chain); 1277 sc->sc_tinfo[sc->sc_nexus->xs->sc_link->scsipi_scsi.target].lubusy 1278 &= ~(1 << sc->sc_nexus->xs->sc_link->scsipi_scsi.lun); 1279 --sc->sc_active; 1280 } 1281 /* 1282 * locate acb of reselecting device 1283 * set sc->sc_nexus to acb 1284 */ 1285 for (acb = sc->nexus_list.tqh_first; acb; 1286 acb = acb->chain.tqe_next) { 1287 if (reselid != (acb->ds.scsi_addr >> 16) || 1288 reselun != (acb->msgout[0] & 0x07)) 1289 continue; 1290 TAILQ_REMOVE(&sc->nexus_list, acb, chain); 1291 sc->sc_nexus = acb; 1292 sc->sc_flags |= acb->status; 1293 acb->status = 0; 1294 DCIAS(kvtop(&acb->stat[0])); 1295 rp->siop_dsa = kvtop((caddr_t)&acb->ds); 1296 rp->siop_sxfer = 1297 sc->sc_sync[acb->xs->sc_link->scsipi_scsi.target].sxfer; 1298 rp->siop_sbcl = 1299 sc->sc_sync[acb->xs->sc_link->scsipi_scsi.target].sbcl; 1300 break; 1301 } 1302 if (acb == NULL) { 1303 printf("%s: target ID %02x reselect nexus_list %p\n", 1304 sc->sc_dev.dv_xname, reselid, 1305 sc->nexus_list.tqh_first); 1306 panic("unable to find reselecting device"); 1307 } 1308 dma_cachectl ((caddr_t)acb, sizeof(*acb)); 1309 rp->siop_temp = 0; 1310 rp->siop_dcntl |= SIOP_DCNTL_STD; 1311 return (0); 1312 } 1313 if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff04) { 1314 #ifdef DEBUG 1315 u_short ctest2 = rp->siop_ctest2; 1316 1317 /* reselect was interrupted (by Sig_P or select) */ 1318 if (siop_debug & 0x100 || 1319 (ctest2 & SIOP_CTEST2_SIGP) == 0) 1320 printf ("%s: reselect interrupted (Sig_P?) scntl1 %x ctest2 %x sfbr %x istat %x/%x\n", 1321 sc->sc_dev.dv_xname, rp->siop_scntl1, 1322 ctest2, rp->siop_sfbr, istat, rp->siop_istat); 1323 #endif 1324 /* XXX assumes it was not select */ 1325 if (sc->sc_nexus == NULL) { 1326 #ifdef DEBUG 1327 printf("%s: reselect interrupted, sc_nexus == NULL\n", 1328 sc->sc_dev.dv_xname); 1329 #if 0 1330 siop_dump(sc); 1331 #ifdef DDB 1332 Debugger(); 1333 #endif 1334 #endif 1335 #endif 1336 rp->siop_dcntl |= SIOP_DCNTL_STD; 1337 return(0); 1338 } 1339 target = sc->sc_nexus->xs->sc_link->scsipi_scsi.target; 1340 rp->siop_temp = 0; 1341 rp->siop_dsa = kvtop((caddr_t)&sc->sc_nexus->ds); 1342 rp->siop_sxfer = sc->sc_sync[target].sxfer; 1343 rp->siop_sbcl = sc->sc_sync[target].sbcl; 1344 rp->siop_dsp = sc->sc_scriptspa; 1345 return (0); 1346 } 1347 if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff06) { 1348 if (acb == NULL) 1349 printf("%s: Bad message-in with no active command?\n", 1350 sc->sc_dev.dv_xname); 1351 /* Unrecognized message in byte */ 1352 dma_cachectl (&acb->msg[1],1); 1353 printf ("%s: Unrecognized message in data sfbr %x msg %x sbcl %x\n", 1354 sc->sc_dev.dv_xname, rp->siop_sfbr, acb->msg[1], rp->siop_sbcl); 1355 /* what should be done here? */ 1356 DCIAS(kvtop(&acb->msg[1])); 1357 rp->siop_dsp = sc->sc_scriptspa + Ent_switch; 1358 return (0); 1359 } 1360 if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff0a) { 1361 /* Status phase wasn't followed by message in phase? */ 1362 printf ("%s: Status phase not followed by message in phase? sbcl %x sbdl %x\n", 1363 sc->sc_dev.dv_xname, rp->siop_sbcl, rp->siop_sbdl); 1364 if (rp->siop_sbcl == 0xa7) { 1365 /* It is now, just continue the script? */ 1366 rp->siop_dcntl |= SIOP_DCNTL_STD; 1367 return (0); 1368 } 1369 } 1370 if (sstat0 == 0 && dstat & SIOP_DSTAT_SIR) { 1371 dma_cachectl (&acb->stat[0], 1); 1372 dma_cachectl (&acb->msg[0], 1); 1373 printf ("SIOP interrupt: %lx sts %x msg %x %x sbcl %x\n", 1374 rp->siop_dsps, acb->stat[0], acb->msg[0], acb->msg[1], 1375 rp->siop_sbcl); 1376 siopreset (sc); 1377 *status = -1; 1378 return 0; /* siopreset has cleaned up */ 1379 } 1380 if (sstat0 & SIOP_SSTAT0_SGE) 1381 printf ("SIOP: SCSI Gross Error\n"); 1382 if (sstat0 & SIOP_SSTAT0_PAR) 1383 printf ("SIOP: Parity Error\n"); 1384 if (dstat & SIOP_DSTAT_IID) 1385 printf ("SIOP: Invalid instruction detected\n"); 1386 bad_phase: 1387 /* 1388 * temporary panic for unhandled conditions 1389 * displays various things about the 53C710 status and registers 1390 * then panics. 1391 * XXXX need to clean this up to print out the info, reset, and continue 1392 */ 1393 printf ("siopchkintr: target %x ds %p\n", target, &acb->ds); 1394 printf ("scripts %lx ds %x rp %x dsp %lx dcmd %lx\n", sc->sc_scriptspa, 1395 kvtop((caddr_t)&acb->ds), kvtop((caddr_t)rp), rp->siop_dsp, 1396 *((long *)&rp->siop_dcmd)); 1397 printf ("siopchkintr: istat %x dstat %x sstat0 %x dsps %lx dsa %lx sbcl %x sts %x msg %x %x sfbr %x\n", 1398 istat, dstat, sstat0, rp->siop_dsps, rp->siop_dsa, 1399 rp->siop_sbcl, acb->stat[0], acb->msg[0], acb->msg[1], rp->siop_sfbr); 1400 #ifdef DEBUG 1401 if (siop_debug & 0x20) 1402 panic("siopchkintr: **** temp ****"); 1403 #endif 1404 #ifdef DDB 1405 Debugger (); 1406 #endif 1407 siopreset (sc); /* hard reset */ 1408 *status = -1; 1409 return 0; /* siopreset cleaned up */ 1410 } 1411 1412 void 1413 siop_select(sc) 1414 struct siop_softc *sc; 1415 { 1416 siop_regmap_p rp; 1417 struct siop_acb *acb = sc->sc_nexus; 1418 1419 #ifdef DEBUG 1420 if (siop_debug & 1) 1421 printf ("%s: select ", sc->sc_dev.dv_xname); 1422 #endif 1423 1424 rp = sc->sc_siopp; 1425 if (acb->xs->xs_control & XS_CTL_POLL || siop_no_dma) { 1426 sc->sc_flags |= SIOP_INTSOFF; 1427 sc->sc_flags &= ~SIOP_INTDEFER; 1428 if ((rp->siop_istat & 0x08) == 0) { 1429 rp->siop_sien = 0; 1430 rp->siop_dien = 0; 1431 } 1432 #if 0 1433 } else if ((sc->sc_flags & SIOP_INTDEFER) == 0) { 1434 sc->sc_flags &= ~SIOP_INTSOFF; 1435 if ((rp->siop_istat & 0x08) == 0) { 1436 rp->siop_sien = sc->sc_sien; 1437 rp->siop_dien = sc->sc_dien; 1438 } 1439 #endif 1440 } 1441 #ifdef DEBUG 1442 if (siop_debug & 1) 1443 printf ("siop_select: target %x cmd %02x ds %p\n", 1444 acb->xs->sc_link->scsipi_scsi.target, acb->cmd.opcode, 1445 &sc->sc_nexus->ds); 1446 #endif 1447 1448 siop_start(sc, acb->xs->sc_link->scsipi_scsi.target, 1449 acb->xs->sc_link->scsipi_scsi.lun, 1450 (u_char *)&acb->cmd, acb->clen, acb->daddr, acb->dleft); 1451 1452 return; 1453 } 1454 1455 /* 1456 * 53C710 interrupt handler 1457 */ 1458 1459 void 1460 siopintr (sc) 1461 register struct siop_softc *sc; 1462 { 1463 siop_regmap_p rp; 1464 register u_char istat, dstat, sstat0; 1465 int status; 1466 int s = splbio(); 1467 1468 istat = sc->sc_istat; 1469 if ((istat & (SIOP_ISTAT_SIP | SIOP_ISTAT_DIP)) == 0) { 1470 splx(s); 1471 return; 1472 } 1473 1474 /* Got a valid interrupt on this device */ 1475 rp = sc->sc_siopp; 1476 dstat = sc->sc_dstat; 1477 sstat0 = sc->sc_sstat0; 1478 if (dstat & SIOP_DSTAT_SIR) 1479 sc->sc_intcode = rp->siop_dsps; 1480 sc->sc_istat = 0; 1481 #ifdef DEBUG 1482 if (siop_debug & 1) 1483 printf ("%s: intr istat %x dstat %x sstat0 %x\n", 1484 sc->sc_dev.dv_xname, istat, dstat, sstat0); 1485 if (!sc->sc_active) { 1486 printf ("%s: spurious interrupt? istat %x dstat %x sstat0 %x nexus %p status %x\n", 1487 sc->sc_dev.dv_xname, istat, dstat, sstat0, 1488 sc->sc_nexus, sc->sc_nexus ? sc->sc_nexus->stat[0] : 0); 1489 } 1490 #endif 1491 1492 #ifdef DEBUG 1493 if (siop_debug & 5) { 1494 DCIAS(kvtop(&sc->sc_nexus->stat[0])); 1495 printf ("%s: intr istat %x dstat %x sstat0 %x dsps %lx sbcl %x sts %x msg %x\n", 1496 sc->sc_dev.dv_xname, istat, dstat, sstat0, 1497 rp->siop_dsps, rp->siop_sbcl, 1498 sc->sc_nexus->stat[0], sc->sc_nexus->msg[0]); 1499 } 1500 #endif 1501 if (sc->sc_flags & SIOP_INTDEFER) { 1502 sc->sc_flags &= ~(SIOP_INTDEFER | SIOP_INTSOFF); 1503 rp->siop_sien = sc->sc_sien; 1504 rp->siop_dien = sc->sc_dien; 1505 } 1506 if (siop_checkintr (sc, istat, dstat, sstat0, &status)) { 1507 #if 1 1508 if (status == 0xff) 1509 printf ("siopintr: status == 0xff\n"); 1510 #endif 1511 if ((sc->sc_flags & (SIOP_INTSOFF | SIOP_INTDEFER)) != SIOP_INTSOFF) { 1512 #if 0 1513 if (rp->siop_sbcl & SIOP_BSY) { 1514 printf ("%s: SCSI bus busy at completion", 1515 sc->sc_dev.dv_xname); 1516 printf(" targ %d sbcl %02x sfbr %x lcrc %02x dsp +%x\n", 1517 sc->sc_nexus->xs->sc_link->scsipi_scsi.target, 1518 rp->siop_sbcl, rp->siop_sfbr, rp->siop_lcrc, 1519 rp->siop_dsp - sc->sc_scriptspa); 1520 } 1521 #endif 1522 siop_scsidone(sc->sc_nexus, sc->sc_nexus ? 1523 sc->sc_nexus->stat[0] : -1); 1524 } 1525 } 1526 splx(s); 1527 } 1528 1529 /* 1530 * This is based on the Progressive Peripherals 33Mhz Zeus driver and will 1531 * not be correct for other 53c710 boards. 1532 * 1533 */ 1534 void 1535 scsi_period_to_siop (sc, target) 1536 struct siop_softc *sc; 1537 int target; 1538 { 1539 int period, offset, sxfer, sbcl = 0; 1540 #ifdef DEBUG_SYNC 1541 int i; 1542 #endif 1543 1544 period = sc->sc_nexus->msg[4]; 1545 offset = sc->sc_nexus->msg[5]; 1546 #ifdef DEBUG_SYNC 1547 sxfer = 0; 1548 if (offset <= SIOP_MAX_OFFSET) 1549 sxfer = offset; 1550 for (i = 0; i < sizeof (sync_tab) / 2; ++i) { 1551 if (period <= sync_tab[i].p) { 1552 sxfer |= sync_tab[i].r & 0x70; 1553 sbcl = sync_tab[i].r & 0x03; 1554 break; 1555 } 1556 } 1557 printf ("siop sync old: siop_sxfr %02x, siop_sbcl %02x\n", sxfer, sbcl); 1558 #endif 1559 for (sbcl = 1; sbcl < 4; ++sbcl) { 1560 sxfer = (period * 4 - 1) / sc->sc_tcp[sbcl] - 3; 1561 if (sxfer >= 0 && sxfer <= 7) 1562 break; 1563 } 1564 if (sbcl > 3) { 1565 printf("siop sync: unable to compute sync params for period %dns\n", 1566 period * 4); 1567 /* 1568 * XXX need to pick a value we can do and renegotiate 1569 */ 1570 sxfer = sbcl = 0; 1571 } else { 1572 sxfer = (sxfer << 4) | ((offset <= SIOP_MAX_OFFSET) ? 1573 offset : SIOP_MAX_OFFSET); 1574 #ifdef DEBUG_SYNC 1575 printf("siop sync: params for period %dns: sxfer %x sbcl %x", 1576 period * 4, sxfer, sbcl); 1577 printf(" actual period %dns\n", 1578 sc->sc_tcp[sbcl] * ((sxfer >> 4) + 4)); 1579 #endif 1580 } 1581 sc->sc_sync[target].sxfer = sxfer; 1582 sc->sc_sync[target].sbcl = sbcl; 1583 #ifdef DEBUG_SYNC 1584 printf ("siop sync: siop_sxfr %02x, siop_sbcl %02x\n", sxfer, sbcl); 1585 #endif 1586 } 1587 1588 #ifdef DEBUG 1589 1590 #if SIOP_TRACE_SIZE 1591 void 1592 siop_dump_trace() 1593 { 1594 int i; 1595 1596 printf("siop trace: next index %d\n", siop_trix); 1597 i = siop_trix; 1598 do { 1599 printf("%3d: '%c' %02x %02x %02x\n", i, siop_trbuf[i], 1600 siop_trbuf[i + 1], siop_trbuf[i + 2], siop_trbuf[i + 3]); 1601 i = (i + 4) & (SIOP_TRACE_SIZE - 1); 1602 } while (i != siop_trix); 1603 } 1604 #endif 1605 1606 void 1607 siop_dump_acb(acb) 1608 struct siop_acb *acb; 1609 { 1610 u_char *b = (u_char *) &acb->cmd; 1611 int i; 1612 1613 printf("acb@%p ", acb); 1614 if (acb->xs == NULL) { 1615 printf("<unused>\n"); 1616 return; 1617 } 1618 printf("(%d:%d) flags %2x clen %2d cmd ", 1619 acb->xs->sc_link->scsipi_scsi.target, 1620 acb->xs->sc_link->scsipi_scsi.lun, acb->flags, acb->clen); 1621 for (i = acb->clen; i; --i) 1622 printf(" %02x", *b++); 1623 printf("\n"); 1624 printf(" xs: %p data %p:%04x ", acb->xs, acb->xs->data, 1625 acb->xs->datalen); 1626 printf("va %p:%lx ", acb->iob_buf, acb->iob_len); 1627 printf("cur %lx:%lx\n", acb->iob_curbuf, acb->iob_curlen); 1628 } 1629 1630 void 1631 siop_dump(sc) 1632 struct siop_softc *sc; 1633 { 1634 struct siop_acb *acb; 1635 siop_regmap_p rp = sc->sc_siopp; 1636 int s; 1637 int i; 1638 1639 s = splbio(); 1640 #if SIOP_TRACE_SIZE 1641 siop_dump_trace(); 1642 #endif 1643 printf("%s@%p regs %p istat %x\n", 1644 sc->sc_dev.dv_xname, sc, rp, rp->siop_istat); 1645 if ((acb = sc->free_list.tqh_first) > 0) { 1646 printf("Free list:\n"); 1647 while (acb) { 1648 siop_dump_acb(acb); 1649 acb = acb->chain.tqe_next; 1650 } 1651 } 1652 if ((acb = sc->ready_list.tqh_first) > 0) { 1653 printf("Ready list:\n"); 1654 while (acb) { 1655 siop_dump_acb(acb); 1656 acb = acb->chain.tqe_next; 1657 } 1658 } 1659 if ((acb = sc->nexus_list.tqh_first) > 0) { 1660 printf("Nexus list:\n"); 1661 while (acb) { 1662 siop_dump_acb(acb); 1663 acb = acb->chain.tqe_next; 1664 } 1665 } 1666 if (sc->sc_nexus) { 1667 printf("Nexus:\n"); 1668 siop_dump_acb(sc->sc_nexus); 1669 } 1670 for (i = 0; i < 8; ++i) { 1671 if (sc->sc_tinfo[i].cmds > 2) { 1672 printf("tgt %d: cmds %d disc %d senses %d lubusy %x\n", 1673 i, sc->sc_tinfo[i].cmds, 1674 sc->sc_tinfo[i].dconns, 1675 sc->sc_tinfo[i].senses, 1676 sc->sc_tinfo[i].lubusy); 1677 } 1678 } 1679 splx(s); 1680 } 1681 #endif 1682