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