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.3 (Berkeley) 02/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 if (state->buflen > SII_MAX_DMA_XFER_LENGTH && 321 (scsicmd->flags & SCSICMD_DATA_TO_DEVICE)) 322 printf("sii_StartCmd: target %d dma %d\n", 323 target, state->buflen); /* XXX */ 324 } 325 326 #ifdef DEBUG 327 if (sii_debug > 1) { 328 printf("sii_StartCmd: %s target %d cmd 0x%x addr %x size %d dma %d\n", 329 scsicmd->sd->sd_driver->d_name, target, 330 scsicmd->cmd[0], scsicmd->buf, scsicmd->buflen, 331 state->dmaDataPhase); 332 } 333 sii_debug_cmd = scsicmd->cmd[0]; 334 if (scsicmd->cmd[0] == SCSI_READ_EXT) { 335 sii_debug_bn = (scsicmd->cmd[2] << 24) | 336 (scsicmd->cmd[3] << 16) | 337 (scsicmd->cmd[4] << 8) | 338 scsicmd->cmd[5]; 339 sii_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8]; 340 } 341 #endif 342 343 /* try to select the target */ 344 regs = sc->sc_regs; 345 346 /* 347 * Another device may have selected us; in which case, 348 * this command will be restarted later. 349 */ 350 if ((status = regs->dstat) & (SII_CI | SII_DI)) { 351 sii_DoIntr(sc, status); 352 return; 353 } 354 355 sc->sc_target = target; 356 if (scsicmd->flags & SCSICMD_USE_SYNC) { 357 printf("sii_StartCmd: doing extended msg\n"); /* XXX */ 358 /* 359 * Setup to send both the identify message and the synchronous 360 * data transfer request. 361 */ 362 sii_buf[0] = SCSI_DIS_REC_IDENTIFY; 363 sii_buf[1] = SCSI_EXTENDED_MSG; 364 sii_buf[2] = 3; /* message length */ 365 sii_buf[3] = SCSI_SYNCHRONOUS_XFER; 366 sii_buf[4] = 0; 367 sii_buf[5] = 3; /* maximum SII chip supports */ 368 369 state->dmaCurPhase = SII_MSG_OUT_PHASE, 370 state->dmalen = 6; 371 CopyToBuffer((u_short *)sii_buf, 372 (volatile u_short *)SII_BUF_ADDR, 6); 373 regs->slcsr = target; 374 regs->dmctrl = 0; 375 regs->dmaddrl = ((unsigned)SII_BUF_ADDR >> 1); 376 regs->dmaddrh = ((unsigned)SII_BUF_ADDR >> 17) & 03; 377 regs->dmlotc = 6; 378 regs->comm = SII_DMA | SII_INXFER | SII_SELECT | SII_ATN | 379 SII_CON | SII_MSG_OUT_PHASE; 380 } else { 381 /* do a chained, select with ATN and programmed I/O command */ 382 regs->data = SCSI_DIS_REC_IDENTIFY; 383 regs->slcsr = target; 384 regs->dmctrl = 0; 385 regs->comm = SII_INXFER | SII_SELECT | SII_ATN | SII_CON | 386 SII_MSG_OUT_PHASE; 387 } 388 MachEmptyWriteBuffer(); 389 390 /* 391 * Wait for something to happen 392 * (should happen soon or we would use interrupts). 393 */ 394 SII_WAIT_UNTIL(status, regs->cstat, status & (SII_CI | SII_DI), 395 SII_WAIT_COUNT/2, retval); 396 397 /* check to see if we are connected OK */ 398 if ((status & (SII_RST | SII_SCH | SII_STATE_MSK)) == 399 (SII_SCH | SII_CON)) { 400 regs->cstat = status; 401 MachEmptyWriteBuffer(); 402 403 #ifdef DEBUG 404 sii_logp->target = target; 405 sii_logp->cstat = status; 406 sii_logp->dstat = 0; 407 sii_logp->comm = regs->comm; 408 sii_logp->msg = -1; 409 if (++sii_logp >= &sii_log[NLOG]) 410 sii_logp = sii_log; 411 #endif 412 413 /* wait a short time for command phase */ 414 SII_WAIT_UNTIL(status, regs->dstat, status & SII_MIS, 415 SII_WAIT_COUNT, retval); 416 #ifdef DEBUG 417 if (sii_debug > 2) 418 printf("sii_StartCmd: ds %x cnt %d\n", status, retval); 419 #endif 420 if ((status & (SII_CI | SII_MIS | SII_PHASE_MSK)) != 421 (SII_MIS | SII_CMD_PHASE)) { 422 printf("sii_StartCmd: timeout cs %x ds %x cnt %d\n", 423 regs->cstat, status, retval); /* XXX */ 424 /* process interrupt or continue until it happens */ 425 if (status & (SII_CI | SII_DI)) 426 sii_DoIntr(sc, status); 427 return; 428 } 429 regs->dstat = SII_DNE; /* clear Msg Out DMA done */ 430 431 /* send command data */ 432 CopyToBuffer((u_short *)state->cmd, 433 (volatile u_short *)state->dmaAddr[0], state->cmdlen); 434 sii_StartDMA(regs, state->dmaCurPhase = SII_CMD_PHASE, 435 state->dmaAddr[0], state->dmalen = scsicmd->cmdlen); 436 437 /* wait a little while for DMA to finish */ 438 SII_WAIT_UNTIL(status, regs->dstat, status & (SII_CI | SII_DI), 439 SII_WAIT_COUNT, retval); 440 #ifdef DEBUG 441 if (sii_debug > 2) 442 printf("sii_StartCmd: ds %x, cnt %d\n", status, retval); 443 #endif 444 if (status & (SII_CI | SII_DI)) 445 sii_DoIntr(sc, status); 446 #ifdef DEBUG 447 if (sii_debug > 2) 448 printf("sii_StartCmd: DONE ds %x\n", regs->dstat); 449 #endif 450 return; 451 } 452 453 /* 454 * Another device may have selected us; in which case, 455 * this command will be restarted later. 456 */ 457 if (status & (SII_CI | SII_DI)) { 458 sii_DoIntr(sc, regs->dstat); 459 return; 460 } 461 462 /* 463 * Disconnect if selection command still in progress. 464 */ 465 if (status & SII_SIP) { 466 error = ENXIO; /* device didn't respond */ 467 regs->comm = SII_DISCON; 468 MachEmptyWriteBuffer(); 469 SII_WAIT_UNTIL(status, regs->cstat, 470 !(status & (SII_CON | SII_SIP)), 471 SII_WAIT_COUNT, retval); 472 } else 473 error = EBUSY; /* couldn't get the bus */ 474 #ifdef DEBUG 475 if (sii_debug > 0) 476 printf("sii_StartCmd: Couldn't select target %d error %d\n", 477 target, error); 478 #endif 479 sc->sc_target = -1; 480 regs->cstat = 0xffff; 481 regs->dstat = 0xffff; 482 regs->comm = 0; 483 MachEmptyWriteBuffer(); 484 sii_CmdDone(sc, target, error); 485 } 486 487 /* 488 * Process interrupt conditions. 489 */ 490 static void 491 sii_DoIntr(sc, dstat) 492 register struct siisoftc *sc; 493 register unsigned dstat; 494 { 495 register SIIRegs *regs = sc->sc_regs; 496 register State *state; 497 register unsigned cstat; 498 register int i; 499 unsigned comm, msg; 500 501 again: 502 comm = regs->comm; 503 504 #ifdef DEBUG 505 if (sii_debug > 3) 506 printf("sii_DoIntr: cs %x, ds %x cm %x ", 507 regs->cstat, dstat, comm); 508 sii_logp->target = sc->sc_target; 509 sii_logp->cstat = regs->cstat; 510 sii_logp->dstat = dstat; 511 sii_logp->comm = comm; 512 sii_logp->msg = -1; 513 if (++sii_logp >= &sii_log[NLOG]) 514 sii_logp = sii_log; 515 #endif 516 517 regs->dstat = dstat; /* acknowledge everything */ 518 MachEmptyWriteBuffer(); 519 520 if (dstat & SII_CI) { 521 /* deglitch cstat register */ 522 msg = regs->cstat; 523 while (msg != (cstat = regs->cstat)) 524 msg = cstat; 525 regs->cstat = cstat; /* acknowledge everything */ 526 MachEmptyWriteBuffer(); 527 #ifdef DEBUG 528 if (sii_logp > sii_log) 529 sii_logp[-1].cstat = cstat; 530 else 531 sii_log[NLOG - 1].cstat = cstat; 532 #endif 533 534 /* check for a BUS RESET */ 535 if (cstat & SII_RST) { 536 printf("sii%d: SCSI bus reset!!\n", sc - sii_softc); 537 /* need to flush disconnected commands */ 538 for (i = 0; i < SII_NCMD; i++) { 539 if (!sc->sc_cmd[i]) 540 continue; 541 sii_CmdDone(sc, i, EIO); 542 } 543 /* rearbitrate synchronous offset */ 544 for (i = 0; i < SII_NCMD; i++) 545 sc->sc_st[i].dmaReqAck = 0; 546 sc->sc_target = -1; 547 return; 548 } 549 550 #ifdef notdef 551 /* 552 * Check for a BUS ERROR. 553 * According to DEC, this feature doesn't really work 554 * and to just clear the bit if it's set. 555 */ 556 if (cstat & SII_BER) { 557 } 558 #endif 559 560 /* check for state change */ 561 if (cstat & SII_SCH) { 562 sii_StateChg(sc, cstat); 563 comm = regs->comm; 564 } 565 } 566 567 /* check for DMA completion */ 568 if (dstat & SII_DNE) { 569 u_short *dma; 570 char *buf; 571 572 /* check for a PARITY ERROR */ 573 if (dstat & SII_IPE) { 574 printf("sii%d: Parity error!!\n", sc - sii_softc); 575 goto abort; 576 } 577 /* 578 * There is a race condition with SII_SCH. There is a short 579 * window between the time a SII_SCH is seen after a disconnect 580 * and when the SII_SCH is cleared. A reselect can happen 581 * in this window and we will clear the SII_SCH without 582 * processing the reconnect. 583 */ 584 if (sc->sc_target < 0) { 585 cstat = regs->cstat; 586 printf("sii%d: target %d DNE?? dev %d,%d cs %x\n", 587 sc - sii_softc, sc->sc_target, 588 regs->slcsr, regs->destat, 589 cstat); /* XXX */ 590 if (cstat & SII_DST) { 591 sc->sc_target = regs->destat; 592 state->prevComm = 0; 593 } else 594 panic("sc_target 1"); 595 } 596 state = &sc->sc_st[sc->sc_target]; 597 /* dmalen = amount left to transfer, i = amount transfered */ 598 i = state->dmalen; 599 state->dmalen = 0; 600 state->dmaCurPhase = -1; 601 #ifdef DEBUG 602 if (sii_debug > 4) { 603 printf("DNE: amt %d ", i); 604 if (!(dstat & SII_TCZ)) 605 printf("no TCZ?? (%d) ", regs->dmlotc); 606 } else if (!(dstat & SII_TCZ)) { 607 printf("sii%d: device %d: no TCZ?? (%d)\n", 608 sc - sii_softc, sc->sc_target, regs->dmlotc); 609 sii_DumpLog(); /* XXX */ 610 } 611 #endif 612 switch (comm & SII_PHASE_MSK) { 613 case SII_CMD_PHASE: 614 state->cmdlen -= i; 615 break; 616 617 case SII_DATA_IN_PHASE: 618 /* check for more data for the same phase */ 619 dma = state->dmaAddr[state->dmaBufIndex]; 620 buf = state->buf; 621 state->buf += i; 622 state->buflen -= i; 623 if (state->buflen > 0 && !(dstat & SII_MIS)) { 624 int len; 625 626 /* start reading next chunk */ 627 len = state->buflen; 628 if (len > SII_MAX_DMA_XFER_LENGTH) 629 len = SII_MAX_DMA_XFER_LENGTH; 630 state->dmaBufIndex = !state->dmaBufIndex; 631 sii_StartDMA(regs, 632 state->dmaCurPhase = SII_DATA_IN_PHASE, 633 state->dmaAddr[state->dmaBufIndex], 634 state->dmalen = len); 635 dstat &= ~(SII_IBF | SII_TBE); 636 } 637 /* copy in the data */ 638 CopyFromBuffer((volatile u_short *)dma, buf, i); 639 break; 640 641 case SII_DATA_OUT_PHASE: 642 state->dmaBufIndex = !state->dmaBufIndex; 643 state->buf += i; 644 state->buflen -= i; 645 646 /* check for more data for the same phase */ 647 if (state->buflen <= 0 || (dstat & SII_MIS)) 648 break; 649 650 /* start next chunk */ 651 i = state->buflen; 652 if (i > SII_MAX_DMA_XFER_LENGTH) { 653 sii_StartDMA(regs, state->dmaCurPhase = 654 SII_DATA_OUT_PHASE, 655 state->dmaAddr[state->dmaBufIndex], 656 state->dmalen = 657 SII_MAX_DMA_XFER_LENGTH); 658 /* prepare for next chunk */ 659 i -= SII_MAX_DMA_XFER_LENGTH; 660 if (i > SII_MAX_DMA_XFER_LENGTH) 661 i = SII_MAX_DMA_XFER_LENGTH; 662 CopyToBuffer((u_short *)(state->buf + 663 SII_MAX_DMA_XFER_LENGTH), 664 (volatile u_short *) 665 state->dmaAddr[!state->dmaBufIndex], i); 666 } else { 667 sii_StartDMA(regs, state->dmaCurPhase = 668 SII_DATA_OUT_PHASE, 669 state->dmaAddr[state->dmaBufIndex], 670 state->dmalen = i); 671 } 672 dstat &= ~(SII_IBF | SII_TBE); 673 break; 674 675 default: 676 printf("sii%d: device %d: unexpected DNE\n", 677 sc - sii_softc, sc->sc_target); 678 #ifdef DEBUG 679 sii_DumpLog(); 680 #endif 681 } 682 } 683 684 /* check for phase change or another MsgIn/Out */ 685 if (dstat & (SII_MIS | SII_IBF | SII_TBE)) { 686 /* 687 * There is a race condition with SII_SCH. There is a short 688 * window between the time a SII_SCH is seen after a disconnect 689 * and when the SII_SCH is cleared. A reselect can happen 690 * in this window and we will clear the SII_SCH without 691 * processing the reconnect. 692 */ 693 if (sc->sc_target < 0) { 694 cstat = regs->cstat; 695 printf("sii%d: target %d MIS?? dev %d,%d cs %x ds %x\n", 696 sc - sii_softc, sc->sc_target, 697 regs->slcsr, regs->destat, 698 cstat, dstat); /* XXX */ 699 if (cstat & SII_DST) { 700 sc->sc_target = regs->destat; 701 state->prevComm = 0; 702 } else 703 panic("sc_target 2"); 704 } 705 state = &sc->sc_st[sc->sc_target]; 706 switch (dstat & SII_PHASE_MSK) { 707 case SII_CMD_PHASE: 708 if (state->dmaPrevPhase >= 0) { 709 /* restart DMA after disconnect/reconnect */ 710 if (state->dmaPrevPhase != SII_CMD_PHASE) { 711 printf("sii%d: device %d: dma reselect phase doesn't match\n", 712 sc - sii_softc, sc->sc_target); 713 goto abort; 714 } 715 state->dmaCurPhase = SII_CMD_PHASE; 716 state->dmaPrevPhase = -1; 717 regs->dmaddrl = state->dmaAddrL; 718 regs->dmaddrh = state->dmaAddrH; 719 regs->dmlotc = state->dmaCnt; 720 if (state->dmaCnt & 1) 721 regs->dmabyte = state->dmaByte; 722 regs->comm = SII_DMA | SII_INXFER | 723 (comm & SII_STATE_MSK) | SII_CMD_PHASE; 724 MachEmptyWriteBuffer(); 725 #ifdef DEBUG 726 if (sii_debug > 4) 727 printf("Cmd dcnt %d dadr %x ", 728 state->dmaCnt, 729 (state->dmaAddrH << 16) | 730 state->dmaAddrL); 731 #endif 732 } else { 733 /* send command data */ 734 i = state->cmdlen; 735 if (i == 0) { 736 printf("sii%d: device %d: cmd count exceeded\n", 737 sc - sii_softc, sc->sc_target); 738 goto abort; 739 } 740 CopyToBuffer((u_short *)state->cmd, 741 (volatile u_short *)state->dmaAddr[0], 742 i); 743 sii_StartDMA(regs, state->dmaCurPhase = 744 SII_CMD_PHASE, state->dmaAddr[0], 745 state->dmalen = i); 746 } 747 /* wait a short time for XFER complete */ 748 SII_WAIT_UNTIL(dstat, regs->dstat, 749 dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i); 750 if (dstat & (SII_CI | SII_DI)) { 751 #ifdef DEBUG 752 if (sii_debug > 4) 753 printf("cnt %d\n", i); 754 else if (sii_debug > 0) 755 printf("sii_DoIntr: cmd wait ds %x cnt %d\n", 756 dstat, i); 757 #endif 758 goto again; 759 } 760 break; 761 762 case SII_DATA_IN_PHASE: 763 case SII_DATA_OUT_PHASE: 764 regs->dmctrl = state->dmaReqAck; 765 if (state->cmdlen > 0) { 766 printf("sii%d: device %d: cmd %x: command data not all sent (%d) 1\n", 767 sc - sii_softc, sc->sc_target, 768 sc->sc_cmd[sc->sc_target]->cmd[0], 769 state->cmdlen); 770 state->cmdlen = 0; 771 #ifdef DEBUG 772 sii_DumpLog(); 773 #endif 774 } 775 if (state->dmaPrevPhase >= 0) { 776 /* restart DMA after disconnect/reconnect */ 777 if (state->dmaPrevPhase != 778 (dstat & SII_PHASE_MSK)) { 779 printf("sii%d: device %d: dma reselect phase doesn't match\n", 780 sc - sii_softc, sc->sc_target); 781 goto abort; 782 } 783 state->dmaCurPhase = state->dmaPrevPhase; 784 state->dmaPrevPhase = -1; 785 regs->dmaddrl = state->dmaAddrL; 786 regs->dmaddrh = state->dmaAddrH; 787 regs->dmlotc = state->dmaCnt; 788 if (state->dmaCnt & 1) 789 regs->dmabyte = state->dmaByte; 790 regs->comm = SII_DMA | SII_INXFER | 791 (comm & SII_STATE_MSK) | 792 state->dmaCurPhase; 793 MachEmptyWriteBuffer(); 794 #ifdef DEBUG 795 if (sii_debug > 4) 796 printf("Data %d dcnt %d dadr %x ", 797 state->dmaDataPhase, 798 state->dmaCnt, 799 (state->dmaAddrH << 16) | 800 state->dmaAddrL); 801 #endif 802 break; 803 } 804 if (state->dmaDataPhase != (dstat & SII_PHASE_MSK)) { 805 printf("sii%d: device %d: cmd %x: dma phase doesn't match\n", 806 sc - sii_softc, sc->sc_target, 807 sc->sc_cmd[sc->sc_target]->cmd[0]); 808 goto abort; 809 } 810 #ifdef DEBUG 811 if (sii_debug > 4) { 812 printf("Data %d ", state->dmaDataPhase); 813 if (sii_debug > 5) 814 printf("\n"); 815 } 816 #endif 817 i = state->buflen; 818 if (i == 0) { 819 printf("sii%d: device %d: data count exceeded\n", 820 sc - sii_softc, sc->sc_target); 821 goto abort; 822 } 823 if (i > SII_MAX_DMA_XFER_LENGTH) 824 i = SII_MAX_DMA_XFER_LENGTH; 825 if ((dstat & SII_PHASE_MSK) == SII_DATA_IN_PHASE) { 826 sii_StartDMA(regs, 827 state->dmaCurPhase = SII_DATA_IN_PHASE, 828 state->dmaAddr[state->dmaBufIndex], 829 state->dmalen = i); 830 break; 831 } 832 /* start first chunk */ 833 if (state->flags & FIRST_DMA) { 834 state->flags &= ~FIRST_DMA; 835 CopyToBuffer((u_short *)state->buf, 836 (volatile u_short *) 837 state->dmaAddr[state->dmaBufIndex], i); 838 } 839 sii_StartDMA(regs, 840 state->dmaCurPhase = SII_DATA_OUT_PHASE, 841 state->dmaAddr[state->dmaBufIndex], 842 state->dmalen = i); 843 i = state->buflen - SII_MAX_DMA_XFER_LENGTH; 844 if (i > 0) { 845 /* prepare for next chunk */ 846 if (i > SII_MAX_DMA_XFER_LENGTH) 847 i = SII_MAX_DMA_XFER_LENGTH; 848 CopyToBuffer((u_short *)(state->buf + 849 SII_MAX_DMA_XFER_LENGTH), 850 (volatile u_short *) 851 state->dmaAddr[!state->dmaBufIndex], i); 852 } 853 break; 854 855 case SII_STATUS_PHASE: 856 if (state->cmdlen > 0) { 857 printf("sii%d: device %d: cmd %x: command data not all sent (%d) 2\n", 858 sc - sii_softc, sc->sc_target, 859 sc->sc_cmd[sc->sc_target]->cmd[0], 860 state->cmdlen); 861 state->cmdlen = 0; 862 #ifdef DEBUG 863 sii_DumpLog(); 864 #endif 865 } 866 867 /* read amount transfered if DMA didn't finish */ 868 if (state->dmalen > 0) { 869 i = state->dmalen - regs->dmlotc; 870 state->dmalen = 0; 871 state->dmaCurPhase = -1; 872 regs->dmlotc = 0; 873 regs->comm = comm & 874 (SII_STATE_MSK | SII_PHASE_MSK); 875 MachEmptyWriteBuffer(); 876 regs->dstat = SII_DNE; 877 MachEmptyWriteBuffer(); 878 #ifdef DEBUG 879 if (sii_debug > 4) 880 printf("DMA amt %d ", i); 881 #endif 882 switch (comm & SII_PHASE_MSK) { 883 case SII_DATA_IN_PHASE: 884 /* copy in the data */ 885 CopyFromBuffer((volatile u_short *) 886 state->dmaAddr[state->dmaBufIndex], 887 state->buf, i); 888 889 case SII_CMD_PHASE: 890 case SII_DATA_OUT_PHASE: 891 state->buflen -= i; 892 } 893 } 894 895 /* read a one byte status message */ 896 state->statusByte = msg = 897 sii_GetByte(regs, SII_STATUS_PHASE); 898 if (msg < 0) { 899 dstat = regs->dstat; 900 goto again; 901 } 902 #ifdef DEBUG 903 if (sii_debug > 4) 904 printf("Status %x ", msg); 905 if (sii_logp > sii_log) 906 sii_logp[-1].msg = msg; 907 else 908 sii_log[NLOG - 1].msg = msg; 909 #endif 910 911 /* do a quick wait for COMMAND_COMPLETE */ 912 SII_WAIT_UNTIL(dstat, regs->dstat, 913 dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i); 914 if (dstat & (SII_CI | SII_DI)) { 915 #ifdef DEBUG 916 if (sii_debug > 4) 917 printf("cnt2 %d\n", i); 918 #endif 919 goto again; 920 } 921 break; 922 923 case SII_MSG_IN_PHASE: 924 /* 925 * Save DMA state if DMA didn't finish. 926 * Be careful not to save state again after reconnect 927 * and see RESTORE_POINTER message. 928 * Note that the SII DMA address is not incremented 929 * as DMA proceeds. 930 */ 931 if (state->dmaCurPhase > 0) { 932 /* save dma registers */ 933 state->dmaPrevPhase = state->dmaCurPhase; 934 state->dmaCurPhase = -1; 935 state->dmaCnt = i = regs->dmlotc; 936 if (dstat & SII_OBB) 937 state->dmaByte = regs->dmabyte; 938 if (i == 0) 939 i = SII_MAX_DMA_XFER_LENGTH; 940 i = state->dmalen - i; 941 /* note: no carry from dmaddrl to dmaddrh */ 942 state->dmaAddrL = regs->dmaddrl + i; 943 state->dmaAddrH = regs->dmaddrh; 944 regs->comm = comm & 945 (SII_STATE_MSK | SII_PHASE_MSK); 946 MachEmptyWriteBuffer(); 947 regs->dstat = SII_DNE; 948 MachEmptyWriteBuffer(); 949 #ifdef DEBUG 950 if (sii_debug > 4) { 951 printf("SavP dcnt %d dadr %x ", 952 state->dmaCnt, 953 (state->dmaAddrH << 16) | 954 state->dmaAddrL); 955 if (((dstat & SII_OBB) != 0) ^ 956 (state->dmaCnt & 1)) 957 printf("OBB??? "); 958 } else if (sii_debug > 0) { 959 if (((dstat & SII_OBB) != 0) ^ 960 (state->dmaCnt & 1)) { 961 printf("sii_DoIntr: OBB??? ds %x cnt %d\n", 962 dstat, state->dmaCnt); 963 sii_DumpLog(); 964 } 965 } 966 #endif 967 } 968 969 /* read a one byte message */ 970 msg = sii_GetByte(regs, SII_MSG_IN_PHASE); 971 if (msg < 0) { 972 dstat = regs->dstat; 973 goto again; 974 } 975 #ifdef DEBUG 976 if (sii_debug > 4) 977 printf("MsgIn %x ", msg); 978 if (sii_logp > sii_log) 979 sii_logp[-1].msg = msg; 980 else 981 sii_log[NLOG - 1].msg = msg; 982 #endif 983 984 /* process message */ 985 switch (msg) { 986 case SCSI_COMMAND_COMPLETE: 987 msg = sc->sc_target; 988 sc->sc_target = -1; 989 /* 990 * Wait a short time for disconnect. 991 * Don't be fooled if SII_BER happens first. 992 * Note: a reselect may happen here. 993 */ 994 SII_WAIT_UNTIL(cstat, regs->cstat, 995 cstat & (SII_RST | SII_SCH), 996 SII_WAIT_COUNT, i); 997 if ((cstat & (SII_RST | SII_SCH | 998 SII_STATE_MSK)) == SII_SCH) { 999 regs->cstat = SII_SCH | SII_BER; 1000 regs->comm = 0; 1001 MachEmptyWriteBuffer(); 1002 /* 1003 * Double check that we didn't miss a 1004 * state change between seeing it and 1005 * clearing the SII_SCH bit. 1006 */ 1007 i = regs->cstat; 1008 if (!(i & SII_SCH) && 1009 (i & SII_STATE_MSK) != 1010 (cstat & SII_STATE_MSK)) 1011 sii_StateChg(sc, i); 1012 } 1013 #ifdef DEBUG 1014 if (sii_debug > 4) 1015 printf("cs %x\n", cstat); 1016 #endif 1017 sii_CmdDone(sc, msg, 0); 1018 break; 1019 1020 case SCSI_EXTENDED_MSG: 1021 /* read the message length */ 1022 msg = sii_GetByte(regs, SII_MSG_IN_PHASE); 1023 if (msg < 0) { 1024 dstat = regs->dstat; 1025 goto again; 1026 } 1027 if (msg == 0) 1028 msg = 256; 1029 sii_StartDMA(regs, SII_MSG_IN_PHASE, 1030 (u_short *)SII_BUF_ADDR, msg); 1031 /* wait a short time for XFER complete */ 1032 SII_WAIT_UNTIL(dstat, regs->dstat, 1033 (dstat & (SII_DNE | SII_TCZ)) == 1034 (SII_DNE | SII_TCZ), 1035 SII_WAIT_COUNT, i); 1036 1037 if ((dstat & (SII_DNE | SII_TCZ | SII_IPE)) != 1038 (SII_DNE | SII_TCZ)) { 1039 #ifdef DEBUG 1040 if (sii_debug > 4) 1041 printf("cnt0 %d\n", i); 1042 else if (sii_debug > 0) 1043 printf("sii_DoIntr: emsg in ds %x cnt %d\n", 1044 dstat, i); 1045 #endif 1046 printf("sii: ds %x cm %x i %d lotc %d\n", 1047 dstat, comm, i, regs->dmlotc); /* XXX */ 1048 sii_DumpLog(); /* XXX */ 1049 goto again; 1050 } 1051 1052 /* clear the DNE, other errors handled later */ 1053 regs->dstat = SII_DNE; 1054 MachEmptyWriteBuffer(); 1055 1056 CopyFromBuffer((volatile u_short *)SII_BUF_ADDR, 1057 sii_buf + 2, msg); 1058 switch (sii_buf[2]) { 1059 case SCSI_MODIFY_DATA_PTR: 1060 i = (sii_buf[3] << 24) | 1061 (sii_buf[4] << 16) | 1062 (sii_buf[5] << 8) | 1063 sii_buf[6]; 1064 if (state->dmaPrevPhase >= 0) { 1065 state->dmaAddrL += i; 1066 state->dmaCnt -= i; 1067 } 1068 break; 1069 1070 case SCSI_SYNCHRONOUS_XFER: 1071 sii_DoSync(regs, state); 1072 break; 1073 1074 case SCSI_EXTENDED_IDENTIFY: 1075 case SCSI_WIDE_XFER: 1076 default: 1077 reject: 1078 /* send a reject message */ 1079 regs->data = SCSI_MESSAGE_REJECT; 1080 regs->comm = SII_INXFER | SII_ATN | 1081 (regs->cstat & SII_STATE_MSK) | 1082 SII_MSG_OUT_PHASE; 1083 MachEmptyWriteBuffer(); 1084 /* wait for XFER complete */ 1085 SII_WAIT_UNTIL(dstat, regs->dstat, 1086 (dstat & 1087 (SII_DNE | SII_PHASE_MSK)) == 1088 (SII_DNE | SII_MSG_OUT_PHASE), 1089 SII_WAIT_COUNT, i); 1090 1091 if ((dstat & 1092 (SII_DNE | SII_PHASE_MSK)) != 1093 (SII_DNE | SII_MSG_OUT_PHASE)) 1094 break; 1095 regs->dstat = SII_DNE; 1096 MachEmptyWriteBuffer(); 1097 } 1098 break; 1099 1100 case SCSI_SAVE_DATA_POINTER: 1101 case SCSI_RESTORE_POINTERS: 1102 /* wait a short time for another msg */ 1103 SII_WAIT_UNTIL(dstat, regs->dstat, 1104 dstat & (SII_CI | SII_DI), 1105 SII_WAIT_COUNT, i); 1106 if (dstat & (SII_CI | SII_DI)) { 1107 #ifdef DEBUG 1108 if (sii_debug > 4) 1109 printf("cnt %d\n", i); 1110 #endif 1111 goto again; 1112 } 1113 break; 1114 1115 case SCSI_DISCONNECT: 1116 state->prevComm = comm; 1117 #ifdef DEBUG 1118 if (sii_debug > 4) 1119 printf("disconn %d ", sc->sc_target); 1120 #endif 1121 /* 1122 * Wait a short time for disconnect. 1123 * Don't be fooled if SII_BER happens first. 1124 * Note: a reselect may happen here. 1125 */ 1126 SII_WAIT_UNTIL(cstat, regs->cstat, 1127 cstat & (SII_RST | SII_SCH), 1128 SII_WAIT_COUNT, i); 1129 if ((cstat & (SII_RST | SII_SCH | 1130 SII_STATE_MSK)) != SII_SCH) { 1131 #ifdef DEBUG 1132 if (sii_debug > 4) 1133 printf("cnt %d\n", i); 1134 #endif 1135 dstat = regs->dstat; 1136 goto again; 1137 } 1138 regs->cstat = SII_SCH | SII_BER; 1139 regs->comm = 0; 1140 MachEmptyWriteBuffer(); 1141 sc->sc_target = -1; 1142 /* 1143 * Double check that we didn't miss a state 1144 * change between seeing it and clearing 1145 * the SII_SCH bit. 1146 */ 1147 i = regs->cstat; 1148 if (!(i & SII_SCH) && (i & SII_STATE_MSK) != 1149 (cstat & SII_STATE_MSK)) 1150 sii_StateChg(sc, i); 1151 break; 1152 1153 case SCSI_MESSAGE_REJECT: 1154 printf("sii%d: device %d: message reject.\n", 1155 sc - sii_softc, sc->sc_target); 1156 goto abort; 1157 1158 default: 1159 if (!(msg & SCSI_IDENTIFY)) { 1160 printf("sii%d: device %d: couldn't handle message 0x%x... ignoring.\n", 1161 sc - sii_softc, sc->sc_target, 1162 msg); 1163 #ifdef DEBUG 1164 sii_DumpLog(); 1165 #endif 1166 break; 1167 } 1168 /* may want to check LUN some day */ 1169 /* wait a short time for another msg */ 1170 SII_WAIT_UNTIL(dstat, regs->dstat, 1171 dstat & (SII_CI | SII_DI), 1172 SII_WAIT_COUNT, i); 1173 if (dstat & (SII_CI | SII_DI)) { 1174 #ifdef DEBUG 1175 if (sii_debug > 4) 1176 printf("cnt %d\n", i); 1177 #endif 1178 goto again; 1179 } 1180 } 1181 break; 1182 1183 case SII_MSG_OUT_PHASE: 1184 #ifdef DEBUG 1185 if (sii_debug > 4) 1186 printf("MsgOut\n"); 1187 #endif 1188 1189 regs->data = SCSI_NO_OP; 1190 regs->comm = SII_INXFER | (comm & SII_STATE_MSK) | 1191 SII_MSG_OUT_PHASE; 1192 MachEmptyWriteBuffer(); 1193 1194 /* wait a short time for XFER complete */ 1195 SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE, 1196 SII_WAIT_COUNT, i); 1197 #ifdef DEBUG 1198 if (sii_debug > 4) 1199 printf("ds %x i %d\n", dstat, i); 1200 #endif 1201 /* just clear the DNE bit and check errors later */ 1202 if (dstat & SII_DNE) { 1203 regs->dstat = SII_DNE; 1204 MachEmptyWriteBuffer(); 1205 } 1206 break; 1207 1208 default: 1209 printf("sii%d: Couldn't handle phase %d... ignoring.\n", 1210 sc - sii_softc, dstat & SII_PHASE_MSK); 1211 } 1212 } 1213 1214 #ifdef DEBUG 1215 if (sii_debug > 3) 1216 printf("\n"); 1217 #endif 1218 /* 1219 * Check to make sure we won't be interrupted again. 1220 * Deglitch dstat register. 1221 */ 1222 msg = regs->dstat; 1223 while (msg != (dstat = regs->dstat)) 1224 msg = dstat; 1225 if (dstat & (SII_CI | SII_DI)) 1226 goto again; 1227 1228 if (sc->sc_target < 0) { 1229 /* look for another device that is ready */ 1230 for (i = 0; i < SII_NCMD; i++) { 1231 /* don't restart a disconnected command */ 1232 if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm) 1233 continue; 1234 sii_StartCmd(sc, i); 1235 break; 1236 } 1237 } 1238 return; 1239 1240 abort: 1241 /* jump here to abort the current command */ 1242 printf("sii%d: device %d: current command terminated\n", 1243 sc - sii_softc, sc->sc_target); 1244 #ifdef DEBUG 1245 sii_DumpLog(); 1246 #endif 1247 1248 if ((cstat = regs->cstat) & SII_CON) { 1249 /* try to send an abort msg for awhile */ 1250 regs->dstat = SII_DNE; 1251 regs->data = SCSI_ABORT; 1252 regs->comm = SII_INXFER | SII_ATN | (cstat & SII_STATE_MSK) | 1253 SII_MSG_OUT_PHASE; 1254 MachEmptyWriteBuffer(); 1255 SII_WAIT_UNTIL(dstat, regs->dstat, 1256 (dstat & (SII_DNE | SII_PHASE_MSK)) == 1257 (SII_DNE | SII_MSG_OUT_PHASE), 1258 2 * SII_WAIT_COUNT, i); 1259 #ifdef DEBUG 1260 if (sii_debug > 0) 1261 printf("Abort: cs %x ds %x i %d\n", cstat, dstat, i); 1262 #endif 1263 if (dstat & (SII_DNE | SII_PHASE_MSK) == 1264 (SII_DNE | SII_MSG_OUT_PHASE)) { 1265 /* disconnect if command in progress */ 1266 regs->comm = SII_DISCON; 1267 MachEmptyWriteBuffer(); 1268 SII_WAIT_UNTIL(cstat, regs->cstat, 1269 !(cstat & SII_CON), SII_WAIT_COUNT, i); 1270 } 1271 } else { 1272 #ifdef DEBUG 1273 if (sii_debug > 0) 1274 printf("Abort: cs %x\n", cstat); 1275 #endif 1276 } 1277 regs->cstat = 0xffff; 1278 regs->dstat = 0xffff; 1279 regs->comm = 0; 1280 MachEmptyWriteBuffer(); 1281 1282 i = sc->sc_target; 1283 sc->sc_target = -1; 1284 sii_CmdDone(sc, i, EIO); 1285 #ifdef DEBUG 1286 if (sii_debug > 4) 1287 printf("sii_DoIntr: after CmdDone target %d\n", sc->sc_target); 1288 #endif 1289 } 1290 1291 static void 1292 sii_StateChg(sc, cstat) 1293 register struct siisoftc *sc; 1294 register unsigned cstat; 1295 { 1296 register SIIRegs *regs = sc->sc_regs; 1297 register State *state; 1298 register int i; 1299 1300 #ifdef DEBUG 1301 if (sii_debug > 4) 1302 printf("SCH: "); 1303 #endif 1304 1305 switch (cstat & SII_STATE_MSK) { 1306 case 0: 1307 /* disconnect */ 1308 i = sc->sc_target; 1309 sc->sc_target = -1; 1310 #ifdef DEBUG 1311 if (sii_debug > 4) 1312 printf("disconn %d ", i); 1313 #endif 1314 if (i >= 0 && !sc->sc_st[i].prevComm) { 1315 printf("sii%d: device %d: spurrious disconnect (%d)\n", 1316 sc - sii_softc, i, regs->slcsr); 1317 sc->sc_st[i].prevComm = 0; 1318 } 1319 break; 1320 1321 case SII_CON: 1322 /* connected as initiator */ 1323 i = regs->slcsr; 1324 if (sc->sc_target == i) 1325 break; 1326 printf("sii%d: device %d: connect to device %d??\n", 1327 sc - sii_softc, sc->sc_target, i); 1328 sc->sc_target = i; 1329 break; 1330 1331 case SII_DST: 1332 /* 1333 * Wait for CON to become valid, 1334 * chip is slow sometimes. 1335 */ 1336 SII_WAIT_UNTIL(cstat, regs->cstat, 1337 cstat & SII_CON, SII_WAIT_COUNT, i); 1338 if (!(cstat & SII_CON)) 1339 panic("sii resel"); 1340 /* FALLTHROUGH */ 1341 1342 case SII_CON | SII_DST: 1343 /* 1344 * Its a reselection. Save the ID and wait for 1345 * interrupts to tell us what to do next 1346 * (should be MSG_IN of IDENTIFY). 1347 * NOTE: sc_target may be >= 0 if we were in 1348 * the process of trying to start a command 1349 * and were reselected before the select 1350 * command finished. 1351 */ 1352 sc->sc_target = i = regs->destat; 1353 regs->comm = SII_CON | SII_DST | SII_MSG_IN_PHASE; 1354 MachEmptyWriteBuffer(); 1355 state = &sc->sc_st[i]; 1356 if (!state->prevComm) { 1357 printf("sii%d: device %d: spurrious reselection\n", 1358 sc - sii_softc, i); 1359 break; 1360 } 1361 state->prevComm = 0; 1362 #ifdef DEBUG 1363 if (sii_debug > 4) 1364 printf("resel %d ", sc->sc_target); 1365 #endif 1366 break; 1367 1368 #ifdef notyet 1369 case SII_DST | SII_TGT: 1370 case SII_CON | SII_DST | SII_TGT: 1371 /* connected as target */ 1372 printf("sii%d: Selected by device %d as target!!\n", 1373 sc - sii_softc, regs->destat); 1374 regs->comm = SII_DISCON; 1375 MachEmptyWriteBuffer(); 1376 SII_WAIT_UNTIL(!(regs->cstat & SII_CON), 1377 SII_WAIT_COUNT, i); 1378 regs->cstat = 0xffff; 1379 regs->dstat = 0xffff; 1380 regs->comm = 0; 1381 break; 1382 #endif 1383 1384 default: 1385 printf("sii%d: Unknown state change (cs %x)!!\n", 1386 sc - sii_softc, cstat); 1387 #ifdef DEBUG 1388 sii_DumpLog(); 1389 #endif 1390 } 1391 } 1392 1393 /* 1394 * Read one byte of data. 1395 */ 1396 static int 1397 sii_GetByte(regs, phase) 1398 register SIIRegs *regs; 1399 int phase; 1400 { 1401 register unsigned dstat; 1402 register unsigned state; 1403 #ifdef PROGXFER 1404 register unsigned data; 1405 1406 dstat = regs->dstat; 1407 state = regs->cstat & SII_STATE_MSK; 1408 regs->dmctrl = 0; 1409 if (!(dstat & SII_IBF) || (dstat & SII_MIS)) { 1410 regs->comm = state | phase; 1411 MachEmptyWriteBuffer(); 1412 /* wait a short time for IBF */ 1413 SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_IBF, 1414 SII_WAIT_COUNT, i); 1415 #ifdef DEBUG 1416 if (!(dstat & SII_IBF)) 1417 printf("status no IBF\n"); 1418 #endif 1419 } 1420 data = regs->data; 1421 if (regs->dstat & SII_DNE) { /* XXX */ 1422 printf("sii_GetByte: DNE set 5\n"); 1423 sii_DumpLog(); 1424 regs->dstat = SII_DNE; 1425 } 1426 regs->comm = SII_INXFER | state | phase; 1427 MachEmptyWriteBuffer(); 1428 1429 /* wait a short time for XFER complete */ 1430 SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE, 1431 SII_WAIT_COUNT, i); 1432 1433 if ((dstat & (SII_DNE | SII_IPE)) != SII_DNE) { 1434 #ifdef DEBUG 1435 if (sii_debug > 4) 1436 printf("cnt0 %d\n", i); 1437 #endif 1438 printf("MsgIn %x ?? ds %x cm %x i %d\n", 1439 data, dstat, comm, i); /* XXX */ 1440 sii_DumpLog(); /* XXX */ 1441 panic("status"); /* XXX */ 1442 goto again; 1443 } 1444 1445 /* clear the DNE, other errors handled later */ 1446 regs->dstat = SII_DNE; 1447 MachEmptyWriteBuffer(); 1448 return (data); 1449 1450 #else /* PROGXFER */ 1451 register int i; 1452 1453 state = regs->cstat & SII_STATE_MSK; 1454 regs->dmctrl = 0; 1455 if (regs->dstat & SII_DNE) { 1456 printf("sii_GetByte: DNE cs %x ds %x cm %x\n", 1457 regs->cstat, regs->dstat, regs->comm); /* XXX */ 1458 regs->dstat = SII_DNE; 1459 } 1460 regs->dmaddrl = ((unsigned)SII_BUF_ADDR >> 1); 1461 regs->dmaddrh = ((unsigned)SII_BUF_ADDR >> 17) & 03; 1462 regs->dmlotc = 1; 1463 regs->comm = SII_DMA | SII_INXFER | state | phase; 1464 MachEmptyWriteBuffer(); 1465 1466 /* wait a short time for XFER complete */ 1467 SII_WAIT_UNTIL(dstat, regs->dstat, 1468 (dstat & (SII_DNE | SII_TCZ)) == (SII_DNE | SII_TCZ), 1469 SII_WAIT_COUNT, i); 1470 1471 if ((dstat & (SII_DNE | SII_TCZ | SII_IPE)) != (SII_DNE | SII_TCZ)) { 1472 printf("sii_GetByte: ds %x cm %x i %d lotc %d\n", 1473 dstat, regs->comm, i, regs->dmlotc); /* XXX */ 1474 sii_DumpLog(); /* XXX */ 1475 return (-1); 1476 } 1477 1478 /* clear the DNE, other errors handled later */ 1479 regs->dstat = SII_DNE; 1480 MachEmptyWriteBuffer(); 1481 1482 /* return one byte of data (optimized CopyFromBuffer()) */ 1483 return (*(volatile u_short *)SII_BUF_ADDR & 0xFF); 1484 #endif /* PROGXFER */ 1485 } 1486 1487 /* 1488 * Exchange messages to initiate synchronous data transfers. 1489 */ 1490 static void 1491 sii_DoSync(regs, state) 1492 register SIIRegs *regs; 1493 register State *state; 1494 { 1495 register unsigned dstat; 1496 register int i; 1497 unsigned len; 1498 1499 printf("sii_DoSync: per %d req/ack %d\n", 1500 sii_buf[3], sii_buf[4]); /* XXX */ 1501 len = sii_buf[4]; 1502 if (len > 3) 1503 len = 3; /* SII chip can only handle 3 max */ 1504 1505 sii_buf[0] = SCSI_EXTENDED_MSG; 1506 sii_buf[1] = 3; /* message length */ 1507 sii_buf[2] = SCSI_SYNCHRONOUS_XFER; 1508 sii_buf[4] = len; 1509 CopyToBuffer((u_short *)sii_buf, (volatile u_short *)SII_BUF_ADDR, 5); 1510 regs->dmaddrl = ((unsigned)SII_BUF_ADDR >> 1); 1511 regs->dmaddrh = ((unsigned)SII_BUF_ADDR >> 17) & 03; 1512 regs->dmlotc = 5; 1513 regs->comm = SII_DMA | SII_INXFER | SII_ATN | 1514 (regs->cstat & SII_STATE_MSK) | SII_MSG_OUT_PHASE; 1515 MachEmptyWriteBuffer(); 1516 1517 /* wait a short time for XFER complete */ 1518 SII_WAIT_UNTIL(dstat, regs->dstat, 1519 (dstat & (SII_DNE | SII_TCZ)) == (SII_DNE | SII_TCZ), 1520 SII_WAIT_COUNT, i); 1521 1522 if ((dstat & (SII_DNE | SII_TCZ)) != (SII_DNE | SII_TCZ)) { 1523 printf("sii_DoSync: ds %x cm %x i %d lotc %d\n", 1524 dstat, regs->comm, i, regs->dmlotc); /* XXX */ 1525 sii_DumpLog(); /* XXX */ 1526 return; 1527 } 1528 1529 /* clear the DNE, other errors handled later */ 1530 regs->dstat = SII_DNE; 1531 regs->comm = regs->comm & SII_STATE_MSK; 1532 MachEmptyWriteBuffer(); 1533 1534 state->dmaReqAck = len; 1535 } 1536 1537 /* 1538 * Issue the sequence of commands to the controller to start DMA. 1539 * NOTE: the data buffer should be word-aligned for DMA out. 1540 */ 1541 static void 1542 sii_StartDMA(regs, phase, dmaAddr, size) 1543 register SIIRegs *regs; /* which SII to use */ 1544 int phase; /* phase to send/receive data */ 1545 u_short *dmaAddr; /* DMA buffer address */ 1546 int size; /* # of bytes to transfer */ 1547 { 1548 1549 if (regs->dstat & SII_DNE) { /* XXX */ 1550 printf("sii_StartDMA: DNE set\n"); 1551 sii_DumpLog(); 1552 regs->dstat = SII_DNE; 1553 } 1554 regs->dmaddrl = ((unsigned)dmaAddr >> 1); 1555 regs->dmaddrh = ((unsigned)dmaAddr >> 17) & 03; 1556 regs->dmlotc = size; 1557 regs->comm = SII_DMA | SII_INXFER | (regs->cstat & SII_STATE_MSK) | 1558 phase; 1559 MachEmptyWriteBuffer(); 1560 1561 #ifdef DEBUG 1562 if (sii_debug > 5) { 1563 printf("sii_StartDMA: cs 0x%x, ds 0x%x, cm 0x%x, size %d\n", 1564 regs->cstat, regs->dstat, regs->comm, size); 1565 } 1566 #endif 1567 } 1568 1569 /* 1570 * Call the device driver's 'done' routine to let it know the command is done. 1571 * The 'done' routine may try to start another command. 1572 * To be fair, we should start pending commands for other devices 1573 * before allowing the same device to start another command. 1574 */ 1575 static void 1576 sii_CmdDone(sc, target, error) 1577 register struct siisoftc *sc; /* which SII to use */ 1578 int target; /* which device is done */ 1579 int error; /* error code if any errors */ 1580 { 1581 register ScsiCmd *scsicmd; 1582 register int i; 1583 1584 scsicmd = sc->sc_cmd[target]; 1585 #ifdef DIAGNOSTIC 1586 if (target < 0 || !scsicmd) 1587 panic("sii_CmdDone"); 1588 #endif 1589 sc->sc_cmd[target] = (ScsiCmd *)0; 1590 #ifdef DEBUG 1591 if (sii_debug > 1) { 1592 printf("sii_CmdDone: %s target %d cmd %x err %d resid %d\n", 1593 scsicmd->sd->sd_driver->d_name, target, 1594 scsicmd->cmd[0], error, sc->sc_st[target].buflen); 1595 } 1596 #endif 1597 1598 /* look for another device that is ready */ 1599 for (i = 0; i < SII_NCMD; i++) { 1600 /* don't restart a disconnected command */ 1601 if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm) 1602 continue; 1603 sii_StartCmd(sc, i); 1604 break; 1605 } 1606 1607 (*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, error, 1608 sc->sc_st[target].buflen, sc->sc_st[target].statusByte); 1609 } 1610 1611 #ifdef DEBUG 1612 sii_DumpLog() 1613 { 1614 register struct sii_log *lp; 1615 1616 printf("sii: cmd %x bn %d cnt %d\n", sii_debug_cmd, sii_debug_bn, 1617 sii_debug_sz); 1618 lp = sii_logp + 1; 1619 if (lp > &sii_log[NLOG]) 1620 lp = sii_log; 1621 while (lp != sii_logp) { 1622 printf("target %d cs %x ds %x cm %x msg %x\n", 1623 lp->target, lp->cstat, lp->dstat, lp->comm, lp->msg); 1624 if (++lp >= &sii_log[NLOG]) 1625 lp = sii_log; 1626 } 1627 } 1628 #endif 1629 #endif 1630