1 /* 2 * Copyright (c) 1992 Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Ralph Campbell. 7 * 8 * %sccs.include.redist.c% 9 * 10 * @(#)sii.c 7.4 (Berkeley) 03/29/92 11 * 12 * from: $Header: /sprite/src/kernel/dev/ds3100.md/RCS/devSII.c, 13 * v 9.2 89/09/14 13:37:41 jhh Exp $ SPRITE (DECWRL)"; 14 */ 15 16 #include "sii.h" 17 #if NSII > 0 18 /* 19 * SCSI interface driver 20 */ 21 #include "param.h" 22 #include "systm.h" 23 #include "dkstat.h" 24 #include "buf.h" 25 #include "conf.h" 26 #include "errno.h" 27 28 #include "machine/machConst.h" 29 #include "device.h" 30 #include "scsi.h" 31 #include "siireg.h" 32 33 int siiprobe(); 34 void siistart(); 35 struct driver siidriver = { 36 "sii", siiprobe, siistart, 0, 37 }; 38 39 typedef struct scsi_state { 40 int statusByte; /* status byte returned during STATUS_PHASE */ 41 int dmaDataPhase; /* which data phase to expect */ 42 int dmaCurPhase; /* SCSI phase if DMA is in progress */ 43 int dmaPrevPhase; /* SCSI phase of DMA suspended by disconnect */ 44 u_short *dmaAddr[2]; /* DMA buffer memory address */ 45 int dmaBufIndex; /* which of the above is currently in use */ 46 int dmalen; /* amount to transfer in this chunk */ 47 int cmdlen; /* total remaining amount of cmd to transfer */ 48 u_char *cmd; /* current pointer within scsicmd->cmd */ 49 int buflen; /* total remaining amount of data to transfer */ 50 char *buf; /* current pointer within scsicmd->buf */ 51 u_short flags; /* see below */ 52 u_short prevComm; /* command reg before disconnect */ 53 u_short dmaCtrl; /* DMA control register if disconnect */ 54 u_short dmaAddrL; /* DMA address register if disconnect */ 55 u_short dmaAddrH; /* DMA address register if disconnect */ 56 u_short dmaCnt; /* DMA count if disconnect */ 57 u_short dmaByte; /* DMA byte if disconnect on odd boundary */ 58 u_short dmaReqAck; /* DMA synchronous xfer offset or 0 if async */ 59 } State; 60 61 /* state flags */ 62 #define FIRST_DMA 0x01 /* true if no data DMA started yet */ 63 64 #define SII_NCMD 7 65 struct siisoftc { 66 SIIRegs *sc_regs; /* HW address of SII controller chip */ 67 int sc_flags; 68 int sc_target; /* target SCSI ID if connected */ 69 ScsiCmd *sc_cmd[SII_NCMD]; /* active command indexed by ID */ 70 State sc_st[SII_NCMD]; /* state info for each active command */ 71 } sii_softc[NSII]; 72 73 /* 74 * MACROS for timing out spin loops. 75 * 76 * Wait until expression is true. 77 * 78 * Control register bits can change at any time so when the CPU 79 * reads a register, the bits might change and 80 * invalidate the setup and hold times for the CPU. 81 * This macro reads the register twice to be sure the value is stable. 82 * 83 * args: var - variable to save control register contents 84 * reg - control register to read 85 * expr - expression to spin on 86 * spincount - maximum number of times through the loop 87 * cntr - variable for number of tries 88 */ 89 #define SII_WAIT_UNTIL(var, reg, expr, spincount, cntr) { \ 90 register unsigned tmp = reg; \ 91 for (cntr = 0; cntr < spincount; cntr++) { \ 92 while (tmp != (var = reg)) \ 93 tmp = var; \ 94 if (expr) \ 95 break; \ 96 if (cntr >= 100) \ 97 DELAY(100); \ 98 } \ 99 } 100 101 #ifdef DEBUG 102 int sii_debug = 1; 103 int sii_debug_cmd; 104 int sii_debug_bn; 105 int sii_debug_sz; 106 #define NLOG 16 107 struct sii_log { 108 u_short cstat; 109 u_short dstat; 110 u_short comm; 111 u_short msg; 112 int target; 113 } sii_log[NLOG], *sii_logp = sii_log; 114 #endif 115 116 u_char sii_buf[256]; /* used for extended messages */ 117 118 #define NORESET 0 119 #define RESET 1 120 #define NOWAIT 0 121 #define WAIT 1 122 123 /* define a safe address in the SCSI buffer for doing status & message DMA */ 124 #define SII_BUF_ADDR (MACH_SCSI_BUFFER_ADDR + SII_MAX_DMA_XFER_LENGTH * 14) 125 126 extern void sii_Reset(); 127 extern void sii_StartCmd(); 128 extern void sii_CmdDone(); 129 extern void sii_DoIntr(); 130 extern void sii_StateChg(); 131 extern void sii_DoSync(); 132 extern void sii_StartDMA(); 133 134 /* 135 * Test to see if device is present. 136 * Return true if found and initialized ok. 137 */ 138 siiprobe(cp) 139 register struct pmax_ctlr *cp; 140 { 141 register struct siisoftc *sc; 142 register int i; 143 144 if (cp->pmax_unit >= NSII) 145 return (0); 146 sc = &sii_softc[cp->pmax_unit]; 147 sc->sc_regs = (SIIRegs *)cp->pmax_addr; 148 sc->sc_flags = cp->pmax_flags; 149 sc->sc_target = -1; /* no command active */ 150 /* 151 * Give each target its own DMA buffer region. 152 * Make it big enough for 2 max transfers so we can ping pong buffers 153 * while we copy the data. 154 */ 155 for (i = 0; i < SII_NCMD; i++) { 156 sc->sc_st[i].dmaAddr[0] = (u_short *)MACH_SCSI_BUFFER_ADDR + 157 2 * SII_MAX_DMA_XFER_LENGTH * i; 158 sc->sc_st[i].dmaAddr[1] = sc->sc_st[i].dmaAddr[0] + 159 SII_MAX_DMA_XFER_LENGTH; 160 } 161 162 printf("sii%d at nexus0 csr 0x%x\n", cp->pmax_unit, cp->pmax_addr); 163 sii_Reset(sc->sc_regs, RESET); 164 return (1); 165 } 166 167 /* 168 * Start activity on a SCSI device. 169 * We maintain information on each device separately since devices can 170 * connect/disconnect during an operation. 171 */ 172 void 173 siistart(scsicmd) 174 register ScsiCmd *scsicmd; /* command to start */ 175 { 176 register struct scsi_device *sdp = scsicmd->sd; 177 register struct siisoftc *sc = &sii_softc[sdp->sd_ctlr]; 178 int s; 179 180 s = splbio(); 181 /* 182 * Check if another command is already in progress. 183 * We may have to change this if we allow SCSI devices with 184 * separate LUNs. 185 */ 186 if (sc->sc_cmd[sdp->sd_drive]) { 187 printf("sii%d: device %s busy at start\n", sdp->sd_ctlr, 188 sdp->sd_driver->d_name); 189 (*sdp->sd_driver->d_done)(scsicmd->unit, EBUSY, 190 scsicmd->buflen, 0); 191 splx(s); 192 } 193 sc->sc_cmd[sdp->sd_drive] = scsicmd; 194 sii_StartCmd(sc, sdp->sd_drive); 195 splx(s); 196 } 197 198 /* 199 * Check to see if any SII chips have pending interrupts 200 * and process as appropriate. 201 */ 202 void 203 siiintr(unit) 204 int unit; 205 { 206 register struct siisoftc *sc = &sii_softc[unit]; 207 unsigned dstat; 208 209 /* 210 * Find which controller caused the interrupt. 211 */ 212 dstat = sc->sc_regs->dstat; 213 if (dstat & (SII_CI | SII_DI)) 214 sii_DoIntr(sc, dstat); 215 } 216 217 /* 218 * Reset the SII chip and do a SCSI reset if 'reset' is true. 219 * NOTE: if !cold && reset, should probably probe for devices 220 * since a SCSI bus reset will set UNIT_ATTENTION. 221 */ 222 static void 223 sii_Reset(regs, reset) 224 register SIIRegs *regs; 225 int reset; /* TRUE => reset SCSI bus */ 226 { 227 228 #ifdef DEBUG 229 if (sii_debug > 1) 230 printf("sii: RESET\n"); 231 #endif 232 /* 233 * Reset the SII chip. 234 */ 235 regs->comm = SII_CHRESET; 236 /* 237 * Set arbitrated bus mode. 238 */ 239 regs->csr = SII_HPM; 240 /* 241 * SII is always ID 7. 242 */ 243 regs->id = SII_ID_IO | 7; 244 /* 245 * Enable SII to drive the SCSI bus. 246 */ 247 regs->dictrl = SII_PRE; 248 regs->dmctrl = 0; 249 250 if (reset) { 251 register int i; 252 253 /* 254 * Assert SCSI bus reset for at least 25 Usec to clear the 255 * world. SII_DO_RST is self clearing. 256 * Delay 250 ms before doing any commands. 257 */ 258 regs->comm = SII_DO_RST; 259 MachEmptyWriteBuffer(); 260 DELAY(250000); 261 262 /* rearbitrate synchronous offset */ 263 for (i = 0; i < SII_NCMD; i++) 264 sii_softc[0].sc_st[i].dmaReqAck = 0; 265 } 266 267 /* 268 * Clear any pending interrupts from the reset. 269 */ 270 regs->cstat = regs->cstat; 271 regs->dstat = regs->dstat; 272 /* 273 * Set up SII for arbitrated bus mode, SCSI parity checking, 274 * Reselect Enable, and Interrupt Enable. 275 */ 276 regs->csr = SII_HPM | SII_RSE | SII_PCE | SII_IE; 277 MachEmptyWriteBuffer(); 278 } 279 280 /* 281 * Start a SCSI command by sending the cmd data 282 * to a SCSI controller via the SII. 283 * Call the device done proceedure if it can't be started. 284 * NOTE: we should be called with interrupts disabled. 285 */ 286 static void 287 sii_StartCmd(sc, target) 288 register struct siisoftc *sc; /* which SII to use */ 289 register int target; /* which command to start */ 290 { 291 register SIIRegs *regs; 292 register ScsiCmd *scsicmd; 293 register State *state; 294 register unsigned status; 295 int error, retval; 296 297 /* if another command is currently in progress, just wait */ 298 if (sc->sc_target >= 0) 299 return; 300 301 /* initialize state information for this command */ 302 scsicmd = sc->sc_cmd[target]; 303 state = &sc->sc_st[target]; 304 state->flags = FIRST_DMA; 305 state->prevComm = 0; 306 state->dmalen = 0; 307 state->dmaCurPhase = -1; 308 state->dmaPrevPhase = -1; 309 state->dmaBufIndex = 0; 310 state->cmd = scsicmd->cmd; 311 state->cmdlen = scsicmd->cmdlen; 312 if ((state->buflen = scsicmd->buflen) == 0) { 313 state->dmaDataPhase = -1; /* illegal phase. shouldn't happen */ 314 state->buf = (char *)0; 315 } else { 316 state->dmaDataPhase = 317 (scsicmd->flags & SCSICMD_DATA_TO_DEVICE) ? 318 SII_DATA_OUT_PHASE : SII_DATA_IN_PHASE; 319 state->buf = scsicmd->buf; 320 } 321 322 #ifdef DEBUG 323 if (sii_debug > 1) { 324 printf("sii_StartCmd: %s target %d cmd 0x%x addr %x size %d dma %d\n", 325 scsicmd->sd->sd_driver->d_name, target, 326 scsicmd->cmd[0], scsicmd->buf, scsicmd->buflen, 327 state->dmaDataPhase); 328 } 329 sii_debug_cmd = scsicmd->cmd[0]; 330 if (scsicmd->cmd[0] == SCSI_READ_EXT) { 331 sii_debug_bn = (scsicmd->cmd[2] << 24) | 332 (scsicmd->cmd[3] << 16) | 333 (scsicmd->cmd[4] << 8) | 334 scsicmd->cmd[5]; 335 sii_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8]; 336 } 337 #endif 338 339 /* try to select the target */ 340 regs = sc->sc_regs; 341 342 /* 343 * Another device may have selected us; in which case, 344 * this command will be restarted later. 345 */ 346 if ((status = regs->dstat) & (SII_CI | SII_DI)) { 347 sii_DoIntr(sc, status); 348 return; 349 } 350 351 sc->sc_target = target; 352 if (scsicmd->flags & SCSICMD_USE_SYNC) { 353 printf("sii_StartCmd: doing extended msg\n"); /* XXX */ 354 /* 355 * Setup to send both the identify message and the synchronous 356 * data transfer request. 357 */ 358 sii_buf[0] = SCSI_DIS_REC_IDENTIFY; 359 sii_buf[1] = SCSI_EXTENDED_MSG; 360 sii_buf[2] = 3; /* message length */ 361 sii_buf[3] = SCSI_SYNCHRONOUS_XFER; 362 sii_buf[4] = 0; 363 sii_buf[5] = 3; /* maximum SII chip supports */ 364 365 state->dmaCurPhase = SII_MSG_OUT_PHASE, 366 state->dmalen = 6; 367 CopyToBuffer((u_short *)sii_buf, 368 (volatile u_short *)SII_BUF_ADDR, 6); 369 regs->slcsr = target; 370 regs->dmctrl = 0; 371 regs->dmaddrl = ((unsigned)SII_BUF_ADDR >> 1); 372 regs->dmaddrh = ((unsigned)SII_BUF_ADDR >> 17) & 03; 373 regs->dmlotc = 6; 374 regs->comm = SII_DMA | SII_INXFER | SII_SELECT | SII_ATN | 375 SII_CON | SII_MSG_OUT_PHASE; 376 } else { 377 /* do a chained, select with ATN and programmed I/O command */ 378 regs->data = SCSI_DIS_REC_IDENTIFY; 379 regs->slcsr = target; 380 regs->dmctrl = 0; 381 regs->comm = SII_INXFER | SII_SELECT | SII_ATN | SII_CON | 382 SII_MSG_OUT_PHASE; 383 } 384 MachEmptyWriteBuffer(); 385 386 /* 387 * Wait for something to happen 388 * (should happen soon or we would use interrupts). 389 */ 390 SII_WAIT_UNTIL(status, regs->cstat, status & (SII_CI | SII_DI), 391 SII_WAIT_COUNT/4, retval); 392 393 /* check to see if we are connected OK */ 394 if ((status & (SII_RST | SII_SCH | SII_STATE_MSK)) == 395 (SII_SCH | SII_CON)) { 396 regs->cstat = status; 397 MachEmptyWriteBuffer(); 398 399 #ifdef DEBUG 400 sii_logp->target = target; 401 sii_logp->cstat = status; 402 sii_logp->dstat = 0; 403 sii_logp->comm = regs->comm; 404 sii_logp->msg = -1; 405 if (++sii_logp >= &sii_log[NLOG]) 406 sii_logp = sii_log; 407 #endif 408 409 /* wait a short time for command phase */ 410 SII_WAIT_UNTIL(status, regs->dstat, status & SII_MIS, 411 SII_WAIT_COUNT, retval); 412 #ifdef DEBUG 413 if (sii_debug > 2) 414 printf("sii_StartCmd: ds %x cnt %d\n", status, retval); 415 #endif 416 if ((status & (SII_CI | SII_MIS | SII_PHASE_MSK)) != 417 (SII_MIS | SII_CMD_PHASE)) { 418 printf("sii_StartCmd: timeout cs %x ds %x cnt %d\n", 419 regs->cstat, status, retval); /* XXX */ 420 /* process interrupt or continue until it happens */ 421 if (status & (SII_CI | SII_DI)) 422 sii_DoIntr(sc, status); 423 return; 424 } 425 regs->dstat = SII_DNE; /* clear Msg Out DMA done */ 426 427 /* send command data */ 428 CopyToBuffer((u_short *)state->cmd, 429 (volatile u_short *)state->dmaAddr[0], state->cmdlen); 430 sii_StartDMA(regs, state->dmaCurPhase = SII_CMD_PHASE, 431 state->dmaAddr[0], state->dmalen = scsicmd->cmdlen); 432 433 /* wait a little while for DMA to finish */ 434 SII_WAIT_UNTIL(status, regs->dstat, status & (SII_CI | SII_DI), 435 SII_WAIT_COUNT, retval); 436 #ifdef DEBUG 437 if (sii_debug > 2) 438 printf("sii_StartCmd: ds %x, cnt %d\n", status, retval); 439 #endif 440 if (status & (SII_CI | SII_DI)) 441 sii_DoIntr(sc, status); 442 #ifdef DEBUG 443 if (sii_debug > 2) 444 printf("sii_StartCmd: DONE ds %x\n", regs->dstat); 445 #endif 446 return; 447 } 448 449 /* 450 * Another device may have selected us; in which case, 451 * this command will be restarted later. 452 */ 453 if (status & (SII_CI | SII_DI)) { 454 sii_DoIntr(sc, regs->dstat); 455 return; 456 } 457 458 /* 459 * Disconnect if selection command still in progress. 460 */ 461 if (status & SII_SIP) { 462 error = ENXIO; /* device didn't respond */ 463 regs->comm = SII_DISCON; 464 MachEmptyWriteBuffer(); 465 SII_WAIT_UNTIL(status, regs->cstat, 466 !(status & (SII_CON | SII_SIP)), 467 SII_WAIT_COUNT, retval); 468 } else 469 error = EBUSY; /* couldn't get the bus */ 470 #ifdef DEBUG 471 if (sii_debug > 1) 472 printf("sii_StartCmd: Couldn't select target %d error %d\n", 473 target, error); 474 #endif 475 sc->sc_target = -1; 476 regs->cstat = 0xffff; 477 regs->dstat = 0xffff; 478 regs->comm = 0; 479 MachEmptyWriteBuffer(); 480 sii_CmdDone(sc, target, error); 481 } 482 483 /* 484 * Process interrupt conditions. 485 */ 486 static void 487 sii_DoIntr(sc, dstat) 488 register struct siisoftc *sc; 489 register unsigned dstat; 490 { 491 register SIIRegs *regs = sc->sc_regs; 492 register State *state; 493 register unsigned cstat; 494 register int i; 495 unsigned comm, msg; 496 497 again: 498 comm = regs->comm; 499 500 #ifdef DEBUG 501 if (sii_debug > 3) 502 printf("sii_DoIntr: cs %x, ds %x cm %x ", 503 regs->cstat, dstat, comm); 504 sii_logp->target = sc->sc_target; 505 sii_logp->cstat = regs->cstat; 506 sii_logp->dstat = dstat; 507 sii_logp->comm = comm; 508 sii_logp->msg = -1; 509 if (++sii_logp >= &sii_log[NLOG]) 510 sii_logp = sii_log; 511 #endif 512 513 regs->dstat = dstat; /* acknowledge everything */ 514 MachEmptyWriteBuffer(); 515 516 if (dstat & SII_CI) { 517 /* deglitch cstat register */ 518 msg = regs->cstat; 519 while (msg != (cstat = regs->cstat)) 520 msg = cstat; 521 regs->cstat = cstat; /* acknowledge everything */ 522 MachEmptyWriteBuffer(); 523 #ifdef DEBUG 524 if (sii_logp > sii_log) 525 sii_logp[-1].cstat = cstat; 526 else 527 sii_log[NLOG - 1].cstat = cstat; 528 #endif 529 530 /* check for a BUS RESET */ 531 if (cstat & SII_RST) { 532 printf("sii%d: SCSI bus reset!!\n", sc - sii_softc); 533 /* need to flush disconnected commands */ 534 for (i = 0; i < SII_NCMD; i++) { 535 if (!sc->sc_cmd[i]) 536 continue; 537 sii_CmdDone(sc, i, EIO); 538 } 539 /* rearbitrate synchronous offset */ 540 for (i = 0; i < SII_NCMD; i++) 541 sc->sc_st[i].dmaReqAck = 0; 542 sc->sc_target = -1; 543 return; 544 } 545 546 #ifdef notdef 547 /* 548 * Check for a BUS ERROR. 549 * According to DEC, this feature doesn't really work 550 * and to just clear the bit if it's set. 551 */ 552 if (cstat & SII_BER) { 553 } 554 #endif 555 556 /* check for state change */ 557 if (cstat & SII_SCH) { 558 sii_StateChg(sc, cstat); 559 comm = regs->comm; 560 } 561 } 562 563 /* check for DMA completion */ 564 if (dstat & SII_DNE) { 565 u_short *dma; 566 char *buf; 567 568 /* check for a PARITY ERROR */ 569 if (dstat & SII_IPE) { 570 printf("sii%d: Parity error!!\n", sc - sii_softc); 571 goto abort; 572 } 573 /* 574 * There is a race condition with SII_SCH. There is a short 575 * window between the time a SII_SCH is seen after a disconnect 576 * and when the SII_SCH is cleared. A reselect can happen 577 * in this window and we will clear the SII_SCH without 578 * processing the reconnect. 579 */ 580 if (sc->sc_target < 0) { 581 cstat = regs->cstat; 582 printf("sii%d: target %d DNE?? dev %d,%d cs %x\n", 583 sc - sii_softc, sc->sc_target, 584 regs->slcsr, regs->destat, 585 cstat); /* XXX */ 586 if (cstat & SII_DST) { 587 sc->sc_target = regs->destat; 588 state->prevComm = 0; 589 } else 590 panic("sc_target 1"); 591 } 592 state = &sc->sc_st[sc->sc_target]; 593 /* dmalen = amount left to transfer, i = amount transfered */ 594 i = state->dmalen; 595 state->dmalen = 0; 596 state->dmaCurPhase = -1; 597 #ifdef DEBUG 598 if (sii_debug > 4) { 599 printf("DNE: amt %d ", i); 600 if (!(dstat & SII_TCZ)) 601 printf("no TCZ?? (%d) ", regs->dmlotc); 602 } else if (!(dstat & SII_TCZ)) { 603 printf("sii%d: device %d: no TCZ?? (%d)\n", 604 sc - sii_softc, sc->sc_target, regs->dmlotc); 605 sii_DumpLog(); /* XXX */ 606 } 607 #endif 608 switch (comm & SII_PHASE_MSK) { 609 case SII_CMD_PHASE: 610 state->cmdlen -= i; 611 break; 612 613 case SII_DATA_IN_PHASE: 614 /* check for more data for the same phase */ 615 dma = state->dmaAddr[state->dmaBufIndex]; 616 buf = state->buf; 617 state->buf += i; 618 state->buflen -= i; 619 if (state->buflen > 0 && !(dstat & SII_MIS)) { 620 int len; 621 622 /* start reading next chunk */ 623 len = state->buflen; 624 if (len > SII_MAX_DMA_XFER_LENGTH) 625 len = SII_MAX_DMA_XFER_LENGTH; 626 state->dmaBufIndex = !state->dmaBufIndex; 627 sii_StartDMA(regs, 628 state->dmaCurPhase = SII_DATA_IN_PHASE, 629 state->dmaAddr[state->dmaBufIndex], 630 state->dmalen = len); 631 dstat &= ~(SII_IBF | SII_TBE); 632 } 633 /* copy in the data */ 634 CopyFromBuffer((volatile u_short *)dma, buf, i); 635 break; 636 637 case SII_DATA_OUT_PHASE: 638 state->dmaBufIndex = !state->dmaBufIndex; 639 state->buf += i; 640 state->buflen -= i; 641 642 /* check for more data for the same phase */ 643 if (state->buflen <= 0 || (dstat & SII_MIS)) 644 break; 645 646 /* start next chunk */ 647 i = state->buflen; 648 if (i > SII_MAX_DMA_XFER_LENGTH) { 649 sii_StartDMA(regs, state->dmaCurPhase = 650 SII_DATA_OUT_PHASE, 651 state->dmaAddr[state->dmaBufIndex], 652 state->dmalen = 653 SII_MAX_DMA_XFER_LENGTH); 654 /* prepare for next chunk */ 655 i -= SII_MAX_DMA_XFER_LENGTH; 656 if (i > SII_MAX_DMA_XFER_LENGTH) 657 i = SII_MAX_DMA_XFER_LENGTH; 658 CopyToBuffer((u_short *)(state->buf + 659 SII_MAX_DMA_XFER_LENGTH), 660 (volatile u_short *) 661 state->dmaAddr[!state->dmaBufIndex], i); 662 } else { 663 sii_StartDMA(regs, state->dmaCurPhase = 664 SII_DATA_OUT_PHASE, 665 state->dmaAddr[state->dmaBufIndex], 666 state->dmalen = i); 667 } 668 dstat &= ~(SII_IBF | SII_TBE); 669 break; 670 671 default: 672 printf("sii%d: device %d: unexpected DNE\n", 673 sc - sii_softc, sc->sc_target); 674 #ifdef DEBUG 675 sii_DumpLog(); 676 #endif 677 } 678 } 679 680 /* check for phase change or another MsgIn/Out */ 681 if (dstat & (SII_MIS | SII_IBF | SII_TBE)) { 682 /* 683 * There is a race condition with SII_SCH. There is a short 684 * window between the time a SII_SCH is seen after a disconnect 685 * and when the SII_SCH is cleared. A reselect can happen 686 * in this window and we will clear the SII_SCH without 687 * processing the reconnect. 688 */ 689 if (sc->sc_target < 0) { 690 cstat = regs->cstat; 691 printf("sii%d: target %d MIS?? dev %d,%d cs %x ds %x\n", 692 sc - sii_softc, sc->sc_target, 693 regs->slcsr, regs->destat, 694 cstat, dstat); /* XXX */ 695 if (cstat & SII_DST) { 696 sc->sc_target = regs->destat; 697 state->prevComm = 0; 698 } else 699 panic("sc_target 2"); 700 } 701 state = &sc->sc_st[sc->sc_target]; 702 switch (dstat & SII_PHASE_MSK) { 703 case SII_CMD_PHASE: 704 if (state->dmaPrevPhase >= 0) { 705 /* restart DMA after disconnect/reconnect */ 706 if (state->dmaPrevPhase != SII_CMD_PHASE) { 707 printf("sii%d: device %d: dma reselect phase doesn't match\n", 708 sc - sii_softc, sc->sc_target); 709 goto abort; 710 } 711 state->dmaCurPhase = SII_CMD_PHASE; 712 state->dmaPrevPhase = -1; 713 regs->dmaddrl = state->dmaAddrL; 714 regs->dmaddrh = state->dmaAddrH; 715 regs->dmlotc = state->dmaCnt; 716 if (state->dmaCnt & 1) 717 regs->dmabyte = state->dmaByte; 718 regs->comm = SII_DMA | SII_INXFER | 719 (comm & SII_STATE_MSK) | SII_CMD_PHASE; 720 MachEmptyWriteBuffer(); 721 #ifdef DEBUG 722 if (sii_debug > 4) 723 printf("Cmd dcnt %d dadr %x ", 724 state->dmaCnt, 725 (state->dmaAddrH << 16) | 726 state->dmaAddrL); 727 #endif 728 } else { 729 /* send command data */ 730 i = state->cmdlen; 731 if (i == 0) { 732 printf("sii%d: device %d: cmd count exceeded\n", 733 sc - sii_softc, sc->sc_target); 734 goto abort; 735 } 736 CopyToBuffer((u_short *)state->cmd, 737 (volatile u_short *)state->dmaAddr[0], 738 i); 739 sii_StartDMA(regs, state->dmaCurPhase = 740 SII_CMD_PHASE, state->dmaAddr[0], 741 state->dmalen = i); 742 } 743 /* wait a short time for XFER complete */ 744 SII_WAIT_UNTIL(dstat, regs->dstat, 745 dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i); 746 if (dstat & (SII_CI | SII_DI)) { 747 #ifdef DEBUG 748 if (sii_debug > 4) 749 printf("cnt %d\n", i); 750 else if (sii_debug > 0) 751 printf("sii_DoIntr: cmd wait ds %x cnt %d\n", 752 dstat, i); 753 #endif 754 goto again; 755 } 756 break; 757 758 case SII_DATA_IN_PHASE: 759 case SII_DATA_OUT_PHASE: 760 regs->dmctrl = state->dmaReqAck; 761 if (state->cmdlen > 0) { 762 printf("sii%d: device %d: cmd %x: command data not all sent (%d) 1\n", 763 sc - sii_softc, sc->sc_target, 764 sc->sc_cmd[sc->sc_target]->cmd[0], 765 state->cmdlen); 766 state->cmdlen = 0; 767 #ifdef DEBUG 768 sii_DumpLog(); 769 #endif 770 } 771 if (state->dmaPrevPhase >= 0) { 772 /* restart DMA after disconnect/reconnect */ 773 if (state->dmaPrevPhase != 774 (dstat & SII_PHASE_MSK)) { 775 printf("sii%d: device %d: dma reselect phase doesn't match\n", 776 sc - sii_softc, sc->sc_target); 777 goto abort; 778 } 779 state->dmaCurPhase = state->dmaPrevPhase; 780 state->dmaPrevPhase = -1; 781 regs->dmaddrl = state->dmaAddrL; 782 regs->dmaddrh = state->dmaAddrH; 783 regs->dmlotc = state->dmaCnt; 784 if (state->dmaCnt & 1) 785 regs->dmabyte = state->dmaByte; 786 regs->comm = SII_DMA | SII_INXFER | 787 (comm & SII_STATE_MSK) | 788 state->dmaCurPhase; 789 MachEmptyWriteBuffer(); 790 #ifdef DEBUG 791 if (sii_debug > 4) 792 printf("Data %d dcnt %d dadr %x ", 793 state->dmaDataPhase, 794 state->dmaCnt, 795 (state->dmaAddrH << 16) | 796 state->dmaAddrL); 797 #endif 798 break; 799 } 800 if (state->dmaDataPhase != (dstat & SII_PHASE_MSK)) { 801 printf("sii%d: device %d: cmd %x: dma phase doesn't match\n", 802 sc - sii_softc, sc->sc_target, 803 sc->sc_cmd[sc->sc_target]->cmd[0]); 804 goto abort; 805 } 806 #ifdef DEBUG 807 if (sii_debug > 4) { 808 printf("Data %d ", state->dmaDataPhase); 809 if (sii_debug > 5) 810 printf("\n"); 811 } 812 #endif 813 i = state->buflen; 814 if (i == 0) { 815 printf("sii%d: device %d: data count exceeded\n", 816 sc - sii_softc, sc->sc_target); 817 goto abort; 818 } 819 if (i > SII_MAX_DMA_XFER_LENGTH) 820 i = SII_MAX_DMA_XFER_LENGTH; 821 if ((dstat & SII_PHASE_MSK) == SII_DATA_IN_PHASE) { 822 sii_StartDMA(regs, 823 state->dmaCurPhase = SII_DATA_IN_PHASE, 824 state->dmaAddr[state->dmaBufIndex], 825 state->dmalen = i); 826 break; 827 } 828 /* start first chunk */ 829 if (state->flags & FIRST_DMA) { 830 state->flags &= ~FIRST_DMA; 831 CopyToBuffer((u_short *)state->buf, 832 (volatile u_short *) 833 state->dmaAddr[state->dmaBufIndex], i); 834 } 835 sii_StartDMA(regs, 836 state->dmaCurPhase = SII_DATA_OUT_PHASE, 837 state->dmaAddr[state->dmaBufIndex], 838 state->dmalen = i); 839 i = state->buflen - SII_MAX_DMA_XFER_LENGTH; 840 if (i > 0) { 841 /* prepare for next chunk */ 842 if (i > SII_MAX_DMA_XFER_LENGTH) 843 i = SII_MAX_DMA_XFER_LENGTH; 844 CopyToBuffer((u_short *)(state->buf + 845 SII_MAX_DMA_XFER_LENGTH), 846 (volatile u_short *) 847 state->dmaAddr[!state->dmaBufIndex], i); 848 } 849 break; 850 851 case SII_STATUS_PHASE: 852 if (state->cmdlen > 0) { 853 printf("sii%d: device %d: cmd %x: command data not all sent (%d) 2\n", 854 sc - sii_softc, sc->sc_target, 855 sc->sc_cmd[sc->sc_target]->cmd[0], 856 state->cmdlen); 857 state->cmdlen = 0; 858 #ifdef DEBUG 859 sii_DumpLog(); 860 #endif 861 } 862 863 /* read amount transfered if DMA didn't finish */ 864 if (state->dmalen > 0) { 865 i = state->dmalen - regs->dmlotc; 866 state->dmalen = 0; 867 state->dmaCurPhase = -1; 868 regs->dmlotc = 0; 869 regs->comm = comm & 870 (SII_STATE_MSK | SII_PHASE_MSK); 871 MachEmptyWriteBuffer(); 872 regs->dstat = SII_DNE; 873 MachEmptyWriteBuffer(); 874 #ifdef DEBUG 875 if (sii_debug > 4) 876 printf("DMA amt %d ", i); 877 #endif 878 switch (comm & SII_PHASE_MSK) { 879 case SII_DATA_IN_PHASE: 880 /* copy in the data */ 881 CopyFromBuffer((volatile u_short *) 882 state->dmaAddr[state->dmaBufIndex], 883 state->buf, i); 884 885 case SII_CMD_PHASE: 886 case SII_DATA_OUT_PHASE: 887 state->buflen -= i; 888 } 889 } 890 891 /* read a one byte status message */ 892 state->statusByte = msg = 893 sii_GetByte(regs, SII_STATUS_PHASE); 894 if (msg < 0) { 895 dstat = regs->dstat; 896 goto again; 897 } 898 #ifdef DEBUG 899 if (sii_debug > 4) 900 printf("Status %x ", msg); 901 if (sii_logp > sii_log) 902 sii_logp[-1].msg = msg; 903 else 904 sii_log[NLOG - 1].msg = msg; 905 #endif 906 907 /* do a quick wait for COMMAND_COMPLETE */ 908 SII_WAIT_UNTIL(dstat, regs->dstat, 909 dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i); 910 if (dstat & (SII_CI | SII_DI)) { 911 #ifdef DEBUG 912 if (sii_debug > 4) 913 printf("cnt2 %d\n", i); 914 #endif 915 goto again; 916 } 917 break; 918 919 case SII_MSG_IN_PHASE: 920 /* 921 * Save DMA state if DMA didn't finish. 922 * Be careful not to save state again after reconnect 923 * and see RESTORE_POINTER message. 924 * Note that the SII DMA address is not incremented 925 * as DMA proceeds. 926 */ 927 if (state->dmaCurPhase > 0) { 928 /* save dma registers */ 929 state->dmaPrevPhase = state->dmaCurPhase; 930 state->dmaCurPhase = -1; 931 state->dmaCnt = i = regs->dmlotc; 932 if (dstat & SII_OBB) 933 state->dmaByte = regs->dmabyte; 934 if (i == 0) 935 i = SII_MAX_DMA_XFER_LENGTH; 936 i = state->dmalen - i; 937 /* note: no carry from dmaddrl to dmaddrh */ 938 state->dmaAddrL = regs->dmaddrl + i; 939 state->dmaAddrH = regs->dmaddrh; 940 regs->comm = comm & 941 (SII_STATE_MSK | SII_PHASE_MSK); 942 MachEmptyWriteBuffer(); 943 regs->dstat = SII_DNE; 944 MachEmptyWriteBuffer(); 945 #ifdef DEBUG 946 if (sii_debug > 4) { 947 printf("SavP dcnt %d dadr %x ", 948 state->dmaCnt, 949 (state->dmaAddrH << 16) | 950 state->dmaAddrL); 951 if (((dstat & SII_OBB) != 0) ^ 952 (state->dmaCnt & 1)) 953 printf("OBB??? "); 954 } else if (sii_debug > 0) { 955 if (((dstat & SII_OBB) != 0) ^ 956 (state->dmaCnt & 1)) { 957 printf("sii_DoIntr: OBB??? ds %x cnt %d\n", 958 dstat, state->dmaCnt); 959 sii_DumpLog(); 960 } 961 } 962 #endif 963 } 964 965 /* read a one byte message */ 966 msg = sii_GetByte(regs, SII_MSG_IN_PHASE); 967 if (msg < 0) { 968 dstat = regs->dstat; 969 goto again; 970 } 971 #ifdef DEBUG 972 if (sii_debug > 4) 973 printf("MsgIn %x ", msg); 974 if (sii_logp > sii_log) 975 sii_logp[-1].msg = msg; 976 else 977 sii_log[NLOG - 1].msg = msg; 978 #endif 979 980 /* process message */ 981 switch (msg) { 982 case SCSI_COMMAND_COMPLETE: 983 msg = sc->sc_target; 984 sc->sc_target = -1; 985 /* 986 * Wait a short time for disconnect. 987 * Don't be fooled if SII_BER happens first. 988 * Note: a reselect may happen here. 989 */ 990 SII_WAIT_UNTIL(cstat, regs->cstat, 991 cstat & (SII_RST | SII_SCH), 992 SII_WAIT_COUNT, i); 993 if ((cstat & (SII_RST | SII_SCH | 994 SII_STATE_MSK)) == SII_SCH) { 995 regs->cstat = SII_SCH | SII_BER; 996 regs->comm = 0; 997 MachEmptyWriteBuffer(); 998 /* 999 * Double check that we didn't miss a 1000 * state change between seeing it and 1001 * clearing the SII_SCH bit. 1002 */ 1003 i = regs->cstat; 1004 if (!(i & SII_SCH) && 1005 (i & SII_STATE_MSK) != 1006 (cstat & SII_STATE_MSK)) 1007 sii_StateChg(sc, i); 1008 } 1009 #ifdef DEBUG 1010 if (sii_debug > 4) 1011 printf("cs %x\n", cstat); 1012 #endif 1013 sii_CmdDone(sc, msg, 0); 1014 break; 1015 1016 case SCSI_EXTENDED_MSG: 1017 /* read the message length */ 1018 msg = sii_GetByte(regs, SII_MSG_IN_PHASE); 1019 if (msg < 0) { 1020 dstat = regs->dstat; 1021 goto again; 1022 } 1023 if (msg == 0) 1024 msg = 256; 1025 sii_StartDMA(regs, SII_MSG_IN_PHASE, 1026 (u_short *)SII_BUF_ADDR, msg); 1027 /* wait a short time for XFER complete */ 1028 SII_WAIT_UNTIL(dstat, regs->dstat, 1029 (dstat & (SII_DNE | SII_TCZ)) == 1030 (SII_DNE | SII_TCZ), 1031 SII_WAIT_COUNT, i); 1032 1033 if ((dstat & (SII_DNE | SII_TCZ | SII_IPE)) != 1034 (SII_DNE | SII_TCZ)) { 1035 #ifdef DEBUG 1036 if (sii_debug > 4) 1037 printf("cnt0 %d\n", i); 1038 else if (sii_debug > 0) 1039 printf("sii_DoIntr: emsg in ds %x cnt %d\n", 1040 dstat, i); 1041 #endif 1042 printf("sii: ds %x cm %x i %d lotc %d\n", 1043 dstat, comm, i, regs->dmlotc); /* XXX */ 1044 sii_DumpLog(); /* XXX */ 1045 goto again; 1046 } 1047 1048 /* clear the DNE, other errors handled later */ 1049 regs->dstat = SII_DNE; 1050 MachEmptyWriteBuffer(); 1051 1052 CopyFromBuffer((volatile u_short *)SII_BUF_ADDR, 1053 sii_buf + 2, msg); 1054 switch (sii_buf[2]) { 1055 case SCSI_MODIFY_DATA_PTR: 1056 i = (sii_buf[3] << 24) | 1057 (sii_buf[4] << 16) | 1058 (sii_buf[5] << 8) | 1059 sii_buf[6]; 1060 if (state->dmaPrevPhase >= 0) { 1061 state->dmaAddrL += i; 1062 state->dmaCnt -= i; 1063 } 1064 break; 1065 1066 case SCSI_SYNCHRONOUS_XFER: 1067 sii_DoSync(regs, state); 1068 break; 1069 1070 case SCSI_EXTENDED_IDENTIFY: 1071 case SCSI_WIDE_XFER: 1072 default: 1073 reject: 1074 /* send a reject message */ 1075 regs->data = SCSI_MESSAGE_REJECT; 1076 regs->comm = SII_INXFER | SII_ATN | 1077 (regs->cstat & SII_STATE_MSK) | 1078 SII_MSG_OUT_PHASE; 1079 MachEmptyWriteBuffer(); 1080 /* wait for XFER complete */ 1081 SII_WAIT_UNTIL(dstat, regs->dstat, 1082 (dstat & 1083 (SII_DNE | SII_PHASE_MSK)) == 1084 (SII_DNE | SII_MSG_OUT_PHASE), 1085 SII_WAIT_COUNT, i); 1086 1087 if ((dstat & 1088 (SII_DNE | SII_PHASE_MSK)) != 1089 (SII_DNE | SII_MSG_OUT_PHASE)) 1090 break; 1091 regs->dstat = SII_DNE; 1092 MachEmptyWriteBuffer(); 1093 } 1094 break; 1095 1096 case SCSI_SAVE_DATA_POINTER: 1097 case SCSI_RESTORE_POINTERS: 1098 /* wait a short time for another msg */ 1099 SII_WAIT_UNTIL(dstat, regs->dstat, 1100 dstat & (SII_CI | SII_DI), 1101 SII_WAIT_COUNT, i); 1102 if (dstat & (SII_CI | SII_DI)) { 1103 #ifdef DEBUG 1104 if (sii_debug > 4) 1105 printf("cnt %d\n", i); 1106 #endif 1107 goto again; 1108 } 1109 break; 1110 1111 case SCSI_DISCONNECT: 1112 state->prevComm = comm; 1113 #ifdef DEBUG 1114 if (sii_debug > 4) 1115 printf("disconn %d ", sc->sc_target); 1116 #endif 1117 /* 1118 * Wait a short time for disconnect. 1119 * Don't be fooled if SII_BER happens first. 1120 * Note: a reselect may happen here. 1121 */ 1122 SII_WAIT_UNTIL(cstat, regs->cstat, 1123 cstat & (SII_RST | SII_SCH), 1124 SII_WAIT_COUNT, i); 1125 if ((cstat & (SII_RST | SII_SCH | 1126 SII_STATE_MSK)) != SII_SCH) { 1127 #ifdef DEBUG 1128 if (sii_debug > 4) 1129 printf("cnt %d\n", i); 1130 #endif 1131 dstat = regs->dstat; 1132 goto again; 1133 } 1134 regs->cstat = SII_SCH | SII_BER; 1135 regs->comm = 0; 1136 MachEmptyWriteBuffer(); 1137 sc->sc_target = -1; 1138 /* 1139 * Double check that we didn't miss a state 1140 * change between seeing it and clearing 1141 * the SII_SCH bit. 1142 */ 1143 i = regs->cstat; 1144 if (!(i & SII_SCH) && (i & SII_STATE_MSK) != 1145 (cstat & SII_STATE_MSK)) 1146 sii_StateChg(sc, i); 1147 break; 1148 1149 case SCSI_MESSAGE_REJECT: 1150 printf("sii%d: device %d: message reject.\n", 1151 sc - sii_softc, sc->sc_target); 1152 goto abort; 1153 1154 default: 1155 if (!(msg & SCSI_IDENTIFY)) { 1156 printf("sii%d: device %d: couldn't handle message 0x%x... ignoring.\n", 1157 sc - sii_softc, sc->sc_target, 1158 msg); 1159 #ifdef DEBUG 1160 sii_DumpLog(); 1161 #endif 1162 break; 1163 } 1164 /* may want to check LUN some day */ 1165 /* wait a short time for another msg */ 1166 SII_WAIT_UNTIL(dstat, regs->dstat, 1167 dstat & (SII_CI | SII_DI), 1168 SII_WAIT_COUNT, i); 1169 if (dstat & (SII_CI | SII_DI)) { 1170 #ifdef DEBUG 1171 if (sii_debug > 4) 1172 printf("cnt %d\n", i); 1173 #endif 1174 goto again; 1175 } 1176 } 1177 break; 1178 1179 case SII_MSG_OUT_PHASE: 1180 #ifdef DEBUG 1181 if (sii_debug > 4) 1182 printf("MsgOut\n"); 1183 #endif 1184 1185 regs->data = SCSI_NO_OP; 1186 regs->comm = SII_INXFER | (comm & SII_STATE_MSK) | 1187 SII_MSG_OUT_PHASE; 1188 MachEmptyWriteBuffer(); 1189 1190 /* wait a short time for XFER complete */ 1191 SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE, 1192 SII_WAIT_COUNT, i); 1193 #ifdef DEBUG 1194 if (sii_debug > 4) 1195 printf("ds %x i %d\n", dstat, i); 1196 #endif 1197 /* just clear the DNE bit and check errors later */ 1198 if (dstat & SII_DNE) { 1199 regs->dstat = SII_DNE; 1200 MachEmptyWriteBuffer(); 1201 } 1202 break; 1203 1204 default: 1205 printf("sii%d: Couldn't handle phase %d... ignoring.\n", 1206 sc - sii_softc, dstat & SII_PHASE_MSK); 1207 } 1208 } 1209 1210 #ifdef DEBUG 1211 if (sii_debug > 3) 1212 printf("\n"); 1213 #endif 1214 /* 1215 * Check to make sure we won't be interrupted again. 1216 * Deglitch dstat register. 1217 */ 1218 msg = regs->dstat; 1219 while (msg != (dstat = regs->dstat)) 1220 msg = dstat; 1221 if (dstat & (SII_CI | SII_DI)) 1222 goto again; 1223 1224 if (sc->sc_target < 0) { 1225 /* look for another device that is ready */ 1226 for (i = 0; i < SII_NCMD; i++) { 1227 /* don't restart a disconnected command */ 1228 if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm) 1229 continue; 1230 sii_StartCmd(sc, i); 1231 break; 1232 } 1233 } 1234 return; 1235 1236 abort: 1237 /* jump here to abort the current command */ 1238 printf("sii%d: device %d: current command terminated\n", 1239 sc - sii_softc, sc->sc_target); 1240 #ifdef DEBUG 1241 sii_DumpLog(); 1242 #endif 1243 1244 if ((cstat = regs->cstat) & SII_CON) { 1245 /* try to send an abort msg for awhile */ 1246 regs->dstat = SII_DNE; 1247 regs->data = SCSI_ABORT; 1248 regs->comm = SII_INXFER | SII_ATN | (cstat & SII_STATE_MSK) | 1249 SII_MSG_OUT_PHASE; 1250 MachEmptyWriteBuffer(); 1251 SII_WAIT_UNTIL(dstat, regs->dstat, 1252 (dstat & (SII_DNE | SII_PHASE_MSK)) == 1253 (SII_DNE | SII_MSG_OUT_PHASE), 1254 2 * SII_WAIT_COUNT, i); 1255 #ifdef DEBUG 1256 if (sii_debug > 0) 1257 printf("Abort: cs %x ds %x i %d\n", cstat, dstat, i); 1258 #endif 1259 if (dstat & (SII_DNE | SII_PHASE_MSK) == 1260 (SII_DNE | SII_MSG_OUT_PHASE)) { 1261 /* disconnect if command in progress */ 1262 regs->comm = SII_DISCON; 1263 MachEmptyWriteBuffer(); 1264 SII_WAIT_UNTIL(cstat, regs->cstat, 1265 !(cstat & SII_CON), SII_WAIT_COUNT, i); 1266 } 1267 } else { 1268 #ifdef DEBUG 1269 if (sii_debug > 0) 1270 printf("Abort: cs %x\n", cstat); 1271 #endif 1272 } 1273 regs->cstat = 0xffff; 1274 regs->dstat = 0xffff; 1275 regs->comm = 0; 1276 MachEmptyWriteBuffer(); 1277 1278 i = sc->sc_target; 1279 sc->sc_target = -1; 1280 sii_CmdDone(sc, i, EIO); 1281 #ifdef DEBUG 1282 if (sii_debug > 4) 1283 printf("sii_DoIntr: after CmdDone target %d\n", sc->sc_target); 1284 #endif 1285 } 1286 1287 static void 1288 sii_StateChg(sc, cstat) 1289 register struct siisoftc *sc; 1290 register unsigned cstat; 1291 { 1292 register SIIRegs *regs = sc->sc_regs; 1293 register State *state; 1294 register int i; 1295 1296 #ifdef DEBUG 1297 if (sii_debug > 4) 1298 printf("SCH: "); 1299 #endif 1300 1301 switch (cstat & SII_STATE_MSK) { 1302 case 0: 1303 /* disconnect */ 1304 i = sc->sc_target; 1305 sc->sc_target = -1; 1306 #ifdef DEBUG 1307 if (sii_debug > 4) 1308 printf("disconn %d ", i); 1309 #endif 1310 if (i >= 0 && !sc->sc_st[i].prevComm) { 1311 printf("sii%d: device %d: spurrious disconnect (%d)\n", 1312 sc - sii_softc, i, regs->slcsr); 1313 sc->sc_st[i].prevComm = 0; 1314 } 1315 break; 1316 1317 case SII_CON: 1318 /* connected as initiator */ 1319 i = regs->slcsr; 1320 if (sc->sc_target == i) 1321 break; 1322 printf("sii%d: device %d: connect to device %d??\n", 1323 sc - sii_softc, sc->sc_target, i); 1324 sc->sc_target = i; 1325 break; 1326 1327 case SII_DST: 1328 /* 1329 * Wait for CON to become valid, 1330 * chip is slow sometimes. 1331 */ 1332 SII_WAIT_UNTIL(cstat, regs->cstat, 1333 cstat & SII_CON, SII_WAIT_COUNT, i); 1334 if (!(cstat & SII_CON)) 1335 panic("sii resel"); 1336 /* FALLTHROUGH */ 1337 1338 case SII_CON | SII_DST: 1339 /* 1340 * Its a reselection. Save the ID and wait for 1341 * interrupts to tell us what to do next 1342 * (should be MSG_IN of IDENTIFY). 1343 * NOTE: sc_target may be >= 0 if we were in 1344 * the process of trying to start a command 1345 * and were reselected before the select 1346 * command finished. 1347 */ 1348 sc->sc_target = i = regs->destat; 1349 regs->comm = SII_CON | SII_DST | SII_MSG_IN_PHASE; 1350 MachEmptyWriteBuffer(); 1351 state = &sc->sc_st[i]; 1352 if (!state->prevComm) { 1353 printf("sii%d: device %d: spurrious reselection\n", 1354 sc - sii_softc, i); 1355 break; 1356 } 1357 state->prevComm = 0; 1358 #ifdef DEBUG 1359 if (sii_debug > 4) 1360 printf("resel %d ", sc->sc_target); 1361 #endif 1362 break; 1363 1364 #ifdef notyet 1365 case SII_DST | SII_TGT: 1366 case SII_CON | SII_DST | SII_TGT: 1367 /* connected as target */ 1368 printf("sii%d: Selected by device %d as target!!\n", 1369 sc - sii_softc, regs->destat); 1370 regs->comm = SII_DISCON; 1371 MachEmptyWriteBuffer(); 1372 SII_WAIT_UNTIL(!(regs->cstat & SII_CON), 1373 SII_WAIT_COUNT, i); 1374 regs->cstat = 0xffff; 1375 regs->dstat = 0xffff; 1376 regs->comm = 0; 1377 break; 1378 #endif 1379 1380 default: 1381 printf("sii%d: Unknown state change (cs %x)!!\n", 1382 sc - sii_softc, cstat); 1383 #ifdef DEBUG 1384 sii_DumpLog(); 1385 #endif 1386 } 1387 } 1388 1389 /* 1390 * Read one byte of data. 1391 */ 1392 static int 1393 sii_GetByte(regs, phase) 1394 register SIIRegs *regs; 1395 int phase; 1396 { 1397 register unsigned dstat; 1398 register unsigned state; 1399 #ifdef PROGXFER 1400 register unsigned data; 1401 1402 dstat = regs->dstat; 1403 state = regs->cstat & SII_STATE_MSK; 1404 regs->dmctrl = 0; 1405 if (!(dstat & SII_IBF) || (dstat & SII_MIS)) { 1406 regs->comm = state | phase; 1407 MachEmptyWriteBuffer(); 1408 /* wait a short time for IBF */ 1409 SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_IBF, 1410 SII_WAIT_COUNT, i); 1411 #ifdef DEBUG 1412 if (!(dstat & SII_IBF)) 1413 printf("status no IBF\n"); 1414 #endif 1415 } 1416 data = regs->data; 1417 if (regs->dstat & SII_DNE) { /* XXX */ 1418 printf("sii_GetByte: DNE set 5\n"); 1419 sii_DumpLog(); 1420 regs->dstat = SII_DNE; 1421 } 1422 regs->comm = SII_INXFER | state | phase; 1423 MachEmptyWriteBuffer(); 1424 1425 /* wait a short time for XFER complete */ 1426 SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE, 1427 SII_WAIT_COUNT, i); 1428 1429 if ((dstat & (SII_DNE | SII_IPE)) != SII_DNE) { 1430 #ifdef DEBUG 1431 if (sii_debug > 4) 1432 printf("cnt0 %d\n", i); 1433 #endif 1434 printf("MsgIn %x ?? ds %x cm %x i %d\n", 1435 data, dstat, comm, i); /* XXX */ 1436 sii_DumpLog(); /* XXX */ 1437 panic("status"); /* XXX */ 1438 goto again; 1439 } 1440 1441 /* clear the DNE, other errors handled later */ 1442 regs->dstat = SII_DNE; 1443 MachEmptyWriteBuffer(); 1444 return (data); 1445 1446 #else /* PROGXFER */ 1447 register int i; 1448 1449 state = regs->cstat & SII_STATE_MSK; 1450 regs->dmctrl = 0; 1451 if (regs->dstat & SII_DNE) { 1452 printf("sii_GetByte: DNE cs %x ds %x cm %x\n", 1453 regs->cstat, regs->dstat, regs->comm); /* XXX */ 1454 regs->dstat = SII_DNE; 1455 } 1456 regs->dmaddrl = ((unsigned)SII_BUF_ADDR >> 1); 1457 regs->dmaddrh = ((unsigned)SII_BUF_ADDR >> 17) & 03; 1458 regs->dmlotc = 1; 1459 regs->comm = SII_DMA | SII_INXFER | state | phase; 1460 MachEmptyWriteBuffer(); 1461 1462 /* wait a short time for XFER complete */ 1463 SII_WAIT_UNTIL(dstat, regs->dstat, 1464 (dstat & (SII_DNE | SII_TCZ)) == (SII_DNE | SII_TCZ), 1465 SII_WAIT_COUNT, i); 1466 1467 if ((dstat & (SII_DNE | SII_TCZ | SII_IPE)) != (SII_DNE | SII_TCZ)) { 1468 printf("sii_GetByte: ds %x cm %x i %d lotc %d\n", 1469 dstat, regs->comm, i, regs->dmlotc); /* XXX */ 1470 sii_DumpLog(); /* XXX */ 1471 return (-1); 1472 } 1473 1474 /* clear the DNE, other errors handled later */ 1475 regs->dstat = SII_DNE; 1476 MachEmptyWriteBuffer(); 1477 1478 /* return one byte of data (optimized CopyFromBuffer()) */ 1479 return (*(volatile u_short *)SII_BUF_ADDR & 0xFF); 1480 #endif /* PROGXFER */ 1481 } 1482 1483 /* 1484 * Exchange messages to initiate synchronous data transfers. 1485 */ 1486 static void 1487 sii_DoSync(regs, state) 1488 register SIIRegs *regs; 1489 register State *state; 1490 { 1491 register unsigned dstat; 1492 register int i; 1493 unsigned len; 1494 1495 printf("sii_DoSync: per %d req/ack %d\n", 1496 sii_buf[3], sii_buf[4]); /* XXX */ 1497 len = sii_buf[4]; 1498 if (len > 3) 1499 len = 3; /* SII chip can only handle 3 max */ 1500 1501 sii_buf[0] = SCSI_EXTENDED_MSG; 1502 sii_buf[1] = 3; /* message length */ 1503 sii_buf[2] = SCSI_SYNCHRONOUS_XFER; 1504 sii_buf[4] = len; 1505 CopyToBuffer((u_short *)sii_buf, (volatile u_short *)SII_BUF_ADDR, 5); 1506 regs->dmaddrl = ((unsigned)SII_BUF_ADDR >> 1); 1507 regs->dmaddrh = ((unsigned)SII_BUF_ADDR >> 17) & 03; 1508 regs->dmlotc = 5; 1509 regs->comm = SII_DMA | SII_INXFER | SII_ATN | 1510 (regs->cstat & SII_STATE_MSK) | SII_MSG_OUT_PHASE; 1511 MachEmptyWriteBuffer(); 1512 1513 /* wait a short time for XFER complete */ 1514 SII_WAIT_UNTIL(dstat, regs->dstat, 1515 (dstat & (SII_DNE | SII_TCZ)) == (SII_DNE | SII_TCZ), 1516 SII_WAIT_COUNT, i); 1517 1518 if ((dstat & (SII_DNE | SII_TCZ)) != (SII_DNE | SII_TCZ)) { 1519 printf("sii_DoSync: ds %x cm %x i %d lotc %d\n", 1520 dstat, regs->comm, i, regs->dmlotc); /* XXX */ 1521 sii_DumpLog(); /* XXX */ 1522 return; 1523 } 1524 1525 /* clear the DNE, other errors handled later */ 1526 regs->dstat = SII_DNE; 1527 regs->comm = regs->comm & SII_STATE_MSK; 1528 MachEmptyWriteBuffer(); 1529 1530 state->dmaReqAck = len; 1531 } 1532 1533 /* 1534 * Issue the sequence of commands to the controller to start DMA. 1535 * NOTE: the data buffer should be word-aligned for DMA out. 1536 */ 1537 static void 1538 sii_StartDMA(regs, phase, dmaAddr, size) 1539 register SIIRegs *regs; /* which SII to use */ 1540 int phase; /* phase to send/receive data */ 1541 u_short *dmaAddr; /* DMA buffer address */ 1542 int size; /* # of bytes to transfer */ 1543 { 1544 1545 if (regs->dstat & SII_DNE) { /* XXX */ 1546 printf("sii_StartDMA: DNE set\n"); 1547 sii_DumpLog(); 1548 regs->dstat = SII_DNE; 1549 } 1550 regs->dmaddrl = ((unsigned)dmaAddr >> 1); 1551 regs->dmaddrh = ((unsigned)dmaAddr >> 17) & 03; 1552 regs->dmlotc = size; 1553 regs->comm = SII_DMA | SII_INXFER | (regs->cstat & SII_STATE_MSK) | 1554 phase; 1555 MachEmptyWriteBuffer(); 1556 1557 #ifdef DEBUG 1558 if (sii_debug > 5) { 1559 printf("sii_StartDMA: cs 0x%x, ds 0x%x, cm 0x%x, size %d\n", 1560 regs->cstat, regs->dstat, regs->comm, size); 1561 } 1562 #endif 1563 } 1564 1565 /* 1566 * Call the device driver's 'done' routine to let it know the command is done. 1567 * The 'done' routine may try to start another command. 1568 * To be fair, we should start pending commands for other devices 1569 * before allowing the same device to start another command. 1570 */ 1571 static void 1572 sii_CmdDone(sc, target, error) 1573 register struct siisoftc *sc; /* which SII to use */ 1574 int target; /* which device is done */ 1575 int error; /* error code if any errors */ 1576 { 1577 register ScsiCmd *scsicmd; 1578 register int i; 1579 1580 scsicmd = sc->sc_cmd[target]; 1581 #ifdef DIAGNOSTIC 1582 if (target < 0 || !scsicmd) 1583 panic("sii_CmdDone"); 1584 #endif 1585 sc->sc_cmd[target] = (ScsiCmd *)0; 1586 #ifdef DEBUG 1587 if (sii_debug > 1) { 1588 printf("sii_CmdDone: %s target %d cmd %x err %d resid %d\n", 1589 scsicmd->sd->sd_driver->d_name, target, 1590 scsicmd->cmd[0], error, sc->sc_st[target].buflen); 1591 } 1592 #endif 1593 1594 /* look for another device that is ready */ 1595 for (i = 0; i < SII_NCMD; i++) { 1596 /* don't restart a disconnected command */ 1597 if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm) 1598 continue; 1599 sii_StartCmd(sc, i); 1600 break; 1601 } 1602 1603 (*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, error, 1604 sc->sc_st[target].buflen, sc->sc_st[target].statusByte); 1605 } 1606 1607 #ifdef DEBUG 1608 sii_DumpLog() 1609 { 1610 register struct sii_log *lp; 1611 1612 printf("sii: cmd %x bn %d cnt %d\n", sii_debug_cmd, sii_debug_bn, 1613 sii_debug_sz); 1614 lp = sii_logp + 1; 1615 if (lp > &sii_log[NLOG]) 1616 lp = sii_log; 1617 while (lp != sii_logp) { 1618 printf("target %d cs %x ds %x cm %x msg %x\n", 1619 lp->target, lp->cstat, lp->dstat, lp->comm, lp->msg); 1620 if (++lp >= &sii_log[NLOG]) 1621 lp = sii_log; 1622 } 1623 } 1624 #endif 1625 #endif 1626