1 /* $NetBSD: siop.c,v 1.63 2009/03/18 17:06:42 cegger Exp $ */
4 * Copyright (c) 1990 The Regents of the University of California.
7 * This code is derived from software contributed to Berkeley by
8 * Van Jacobson of Lawrence Berkeley Laboratory.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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
34 * @(#)siop.c 7.5 (Berkeley) 5/4/91
38 * Copyright (c) 1994 Michael L. Hitch
40 * This code is derived from software contributed to Berkeley by
41 * Van Jacobson of Lawrence Berkeley Laboratory.
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
52 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
53 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
54 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
55 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
56 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
57 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
58 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
59 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
61 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
63 * @(#)siop.c 7.5 (Berkeley) 5/4/91
67 * AMIGA 53C710 scsi adaptor driver
72 #include <sys/cdefs.h>
73 __KERNEL_RCSID(0, "$NetBSD: siop.c,v 1.63 2009/03/18 17:06:42 cegger Exp $");
75 #include <sys/param.h>
76 #include <sys/systm.h>
77 #include <sys/callout.h>
78 #include <sys/kernel.h>
79 #include <sys/device.h>
80 #include <sys/disklabel.h>
82 #include <sys/malloc.h>
84 #include <uvm/uvm_extern.h>
86 #include <dev/scsipi/scsi_all.h>
87 #include <dev/scsipi/scsipi_all.h>
88 #include <dev/scsipi/scsiconf.h>
89 #include <machine/cpu.h>
91 #include <m68k/cacheops.h>
93 #include <amiga/amiga/custom.h>
94 #include <amiga/amiga/isr.h>
95 #include <amiga/dev/siopreg.h>
96 #include <amiga/dev/siopvar.h>
100 * In u-seconds, primarily for state changes on the SPC.
102 #define SCSI_CMD_WAIT 500000 /* wait per step of 'immediate' cmds */
103 #define SCSI_DATA_WAIT 500000 /* wait per data in/out step */
104 #define SCSI_INIT_WAIT 500000 /* wait per step (both) during init */
106 void siop_select(struct siop_softc
*);
107 void siopabort(struct siop_softc
*, siop_regmap_p
, const char *);
108 void sioperror(struct siop_softc
*, siop_regmap_p
, u_char
);
109 void siopstart(struct siop_softc
*);
110 int siop_checkintr(struct siop_softc
*, u_char
, u_char
, u_char
, int *);
111 void siopreset(struct siop_softc
*);
112 void siopsetdelay(int);
113 void siop_scsidone(struct siop_acb
*, int);
114 void siop_timeout(void *);
115 void siop_sched(struct siop_softc
*);
116 void siop_poll(struct siop_softc
*, struct siop_acb
*);
117 void siopintr(struct siop_softc
*);
118 void scsi_period_to_siop(struct siop_softc
*, int);
119 void siop_start(struct siop_softc
*, int, int, u_char
*, int, u_char
*, int);
120 void siop_dump_acb(struct siop_acb
*);
124 #include <amiga/dev/siop_script.out>
126 /* default to not inhibit sync negotiation on any drive */
127 u_char siop_inhibit_sync
[8] = { 0, 0, 0, 0, 0, 0, 0 }; /* initialize, so patchable */
128 u_char siop_allow_disc
[8] = {3, 3, 3, 3, 3, 3, 3, 3};
131 int siop_reset_delay
= 250; /* delay after reset, in milleseconds */
133 int siop_cmd_wait
= SCSI_CMD_WAIT
;
134 int siop_data_wait
= SCSI_DATA_WAIT
;
135 int siop_init_wait
= SCSI_INIT_WAIT
;
139 * sync period transfer lookup - only valid for 66 MHz clock
142 unsigned char p
; /* period from sync request message */
143 unsigned char r
; /* siop_period << 4 | sbcl */
175 * 0x02 - DMA chaining
177 * 0x08 - phase mismatch
179 * 0x20 - panic on unhandled exceptions
180 * 0x100 - disconnect/reselect
183 int siopsync_debug
= 0;
184 int siopdma_hits
= 0;
185 int siopdma_misses
= 0;
186 int siopchain_ints
= 0;
190 #define SIOP_TRACE_SIZE 128
191 #define SIOP_TRACE(a,b,c,d) \
192 siop_trbuf[siop_trix] = (a); \
193 siop_trbuf[siop_trix+1] = (b); \
194 siop_trbuf[siop_trix+2] = (c); \
195 siop_trbuf[siop_trix+3] = (d); \
196 siop_trix = (siop_trix + 4) & (SIOP_TRACE_SIZE - 1);
197 u_char siop_trbuf
[SIOP_TRACE_SIZE
];
199 void siop_dump(struct siop_softc
*);
200 void siop_dump_trace(void);
202 #define SIOP_TRACE(a,b,c,d)
207 * default minphys routine for siop based controllers
210 siop_minphys(struct buf
*bp
)
214 * No max transfer at this level.
220 * used by specific siop controller
224 siop_scsipi_request(struct scsipi_channel
*chan
, scsipi_adapter_req_t req
,
227 struct scsipi_xfer
*xs
;
228 struct scsipi_periph
*periph
;
229 struct siop_acb
*acb
;
230 struct siop_softc
*sc
= (void *)chan
->chan_adapter
->adapt_dev
;
234 case ADAPTER_REQ_RUN_XFER
:
236 periph
= xs
->xs_periph
;
237 flags
= xs
->xs_control
;
240 if (flags
& XS_CTL_DATA_UIO
)
241 panic("siop: scsi data uio requested");
244 if (sc
->sc_nexus
&& flags
& XS_CTL_POLL
)
245 /* panic("siop_scsicmd: busy");*/
246 printf("siop_scsicmd: busy\n");
249 acb
= sc
->free_list
.tqh_first
;
251 TAILQ_REMOVE(&sc
->free_list
, acb
, chain
);
257 * This should never happen as we track the resources
261 scsipi_printaddr(periph
);
262 printf("unable to allocate acb\n");
263 panic("siop_scsipi_request");
267 acb
->flags
= ACB_ACTIVE
;
269 memcpy(&acb
->cmd
, xs
->cmd
, xs
->cmdlen
);
270 acb
->clen
= xs
->cmdlen
;
271 acb
->daddr
= xs
->data
;
272 acb
->dleft
= xs
->datalen
;
275 TAILQ_INSERT_TAIL(&sc
->ready_list
, acb
, chain
);
277 if (sc
->sc_nexus
== NULL
)
282 if (flags
& XS_CTL_POLL
|| siop_no_dma
)
286 case ADAPTER_REQ_GROW_RESOURCES
:
289 case ADAPTER_REQ_SET_XFER_MODE
:
295 siop_poll(struct siop_softc
*sc
, struct siop_acb
*acb
)
297 siop_regmap_p rp
= sc
->sc_siopp
;
298 struct scsipi_xfer
*xs
= acb
->xs
;
308 to
= xs
->timeout
/ 1000;
309 if (sc
->nexus_list
.tqh_first
)
310 printf("%s: siop_poll called with disconnected device\n",
311 sc
->sc_dev
.dv_xname
);
313 /* use cmd_wait values? */
316 while (((istat
= rp
->siop_istat
) &
317 (SIOP_ISTAT_SIP
| SIOP_ISTAT_DIP
)) == 0) {
320 printf ("waiting: tgt %d cmd %02x sbcl %02x dsp %lx (+%lx) dcmd %lx ds %p timeout %d\n",
321 xs
->xs_periph
->periph_target
, acb
->cmd
.opcode
,
322 rp
->siop_sbcl
, rp
->siop_dsp
,
323 rp
->siop_dsp
- sc
->sc_scriptspa
,
324 *((volatile long *)&rp
->siop_dcmd
), &acb
->ds
, acb
->xs
->timeout
);
335 sstat0
= rp
->siop_sstat0
;
336 dstat
= rp
->siop_dstat
;
337 if (siop_checkintr(sc
, istat
, dstat
, sstat0
, &status
)) {
338 if (acb
!= sc
->sc_nexus
)
339 printf("%s: siop_poll disconnected device completed\n",
340 sc
->sc_dev
.dv_xname
);
341 else if ((sc
->sc_flags
& SIOP_INTDEFER
) == 0) {
342 sc
->sc_flags
&= ~SIOP_INTSOFF
;
343 rp
->siop_sien
= sc
->sc_sien
;
344 rp
->siop_dien
= sc
->sc_dien
;
346 siop_scsidone(sc
->sc_nexus
, status
);
349 if (xs
->xs_status
& XS_STS_DONE
)
356 * start next command that's ready
359 siop_sched(struct siop_softc
*sc
)
361 struct scsipi_periph
*periph
;
362 struct siop_acb
*acb
;
367 printf("%s: siop_sched- nexus %p/%d ready %p/%d\n",
368 sc
->sc_dev
.dv_xname
, sc
->sc_nexus
,
369 sc
->sc_nexus
->xs
->xs_periph
->periph_target
,
370 sc
->ready_list
.tqh_first
,
371 sc
->ready_list
.tqh_first
->xs
->xs_periph
->periph_target
);
375 for (acb
= sc
->ready_list
.tqh_first
; acb
; acb
= acb
->chain
.tqe_next
) {
376 periph
= acb
->xs
->xs_periph
;
377 i
= periph
->periph_target
;
378 if(!(sc
->sc_tinfo
[i
].lubusy
& (1 << periph
->periph_lun
))) {
379 struct siop_tinfo
*ti
= &sc
->sc_tinfo
[i
];
381 TAILQ_REMOVE(&sc
->ready_list
, acb
, chain
);
383 periph
= acb
->xs
->xs_periph
;
384 ti
= &sc
->sc_tinfo
[periph
->periph_target
];
385 ti
->lubusy
|= (1 << periph
->periph_lun
);
392 printf("%s: siop_sched didn't find ready command\n",
393 sc
->sc_dev
.dv_xname
);
398 if (acb
->xs
->xs_control
& XS_CTL_RESET
)
402 acb
->cmd
.bytes
[0] |= slp
->scsipi_scsi
.lun
<< 5; /* XXXX */
409 siop_scsidone(struct siop_acb
*acb
, int stat
)
411 struct scsipi_xfer
*xs
;
412 struct scsipi_periph
*periph
;
413 struct siop_softc
*sc
;
416 if (acb
== NULL
|| (xs
= acb
->xs
) == NULL
) {
418 printf("siop_scsidone: NULL acb or scsipi_xfer\n");
419 #if defined(DEBUG) && defined(DDB)
426 callout_stop(&xs
->xs_callout
);
428 periph
= xs
->xs_periph
;
429 sc
= (void *)periph
->periph_channel
->chan_adapter
->adapt_dev
;
432 xs
->resid
= 0; /* XXXX */
434 if (xs
->error
== XS_NOERROR
) {
435 if (stat
== SCSI_CHECK
|| stat
== SCSI_BUSY
)
440 * Remove the ACB from whatever queue it's on. We have to do a bit of
441 * a hack to figure out which queue it's on. Note that it is *not*
442 * necessary to cdr down the ready queue, but we must cdr down the
443 * nexus queue and see if it's there, so we can mark the unit as no
444 * longer busy. This code is sickening, but it works.
446 if (acb
== sc
->sc_nexus
) {
448 sc
->sc_tinfo
[periph
->periph_target
].lubusy
&=
449 ~(1<<periph
->periph_lun
);
450 if (sc
->ready_list
.tqh_first
)
451 dosched
= 1; /* start next command */
453 SIOP_TRACE('d','a',stat
,0)
454 } else if (sc
->ready_list
.tqh_last
== &acb
->chain
.tqe_next
) {
455 TAILQ_REMOVE(&sc
->ready_list
, acb
, chain
);
456 SIOP_TRACE('d','r',stat
,0)
458 register struct siop_acb
*acb2
;
459 for (acb2
= sc
->nexus_list
.tqh_first
; acb2
;
460 acb2
= acb2
->chain
.tqe_next
)
462 TAILQ_REMOVE(&sc
->nexus_list
, acb
, chain
);
463 sc
->sc_tinfo
[periph
->periph_target
].lubusy
464 &= ~(1<<periph
->periph_lun
);
470 else if (acb
->chain
.tqe_next
) {
471 TAILQ_REMOVE(&sc
->ready_list
, acb
, chain
);
474 printf("%s: can't find matching acb\n",
475 sc
->sc_dev
.dv_xname
);
480 SIOP_TRACE('d','n',stat
,0);
482 /* Put it on the free list. */
483 acb
->flags
= ACB_FREE
;
484 TAILQ_INSERT_HEAD(&sc
->free_list
, acb
, chain
);
486 sc
->sc_tinfo
[periph
->periph_target
].cmds
++;
490 if (dosched
&& sc
->sc_nexus
== NULL
)
495 siopabort(register struct siop_softc
*sc
, siop_regmap_p rp
, const char *where
)
501 printf ("%s: abort %s: dstat %02x, sstat0 %02x sbcl %02x\n",
503 where
, rp
->siop_dstat
, rp
->siop_sstat0
, rp
->siop_sbcl
);
505 if (sc
->sc_active
> 0) {
507 SET_SBIC_cmd (rp
, SBIC_CMD_ABORT
);
510 GET_SBIC_asr (rp
, asr
);
511 if (asr
& (SBIC_ASR_BSY
|SBIC_ASR_LCI
))
513 /* ok, get more drastic.. */
515 SET_SBIC_cmd (rp
, SBIC_CMD_RESET
);
517 SBIC_WAIT(rp
, SBIC_ASR_INT
, 0);
518 GET_SBIC_csr (rp
, csr
); /* clears interrupt also */
525 SBIC_WAIT (rp
, SBIC_ASR_INT
, 0);
526 GET_SBIC_csr (rp
, csr
);
528 while ((csr
!= SBIC_CSR_DISC
) && (csr
!= SBIC_CSR_DISC_1
)
529 && (csr
!= SBIC_CSR_CMD_INVALID
));
532 /* lets just hope it worked.. */
534 for (i
= 0; i
< 2; ++i
) {
535 if (sc
->sc_iob
[i
].sc_xs
&& &sc
->sc_iob
[i
] !=
537 printf ("siopabort: cleanup!\n");
538 sc
->sc_iob
[i
].sc_xs
= NULL
;
541 #endif /* fix_this */
542 /* sc->sc_active = 0; */
547 siopinitialize(struct siop_softc
*sc
)
551 extern u_long scsi_nosync
;
552 extern int shift_nosync
;
555 * Need to check that scripts is on a long word boundary
556 * Also should verify that dev doesn't span non-contiguous
559 sc
->sc_scriptspa
= kvtop((void *)__UNCONST(scripts
));
562 * malloc sc_acb to ensure that DS is on a long word boundary.
565 sc
->sc_acb
= malloc(sizeof(struct siop_acb
) * SIOP_NACB
,
567 if (sc
->sc_acb
== NULL
)
568 panic("siopinitialize: ACB malloc failed!");
570 sc
->sc_tcp
[1] = 1000 / sc
->sc_clock_freq
;
571 sc
->sc_tcp
[2] = 1500 / sc
->sc_clock_freq
;
572 sc
->sc_tcp
[3] = 2000 / sc
->sc_clock_freq
;
573 sc
->sc_minsync
= sc
->sc_tcp
[1]; /* in 4ns units */
574 if (sc
->sc_minsync
< 25)
576 if (sc
->sc_clock_freq
<= 25) {
577 sc
->sc_dcntl
|= 0x80; /* SCLK/1 */
578 sc
->sc_tcp
[0] = sc
->sc_tcp
[1];
579 } else if (sc
->sc_clock_freq
<= 37) {
580 sc
->sc_dcntl
|= 0x40; /* SCLK/1.5 */
581 sc
->sc_tcp
[0] = sc
->sc_tcp
[2];
582 } else if (sc
->sc_clock_freq
<= 50) {
583 sc
->sc_dcntl
|= 0x00; /* SCLK/2 */
584 sc
->sc_tcp
[0] = sc
->sc_tcp
[3];
586 sc
->sc_dcntl
|= 0xc0; /* SCLK/3 */
587 sc
->sc_tcp
[0] = 3000 / sc
->sc_clock_freq
;
591 inhibit_sync
= (scsi_nosync
>> shift_nosync
) & 0xff;
595 printf("%s: Inhibiting synchronous transfer %02x\n",
596 sc
->sc_dev
.dv_xname
, inhibit_sync
);
598 for (i
= 0; i
< 8; ++i
)
599 if (inhibit_sync
& (1 << i
))
600 siop_inhibit_sync
[i
] = 1;
607 siop_timeout(void *arg
)
609 struct siop_acb
*acb
;
610 struct scsipi_periph
*periph
;
611 struct siop_softc
*sc
;
615 periph
= acb
->xs
->xs_periph
;
616 sc
= device_private(periph
->periph_channel
->chan_adapter
->adapt_dev
);
617 scsipi_printaddr(periph
);
618 printf("timed out\n");
622 acb
->xs
->error
= XS_TIMEOUT
;
629 siopreset(struct siop_softc
*sc
)
634 struct siop_acb
*acb
;
638 if (sc
->sc_flags
& SIOP_ALIVE
)
639 siopabort(sc
, rp
, "reset");
641 printf("%s: ", sc
->sc_dev
.dv_xname
); /* XXXX */
647 * XXX - is this really needed?
649 rp
->siop_istat
|= SIOP_ISTAT_ABRT
; /* abort current script */
650 rp
->siop_istat
|= SIOP_ISTAT_RST
; /* reset chip */
651 rp
->siop_istat
&= ~SIOP_ISTAT_RST
;
653 * Reset SCSI bus (do we really want this?)
656 rp
->siop_scntl1
|= SIOP_SCNTL1_RST
;
658 rp
->siop_scntl1
&= ~SIOP_SCNTL1_RST
;
661 * Set up various chip parameters
663 rp
->siop_scntl0
= SIOP_ARB_FULL
| SIOP_SCNTL0_EPC
| SIOP_SCNTL0_EPG
;
664 rp
->siop_scntl1
= SIOP_SCNTL1_ESR
;
665 rp
->siop_dcntl
= sc
->sc_dcntl
;
666 rp
->siop_dmode
= 0x80; /* burst length = 4 */
667 rp
->siop_sien
= 0x00; /* don't enable interrupts yet */
668 rp
->siop_dien
= 0x00; /* don't enable interrupts yet */
669 rp
->siop_scid
= 1 << sc
->sc_channel
.chan_id
;
671 rp
->siop_ctest0
|= SIOP_CTEST0_BTD
| SIOP_CTEST0_EAN
;
672 rp
->siop_ctest7
|= sc
->sc_ctest7
;
674 /* will need to re-negotiate sync xfers */
675 memset(&sc
->sc_sync
, 0, sizeof (sc
->sc_sync
));
678 if (i
& SIOP_ISTAT_SIP
)
679 dummy
= rp
->siop_sstat0
;
680 if (i
& SIOP_ISTAT_DIP
)
681 dummy
= rp
->siop_dstat
;
685 delay (siop_reset_delay
* 1000);
686 printf("siop id %d reset V%d\n", sc
->sc_channel
.chan_id
,
687 rp
->siop_ctest8
>> 4);
689 if ((sc
->sc_flags
& SIOP_ALIVE
) == 0) {
690 TAILQ_INIT(&sc
->ready_list
);
691 TAILQ_INIT(&sc
->nexus_list
);
692 TAILQ_INIT(&sc
->free_list
);
695 memset(acb
, 0, sizeof(struct siop_acb
) * SIOP_NACB
);
696 for (i
= 0; i
< SIOP_NACB
; i
++) {
697 TAILQ_INSERT_TAIL(&sc
->free_list
, acb
, chain
);
700 memset(sc
->sc_tinfo
, 0, sizeof(sc
->sc_tinfo
));
702 if (sc
->sc_nexus
!= NULL
) {
703 sc
->sc_nexus
->xs
->error
= XS_RESET
;
704 siop_scsidone(sc
->sc_nexus
, sc
->sc_nexus
->stat
[0]);
706 while ((acb
= sc
->nexus_list
.tqh_first
) > 0) {
707 acb
->xs
->error
= XS_RESET
;
708 siop_scsidone(acb
, acb
->stat
[0]);
712 sc
->sc_flags
|= SIOP_ALIVE
;
713 sc
->sc_flags
&= ~(SIOP_INTDEFER
|SIOP_INTSOFF
);
714 /* enable SCSI and DMA interrupts */
715 sc
->sc_sien
= SIOP_SIEN_M_A
| SIOP_SIEN_STO
| /*SIOP_SIEN_SEL |*/ SIOP_SIEN_SGE
|
716 SIOP_SIEN_UDC
| SIOP_SIEN_RST
| SIOP_SIEN_PAR
;
717 sc
->sc_dien
= SIOP_DIEN_BF
| SIOP_DIEN_ABRT
| SIOP_DIEN_SIR
|
718 /*SIOP_DIEN_WTD |*/ SIOP_DIEN_IID
;
719 rp
->siop_sien
= sc
->sc_sien
;
720 rp
->siop_dien
= sc
->sc_dien
;
724 * Setup Data Storage for 53C710 and start SCRIPTS processing
728 siop_start(struct siop_softc
*sc
, int target
, int lun
, u_char
*cbuf
, int clen
,
729 u_char
*buf
, int len
)
731 siop_regmap_p rp
= sc
->sc_siopp
;
735 struct siop_acb
*acb
= sc
->sc_nexus
;
741 if (siop_debug
& 0x100 && rp
->siop_sbcl
& SIOP_BSY
) {
742 printf ("ACK! siop was busy: rp %p script %p dsa %p active %ld\n",
743 rp
, &scripts
, &acb
->ds
, sc
->sc_active
);
744 printf ("istat %02x sfbr %02x lcrc %02x sien %02x dien %02x\n",
745 rp
->siop_istat
, rp
->siop_sfbr
, rp
->siop_lcrc
,
746 rp
->siop_sien
, rp
->siop_dien
);
752 acb
->msgout
[0] = MSG_IDENTIFY
| lun
;
753 if (siop_allow_disc
[target
] & 2 ||
754 (siop_allow_disc
[target
] && len
== 0))
755 acb
->msgout
[0] = MSG_IDENTIFY_DR
| lun
;
759 acb
->ds
.scsi_addr
= (0x10000 << target
) | (sc
->sc_sync
[target
].sxfer
<< 8);
761 acb
->ds
.idbuf
= (char *) kvtop(&acb
->msgout
[0]);
762 acb
->ds
.cmdlen
= clen
;
763 acb
->ds
.cmdbuf
= (char *) kvtop(cbuf
);
765 acb
->ds
.stsbuf
= (char *) kvtop(&acb
->stat
[0]);
767 acb
->ds
.msgbuf
= (char *) kvtop(&acb
->msg
[0]);
769 acb
->ds
.msginlen
= 1;
770 acb
->ds
.extmsglen
= 1;
771 acb
->ds
.synmsglen
= 3;
772 acb
->ds
.msginbuf
= (char *) kvtop(&acb
->msg
[1]);
773 acb
->ds
.extmsgbuf
= (char *) kvtop(&acb
->msg
[2]);
774 acb
->ds
.synmsgbuf
= (char *) kvtop(&acb
->msg
[3]);
775 memset(&acb
->ds
.chain
, 0, sizeof (acb
->ds
.chain
));
778 * Negotiate wide is the initial negotiation state; since the 53c710
779 * doesn't do wide transfers, just begin the synchronous transfer
782 if (sc
->sc_sync
[target
].state
== NEG_WIDE
) {
783 if (siop_inhibit_sync
[target
]) {
784 sc
->sc_sync
[target
].state
= NEG_DONE
;
785 sc
->sc_sync
[target
].sbcl
= 0;
786 sc
->sc_sync
[target
].sxfer
= 0;
789 printf ("Forcing target %d asynchronous\n", target
);
794 acb
->msgout
[1] = MSG_EXT_MESSAGE
;
796 acb
->msgout
[3] = MSG_SYNC_REQ
;
797 #ifdef MAXTOR_SYNC_KLUDGE
798 acb
->msgout
[4] = 50 / 4; /* ask for ridiculous period */
800 acb
->msgout
[4] = sc
->sc_minsync
;
802 acb
->msgout
[5] = SIOP_MAX_OFFSET
;
804 sc
->sc_sync
[target
].state
= NEG_WAITS
;
807 printf ("Sending sync request to target %d\n", target
);
813 * Build physical DMA addresses for scatter/gather I/O
817 acb
->iob_curbuf
= acb
->iob_curlen
= 0;
823 acb
->ds
.chain
[nchain
].databuf
= (char *) kvtop (addr
);
824 if (count
< (tcount
= PAGE_SIZE
- ((int) addr
& PGOFSET
)))
826 acb
->ds
.chain
[nchain
].datalen
= tcount
;
829 if (acb
->ds
.chain
[nchain
].databuf
== dmaend
) {
830 dmaend
+= acb
->ds
.chain
[nchain
].datalen
;
831 acb
->ds
.chain
[nchain
].datalen
= 0;
832 acb
->ds
.chain
[--nchain
].datalen
+= tcount
;
838 dmaend
= acb
->ds
.chain
[nchain
].databuf
+
839 acb
->ds
.chain
[nchain
].datalen
;
840 acb
->ds
.chain
[nchain
].datalen
= tcount
;
842 if (nchain
) /* Don't count miss on first one */
849 if (nchain
!= 1 && len
!= 0 && siop_debug
& 3) {
850 printf ("DMA chaining set: %d\n", nchain
);
851 for (i
= 0; i
< nchain
; ++i
) {
852 printf (" [%d] %8p %lx\n", i
, acb
->ds
.chain
[i
].databuf
,
853 acb
->ds
.chain
[i
].datalen
);
858 /* push data cache for all data the 53c710 needs to access */
859 dma_cachectl ((void *)acb
, sizeof (struct siop_acb
));
860 dma_cachectl (cbuf
, clen
);
861 if (buf
!= NULL
&& len
!= 0)
862 dma_cachectl (buf
, len
);
864 if (siop_debug
& 0x100 && rp
->siop_sbcl
& SIOP_BSY
) {
865 printf ("ACK! siop was busy at start: rp %p script %p dsa %p active %ld\n",
866 rp
, &scripts
, &acb
->ds
, sc
->sc_active
);
872 if (sc
->nexus_list
.tqh_first
== NULL
) {
873 callout_reset(&acb
->xs
->xs_callout
,
874 mstohz(acb
->xs
->timeout
) + 1, siop_timeout
, acb
);
875 if (rp
->siop_istat
& SIOP_ISTAT_CON
)
876 printf("%s: siop_select while connected?\n",
877 sc
->sc_dev
.dv_xname
);
879 rp
->siop_sbcl
= sc
->sc_sync
[target
].sbcl
;
880 rp
->siop_dsa
= kvtop((void *)&acb
->ds
);
881 rp
->siop_dsp
= sc
->sc_scriptspa
;
882 SIOP_TRACE('s',1,0,0)
884 if ((rp
->siop_istat
& SIOP_ISTAT_CON
) == 0) {
885 rp
->siop_istat
= SIOP_ISTAT_SIGP
;
886 SIOP_TRACE('s',2,0,0);
889 SIOP_TRACE('s',3,rp
->siop_istat
,0);
898 * Process a DMA or SCSI interrupt from the 53C710 SIOP
902 siop_checkintr(struct siop_softc
*sc
, u_char istat
, u_char dstat
,
903 u_char sstat0
, int *status
)
905 siop_regmap_p rp
= sc
->sc_siopp
;
906 struct siop_acb
*acb
= sc
->sc_nexus
;
908 int dfifo
, dbc
, sstat1
;
910 dfifo
= rp
->siop_dfifo
;
912 sstat1
= rp
->siop_sstat1
;
913 rp
->siop_ctest8
|= SIOP_CTEST8_CLF
;
914 while ((rp
->siop_ctest1
& SIOP_CTEST1_FMT
) != SIOP_CTEST1_FMT
)
916 rp
->siop_ctest8
&= ~SIOP_CTEST8_CLF
;
920 if (siop_debug
& 0x100) {
921 DCIAS(&acb
->stat
[0]); /* XXX */
922 printf ("siopchkintr: istat %x dstat %x sstat0 %x dsps %x sbcl %x sts %x msg %x\n",
923 istat
, dstat
, sstat0
, rp
->siop_dsps
, rp
->siop_sbcl
, acb
->stat
[0], acb
->msg
[0]);
924 printf ("sync msg in: %02x %02x %02x %02x %02x %02x\n",
925 acb
->msg
[0], acb
->msg
[1], acb
->msg
[2],
926 acb
->msg
[3], acb
->msg
[4], acb
->msg
[5]);
929 if (rp
->siop_dsp
&& (rp
->siop_dsp
< sc
->sc_scriptspa
||
930 rp
->siop_dsp
>= sc
->sc_scriptspa
+ sizeof(scripts
))) {
931 printf ("%s: dsp not within script dsp %lx scripts %lx:%lx",
932 sc
->sc_dev
.dv_xname
, rp
->siop_dsp
, sc
->sc_scriptspa
,
933 sc
->sc_scriptspa
+ sizeof(scripts
));
934 printf(" istat %x dstat %x sstat0 %x\n",
935 istat
, dstat
, sstat0
);
941 SIOP_TRACE('i',dstat
,istat
,(istat
&SIOP_ISTAT_DIP
)?rp
->siop_dsps
&0xff:sstat0
);
942 if (dstat
& SIOP_DSTAT_SIR
&& rp
->siop_dsps
== 0xff00) {
943 /* Normal completion status, or check condition */
945 if (rp
->siop_dsa
!= kvtop((void *)&acb
->ds
)) {
946 printf ("siop: invalid dsa: %lx %x\n", rp
->siop_dsa
,
947 (unsigned)kvtop((void *)&acb
->ds
));
948 panic("*** siop DSA invalid ***");
951 target
= acb
->xs
->xs_periph
->periph_target
;
952 if (sc
->sc_sync
[target
].state
== NEG_WAITS
) {
953 if (acb
->msg
[1] == 0xff)
954 printf ("%s: target %d ignored sync request\n",
955 sc
->sc_dev
.dv_xname
, target
);
956 else if (acb
->msg
[1] == MSG_REJECT
)
957 printf ("%s: target %d rejected sync request\n",
958 sc
->sc_dev
.dv_xname
, target
);
960 /* XXX - need to set sync transfer parameters */
961 printf("%s: target %d (sync) %02x %02x %02x\n",
962 sc
->sc_dev
.dv_xname
, target
, acb
->msg
[1],
963 acb
->msg
[2], acb
->msg
[3]);
964 sc
->sc_sync
[target
].state
= NEG_DONE
;
966 dma_cachectl(&acb
->stat
[0], 1);
967 *status
= acb
->stat
[0];
969 if (rp
->siop_sbcl
& SIOP_BSY
) {
970 /*printf ("ACK! siop was busy at end: rp %x script %x dsa %x\n",
971 rp, &scripts, &acb->ds);*/
976 if (acb
->msg
[0] != 0x00)
977 printf("%s: message was not COMMAND COMPLETE: %x\n",
978 sc
->sc_dev
.dv_xname
, acb
->msg
[0]);
980 if (sc
->nexus_list
.tqh_first
)
981 rp
->siop_dcntl
|= SIOP_DCNTL_STD
;
984 if (dstat
& SIOP_DSTAT_SIR
&& rp
->siop_dsps
== 0xff0b) {
985 target
= acb
->xs
->xs_periph
->periph_target
;
986 if (acb
->msg
[1] == MSG_EXT_MESSAGE
&& acb
->msg
[2] == 3 &&
987 acb
->msg
[3] == MSG_SYNC_REQ
) {
990 printf ("sync msg in: %02x %02x %02x %02x %02x %02x\n",
991 acb
->msg
[0], acb
->msg
[1], acb
->msg
[2],
992 acb
->msg
[3], acb
->msg
[4], acb
->msg
[5]);
994 sc
->sc_sync
[target
].sxfer
= 0;
995 sc
->sc_sync
[target
].sbcl
= 0;
996 if (acb
->msg
[2] == 3 &&
997 acb
->msg
[3] == MSG_SYNC_REQ
&&
1001 * Kludge for my Maxtor XT8580S
1002 * It accepts whatever we request, even
1003 * though it won't work. So we ask for
1004 * a short period than we can handle. If
1005 * the device says it can do it, use 208ns.
1006 * If the device says it can do less than
1007 * 100ns, then we limit it to 100ns.
1009 if (acb
->msg
[4] && acb
->msg
[4] < 100 / 4) {
1011 printf ("%d: target %d wanted %dns period\n",
1012 sc
->sc_dev
.dv_xname
, target
,
1015 if (acb
->msg
[4] == 50 / 4)
1016 acb
->msg
[4] = 208 / 4;
1018 acb
->msg
[4] = 100 / 4;
1020 #endif /* MAXTOR_KLUDGE */
1021 printf ("%s: target %d now synchronous, period=%dns, offset=%d\n",
1022 sc
->sc_dev
.dv_xname
, target
,
1023 acb
->msg
[4] * 4, acb
->msg
[5]);
1024 scsi_period_to_siop (sc
, target
);
1026 rp
->siop_sxfer
= sc
->sc_sync
[target
].sxfer
;
1027 rp
->siop_sbcl
= sc
->sc_sync
[target
].sbcl
;
1028 if (sc
->sc_sync
[target
].state
== NEG_WAITS
) {
1029 sc
->sc_sync
[target
].state
= NEG_DONE
;
1030 rp
->siop_dsp
= sc
->sc_scriptspa
+ Ent_clear_ack
;
1033 rp
->siop_dcntl
|= SIOP_DCNTL_STD
;
1034 sc
->sc_sync
[target
].state
= NEG_DONE
;
1037 /* XXX - not SDTR message */
1039 if (sstat0
& SIOP_SSTAT0_M_A
) { /* Phase mismatch */
1043 printf("%s: Phase mismatch with no active command?\n",
1044 sc
->sc_dev
.dv_xname
);
1048 adjust
= ((dfifo
- (dbc
& 0x7f)) & 0x7f);
1049 if (sstat1
& SIOP_SSTAT1_ORF
)
1051 if (sstat1
& SIOP_SSTAT1_OLF
)
1054 *((long *)__UNVOLATILE(&rp
->siop_dcmd
)) & 0xffffff;
1055 acb
->iob_curlen
+= adjust
;
1057 *((long *)__UNVOLATILE(&rp
->siop_dnad
)) - adjust
;
1059 if (siop_debug
& 0x100) {
1061 printf ("Phase mismatch: curbuf %lx curlen %lx dfifo %x dbc %x sstat1 %x adjust %x sbcl %x starts %d acb %p\n",
1062 acb
->iob_curbuf
, acb
->iob_curlen
, dfifo
,
1063 dbc
, sstat1
, adjust
, rp
->siop_sbcl
,
1065 if (acb
->ds
.chain
[1].datalen
) {
1066 for (i
= 0; acb
->ds
.chain
[i
].datalen
; ++i
)
1067 printf("chain[%d] addr %p len %lx\n",
1068 i
, acb
->ds
.chain
[i
].databuf
,
1069 acb
->ds
.chain
[i
].datalen
);
1073 dma_cachectl ((void *)acb
, sizeof(*acb
));
1076 SIOP_TRACE('m',rp
->siop_sbcl
,(rp
->siop_dsp
>>8),rp
->siop_dsp
);
1078 printf ("Phase mismatch: %x dsp +%lx dcmd %lx\n",
1080 rp
->siop_dsp
- sc
->sc_scriptspa
,
1081 *((volatile long *)&rp
->siop_dcmd
));
1083 if ((rp
->siop_sbcl
& SIOP_REQ
) == 0) {
1084 printf ("Phase mismatch: REQ not asserted! %02x dsp %lx\n",
1085 rp
->siop_sbcl
, rp
->siop_dsp
);
1086 #if defined(DEBUG) && defined(DDB)
1087 /*Debugger(); XXX is*/
1090 switch (rp
->siop_sbcl
& 7) {
1091 case 0: /* data out */
1092 case 1: /* data in */
1093 case 2: /* status */
1094 case 3: /* command */
1095 case 6: /* message in */
1096 case 7: /* message out */
1097 rp
->siop_dsp
= sc
->sc_scriptspa
+ Ent_switch
;
1104 if (sstat0
& SIOP_SSTAT0_STO
) { /* Select timed out */
1107 printf("%s: Select timeout with no active command?\n",
1108 sc
->sc_dev
.dv_xname
);
1109 if (rp
->siop_sbcl
& SIOP_BSY
) {
1110 printf ("ACK! siop was busy at timeout: rp %p script %p dsa %p\n",
1111 rp
, &scripts
, &acb
->ds
);
1112 printf(" sbcl %x sdid %x istat %x dstat %x sstat0 %x\n",
1113 rp
->siop_sbcl
, rp
->siop_sdid
, istat
, dstat
, sstat0
);
1114 if (!(rp
->siop_sbcl
& SIOP_BSY
)) {
1115 printf ("Yikes, it's not busy now!\n");
1118 if (sc
->nexus_list
.tqh_first
)
1119 rp
->siop_dsp
= sc
->sc_scriptspa
+ Ent_wait_reselect
;
1123 /* rp->siop_dcntl |= SIOP_DCNTL_STD;*/
1131 acb
->xs
->error
= XS_SELTIMEOUT
;
1132 if (sc
->nexus_list
.tqh_first
)
1133 rp
->siop_dsp
= sc
->sc_scriptspa
+ Ent_wait_reselect
;
1137 target
= acb
->xs
->xs_periph
->periph_target
;
1140 if (sstat0
& SIOP_SSTAT0_UDC
) {
1143 printf("%s: Unexpected disconnect with no active command?\n",
1144 sc
->sc_dev
.dv_xname
);
1145 printf ("%s: target %d disconnected unexpectedly\n",
1146 sc
->sc_dev
.dv_xname
, target
);
1149 siopabort (sc
, rp
, "siopchkintr");
1152 if (sc
->nexus_list
.tqh_first
)
1153 rp
->siop_dsp
= sc
->sc_scriptspa
+ Ent_wait_reselect
;
1154 return (acb
!= NULL
);
1156 if (dstat
& SIOP_DSTAT_SIR
&& (rp
->siop_dsps
== 0xff01 ||
1157 rp
->siop_dsps
== 0xff02)) {
1159 if (siop_debug
& 0x100)
1160 printf ("%s: ID %02x disconnected TEMP %lx (+%lx) curbuf %lx curlen %lx buf %p len %lx dfifo %x dbc %x sstat1 %x starts %d acb %p\n",
1161 sc
->sc_dev
.dv_xname
, 1 << target
, rp
->siop_temp
,
1162 rp
->siop_temp
? rp
->siop_temp
- sc
->sc_scriptspa
: 0,
1163 acb
->iob_curbuf
, acb
->iob_curlen
,
1164 acb
->ds
.chain
[0].databuf
, acb
->ds
.chain
[0].datalen
, dfifo
, dbc
, sstat1
, siopstarts
, acb
);
1167 printf("%s: Disconnect with no active command?\n",
1168 sc
->sc_dev
.dv_xname
);
1172 * XXXX need to update iob_curbuf/iob_curlen to reflect
1173 * current data transferred. If device disconnected in
1174 * the middle of a DMA block, they should already be set
1175 * by the phase change interrupt. If the disconnect
1176 * occurs on a DMA block boundary, we have to figure out
1177 * which DMA block it was.
1179 if (acb
->iob_len
&& rp
->siop_temp
) {
1180 int n
= rp
->siop_temp
- sc
->sc_scriptspa
;
1182 if (acb
->iob_curlen
&& acb
->iob_curlen
!= acb
->ds
.chain
[0].datalen
)
1183 printf("%s: iob_curbuf/len already set? n %x iob %lx/%lx chain[0] %p/%lx\n",
1184 sc
->sc_dev
.dv_xname
, n
, acb
->iob_curbuf
, acb
->iob_curlen
,
1185 acb
->ds
.chain
[0].databuf
, acb
->ds
.chain
[0].datalen
);
1187 n
= (n
- Ent_dataout
) / 16;
1189 n
= (n
- Ent_datain
) / 16;
1190 if (n
<= 0 && n
> DMAMAXIO
)
1191 printf("TEMP invalid %d\n", n
);
1193 acb
->iob_curbuf
= (u_long
)acb
->ds
.chain
[n
].databuf
;
1194 acb
->iob_curlen
= acb
->ds
.chain
[n
].datalen
;
1197 if (siop_debug
& 0x100) {
1198 printf("%s: TEMP offset %d", sc
->sc_dev
.dv_xname
, n
);
1199 printf(" curbuf %lx curlen %lx\n", acb
->iob_curbuf
,
1205 * If data transfer was interrupted by disconnect, iob_curbuf
1206 * and iob_curlen should reflect the point of interruption.
1207 * Adjust the DMA chain so that the data transfer begins
1208 * at the appropriate place upon reselection.
1209 * XXX This should only be done on save data pointer message?
1211 if (acb
->iob_curlen
) {
1215 if (siop_debug
& 0x100)
1216 printf ("%s: adjusting DMA chain\n",
1217 sc
->sc_dev
.dv_xname
);
1218 if (rp
->siop_dsps
== 0xff02)
1219 printf ("%s: ID %02x disconnected without Save Data Pointers\n",
1220 sc
->sc_dev
.dv_xname
, 1 << target
);
1222 /* XXX is: if (rp->siop_dsps != 0xff02) { */
1223 /* not disconnected without save data ptr */
1224 for (i
= 0; i
< DMAMAXIO
; ++i
) {
1225 if (acb
->ds
.chain
[i
].datalen
== 0)
1227 if (acb
->iob_curbuf
>= (long)acb
->ds
.chain
[i
].databuf
&&
1228 acb
->iob_curbuf
< (long)(acb
->ds
.chain
[i
].databuf
+
1229 acb
->ds
.chain
[i
].datalen
))
1232 if (i
>= DMAMAXIO
|| acb
->ds
.chain
[i
].datalen
== 0) {
1233 printf("couldn't find saved data pointer: ");
1234 printf("curbuf %lx curlen %lx i %d\n",
1235 acb
->iob_curbuf
, acb
->iob_curlen
, i
);
1242 if (siop_debug
& 0x100)
1243 printf(" chain[0]: %p/%lx -> %lx/%lx\n",
1244 acb
->ds
.chain
[0].databuf
,
1245 acb
->ds
.chain
[0].datalen
,
1249 acb
->ds
.chain
[0].databuf
= (char *)acb
->iob_curbuf
;
1250 acb
->ds
.chain
[0].datalen
= acb
->iob_curlen
;
1251 for (j
= 1, ++i
; i
< DMAMAXIO
&& acb
->ds
.chain
[i
].datalen
; ++i
, ++j
) {
1253 if (siop_debug
& 0x100)
1254 printf(" chain[%d]: %p/%lx -> %p/%lx\n", j
,
1255 acb
->ds
.chain
[j
].databuf
,
1256 acb
->ds
.chain
[j
].datalen
,
1257 acb
->ds
.chain
[i
].databuf
,
1258 acb
->ds
.chain
[i
].datalen
);
1260 acb
->ds
.chain
[j
].databuf
= acb
->ds
.chain
[i
].databuf
;
1261 acb
->ds
.chain
[j
].datalen
= acb
->ds
.chain
[i
].datalen
;
1264 acb
->ds
.chain
[j
].datalen
= 0;
1265 DCIAS(kvtop((void *)&acb
->ds
.chain
));
1267 ++sc
->sc_tinfo
[target
].dconns
;
1269 * add nexus to waiting list
1271 * try to start another command for another target/lun
1273 acb
->status
= sc
->sc_flags
& SIOP_INTSOFF
;
1274 TAILQ_INSERT_HEAD(&sc
->nexus_list
, acb
, chain
);
1275 sc
->sc_nexus
= NULL
; /* no current device */
1276 /* start script to wait for reselect */
1277 if (sc
->sc_nexus
== NULL
)
1278 rp
->siop_dsp
= sc
->sc_scriptspa
+ Ent_wait_reselect
;
1279 /* XXXX start another command ? */
1280 if (sc
->ready_list
.tqh_first
)
1284 if (dstat
& SIOP_DSTAT_SIR
&& rp
->siop_dsps
== 0xff03) {
1285 int reselid
= rp
->siop_scratch
& 0x7f;
1286 int reselun
= rp
->siop_sfbr
& 0x07;
1288 sc
->sc_sstat1
= rp
->siop_sbcl
; /* XXXX save current SBCL */
1290 if (siop_debug
& 0x100)
1291 printf ("%s: target ID %02x reselected dsps %lx\n",
1292 sc
->sc_dev
.dv_xname
, reselid
,
1294 if ((rp
->siop_sfbr
& 0x80) == 0)
1295 printf("%s: Reselect message in was not identify: %x\n",
1296 sc
->sc_dev
.dv_xname
, rp
->siop_sfbr
);
1300 if (siop_debug
& 0x100)
1301 printf ("%s: reselect ID %02x w/active\n",
1302 sc
->sc_dev
.dv_xname
, reselid
);
1304 TAILQ_INSERT_HEAD(&sc
->ready_list
, sc
->sc_nexus
, chain
);
1305 sc
->sc_tinfo
[sc
->sc_nexus
->xs
->xs_periph
->periph_target
].lubusy
1306 &= ~(1 << sc
->sc_nexus
->xs
->xs_periph
->periph_lun
);
1310 * locate acb of reselecting device
1311 * set sc->sc_nexus to acb
1313 for (acb
= sc
->nexus_list
.tqh_first
; acb
;
1314 acb
= acb
->chain
.tqe_next
) {
1315 if (reselid
!= (acb
->ds
.scsi_addr
>> 16) ||
1316 reselun
!= (acb
->msgout
[0] & 0x07))
1318 TAILQ_REMOVE(&sc
->nexus_list
, acb
, chain
);
1320 sc
->sc_flags
|= acb
->status
;
1322 DCIAS(kvtop(&acb
->stat
[0]));
1323 rp
->siop_dsa
= kvtop((void *)&acb
->ds
);
1325 sc
->sc_sync
[acb
->xs
->xs_periph
->periph_target
].sxfer
;
1327 sc
->sc_sync
[acb
->xs
->xs_periph
->periph_target
].sbcl
;
1331 printf("%s: target ID %02x reselect nexus_list %p\n",
1332 sc
->sc_dev
.dv_xname
, reselid
,
1333 sc
->nexus_list
.tqh_first
);
1334 panic("unable to find reselecting device");
1336 dma_cachectl ((void *)acb
, sizeof(*acb
));
1338 rp
->siop_dcntl
|= SIOP_DCNTL_STD
;
1341 if (dstat
& SIOP_DSTAT_SIR
&& rp
->siop_dsps
== 0xff04) {
1343 u_short ctest2
= rp
->siop_ctest2
;
1345 /* reselect was interrupted (by Sig_P or select) */
1346 if (siop_debug
& 0x100 ||
1347 (ctest2
& SIOP_CTEST2_SIGP
) == 0)
1348 printf ("%s: reselect interrupted (Sig_P?) scntl1 %x ctest2 %x sfbr %x istat %x/%x\n",
1349 sc
->sc_dev
.dv_xname
, rp
->siop_scntl1
,
1350 ctest2
, rp
->siop_sfbr
, istat
, rp
->siop_istat
);
1352 /* XXX assumes it was not select */
1353 if (sc
->sc_nexus
== NULL
) {
1355 printf("%s: reselect interrupted, sc_nexus == NULL\n",
1356 sc
->sc_dev
.dv_xname
);
1364 rp
->siop_dcntl
|= SIOP_DCNTL_STD
;
1367 target
= sc
->sc_nexus
->xs
->xs_periph
->periph_target
;
1369 rp
->siop_dsa
= kvtop((void *)&sc
->sc_nexus
->ds
);
1370 rp
->siop_sxfer
= sc
->sc_sync
[target
].sxfer
;
1371 rp
->siop_sbcl
= sc
->sc_sync
[target
].sbcl
;
1372 rp
->siop_dsp
= sc
->sc_scriptspa
;
1375 if (dstat
& SIOP_DSTAT_SIR
&& rp
->siop_dsps
== 0xff06) {
1377 printf("%s: Bad message-in with no active command?\n",
1378 sc
->sc_dev
.dv_xname
);
1379 /* Unrecognized message in byte */
1380 dma_cachectl (&acb
->msg
[1],1);
1381 printf ("%s: Unrecognized message in data sfbr %x msg %x sbcl %x\n",
1382 sc
->sc_dev
.dv_xname
, rp
->siop_sfbr
, acb
->msg
[1], rp
->siop_sbcl
);
1383 /* what should be done here? */
1384 DCIAS(kvtop(&acb
->msg
[1]));
1385 rp
->siop_dsp
= sc
->sc_scriptspa
+ Ent_clear_ack
;
1388 if (dstat
& SIOP_DSTAT_SIR
&& rp
->siop_dsps
== 0xff0a) {
1389 /* Status phase wasn't followed by message in phase? */
1390 printf ("%s: Status phase not followed by message in phase? sbcl %x sbdl %x\n",
1391 sc
->sc_dev
.dv_xname
, rp
->siop_sbcl
, rp
->siop_sbdl
);
1392 if (rp
->siop_sbcl
== 0xa7) {
1393 /* It is now, just continue the script? */
1394 rp
->siop_dcntl
|= SIOP_DCNTL_STD
;
1398 if (sstat0
== 0 && dstat
& SIOP_DSTAT_SIR
) {
1399 dma_cachectl (&acb
->stat
[0], 1);
1400 dma_cachectl (&acb
->msg
[0], 1);
1401 printf ("SIOP interrupt: %lx sts %x msg %x %x sbcl %x\n",
1402 rp
->siop_dsps
, acb
->stat
[0], acb
->msg
[0], acb
->msg
[1],
1406 return 0; /* siopreset has cleaned up */
1408 if (sstat0
& SIOP_SSTAT0_SGE
)
1409 printf ("SIOP: SCSI Gross Error\n");
1410 if (sstat0
& SIOP_SSTAT0_PAR
)
1411 printf ("SIOP: Parity Error\n");
1412 if (dstat
& SIOP_DSTAT_IID
)
1413 printf ("SIOP: Invalid instruction detected\n");
1416 * temporary panic for unhandled conditions
1417 * displays various things about the 53C710 status and registers
1419 * XXXX need to clean this up to print out the info, reset, and continue
1421 printf ("siopchkintr: target %x ds %p\n", target
, &acb
->ds
);
1422 printf ("scripts %lx ds %x rp %x dsp %lx dcmd %lx\n",
1423 sc
->sc_scriptspa
, (unsigned)kvtop((void *)&acb
->ds
),
1424 (unsigned)kvtop((void *)__UNVOLATILE(rp
)), rp
->siop_dsp
,
1425 *((volatile long *)&rp
->siop_dcmd
));
1426 printf ("siopchkintr: istat %x dstat %x sstat0 %x dsps %lx dsa %lx sbcl %x sts %x msg %x %x sfbr %x\n",
1427 istat
, dstat
, sstat0
, rp
->siop_dsps
, rp
->siop_dsa
,
1428 rp
->siop_sbcl
, acb
->stat
[0], acb
->msg
[0], acb
->msg
[1], rp
->siop_sfbr
);
1430 if (siop_debug
& 0x20)
1431 panic("siopchkintr: **** temp ****");
1436 siopreset (sc
); /* hard reset */
1438 return 0; /* siopreset cleaned up */
1442 siop_select(struct siop_softc
*sc
)
1445 struct siop_acb
*acb
= sc
->sc_nexus
;
1449 printf ("%s: select ", sc
->sc_dev
.dv_xname
);
1453 if (acb
->xs
->xs_control
& XS_CTL_POLL
|| siop_no_dma
) {
1454 sc
->sc_flags
|= SIOP_INTSOFF
;
1455 sc
->sc_flags
&= ~SIOP_INTDEFER
;
1456 if ((rp
->siop_istat
& 0x08) == 0) {
1461 } else if ((sc
->sc_flags
& SIOP_INTDEFER
) == 0) {
1462 sc
->sc_flags
&= ~SIOP_INTSOFF
;
1463 if ((rp
->siop_istat
& 0x08) == 0) {
1464 rp
->siop_sien
= sc
->sc_sien
;
1465 rp
->siop_dien
= sc
->sc_dien
;
1471 printf ("siop_select: target %x cmd %02x ds %p\n",
1472 acb
->xs
->xs_periph
->periph_target
, acb
->cmd
.opcode
,
1476 siop_start(sc
, acb
->xs
->xs_periph
->periph_target
,
1477 acb
->xs
->xs_periph
->periph_lun
,
1478 (u_char
*)&acb
->cmd
, acb
->clen
, acb
->daddr
, acb
->dleft
);
1484 * 53C710 interrupt handler
1488 siopintr(register struct siop_softc
*sc
)
1491 register u_char istat
, dstat
, sstat0
;
1495 istat
= sc
->sc_istat
;
1496 if ((istat
& (SIOP_ISTAT_SIP
| SIOP_ISTAT_DIP
)) == 0) {
1501 /* Got a valid interrupt on this device */
1503 dstat
= sc
->sc_dstat
;
1504 sstat0
= sc
->sc_sstat0
;
1505 if (dstat
& SIOP_DSTAT_SIR
)
1506 sc
->sc_intcode
= rp
->siop_dsps
;
1510 printf ("%s: intr istat %x dstat %x sstat0 %x\n",
1511 sc
->sc_dev
.dv_xname
, istat
, dstat
, sstat0
);
1512 if (!sc
->sc_active
) {
1513 printf ("%s: spurious interrupt? istat %x dstat %x sstat0 %x nexus %p status %x\n",
1514 sc
->sc_dev
.dv_xname
, istat
, dstat
, sstat0
,
1515 sc
->sc_nexus
, sc
->sc_nexus
? sc
->sc_nexus
->stat
[0] : 0);
1520 if (siop_debug
& 5) {
1521 DCIAS(kvtop(&sc
->sc_nexus
->stat
[0]));
1522 printf ("%s: intr istat %x dstat %x sstat0 %x dsps %lx sbcl %x sts %x msg %x\n",
1523 sc
->sc_dev
.dv_xname
, istat
, dstat
, sstat0
,
1524 rp
->siop_dsps
, rp
->siop_sbcl
,
1525 sc
->sc_nexus
->stat
[0], sc
->sc_nexus
->msg
[0]);
1528 if (sc
->sc_flags
& SIOP_INTDEFER
) {
1529 sc
->sc_flags
&= ~(SIOP_INTDEFER
| SIOP_INTSOFF
);
1530 rp
->siop_sien
= sc
->sc_sien
;
1531 rp
->siop_dien
= sc
->sc_dien
;
1533 if (siop_checkintr (sc
, istat
, dstat
, sstat0
, &status
)) {
1536 printf ("siopintr: status == 0xff\n");
1538 if ((sc
->sc_flags
& (SIOP_INTSOFF
| SIOP_INTDEFER
)) != SIOP_INTSOFF
) {
1540 if (rp
->siop_sbcl
& SIOP_BSY
) {
1541 printf ("%s: SCSI bus busy at completion",
1542 sc
->sc_dev
.dv_xname
);
1543 printf(" targ %d sbcl %02x sfbr %x lcrc %02x dsp +%x\n",
1544 sc
->sc_nexus
->xs
->xs_periph
->periph_target
,
1545 rp
->siop_sbcl
, rp
->siop_sfbr
, rp
->siop_lcrc
,
1546 rp
->siop_dsp
- sc
->sc_scriptspa
);
1549 siop_scsidone(sc
->sc_nexus
, sc
->sc_nexus
?
1550 sc
->sc_nexus
->stat
[0] : -1);
1557 * This is based on the Progressive Peripherals 33Mhz Zeus driver and will
1558 * not be correct for other 53c710 boards.
1562 scsi_period_to_siop(struct siop_softc
*sc
, int target
)
1564 int period
, offset
, sxfer
, sbcl
= 0;
1569 period
= sc
->sc_nexus
->msg
[4];
1570 offset
= sc
->sc_nexus
->msg
[5];
1573 if (offset
<= SIOP_MAX_OFFSET
)
1575 for (i
= 0; i
< sizeof (sync_tab
) / 2; ++i
) {
1576 if (period
<= sync_tab
[i
].p
) {
1577 sxfer
|= sync_tab
[i
].r
& 0x70;
1578 sbcl
= sync_tab
[i
].r
& 0x03;
1582 printf ("siop sync old: siop_sxfr %02x, siop_sbcl %02x\n", sxfer
, sbcl
);
1584 for (sbcl
= 1; sbcl
< 4; ++sbcl
) {
1585 sxfer
= (period
* 4 - 1) / sc
->sc_tcp
[sbcl
] - 3;
1586 if (sxfer
>= 0 && sxfer
<= 7)
1590 printf("siop sync: unable to compute sync params for period %dns\n",
1593 * XXX need to pick a value we can do and renegotiate
1597 sxfer
= (sxfer
<< 4) | ((offset
<= SIOP_MAX_OFFSET
) ?
1598 offset
: SIOP_MAX_OFFSET
);
1600 printf("siop sync: params for period %dns: sxfer %x sbcl %x",
1601 period
* 4, sxfer
, sbcl
);
1602 printf(" actual period %dns\n",
1603 sc
->sc_tcp
[sbcl
] * ((sxfer
>> 4) + 4));
1606 sc
->sc_sync
[target
].sxfer
= sxfer
;
1607 sc
->sc_sync
[target
].sbcl
= sbcl
;
1609 printf ("siop sync: siop_sxfr %02x, siop_sbcl %02x\n", sxfer
, sbcl
);
1617 siop_dump_trace(void)
1621 printf("siop trace: next index %d\n", siop_trix
);
1624 printf("%3d: '%c' %02x %02x %02x\n", i
, siop_trbuf
[i
],
1625 siop_trbuf
[i
+ 1], siop_trbuf
[i
+ 2], siop_trbuf
[i
+ 3]);
1626 i
= (i
+ 4) & (SIOP_TRACE_SIZE
- 1);
1627 } while (i
!= siop_trix
);
1632 siop_dump_acb(struct siop_acb
*acb
)
1634 u_char
*b
= (u_char
*) &acb
->cmd
;
1637 printf("acb@%p ", acb
);
1638 if (acb
->xs
== NULL
) {
1639 printf("<unused>\n");
1642 printf("(%d:%d) flags %2x clen %2d cmd ",
1643 acb
->xs
->xs_periph
->periph_target
,
1644 acb
->xs
->xs_periph
->periph_lun
, acb
->flags
, acb
->clen
);
1645 for (i
= acb
->clen
; i
; --i
)
1646 printf(" %02x", *b
++);
1648 printf(" xs: %p data %p:%04x ", acb
->xs
, acb
->xs
->data
,
1650 printf("va %p:%lx ", acb
->iob_buf
, acb
->iob_len
);
1651 printf("cur %lx:%lx\n", acb
->iob_curbuf
, acb
->iob_curlen
);
1655 siop_dump(struct siop_softc
*sc
)
1657 struct siop_acb
*acb
;
1658 siop_regmap_p rp
= sc
->sc_siopp
;
1666 printf("%s@%p regs %p istat %x\n",
1667 sc
->sc_dev
.dv_xname
, sc
, rp
, rp
->siop_istat
);
1668 if ((acb
= sc
->free_list
.tqh_first
) > 0) {
1669 printf("Free list:\n");
1672 acb
= acb
->chain
.tqe_next
;
1675 if ((acb
= sc
->ready_list
.tqh_first
) > 0) {
1676 printf("Ready list:\n");
1679 acb
= acb
->chain
.tqe_next
;
1682 if ((acb
= sc
->nexus_list
.tqh_first
) > 0) {
1683 printf("Nexus list:\n");
1686 acb
= acb
->chain
.tqe_next
;
1691 siop_dump_acb(sc
->sc_nexus
);
1693 for (i
= 0; i
< 8; ++i
) {
1694 if (sc
->sc_tinfo
[i
].cmds
> 2) {
1695 printf("tgt %d: cmds %d disc %d lubusy %x\n",
1696 i
, sc
->sc_tinfo
[i
].cmds
,
1697 sc
->sc_tinfo
[i
].dconns
,
1698 sc
->sc_tinfo
[i
].lubusy
);