Sync usage with man page.
[netbsd-mini2440.git] / sys / arch / pmax / ibus / sii.c
bloba82e5f56c92dcad5757ebfe31f22d9627a225369
1 /* $NetBSD: sii.c,v 1.7 2009/03/14 21:04:14 dsl Exp $ */
3 /*-
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Ralph Campbell and Rick Macklem.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
34 * @(#)sii.c 8.2 (Berkeley) 11/30/93
36 * from: Header: /sprite/src/kernel/dev/ds3100.md/RCS/devSII.c,
37 * v 9.2 89/09/14 13:37:41 jhh Exp $ SPRITE (DECWRL)";
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: sii.c,v 1.7 2009/03/14 21:04:14 dsl Exp $");
43 #include "sii.h"
45 * SCSI interface driver
47 #include <sys/param.h>
48 #include <sys/buf.h>
49 #include <sys/conf.h>
50 #include <sys/device.h>
51 #include <sys/systm.h>
53 #include <machine/locore.h>
55 #include <dev/scsipi/scsi_all.h>
56 #include <dev/scsipi/scsi_message.h>
57 #include <dev/scsipi/scsipi_all.h>
58 #include <dev/scsipi/scsipi_disk.h>
59 #include <dev/scsipi/scsiconf.h>
61 /* old 4.4BSD/pmax scsi drivers */
62 #include <pmax/ibus/siireg.h> /* device registers */
63 #include <pmax/ibus/siivar.h> /* softc and prototypes */
65 #include <pmax/pmax/machdep.h> /* prom_scsiid prototype */
67 /* XXX not in dev/scsipi/scsi_message.h */
68 #define MSG_EXT_MODIFY_DATA_PTR 0x00
70 extern struct cfdriver sii_cd;
73 * MACROS for timing out spin loops.
75 * Wait until expression is true.
77 * Control register bits can change at any time so when the CPU
78 * reads a register, the bits might change and
79 * invalidate the setup and hold times for the CPU.
80 * This macro reads the register twice to be sure the value is stable.
82 * args: var - variable to save control register contents
83 * reg - control register to read
84 * expr - expression to spin on
85 * spincount - maximum number of times through the loop
86 * cntr - variable for number of tries
88 #define SII_WAIT_UNTIL(var, reg, expr, spincount, cntr) { \
89 u_int tmp = reg; \
90 for (cntr = 0; cntr < spincount; cntr++) { \
91 while (tmp != (var = reg)) \
92 tmp = var; \
93 if (expr) \
94 break; \
95 if (cntr >= 100) \
96 DELAY(100); \
97 } \
100 #ifdef DEBUG
101 int sii_debug = 1;
102 int sii_debug_cmd;
103 int sii_debug_bn;
104 int sii_debug_sz;
105 #define NLOG 16
106 struct sii_log {
107 u_short cstat;
108 u_short dstat;
109 u_short comm;
110 u_short msg;
111 int rlen;
112 int dlen;
113 int target;
114 } sii_log[NLOG], *sii_logp = sii_log;
115 #endif
117 static u_char sii_buf[256]; /* used for extended messages */
119 #define NORESET 0
120 #define RESET 1
121 #define NOWAIT 0
122 #define WAIT 1
126 * Define a safe address in the SCSI buffer for doing status & message DMA
127 * XXX why not add another field to softc?
129 #define SII_BUF_ADDR(sc) ((sc)->sc_buf + SII_MAX_DMA_XFER_LENGTH * 14)
132 * Forward references
135 static void sii_Reset(struct siisoftc *sc, int resetbus);
136 static void sii_StartCmd(struct siisoftc *sc, int target);
137 static void sii_CmdDone(struct siisoftc *sc, int target, int error);
138 static void sii_DoIntr(struct siisoftc *sc, u_int dstat);
139 static void sii_StateChg(struct siisoftc *sc, u_int cstat);
140 static int sii_GetByte(SIIRegs *regs, int phase, int ack);
141 static void sii_DoSync(SIIRegs *regs, State *state);
142 static void sii_StartDMA(SIIRegs *regs, int phase, u_short *dmaAddr,
143 int size);
145 #ifdef DEBUG
146 static void sii_DumpLog(void);
147 #endif
151 * Match driver based on name
153 void
154 siiattach(struct siisoftc *sc)
156 int i;
158 sc->sc_target = -1; /* no command active */
161 * Give each target its own DMA buffer region.
162 * Make it big enough for 2 max transfers so we can ping pong buffers
163 * while we copy the data.
165 for (i = 0; i < SII_NCMD; i++) {
166 sc->sc_st[i].dmaAddr[0] = (u_short *)
167 sc->sc_buf + 2 * SII_MAX_DMA_XFER_LENGTH * i;
168 sc->sc_st[i].dmaAddr[1] = sc->sc_st[i].dmaAddr[0] +
169 SII_MAX_DMA_XFER_LENGTH;
172 sii_Reset(sc, RESET);
173 printf(": target %d\n", sc->sc_regs->id & SII_IDMSK);
175 sc->sc_adapter.adapt_dev = &sc->sc_dev;
176 sc->sc_adapter.adapt_nchannels = 1;
177 sc->sc_adapter.adapt_openings = 7;
178 sc->sc_adapter.adapt_max_periph = 1;
179 sc->sc_adapter.adapt_ioctl = NULL;
180 sc->sc_adapter.adapt_minphys = minphys;
181 sc->sc_adapter.adapt_request = sii_scsi_request;
183 sc->sc_channel.chan_adapter = &sc->sc_adapter;
184 sc->sc_channel.chan_bustype = &scsi_bustype;
185 sc->sc_channel.chan_channel = 0;
186 sc->sc_channel.chan_ntargets = 8;
187 sc->sc_channel.chan_nluns = 8;
188 sc->sc_channel.chan_id = sc->sc_regs->id & SII_IDMSK;
192 * Now try to attach all the sub-devices
194 config_found(&sc->sc_dev, &sc->sc_channel, scsiprint);
198 * Start activity on a SCSI device.
199 * We maintain information on each device separately since devices can
200 * connect/disconnect during an operation.
203 void
204 sii_scsi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req, void *arg)
206 struct scsipi_xfer *xs;
207 struct scsipi_periph *periph;
208 struct siisoftc *sc = (void *)chan->chan_adapter->adapt_dev;
209 int target;
210 int s;
211 int count;
213 switch (req) {
214 case ADAPTER_REQ_RUN_XFER:
215 xs = arg;
216 periph = xs->xs_periph;
217 target = periph->periph_target;
218 s = splbio();
219 if (sc->sc_cmd[target]) {
220 splx(s);
221 xs->error = XS_RESOURCE_SHORTAGE;
222 scsipi_done(xs);
223 printf("[busy at start]\n");
224 return;
227 * Build a ScsiCmd for this command and start it.
229 sc->sc_xs[target] = xs;
230 sc->sc_cmd[target] = &sc->sc_cmd_fake[target]; /* XXX */
231 sc->sc_cmd[target]->unit = 0;
232 sc->sc_cmd[target]->flags = 0;
233 sc->sc_cmd[target]->buflen = xs->datalen;
234 sc->sc_cmd[target]->buf = xs->data;
235 sc->sc_cmd[target]->cmdlen = xs->cmdlen;
236 sc->sc_cmd[target]->cmd = (u_char *)xs->cmd;
237 sc->sc_cmd[target]->lun = xs->xs_periph->periph_lun;
238 sii_StartCmd(sc, target);
239 splx(s);
240 if ((xs->xs_control & XS_CTL_POLL) == 0)
241 return;
242 count = xs->timeout;
243 while (count) {
244 if ((xs->xs_status & XS_STS_DONE) != 0)
245 return;
246 siiintr(sc);
247 /* XXX schedule another command? */
248 DELAY(1000);
249 --count;
251 xs->error = XS_TIMEOUT;
252 scsipi_done(xs);
253 return;
254 case ADAPTER_REQ_GROW_RESOURCES:
255 /* XXX Not supported. */
256 return;
258 case ADAPTER_REQ_SET_XFER_MODE:
259 /* XXX Not supported. */
260 return;
265 * Check to see if any SII chips have pending interrupts
266 * and process as appropriate.
269 siiintr(void *xxxsc)
271 struct siisoftc *sc = xxxsc;
272 u_int dstat;
275 * Find which controller caused the interrupt.
277 dstat = sc->sc_regs->dstat;
278 if (dstat & (SII_CI | SII_DI)) {
279 sii_DoIntr(sc, dstat);
280 return (0); /* XXX */
283 return (1); /* XXX spurious interrupt? */
287 * Reset the SII chip and do a SCSI reset if 'reset' is true.
288 * NOTE: if !cold && reset, should probably probe for devices
289 * since a SCSI bus reset will set UNIT_ATTENTION.
291 static void
292 sii_Reset(struct siisoftc* sc, int reset)
293 /* reset: TRUE => reset SCSI bus */
295 SIIRegs *regs = sc->sc_regs;
297 #ifdef DEBUG
298 if (sii_debug > 1)
299 printf("sii: RESET\n");
300 #endif
302 * Reset the SII chip.
304 regs->comm = SII_CHRESET;
306 * Set arbitrated bus mode.
308 regs->csr = SII_HPM;
310 * Set host adapter ID (from PROM sciiidN variable).
312 /* XXX device_unit() abuse */
313 regs->id = SII_ID_IO | prom_scsiid(device_unit(&sc->sc_dev));
315 * Enable SII to drive the SCSI bus.
317 regs->dictrl = SII_PRE;
318 regs->dmctrl = 0;
320 if (reset) {
321 int i;
324 * Assert SCSI bus reset for at least 25 Usec to clear the
325 * world. SII_DO_RST is self clearing.
326 * Delay 250 ms before doing any commands.
328 regs->comm = SII_DO_RST;
329 wbflush();
330 DELAY(250000);
332 /* rearbitrate synchronous offset */
333 for (i = 0; i < SII_NCMD; i++)
334 sc->sc_st[i].dmaReqAck = 0;
338 * Clear any pending interrupts from the reset.
340 regs->cstat = regs->cstat;
341 regs->dstat = regs->dstat;
343 * Set up SII for arbitrated bus mode, SCSI parity checking,
344 * Reselect Enable, and Interrupt Enable.
346 regs->csr = SII_HPM | SII_RSE | SII_PCE | SII_IE;
347 wbflush();
351 * Start a SCSI command by sending the cmd data
352 * to a SCSI controller via the SII.
353 * Call the device done proceedure if it can't be started.
354 * NOTE: we should be called with interrupts disabled.
356 static void
357 sii_StartCmd(struct siisoftc *sc, int target)
358 /* sc: which SII to use */
359 /* target: which command to start */
361 SIIRegs *regs;
362 ScsiCmd *scsicmd;
363 State *state;
364 u_int status;
365 int error, retval;
367 /* if another command is currently in progress, just wait */
368 if (sc->sc_target >= 0)
369 return;
371 /* initialize state information for this command */
372 scsicmd = sc->sc_cmd[target];
373 state = &sc->sc_st[target];
374 state->flags = FIRST_DMA;
375 state->prevComm = 0;
376 state->dmalen = 0;
377 state->dmaCurPhase = -1;
378 state->dmaPrevPhase = -1;
379 state->dmaBufIndex = 0;
380 state->cmd = scsicmd->cmd;
381 state->cmdlen = scsicmd->cmdlen;
382 if ((state->buflen = scsicmd->buflen) == 0) {
383 state->dmaDataPhase = -1; /* illegal phase. shouldn't happen */
384 state->buf = (char *)0;
385 } else {
386 state->buf = scsicmd->buf;
389 #ifdef DEBUG
390 if (sii_debug > 1) {
391 printf("sii_StartCmd: %s target %d cmd 0x%x addr %p size %d DMA %d\n",
392 sc->sc_dev.dv_xname,
393 target, scsicmd->cmd[0], scsicmd->buf, scsicmd->buflen,
394 state->dmaDataPhase);
396 sii_debug_cmd = scsicmd->cmd[0];
397 if (scsicmd->cmd[0] == READ_10 ||
398 scsicmd->cmd[0] == WRITE_10) {
399 sii_debug_bn = (scsicmd->cmd[2] << 24) |
400 (scsicmd->cmd[3] << 16) |
401 (scsicmd->cmd[4] << 8) |
402 scsicmd->cmd[5];
403 sii_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8];
404 } else {
405 sii_debug_bn = 0;
406 sii_debug_sz = 0;
408 #endif
410 /* try to select the target */
411 regs = sc->sc_regs;
414 * Another device may have selected us; in which case,
415 * this command will be restarted later.
417 if ((status = regs->dstat) & (SII_CI | SII_DI)) {
418 sii_DoIntr(sc, status);
419 return;
422 sc->sc_target = target;
423 #if 0
424 /* seem to have problems with synchronous transfers */
425 if (scsicmd->flags & SCSICMD_USE_SYNC) {
426 printf("sii_StartCmd: doing extended msg\n"); /* XXX */
428 * Setup to send both the identify message and the synchronous
429 * data transfer request.
431 sii_buf[0] = MSG_IDENTIFYFLAG | MSG_IDENTIFY_DISCFLAG;
432 sii_buf[1] = MSG_EXTENDED;
433 sii_buf[2] = MSG_EXT_SDTR_LEN;
434 sii_buf[3] = MSG_EXT_SDTR;
435 sii_buf[4] = 0;
436 sii_buf[5] = 3; /* maximum SII chip supports */
438 state->dmaCurPhase = SII_MSG_OUT_PHASE,
439 state->dmalen = 6;
440 sc->sii_copytobuf((u_short *)sii_buf,
441 (volatile u_short *)SII_BUF_ADDR(sc), 6);
442 regs->slcsr = target;
443 regs->dmctrl = state->dmaReqAck;
444 regs->dmaddrl = (u_short)(SII_BUF_ADDR(sc) >> 1);
445 regs->dmaddrh = (u_short)(SII_BUF_ADDR(sc) >> 17) & 03;
446 regs->dmlotc = 6;
447 regs->comm = SII_DMA | SII_INXFER | SII_SELECT | SII_ATN |
448 SII_CON | SII_MSG_OUT_PHASE;
449 } else
450 #endif
452 /* do a chained, select with ATN and programmed I/O command */
453 regs->data = MSG_IDENTIFYFLAG | MSG_IDENTIFY_DISCFLAG |
454 scsicmd->lun;
455 regs->slcsr = target;
456 regs->dmctrl = state->dmaReqAck;
457 regs->comm = SII_INXFER | SII_SELECT | SII_ATN | SII_CON |
458 SII_MSG_OUT_PHASE;
460 wbflush();
463 * Wait for something to happen
464 * (should happen soon or we would use interrupts).
466 SII_WAIT_UNTIL(status, regs->cstat, status & (SII_CI | SII_DI),
467 SII_WAIT_COUNT/4, retval);
469 /* check to see if we are connected OK */
470 if ((status & (SII_RST | SII_SCH | SII_STATE_MSK)) ==
471 (SII_SCH | SII_CON)) {
472 regs->cstat = status;
473 wbflush();
475 #ifdef DEBUG
476 sii_logp->target = target;
477 sii_logp->cstat = status;
478 sii_logp->dstat = 0;
479 sii_logp->comm = regs->comm;
480 sii_logp->msg = -1;
481 sii_logp->rlen = state->buflen;
482 sii_logp->dlen = state->dmalen;
483 if (++sii_logp >= &sii_log[NLOG])
484 sii_logp = sii_log;
485 #endif
487 /* wait a short time for command phase */
488 SII_WAIT_UNTIL(status, regs->dstat, status & SII_MIS,
489 SII_WAIT_COUNT, retval);
490 #ifdef DEBUG
491 if (sii_debug > 2)
492 printf("sii_StartCmd: ds %x cnt %d\n", status, retval);
493 #endif
494 if ((status & (SII_CI | SII_MIS | SII_PHASE_MSK)) !=
495 (SII_MIS | SII_CMD_PHASE)) {
496 printf("sii_StartCmd: timeout cs %x ds %x cnt %d\n",
497 regs->cstat, status, retval); /* XXX */
498 /* process interrupt or continue until it happens */
499 if (status & (SII_CI | SII_DI))
500 sii_DoIntr(sc, status);
501 return;
503 regs->dstat = SII_DNE; /* clear Msg Out DMA done */
505 /* send command data */
506 sc->sii_copytobuf((u_short *)state->cmd,
507 (volatile u_short *)state->dmaAddr[0], state->cmdlen);
508 sii_StartDMA(regs, state->dmaCurPhase = SII_CMD_PHASE,
509 state->dmaAddr[0], state->dmalen = scsicmd->cmdlen);
511 /* wait a little while for DMA to finish */
512 SII_WAIT_UNTIL(status, regs->dstat, status & (SII_CI | SII_DI),
513 SII_WAIT_COUNT, retval);
514 #ifdef DEBUG
515 if (sii_debug > 2)
516 printf("sii_StartCmd: ds %x, cnt %d\n", status, retval);
517 #endif
518 if (status & (SII_CI | SII_DI))
519 sii_DoIntr(sc, status);
520 #ifdef DEBUG
521 if (sii_debug > 2)
522 printf("sii_StartCmd: DONE ds %x\n", regs->dstat);
523 #endif
524 return;
528 * Another device may have selected us; in which case,
529 * this command will be restarted later.
531 if (status & (SII_CI | SII_DI)) {
532 sii_DoIntr(sc, regs->dstat);
533 return;
537 * Disconnect if selection command still in progress.
539 if (status & SII_SIP) {
540 error = ENXIO; /* device didn't respond */
541 regs->comm = SII_DISCON;
542 wbflush();
543 SII_WAIT_UNTIL(status, regs->cstat,
544 !(status & (SII_CON | SII_SIP)),
545 SII_WAIT_COUNT, retval);
546 } else
547 error = EBUSY; /* couldn't get the bus */
548 #ifdef DEBUG
549 if (sii_debug > 1)
550 printf("sii_StartCmd: Couldn't select target %d error %d\n",
551 target, error);
552 #endif
553 sc->sc_target = -1;
554 regs->cstat = 0xffff;
555 regs->dstat = 0xffff;
556 regs->comm = 0;
557 wbflush();
558 sii_CmdDone(sc, target, error);
562 * Process interrupt conditions.
564 static void
565 sii_DoIntr(struct siisoftc *sc, u_int dstat)
567 SIIRegs *regs = sc->sc_regs;
568 State *state;
569 u_int cstat;
570 int i, msg;
571 u_int comm;
573 again:
574 comm = regs->comm;
576 #ifdef DEBUG
577 if (sii_debug > 3)
578 printf("sii_DoIntr: cs %x, ds %x cm %x ",
579 regs->cstat, dstat, comm);
580 sii_logp->target = sc->sc_target;
581 sii_logp->cstat = regs->cstat;
582 sii_logp->dstat = dstat;
583 sii_logp->comm = comm;
584 sii_logp->msg = -1;
585 if (sc->sc_target >= 0) {
586 sii_logp->rlen = sc->sc_st[sc->sc_target].buflen;
587 sii_logp->dlen = sc->sc_st[sc->sc_target].dmalen;
588 } else {
589 sii_logp->rlen = 0;
590 sii_logp->dlen = 0;
592 if (++sii_logp >= &sii_log[NLOG])
593 sii_logp = sii_log;
594 #endif
596 regs->dstat = dstat; /* acknowledge everything */
597 wbflush();
599 if (dstat & SII_CI) {
600 /* deglitch cstat register */
601 msg = regs->cstat;
602 while (msg != (cstat = regs->cstat))
603 msg = cstat;
604 regs->cstat = cstat; /* acknowledge everything */
605 wbflush();
606 #ifdef DEBUG
607 if (sii_logp > sii_log)
608 sii_logp[-1].cstat = cstat;
609 else
610 sii_log[NLOG - 1].cstat = cstat;
611 #endif
613 /* check for a BUS RESET */
614 if (cstat & SII_RST) {
615 printf("%s: SCSI bus reset!!\n", sc->sc_dev.dv_xname);
616 /* need to flush disconnected commands */
617 for (i = 0; i < SII_NCMD; i++) {
618 if (!sc->sc_cmd[i])
619 continue;
620 sii_CmdDone(sc, i, EIO);
622 /* rearbitrate synchronous offset */
623 for (i = 0; i < SII_NCMD; i++)
624 sc->sc_st[i].dmaReqAck = 0;
625 sc->sc_target = -1;
626 return;
629 #ifdef notdef
631 * Check for a BUS ERROR.
632 * According to DEC, this feature doesn't really work
633 * and to just clear the bit if it's set.
635 if (cstat & SII_BER) {
636 regs->cstat = SII_BER;
637 wbflush();
639 #endif
641 /* check for state change */
642 if (cstat & SII_SCH) {
643 sii_StateChg(sc, cstat);
644 comm = regs->comm;
648 /* check for DMA completion */
649 if (dstat & SII_DNE) {
650 u_short *dma;
651 char *buf;
654 * There is a race condition with SII_SCH. There is a short
655 * window between the time a SII_SCH is seen after a disconnect
656 * and when the SII_SCH is cleared. A reselect can happen
657 * in this window and we will clear the SII_SCH without
658 * processing the reconnect.
660 if (sc->sc_target < 0) {
661 cstat = regs->cstat;
662 printf("%s: target %d DNE?? dev %d,%d cs %x\n",
663 sc->sc_dev.dv_xname, sc->sc_target,
664 regs->slcsr, regs->destat,
665 cstat); /* XXX */
666 if (cstat & SII_DST) {
667 sc->sc_target = regs->destat;
668 state = &sc->sc_st[sc->sc_target];
669 state->prevComm = 0;
670 } else
671 panic("sc_target 1");
673 state = &sc->sc_st[sc->sc_target];
674 /* check for a PARITY ERROR */
675 if (dstat & SII_IPE) {
676 state->flags |= PARITY_ERR;
677 printf("%s: Parity error!!\n", sc->sc_dev.dv_xname);
678 goto abort;
680 /* dmalen = amount left to transfer, i = amount transfered */
681 i = state->dmalen;
682 state->dmalen = 0;
683 state->dmaCurPhase = -1;
684 #ifdef DEBUG
685 if (sii_debug > 4) {
686 printf("DNE: amt %d ", i);
687 if (!(dstat & SII_TCZ))
688 printf("no TCZ?? (%d) ", regs->dmlotc);
689 } else if (!(dstat & SII_TCZ)) {
690 printf("%s: device %d: no TCZ?? (%d)\n",
691 sc->sc_dev.dv_xname, sc->sc_target, regs->dmlotc);
692 sii_DumpLog(); /* XXX */
694 #endif
695 switch (comm & SII_PHASE_MSK) {
696 case SII_CMD_PHASE:
697 state->cmdlen -= i;
698 break;
700 case SII_DATA_IN_PHASE:
701 /* check for more data for the same phase */
702 dma = state->dmaAddr[state->dmaBufIndex];
703 buf = state->buf;
704 state->buf += i;
705 state->buflen -= i;
706 if (state->buflen > 0 && !(dstat & SII_MIS)) {
707 int len;
709 /* start reading next chunk */
710 len = state->buflen;
711 if (len > SII_MAX_DMA_XFER_LENGTH)
712 len = SII_MAX_DMA_XFER_LENGTH;
713 state->dmaBufIndex = !state->dmaBufIndex;
714 sii_StartDMA(regs,
715 state->dmaCurPhase = SII_DATA_IN_PHASE,
716 state->dmaAddr[state->dmaBufIndex],
717 state->dmaCnt = state->dmalen = len);
718 dstat &= ~(SII_IBF | SII_TBE);
720 /* copy in the data */
721 sc->sii_copyfrombuf((volatile u_short *)dma, buf, i);
722 break;
724 case SII_DATA_OUT_PHASE:
725 state->dmaBufIndex = !state->dmaBufIndex;
726 state->buf += i;
727 state->buflen -= i;
729 /* check for more data for the same phase */
730 if (state->buflen <= 0 || (dstat & SII_MIS))
731 break;
733 /* start next chunk */
734 i = state->buflen;
735 if (i > SII_MAX_DMA_XFER_LENGTH) {
736 sii_StartDMA(regs, state->dmaCurPhase =
737 SII_DATA_OUT_PHASE,
738 state->dmaAddr[state->dmaBufIndex],
739 state->dmaCnt = state->dmalen =
740 SII_MAX_DMA_XFER_LENGTH);
741 /* prepare for next chunk */
742 i -= SII_MAX_DMA_XFER_LENGTH;
743 if (i > SII_MAX_DMA_XFER_LENGTH)
744 i = SII_MAX_DMA_XFER_LENGTH;
745 sc->sii_copytobuf((u_short *)(state->buf +
746 SII_MAX_DMA_XFER_LENGTH),
747 (volatile u_short *)
748 state->dmaAddr[!state->dmaBufIndex], i);
749 } else {
750 sii_StartDMA(regs, state->dmaCurPhase =
751 SII_DATA_OUT_PHASE,
752 state->dmaAddr[state->dmaBufIndex],
753 state->dmaCnt = state->dmalen = i);
755 dstat &= ~(SII_IBF | SII_TBE);
759 /* check for phase change or another MsgIn/Out */
760 if (dstat & (SII_MIS | SII_IBF | SII_TBE)) {
762 * There is a race condition with SII_SCH. There is a short
763 * window between the time a SII_SCH is seen after a disconnect
764 * and when the SII_SCH is cleared. A reselect can happen
765 * in this window and we will clear the SII_SCH without
766 * processing the reconnect.
768 if (sc->sc_target < 0) {
769 cstat = regs->cstat;
770 printf("%s: target %d MIS?? dev %d,%d cs %x ds %x\n",
771 sc->sc_dev.dv_xname, sc->sc_target,
772 regs->slcsr, regs->destat,
773 cstat, dstat); /* XXX */
774 if (cstat & SII_DST) {
775 sc->sc_target = regs->destat;
776 state = &sc->sc_st[sc->sc_target];
777 state->prevComm = 0;
778 } else {
779 #ifdef DEBUG
780 sii_DumpLog();
781 #endif
782 panic("sc_target 2");
785 state = &sc->sc_st[sc->sc_target];
786 switch (dstat & SII_PHASE_MSK) {
787 case SII_CMD_PHASE:
788 if (state->dmaPrevPhase >= 0) {
789 /* restart DMA after disconnect/reconnect */
790 if (state->dmaPrevPhase != SII_CMD_PHASE) {
791 printf("%s: device %d: DMA reselect phase doesn't match\n",
792 sc->sc_dev.dv_xname, sc->sc_target);
793 goto abort;
795 state->dmaCurPhase = SII_CMD_PHASE;
796 state->dmaPrevPhase = -1;
797 regs->dmaddrl = state->dmaAddrL;
798 regs->dmaddrh = state->dmaAddrH;
799 regs->dmlotc = state->dmaCnt;
800 if (state->dmaCnt & 1)
801 regs->dmabyte = state->dmaByte;
802 regs->comm = SII_DMA | SII_INXFER |
803 (comm & SII_STATE_MSK) | SII_CMD_PHASE;
804 wbflush();
805 #ifdef DEBUG
806 if (sii_debug > 4)
807 printf("Cmd dcnt %d dadr %x ",
808 state->dmaCnt,
809 (state->dmaAddrH << 16) |
810 state->dmaAddrL);
811 #endif
812 } else {
813 /* send command data */
814 i = state->cmdlen;
815 if (i == 0) {
816 printf("%s: device %d: cmd count exceeded\n",
817 sc->sc_dev.dv_xname, sc->sc_target);
818 goto abort;
820 sc->sii_copytobuf((u_short *)state->cmd,
821 (volatile u_short *)state->dmaAddr[0],
823 sii_StartDMA(regs, state->dmaCurPhase =
824 SII_CMD_PHASE, state->dmaAddr[0],
825 state->dmaCnt = state->dmalen = i);
827 /* wait a short time for XFER complete */
828 SII_WAIT_UNTIL(dstat, regs->dstat,
829 dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i);
830 if (dstat & (SII_CI | SII_DI)) {
831 #ifdef DEBUG
832 if (sii_debug > 4)
833 printf("cnt %d\n", i);
834 else if (sii_debug > 0)
835 printf("sii_DoIntr: cmd wait ds %x cnt %d\n",
836 dstat, i);
837 #endif
838 goto again;
840 break;
842 case SII_DATA_IN_PHASE:
843 case SII_DATA_OUT_PHASE:
844 if (state->cmdlen > 0) {
845 printf("%s: device %d: cmd %x: command data not all sent (%d) 1\n",
846 sc->sc_dev.dv_xname, sc->sc_target,
847 sc->sc_cmd[sc->sc_target]->cmd[0],
848 state->cmdlen);
849 state->cmdlen = 0;
850 #ifdef DEBUG
851 sii_DumpLog();
852 #endif
854 if (state->dmaPrevPhase >= 0) {
855 /* restart DMA after disconnect/reconnect */
856 if (state->dmaPrevPhase !=
857 (dstat & SII_PHASE_MSK)) {
858 printf("%s: device %d: DMA reselect phase doesn't match\n",
859 sc->sc_dev.dv_xname, sc->sc_target);
860 goto abort;
862 state->dmaCurPhase = state->dmaPrevPhase;
863 state->dmaPrevPhase = -1;
864 regs->dmaddrl = state->dmaAddrL;
865 regs->dmaddrh = state->dmaAddrH;
866 regs->dmlotc = state->dmaCnt;
867 if (state->dmaCnt & 1)
868 regs->dmabyte = state->dmaByte;
869 regs->comm = SII_DMA | SII_INXFER |
870 (comm & SII_STATE_MSK) |
871 state->dmaCurPhase;
872 wbflush();
873 #ifdef DEBUG
874 if (sii_debug > 4)
875 printf("Data %d dcnt %d dadr %x ",
876 state->dmaDataPhase,
877 state->dmaCnt,
878 (state->dmaAddrH << 16) |
879 state->dmaAddrL);
880 #endif
881 break;
883 #ifdef DEBUG
884 if (sii_debug > 4) {
885 printf("Data %d ", state->dmaDataPhase);
886 if (sii_debug > 5)
887 printf("\n");
889 #endif
890 i = state->buflen;
891 if (i == 0) {
892 printf("%s: device %d: data count exceeded\n",
893 sc->sc_dev.dv_xname, sc->sc_target);
894 goto abort;
896 if (i > SII_MAX_DMA_XFER_LENGTH)
897 i = SII_MAX_DMA_XFER_LENGTH;
898 if ((dstat & SII_PHASE_MSK) == SII_DATA_IN_PHASE) {
899 sii_StartDMA(regs,
900 state->dmaCurPhase = SII_DATA_IN_PHASE,
901 state->dmaAddr[state->dmaBufIndex],
902 state->dmaCnt = state->dmalen = i);
903 break;
905 /* start first chunk */
906 if (state->flags & FIRST_DMA) {
907 state->flags &= ~FIRST_DMA;
908 sc->sii_copytobuf((u_short *)state->buf,
909 (volatile u_short *)
910 state->dmaAddr[state->dmaBufIndex], i);
912 sii_StartDMA(regs,
913 state->dmaCurPhase = SII_DATA_OUT_PHASE,
914 state->dmaAddr[state->dmaBufIndex],
915 state->dmaCnt = state->dmalen = i);
916 i = state->buflen - SII_MAX_DMA_XFER_LENGTH;
917 if (i > 0) {
918 /* prepare for next chunk */
919 if (i > SII_MAX_DMA_XFER_LENGTH)
920 i = SII_MAX_DMA_XFER_LENGTH;
921 sc->sii_copytobuf((u_short *)(state->buf +
922 SII_MAX_DMA_XFER_LENGTH),
923 (volatile u_short *)
924 state->dmaAddr[!state->dmaBufIndex], i);
926 break;
928 case SII_STATUS_PHASE:
929 if (state->cmdlen > 0) {
930 printf("%s: device %d: cmd %x: command data not all sent (%d) 2\n",
931 sc->sc_dev.dv_xname, sc->sc_target,
932 sc->sc_cmd[sc->sc_target]->cmd[0],
933 state->cmdlen);
934 state->cmdlen = 0;
935 #ifdef DEBUG
936 sii_DumpLog();
937 #endif
940 /* read amount transfered if DMA didn't finish */
941 if (state->dmalen > 0) {
942 i = state->dmalen - regs->dmlotc;
943 state->dmalen = 0;
944 state->dmaCurPhase = -1;
945 regs->dmlotc = 0;
946 regs->comm = comm &
947 (SII_STATE_MSK | SII_PHASE_MSK);
948 wbflush();
949 regs->dstat = SII_DNE;
950 wbflush();
951 #ifdef DEBUG
952 if (sii_debug > 4)
953 printf("DMA amt %d ", i);
954 #endif
955 switch (comm & SII_PHASE_MSK) {
956 case SII_DATA_IN_PHASE:
957 /* copy in the data */
958 sc->sii_copyfrombuf((volatile u_short*)
959 state->dmaAddr[state->dmaBufIndex],
960 state->buf, i);
962 case SII_CMD_PHASE:
963 case SII_DATA_OUT_PHASE:
964 state->buflen -= i;
968 /* read a one byte status message */
969 state->statusByte = msg =
970 sii_GetByte(regs, SII_STATUS_PHASE, 1);
971 if (msg < 0) {
972 dstat = regs->dstat;
973 goto again;
975 #ifdef DEBUG
976 if (sii_debug > 4)
977 printf("Status %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
984 /* do a quick wait for COMMAND_COMPLETE */
985 SII_WAIT_UNTIL(dstat, regs->dstat,
986 dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i);
987 if (dstat & (SII_CI | SII_DI)) {
988 #ifdef DEBUG
989 if (sii_debug > 4)
990 printf("cnt2 %d\n", i);
991 #endif
992 goto again;
994 break;
996 case SII_MSG_IN_PHASE:
998 * Save DMA state if DMA didn't finish.
999 * Be careful not to save state again after reconnect
1000 * and see RESTORE_POINTER message.
1001 * Note that the SII DMA address is not incremented
1002 * as DMA proceeds.
1004 if (state->dmaCurPhase >= 0) {
1005 /* save DMA registers */
1006 state->dmaPrevPhase = state->dmaCurPhase;
1007 state->dmaCurPhase = -1;
1008 if (dstat & SII_OBB)
1009 state->dmaByte = regs->dmabyte;
1010 i = regs->dmlotc;
1011 if (i != 0)
1012 i = state->dmaCnt - i;
1013 /* note: no carry from dmaddrl to dmaddrh */
1014 state->dmaAddrL = regs->dmaddrl + i;
1015 state->dmaAddrH = regs->dmaddrh;
1016 state->dmaCnt = regs->dmlotc;
1017 if (state->dmaCnt == 0)
1018 state->dmaCnt = SII_MAX_DMA_XFER_LENGTH;
1019 regs->comm = comm &
1020 (SII_STATE_MSK | SII_PHASE_MSK);
1021 wbflush();
1022 regs->dstat = SII_DNE;
1023 wbflush();
1024 #ifdef DEBUG
1025 if (sii_debug > 4) {
1026 printf("SavP dcnt %d dadr %x ",
1027 state->dmaCnt,
1028 (state->dmaAddrH << 16) |
1029 state->dmaAddrL);
1030 if (((dstat & SII_OBB) != 0) ^
1031 (state->dmaCnt & 1))
1032 printf("OBB??? ");
1033 } else if (sii_debug > 0) {
1034 if (((dstat & SII_OBB) != 0) ^
1035 (state->dmaCnt & 1)) {
1036 printf("sii_DoIntr: OBB??? ds %x cnt %d\n",
1037 dstat, state->dmaCnt);
1038 sii_DumpLog();
1041 #endif
1044 /* read a one byte message */
1045 msg = sii_GetByte(regs, SII_MSG_IN_PHASE, 0);
1046 if (msg < 0) {
1047 dstat = regs->dstat;
1048 goto again;
1050 #ifdef DEBUG
1051 if (sii_debug > 4)
1052 printf("MsgIn %x ", msg);
1053 if (sii_logp > sii_log)
1054 sii_logp[-1].msg = msg;
1055 else
1056 sii_log[NLOG - 1].msg = msg;
1057 #endif
1059 /* process message */
1060 switch (msg) {
1061 case MSG_CMDCOMPLETE:
1062 /* acknowledge last byte */
1063 regs->comm = SII_INXFER | SII_MSG_IN_PHASE |
1064 (comm & SII_STATE_MSK);
1065 SII_WAIT_UNTIL(dstat, regs->dstat,
1066 dstat & SII_DNE, SII_WAIT_COUNT, i);
1067 regs->dstat = SII_DNE;
1068 wbflush();
1069 msg = sc->sc_target;
1070 sc->sc_target = -1;
1072 * Wait a short time for disconnect.
1073 * Don't be fooled if SII_BER happens first.
1074 * Note: a reselect may happen here.
1076 SII_WAIT_UNTIL(cstat, regs->cstat,
1077 cstat & (SII_RST | SII_SCH),
1078 SII_WAIT_COUNT, i);
1079 if ((cstat & (SII_RST | SII_SCH |
1080 SII_STATE_MSK)) == SII_SCH) {
1081 regs->cstat = SII_SCH | SII_BER;
1082 regs->comm = 0;
1083 wbflush();
1085 * Double check that we didn't miss a
1086 * state change between seeing it and
1087 * clearing the SII_SCH bit.
1089 i = regs->cstat;
1090 if (!(i & SII_SCH) &&
1091 (i & SII_STATE_MSK) !=
1092 (cstat & SII_STATE_MSK))
1093 sii_StateChg(sc, i);
1095 #ifdef DEBUG
1096 if (sii_debug > 4)
1097 printf("cs %x\n", cstat);
1098 #endif
1099 sii_CmdDone(sc, msg, 0);
1100 break;
1102 case MSG_EXTENDED:
1103 /* acknowledge last byte */
1104 regs->comm = SII_INXFER | SII_MSG_IN_PHASE |
1105 (comm & SII_STATE_MSK);
1106 SII_WAIT_UNTIL(dstat, regs->dstat,
1107 dstat & SII_DNE, SII_WAIT_COUNT, i);
1108 regs->dstat = SII_DNE;
1109 wbflush();
1110 /* read the message length */
1111 msg = sii_GetByte(regs, SII_MSG_IN_PHASE, 1);
1112 if (msg < 0) {
1113 dstat = regs->dstat;
1114 goto again;
1116 sii_buf[1] = msg; /* message length */
1117 if (msg == 0)
1118 msg = 256;
1120 * We read and acknowlege all the bytes
1121 * except the last so we can assert ATN
1122 * if needed before acknowledging the last.
1124 for (i = 0; i < msg; i++) {
1125 dstat = sii_GetByte(regs,
1126 SII_MSG_IN_PHASE, i < msg - 1);
1127 if ((int)dstat < 0) {
1128 dstat = regs->dstat;
1129 goto again;
1131 sii_buf[i + 2] = dstat;
1134 switch (sii_buf[2]) {
1135 case MSG_EXT_MODIFY_DATA_PTR:
1136 /* acknowledge last byte */
1137 regs->comm = SII_INXFER |
1138 SII_MSG_IN_PHASE |
1139 (comm & SII_STATE_MSK);
1140 SII_WAIT_UNTIL(dstat, regs->dstat,
1141 dstat & SII_DNE,
1142 SII_WAIT_COUNT, i);
1143 regs->dstat = SII_DNE;
1144 wbflush();
1145 i = (sii_buf[3] << 24) |
1146 (sii_buf[4] << 16) |
1147 (sii_buf[5] << 8) |
1148 sii_buf[6];
1149 if (state->dmaPrevPhase >= 0) {
1150 state->dmaAddrL += i;
1151 state->dmaCnt -= i;
1153 break;
1155 case MSG_EXT_SDTR_LEN:
1157 * Acknowledge last byte and
1158 * signal a request for MSG_OUT.
1160 regs->comm = SII_INXFER | SII_ATN |
1161 SII_MSG_IN_PHASE |
1162 (comm & SII_STATE_MSK);
1163 SII_WAIT_UNTIL(dstat, regs->dstat,
1164 dstat & SII_DNE,
1165 SII_WAIT_COUNT, i);
1166 regs->dstat = SII_DNE;
1167 wbflush();
1168 sii_DoSync(regs, state);
1169 break;
1171 default:
1172 reject:
1174 * Acknowledge last byte and
1175 * signal a request for MSG_OUT.
1177 regs->comm = SII_INXFER | SII_ATN |
1178 SII_MSG_IN_PHASE |
1179 (comm & SII_STATE_MSK);
1180 SII_WAIT_UNTIL(dstat, regs->dstat,
1181 dstat & SII_DNE,
1182 SII_WAIT_COUNT, i);
1183 regs->dstat = SII_DNE;
1184 wbflush();
1186 /* wait for MSG_OUT phase */
1187 SII_WAIT_UNTIL(dstat, regs->dstat,
1188 dstat & SII_TBE,
1189 SII_WAIT_COUNT, i);
1191 /* send a reject message */
1192 regs->data = MSG_MESSAGE_REJECT;
1193 regs->comm = SII_INXFER |
1194 (regs->cstat & SII_STATE_MSK) |
1195 SII_MSG_OUT_PHASE;
1196 SII_WAIT_UNTIL(dstat, regs->dstat,
1197 dstat & SII_DNE,
1198 SII_WAIT_COUNT, i);
1199 regs->dstat = SII_DNE;
1200 wbflush();
1202 break;
1204 case MSG_SAVEDATAPOINTER:
1205 case MSG_RESTOREPOINTERS:
1206 /* acknowledge last byte */
1207 regs->comm = SII_INXFER | SII_MSG_IN_PHASE |
1208 (comm & SII_STATE_MSK);
1209 SII_WAIT_UNTIL(dstat, regs->dstat,
1210 dstat & SII_DNE, SII_WAIT_COUNT, i);
1211 regs->dstat = SII_DNE;
1212 wbflush();
1213 /* wait a short time for another msg */
1214 SII_WAIT_UNTIL(dstat, regs->dstat,
1215 dstat & (SII_CI | SII_DI),
1216 SII_WAIT_COUNT, i);
1217 if (dstat & (SII_CI | SII_DI)) {
1218 #ifdef DEBUG
1219 if (sii_debug > 4)
1220 printf("cnt %d\n", i);
1221 #endif
1222 goto again;
1224 break;
1226 case MSG_DISCONNECT:
1227 /* acknowledge last byte */
1228 regs->comm = SII_INXFER | SII_MSG_IN_PHASE |
1229 (comm & SII_STATE_MSK);
1230 SII_WAIT_UNTIL(dstat, regs->dstat,
1231 dstat & SII_DNE, SII_WAIT_COUNT, i);
1232 regs->dstat = SII_DNE;
1233 wbflush();
1234 state->prevComm = comm;
1235 #ifdef DEBUG
1236 if (sii_debug > 4)
1237 printf("disconn %d ", sc->sc_target);
1238 #endif
1240 * Wait a short time for disconnect.
1241 * Don't be fooled if SII_BER happens first.
1242 * Note: a reselect may happen here.
1244 SII_WAIT_UNTIL(cstat, regs->cstat,
1245 cstat & (SII_RST | SII_SCH),
1246 SII_WAIT_COUNT, i);
1247 if ((cstat & (SII_RST | SII_SCH |
1248 SII_STATE_MSK)) != SII_SCH) {
1249 #ifdef DEBUG
1250 if (sii_debug > 4)
1251 printf("cnt %d\n", i);
1252 #endif
1253 dstat = regs->dstat;
1254 goto again;
1256 regs->cstat = SII_SCH | SII_BER;
1257 regs->comm = 0;
1258 wbflush();
1259 sc->sc_target = -1;
1261 * Double check that we didn't miss a state
1262 * change between seeing it and clearing
1263 * the SII_SCH bit.
1265 i = regs->cstat;
1266 if (!(i & SII_SCH) && (i & SII_STATE_MSK) !=
1267 (cstat & SII_STATE_MSK))
1268 sii_StateChg(sc, i);
1269 break;
1271 case MSG_MESSAGE_REJECT:
1272 /* acknowledge last byte */
1273 regs->comm = SII_INXFER | SII_MSG_IN_PHASE |
1274 (comm & SII_STATE_MSK);
1275 SII_WAIT_UNTIL(dstat, regs->dstat,
1276 dstat & SII_DNE, SII_WAIT_COUNT, i);
1277 regs->dstat = SII_DNE;
1278 wbflush();
1279 printf("%s: device %d: message reject.\n",
1280 sc->sc_dev.dv_xname, sc->sc_target);
1281 break;
1283 default:
1284 if (!(msg & MSG_IDENTIFYFLAG)) {
1285 printf("%s: device %d: couldn't handle "
1286 "message 0x%x... rejecting.\n",
1287 sc->sc_dev.dv_xname, sc->sc_target,
1288 msg);
1289 #ifdef DEBUG
1290 sii_DumpLog();
1291 #endif
1292 goto reject;
1294 /* acknowledge last byte */
1295 regs->comm = SII_INXFER | SII_MSG_IN_PHASE |
1296 (comm & SII_STATE_MSK);
1297 SII_WAIT_UNTIL(dstat, regs->dstat,
1298 dstat & SII_DNE, SII_WAIT_COUNT, i);
1299 regs->dstat = SII_DNE;
1300 wbflush();
1301 /* may want to check LUN some day */
1302 /* wait a short time for another msg */
1303 SII_WAIT_UNTIL(dstat, regs->dstat,
1304 dstat & (SII_CI | SII_DI),
1305 SII_WAIT_COUNT, i);
1306 if (dstat & (SII_CI | SII_DI)) {
1307 #ifdef DEBUG
1308 if (sii_debug > 4)
1309 printf("cnt %d\n", i);
1310 #endif
1311 goto again;
1314 break;
1316 case SII_MSG_OUT_PHASE:
1317 #ifdef DEBUG
1318 if (sii_debug > 4)
1319 printf("MsgOut\n");
1320 #endif
1321 printf("MsgOut %x\n", state->flags); /* XXX */
1324 * Check for parity error.
1325 * Hardware will automatically set ATN
1326 * to request the device for a MSG_OUT phase.
1328 if (state->flags & PARITY_ERR) {
1329 state->flags &= ~PARITY_ERR;
1330 regs->data = MSG_PARITY_ERROR;
1331 } else
1332 regs->data = MSG_NOOP;
1333 regs->comm = SII_INXFER | (comm & SII_STATE_MSK) |
1334 SII_MSG_OUT_PHASE;
1335 wbflush();
1337 /* wait a short time for XFER complete */
1338 SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE,
1339 SII_WAIT_COUNT, i);
1340 #ifdef DEBUG
1341 if (sii_debug > 4)
1342 printf("ds %x i %d\n", dstat, i);
1343 #endif
1344 /* just clear the DNE bit and check errors later */
1345 if (dstat & SII_DNE) {
1346 regs->dstat = SII_DNE;
1347 wbflush();
1349 break;
1351 default:
1352 printf("%s: Couldn't handle phase %d... ignoring.\n",
1353 sc->sc_dev.dv_xname, dstat & SII_PHASE_MSK);
1357 #ifdef DEBUG
1358 if (sii_debug > 3)
1359 printf("\n");
1360 #endif
1362 * Check to make sure we won't be interrupted again.
1363 * Deglitch dstat register.
1365 msg = regs->dstat;
1366 while (msg != (dstat = regs->dstat))
1367 msg = dstat;
1368 if (dstat & (SII_CI | SII_DI))
1369 goto again;
1371 if (sc->sc_target < 0) {
1372 /* look for another device that is ready */
1373 for (i = 0; i < SII_NCMD; i++) {
1374 /* don't restart a disconnected command */
1375 if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm)
1376 continue;
1377 sii_StartCmd(sc, i);
1378 break;
1381 return;
1383 abort:
1384 /* jump here to abort the current command */
1385 printf("%s: device %d: current command terminated\n",
1386 sc->sc_dev.dv_xname, sc->sc_target);
1387 #ifdef DEBUG
1388 sii_DumpLog();
1389 #endif
1391 if ((cstat = regs->cstat) & SII_CON) {
1392 /* try to send an abort msg for awhile */
1393 regs->dstat = SII_DNE;
1394 regs->data = MSG_ABORT;
1395 regs->comm = SII_INXFER | SII_ATN | (cstat & SII_STATE_MSK) |
1396 SII_MSG_OUT_PHASE;
1397 wbflush();
1398 SII_WAIT_UNTIL(dstat, regs->dstat,
1399 (dstat & (SII_DNE | SII_PHASE_MSK)) ==
1400 (SII_DNE | SII_MSG_OUT_PHASE),
1401 2 * SII_WAIT_COUNT, i);
1402 #ifdef DEBUG
1403 if (sii_debug > 0)
1404 printf("Abort: cs %x ds %x i %d\n", cstat, dstat, i);
1405 #endif
1406 if ((dstat & (SII_DNE | SII_PHASE_MSK)) ==
1407 (SII_DNE | SII_MSG_OUT_PHASE)) {
1408 /* disconnect if command in progress */
1409 regs->comm = SII_DISCON;
1410 wbflush();
1411 SII_WAIT_UNTIL(cstat, regs->cstat,
1412 !(cstat & SII_CON), SII_WAIT_COUNT, i);
1414 } else {
1415 #ifdef DEBUG
1416 if (sii_debug > 0)
1417 printf("Abort: cs %x\n", cstat);
1418 #endif
1420 regs->cstat = 0xffff;
1421 regs->dstat = 0xffff;
1422 regs->comm = 0;
1423 wbflush();
1425 i = sc->sc_target;
1426 sc->sc_target = -1;
1427 sii_CmdDone(sc, i, EIO);
1428 #ifdef DEBUG
1429 if (sii_debug > 4)
1430 printf("sii_DoIntr: after CmdDone target %d\n", sc->sc_target);
1431 #endif
1434 static void
1435 sii_StateChg(struct siisoftc *sc, u_int cstat)
1437 SIIRegs *regs = sc->sc_regs;
1438 State *state;
1439 int i;
1441 #ifdef DEBUG
1442 if (sii_debug > 4)
1443 printf("SCH: ");
1444 #endif
1446 switch (cstat & SII_STATE_MSK) {
1447 case 0:
1448 /* disconnect */
1449 i = sc->sc_target;
1450 sc->sc_target = -1;
1451 #ifdef DEBUG
1452 if (sii_debug > 4)
1453 printf("disconn %d ", i);
1454 #endif
1455 if (i >= 0 && !sc->sc_st[i].prevComm) {
1456 printf("%s: device %d: spurrious disconnect (%d)\n",
1457 sc->sc_dev.dv_xname, i, regs->slcsr);
1458 sc->sc_st[i].prevComm = 0;
1460 break;
1462 case SII_CON:
1463 /* connected as initiator */
1464 i = regs->slcsr;
1465 if (sc->sc_target == i)
1466 break;
1467 printf("%s: device %d: connect to device %d??\n",
1468 sc->sc_dev.dv_xname, sc->sc_target, i);
1469 sc->sc_target = i;
1470 break;
1472 case SII_DST:
1474 * Wait for CON to become valid,
1475 * chip is slow sometimes.
1477 SII_WAIT_UNTIL(cstat, regs->cstat,
1478 cstat & SII_CON, SII_WAIT_COUNT, i);
1479 if (!(cstat & SII_CON))
1480 panic("sii resel");
1481 /* FALLTHROUGH */
1483 case SII_CON | SII_DST:
1485 * Its a reselection. Save the ID and wait for
1486 * interrupts to tell us what to do next
1487 * (should be MSG_IN of IDENTIFY).
1488 * NOTE: sc_target may be >= 0 if we were in
1489 * the process of trying to start a command
1490 * and were reselected before the select
1491 * command finished.
1493 sc->sc_target = i = regs->destat;
1494 state = &sc->sc_st[i];
1495 regs->comm = SII_CON | SII_DST | SII_MSG_IN_PHASE;
1496 regs->dmctrl = state->dmaReqAck;
1497 wbflush();
1498 if (!state->prevComm) {
1499 printf("%s: device %d: spurious reselection\n",
1500 sc->sc_dev.dv_xname, i);
1501 break;
1503 state->prevComm = 0;
1504 #ifdef DEBUG
1505 if (sii_debug > 4)
1506 printf("resel %d ", sc->sc_target);
1507 #endif
1508 break;
1510 #ifdef notyet
1511 case SII_DST | SII_TGT:
1512 case SII_CON | SII_DST | SII_TGT:
1513 /* connected as target */
1514 printf("%s: Selected by device %d as target!!\n",
1515 sc->sc_dev.dv_xname, regs->destat);
1516 regs->comm = SII_DISCON;
1517 wbflush();
1518 SII_WAIT_UNTIL(!(regs->cstat & SII_CON),
1519 SII_WAIT_COUNT, i);
1520 regs->cstat = 0xffff;
1521 regs->dstat = 0xffff;
1522 regs->comm = 0;
1523 break;
1524 #endif
1526 default:
1527 printf("%s: Unknown state change (cs %x)!!\n",
1528 sc->sc_dev.dv_xname, cstat);
1529 #ifdef DEBUG
1530 sii_DumpLog();
1531 #endif
1536 * Read one byte of data.
1537 * If 'ack' is true, acknowledge the byte.
1539 static int
1540 sii_GetByte(SIIRegs *regs, int phase, int ack)
1542 u_int dstat;
1543 u_int state;
1544 int i;
1545 int data;
1547 dstat = regs->dstat;
1548 state = regs->cstat & SII_STATE_MSK;
1549 i = -1;
1550 if (!(dstat & SII_IBF) || (dstat & SII_MIS)) {
1551 regs->comm = state | phase;
1552 wbflush();
1553 /* wait a short time for IBF */
1554 SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_IBF,
1555 SII_WAIT_COUNT, i);
1556 #ifdef DEBUG
1557 if (!(dstat & SII_IBF))
1558 printf("status no IBF\n");
1559 #endif
1561 if (dstat & SII_DNE) { /* XXX */
1562 printf("sii_GetByte: DNE set 5\n");
1563 #ifdef DEBUG
1564 sii_DumpLog();
1565 #endif
1566 regs->dstat = SII_DNE;
1568 data = regs->data;
1569 /* check for parity error */
1570 if (dstat & SII_IPE) {
1571 #ifdef DEBUG
1572 if (sii_debug > 4)
1573 printf("cnt0 %d\n", i);
1574 #endif
1575 printf("sii_GetByte: data %x ?? ds %x cm %x i %d\n",
1576 data, dstat, regs->comm, i); /* XXX */
1577 data = -1;
1578 ack = 1;
1581 if (ack) {
1582 regs->comm = SII_INXFER | state | phase;
1583 wbflush();
1585 /* wait a short time for XFER complete */
1586 SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE,
1587 SII_WAIT_COUNT, i);
1589 /* clear the DNE */
1590 if (dstat & SII_DNE) {
1591 regs->dstat = SII_DNE;
1592 wbflush();
1596 return (data);
1600 * Exchange messages to initiate synchronous data transfers.
1602 static void
1603 sii_DoSync(SIIRegs *regs, State *state)
1605 u_int dstat, comm;
1606 int i, j;
1607 u_int len;
1609 #ifdef DEBUG
1610 if (sii_debug)
1611 printf("sii_DoSync: len %d per %d req/ack %d\n",
1612 sii_buf[1], sii_buf[3], sii_buf[4]);
1613 #endif
1615 /* SII chip can only handle a minimum transfer period of ??? */
1616 if (sii_buf[3] < 64)
1617 sii_buf[3] = 64;
1618 /* SII chip can only handle a maximum REQ/ACK offset of 3 */
1619 len = sii_buf[4];
1620 if (len > 3)
1621 len = 3;
1623 sii_buf[0] = MSG_EXTENDED;
1624 sii_buf[1] = MSG_EXT_SDTR_LEN;
1625 sii_buf[2] = MSG_EXT_SDTR;
1626 sii_buf[4] = len;
1627 #if 1
1628 comm = SII_INXFER | SII_ATN | SII_MSG_OUT_PHASE |
1629 (regs->cstat & SII_STATE_MSK);
1630 regs->comm = comm & ~SII_INXFER;
1631 for (j = 0; j < 5; j++) {
1632 /* wait for target to request the next byte */
1633 SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_TBE,
1634 SII_WAIT_COUNT, i);
1635 if (!(dstat & SII_TBE) ||
1636 (dstat & SII_PHASE_MSK) != SII_MSG_OUT_PHASE) {
1637 printf("sii_DoSync: TBE? ds %x cm %x i %d\n",
1638 dstat, comm, i); /* XXX */
1639 return;
1642 /* the last message byte should have ATN off */
1643 if (j == 4)
1644 comm &= ~SII_ATN;
1646 regs->data = sii_buf[j];
1647 regs->comm = comm;
1648 wbflush();
1650 /* wait a short time for XFER complete */
1651 SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE,
1652 SII_WAIT_COUNT, i);
1654 if (!(dstat & SII_DNE)) {
1655 printf("sii_DoSync: DNE? ds %x cm %x i %d\n",
1656 dstat, comm, i); /* XXX */
1657 return;
1660 /* clear the DNE, other errors handled later */
1661 regs->dstat = SII_DNE;
1662 wbflush();
1664 #else /* 0 */
1665 sc->sii_copytobuf((u_short *)sii_buf,
1666 (volatile u_short *)SII_BUF_ADDR(sc), 5);
1667 printf("sii_DoSync: %x %x %x ds %x\n",
1668 ((volatile u_short *)SII_BUF_ADDR(sc))[0],
1669 ((volatile u_short *)SII_BUF_ADDR(sc))[2],
1670 ((volatile u_short *)SII_BUF_ADDR(sc))[4],
1671 regs->dstat); /* XXX */
1672 regs->dmaddrl = (u_short)(SII_BUF_ADDR(sc) >> 1);
1673 regs->dmaddrh = (u_short)(SII_BUF_ADDR(sc) >> 17) & 03;
1674 regs->dmlotc = 5;
1675 regs->comm = SII_DMA | SII_INXFER | SII_ATN |
1676 (regs->cstat & SII_STATE_MSK) | SII_MSG_OUT_PHASE;
1677 wbflush();
1679 /* wait a short time for XFER complete */
1680 SII_WAIT_UNTIL(dstat, regs->dstat,
1681 (dstat & (SII_DNE | SII_TCZ)) == (SII_DNE | SII_TCZ),
1682 SII_WAIT_COUNT, i);
1684 if ((dstat & (SII_DNE | SII_TCZ)) != (SII_DNE | SII_TCZ)) {
1685 printf("sii_DoSync: ds %x cm %x i %d lotc %d\n",
1686 dstat, regs->comm, i, regs->dmlotc); /* XXX */
1687 sii_DumpLog(); /* XXX */
1688 return;
1690 /* clear the DNE, other errors handled later */
1691 regs->dstat = SII_DNE;
1692 wbflush();
1693 #endif /* 0 */
1695 #if 0
1696 SII_WAIT_UNTIL(dstat, regs->dstat, dstat & (SII_CI | SII_DI),
1697 SII_WAIT_COUNT, i);
1698 printf("sii_DoSync: ds %x cm %x i %d lotc %d\n",
1699 dstat, regs->comm, i, regs->dmlotc); /* XXX */
1700 #endif
1702 state->dmaReqAck = len;
1706 * Issue the sequence of commands to the controller to start DMA.
1707 * NOTE: the data buffer should be word-aligned for DMA out.
1709 static void
1710 sii_StartDMA(SIIRegs *regs, int phase, u_short *dmaAddr, int size)
1711 /* regs: which SII to use */
1712 /* phase: phase to send/receive data */
1713 /* dmaAddr: DMA buffer address */
1714 /* size: # of bytes to transfer */
1717 if (regs->dstat & SII_DNE) { /* XXX */
1718 regs->dstat = SII_DNE;
1719 printf("sii_StartDMA: DNE set\n");
1720 #ifdef DEBUG
1721 sii_DumpLog();
1722 #endif
1724 regs->dmaddrl = ((u_long)dmaAddr >> 1);
1725 regs->dmaddrh = ((u_long)dmaAddr >> 17) & 03;
1726 regs->dmlotc = size;
1727 regs->comm = SII_DMA | SII_INXFER | (regs->cstat & SII_STATE_MSK) |
1728 phase;
1729 wbflush();
1731 #ifdef DEBUG
1732 if (sii_debug > 5) {
1733 printf("sii_StartDMA: cs 0x%x, ds 0x%x, cm 0x%x, size %d\n",
1734 regs->cstat, regs->dstat, regs->comm, size);
1736 #endif
1740 * Call the device driver's 'done' routine to let it know the command is done.
1741 * The 'done' routine may try to start another command.
1742 * To be fair, we should start pending commands for other devices
1743 * before allowing the same device to start another command.
1745 static void
1746 sii_CmdDone(struct siisoftc *sc, int target, int error)
1747 /* sc: which SII to use */
1748 /* target: which device is done */
1749 /* error: error code if any errors */
1751 ScsiCmd *scsicmd;
1752 int i;
1754 scsicmd = sc->sc_cmd[target];
1755 #ifdef DIAGNOSTIC
1756 if (target < 0 || !scsicmd)
1757 panic("sii_CmdDone");
1758 #endif
1759 sc->sc_cmd[target] = (ScsiCmd *)0;
1760 #ifdef DEBUG
1761 if (sii_debug > 1) {
1762 printf("sii_CmdDone: %s target %d cmd %x err %d resid %d\n",
1763 sc->sc_dev.dv_xname,
1764 target, scsicmd->cmd[0], error, sc->sc_st[target].buflen);
1766 #endif
1768 /* look for another device that is ready */
1769 for (i = 0; i < SII_NCMD; i++) {
1770 /* don't restart a disconnected command */
1771 if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm)
1772 continue;
1773 sii_StartCmd(sc, i);
1774 break;
1777 sc->sc_xs[target]->status = sc->sc_st[target].statusByte;
1779 * Convert SII driver error code to MI SCSI XS_*.
1781 switch (error) {
1782 case 0:
1783 sc->sc_xs[target]->error = XS_NOERROR;
1784 break;
1785 case ENXIO:
1786 sc->sc_xs[target]->error = XS_SELTIMEOUT;
1787 break;
1788 case EBUSY:
1789 sc->sc_xs[target]->error = XS_BUSY;
1790 break;
1791 case EIO:
1792 sc->sc_xs[target]->error = XS_DRIVER_STUFFUP;
1793 break;
1794 default:
1795 sc->sc_xs[target]->error = XS_DRIVER_STUFFUP;
1797 sc->sc_xs[target]->resid = sc->sc_st[target].buflen;
1798 scsipi_done(sc->sc_xs[target]);
1801 #ifdef DEBUG
1802 static void
1803 sii_DumpLog(void)
1805 struct sii_log *lp;
1807 printf("sii: cmd %x bn %d cnt %d\n", sii_debug_cmd, sii_debug_bn,
1808 sii_debug_sz);
1809 lp = sii_logp;
1810 do {
1811 printf("target %d cs %x ds %x cm %x msg %x rlen %x dlen %x\n",
1812 lp->target, lp->cstat, lp->dstat, lp->comm, lp->msg,
1813 lp->rlen, lp->dlen);
1814 if (++lp >= &sii_log[NLOG])
1815 lp = sii_log;
1816 } while (lp != sii_logp);
1818 #endif