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