1 /* $NetBSD: sci.c,v 1.32 2005/06/13 21:34:17 jmc 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 * @(#)scsi.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 * @(#)scsi.c 7.5 (Berkeley) 5/4/91
67 * AMIGA NCR 5380 scsi adaptor driver
70 #include <sys/cdefs.h>
71 __KERNEL_RCSID(0, "$NetBSD: sci.c,v 1.32 2005/06/13 21:34:17 jmc Exp $");
73 #include <sys/param.h>
74 #include <sys/systm.h>
75 #include <sys/device.h>
76 #include <sys/disklabel.h>
78 #include <dev/scsipi/scsi_all.h>
79 #include <dev/scsipi/scsipi_all.h>
80 #include <dev/scsipi/scsiconf.h>
81 #include <uvm/uvm_extern.h>
82 #include <machine/pmap.h>
83 #include <machine/cpu.h>
84 #include <amiga/amiga/device.h>
85 #include <amiga/amiga/custom.h>
86 #include <amiga/amiga/isr.h>
87 #include <amiga/dev/scireg.h>
88 #include <amiga/dev/scivar.h>
92 * In u-seconds, primarily for state changes on the SPC.
94 #define SCI_CMD_WAIT 50000 /* wait per step of 'immediate' cmds */
95 #define SCI_DATA_WAIT 50000 /* wait per data in/out step */
96 #define SCI_INIT_WAIT 50000 /* wait per step (both) during init */
98 int sciicmd(struct sci_softc
*, int, void *, int, void *, int,u_char
);
99 int scigo(struct sci_softc
*, struct scsipi_xfer
*);
100 int sciselectbus(struct sci_softc
*, u_char
, u_char
);
101 void sciabort(struct sci_softc
*, const char *);
102 void scierror(struct sci_softc
*, u_char
);
103 void scisetdelay(int);
104 void sci_scsidone(struct sci_softc
*, int);
105 void sci_donextcmd(struct sci_softc
*);
106 int sci_ixfer_out(struct sci_softc
*, int, register u_char
*, int);
107 void sci_ixfer_in(struct sci_softc
*, int, register u_char
*, int);
109 int sci_cmd_wait
= SCI_CMD_WAIT
;
110 int sci_data_wait
= SCI_DATA_WAIT
;
111 int sci_init_wait
= SCI_INIT_WAIT
;
116 #define QPRINTF(a) if (sci_debug > 1) printf a
123 * default minphys routine for sci based controllers
126 sci_minphys(struct buf
*bp
)
130 * No max transfer at this level.
136 * used by specific sci controller
138 * it appears that the higher level code does nothing with LUN's
139 * so I will too. I could plug it in, however so could they
140 * in scsi_scsipi_cmd().
143 sci_scsipi_request(struct scsipi_channel
*chan
, scsipi_adapter_req_t req
,
146 struct scsipi_xfer
*xs
;
147 struct scsipi_periph
*periph
;
148 struct sci_softc
*dev
= (void *)chan
->chan_adapter
->adapt_dev
;
152 case ADAPTER_REQ_RUN_XFER
:
154 periph
= xs
->xs_periph
;
155 flags
= xs
->xs_control
;
157 if (flags
& XS_CTL_DATA_UIO
)
158 panic("sci: scsi data uio requested");
162 if (dev
->sc_xs
&& flags
& XS_CTL_POLL
)
163 panic("sci_scsicmd: busy");
167 * This should never happen as we track the resources
171 scsipi_printaddr(periph
);
172 printf("unable to allocate scb\n");
173 panic("sea_scsipi_request");
181 * nothing is pending do it now.
187 case ADAPTER_REQ_GROW_RESOURCES
:
190 case ADAPTER_REQ_SET_XFER_MODE
:
196 * entered with dev->sc_xs pointing to the next xfer to perform
199 sci_donextcmd(struct sci_softc
*dev
)
201 struct scsipi_xfer
*xs
;
202 struct scsipi_periph
*periph
;
203 int flags
, phase
, stat
;
206 periph
= xs
->xs_periph
;
207 flags
= xs
->xs_control
;
209 if (flags
& XS_CTL_DATA_IN
)
210 phase
= DATA_IN_PHASE
;
211 else if (flags
& XS_CTL_DATA_OUT
)
212 phase
= DATA_OUT_PHASE
;
214 phase
= STATUS_PHASE
;
216 if (flags
& XS_CTL_RESET
)
219 dev
->sc_stat
[0] = -1;
220 xs
->cmd
->bytes
[0] |= periph
->periph_lun
<< 5;
221 if (phase
== STATUS_PHASE
|| flags
& XS_CTL_POLL
)
222 stat
= sciicmd(dev
, periph
->periph_target
, xs
->cmd
, xs
->cmdlen
,
223 xs
->data
, xs
->datalen
, phase
);
224 else if (scigo(dev
, xs
) == 0)
227 stat
= dev
->sc_stat
[0];
229 sci_scsidone(dev
, stat
);
233 sci_scsidone(struct sci_softc
*dev
, int stat
)
235 struct scsipi_xfer
*xs
;
240 panic("sci_scsidone");
254 xs
->error
= XS_DRIVER_STUFFUP
;
255 QPRINTF(("sci_scsicmd() bad %x\n", stat
));
265 sciabort(struct sci_softc
*dev
, const char *where
)
267 printf ("%s: abort %s: csr = 0x%02x, bus = 0x%02x\n",
268 dev
->sc_dev
.dv_xname
, where
, *dev
->sci_csr
, *dev
->sci_bus_csr
);
270 if (dev
->sc_flags
& SCI_SELECTED
) {
272 /* lets just hope it worked.. */
273 dev
->sc_flags
&= ~SCI_SELECTED
;
280 * XXX Set/reset long delays.
282 * if delay == 0, reset default delays
283 * if delay < 0, set both delays to default long initialization values
284 * if delay > 0, set both delays to this value
286 * Used when a devices is expected to respond slowly (e.g. during
292 static int saved_cmd_wait
, saved_data_wait
;
295 saved_cmd_wait
= sci_cmd_wait
;
296 saved_data_wait
= sci_data_wait
;
298 sci_cmd_wait
= sci_data_wait
= del
;
300 sci_cmd_wait
= sci_data_wait
= sci_init_wait
;
302 sci_cmd_wait
= saved_cmd_wait
;
303 sci_data_wait
= saved_data_wait
;
308 scireset(struct sci_softc
*dev
)
313 dev
->sc_flags
&= ~SCI_SELECTED
;
314 if (dev
->sc_flags
& SCI_ALIVE
)
315 sciabort(dev
, "reset");
317 printf("%s: ", dev
->sc_dev
.dv_xname
);
320 /* preserve our ID for now */
326 *dev
->sci_icmd
= SCI_ICMD_TEST
;
327 *dev
->sci_icmd
= SCI_ICMD_TEST
| SCI_ICMD_RST
;
332 * Set up various chip parameters
336 *dev
->sci_sel_enb
= 0;
338 /* anything else was zeroed by reset */
342 printf("sci id %d\n", my_id
);
343 dev
->sc_flags
|= SCI_ALIVE
;
347 scierror(struct sci_softc
*dev
, u_char csr
)
349 struct scsipi_xfer
*xs
;
357 if (xs
->xs_control
& XS_CTL_SILENT
)
360 printf("%s: ", dev
->sc_dev
.dv_xname
);
361 printf("csr == 0x%02i\n", csr
); /* XXX */
365 * select the bus, return when selected or error.
368 sciselectbus(struct sci_softc
*dev
, u_char target
, u_char our_addr
)
370 register int timeo
= 2500;
372 QPRINTF (("sciselectbus %d\n", target
));
374 /* if we're already selected, return */
375 if (dev
->sc_flags
& SCI_SELECTED
) /* XXXX */
378 if ((*dev
->sci_bus_csr
& (SCI_BUS_BSY
|SCI_BUS_SEL
)) &&
379 (*dev
->sci_bus_csr
& (SCI_BUS_BSY
|SCI_BUS_SEL
)) &&
380 (*dev
->sci_bus_csr
& (SCI_BUS_BSY
|SCI_BUS_SEL
)))
384 *dev
->sci_odata
= 0x80 + (1 << target
);
385 *dev
->sci_icmd
= SCI_ICMD_DATA
|SCI_ICMD_SEL
;
386 while ((*dev
->sci_bus_csr
& SCI_BUS_BSY
) == 0) {
395 dev
->sc_flags
|= SCI_SELECTED
;
403 sci_ixfer_out(register struct sci_softc
*dev
, int len
, register u_char
*buf
,
406 register int wait
= sci_data_wait
;
409 QPRINTF(("sci_ixfer_out {%d} %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
410 len
, buf
[0], buf
[1], buf
[2], buf
[3], buf
[4], buf
[5],
411 buf
[6], buf
[7], buf
[8], buf
[9]));
413 *dev
->sci_tcmd
= phase
;
414 *dev
->sci_icmd
= SCI_ICMD_DATA
;
415 for (;len
> 0; len
--) {
416 csr
= *dev
->sci_bus_csr
;
417 while (!(csr
& SCI_BUS_REQ
)) {
418 if ((csr
& SCI_BUS_BSY
) == 0 || --wait
< 0) {
421 printf("sci_ixfer_out fail: l%d i%x w%d\n",
427 csr
= *dev
->sci_bus_csr
;
430 if (!(*dev
->sci_csr
& SCI_CSR_PHASE_MATCH
))
432 *dev
->sci_odata
= *buf
;
433 *dev
->sci_icmd
= SCI_ICMD_DATA
|SCI_ICMD_ACK
;
435 while (*dev
->sci_bus_csr
& SCI_BUS_REQ
);
436 *dev
->sci_icmd
= SCI_ICMD_DATA
;
439 QPRINTF(("sci_ixfer_out done\n"));
444 sci_ixfer_in(struct sci_softc
*dev
, int len
, register u_char
*buf
, int phase
)
446 int wait
= sci_data_wait
;
448 volatile register u_char
*sci_bus_csr
= dev
->sci_bus_csr
;
449 volatile register u_char
*sci_data
= dev
->sci_data
;
450 volatile register u_char
*sci_icmd
= dev
->sci_icmd
;
457 QPRINTF(("sci_ixfer_in %d, csr=%02x\n", len
, csr
));
459 *dev
->sci_tcmd
= phase
;
461 for (;len
> 0; len
--) {
463 while (!(csr
& SCI_BUS_REQ
)) {
464 if (!(csr
& SCI_BUS_BSY
) || --wait
< 0) {
467 printf("sci_ixfer_in fail: l%d i%x w%d\n",
477 if (!(*dev
->sci_csr
& SCI_CSR_PHASE_MATCH
))
480 *sci_icmd
= SCI_ICMD_ACK
;
482 while (*sci_bus_csr
& SCI_BUS_REQ
);
486 QPRINTF(("sci_ixfer_in {%d} %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
487 len
, obp
[0], obp
[1], obp
[2], obp
[3], obp
[4], obp
[5],
488 obp
[6], obp
[7], obp
[8], obp
[9]));
492 * SCSI 'immediate' command: issue a command to some SCSI device
493 * and get back an 'immediate' response (i.e., do programmed xfer
494 * to get the response data). 'cbuf' is a buffer containing a scsi
495 * command of length clen bytes. 'buf' is a buffer of length 'len'
496 * bytes for data. The transfer direction is determined by the device
497 * (i.e., by the scsi bus data xfer phase). If 'len' is zero, the
498 * command must supply no data. 'xferphase' is the bus phase the
499 * caller expects to happen after the command is issued. It should
500 * be one of DATA_IN_PHASE, DATA_OUT_PHASE or STATUS_PHASE.
503 sciicmd(struct sci_softc
*dev
, int target
, void *cbuf
, int clen
, void *buf
,
504 int len
, u_char xferphase
)
509 /* select the SCSI bus (it's an error if bus isn't free) */
510 if (sciselectbus (dev
, target
, dev
->sc_scsi_addr
))
513 * Wait for a phase change (or error) then let the device
514 * sequence us through the various SCSI phases.
516 dev
->sc_stat
[0] = 0xff;
517 dev
->sc_msg
[0] = 0xff;
522 while ((*dev
->sci_bus_csr
& (SCI_BUS_REQ
|SCI_BUS_BSY
)) == SCI_BUS_BSY
);
524 QPRINTF((">CSR:%02x<", *dev
->sci_bus_csr
));
525 if ((*dev
->sci_bus_csr
& SCI_BUS_REQ
) == 0) {
528 phase
= SCI_PHASE(*dev
->sci_bus_csr
);
532 if (sci_ixfer_out (dev
, clen
, cbuf
, phase
))
540 wait
= sci_data_wait
;
541 sci_ixfer_in (dev
, len
, buf
, phase
);
542 phase
= STATUS_PHASE
;
548 wait
= sci_data_wait
;
549 if (sci_ixfer_out (dev
, len
, buf
, phase
))
551 phase
= STATUS_PHASE
;
555 dev
->sc_msg
[0] = 0xff;
556 sci_ixfer_in (dev
, 1, dev
->sc_msg
,phase
);
557 dev
->sc_flags
&= ~SCI_SELECTED
;
558 while (*dev
->sci_bus_csr
& SCI_BUS_BSY
);
563 phase
= STATUS_PHASE
;
567 sci_ixfer_in (dev
, 1, dev
->sc_stat
, phase
);
568 phase
= MESG_IN_PHASE
;
575 printf("sci: unexpected phase %d in icmd from %d\n",
586 sciabort(dev
, "icmd");
588 QPRINTF(("=STS:%02x=", dev
->sc_stat
[0]));
589 return (dev
->sc_stat
[0]);
593 scigo(struct sci_softc
*dev
, struct scsipi_xfer
*xs
)
598 target
= xs
->xs_periph
->periph_target
;
603 sciicmd (dev
, target
, (u_char
*) xs
->cmd
, xs
->cmdlen
,
605 xs
->xs_control
& XS_CTL_DATA_IN
? DATA_IN_PHASE
: DATA_OUT_PHASE
);
610 /* select the SCSI bus (it's an error if bus isn't free) */
611 if (sciselectbus (dev
, target
, dev
->sc_scsi_addr
))
614 * Wait for a phase change (or error) then let the device
615 * sequence us through the various SCSI phases.
617 dev
->sc_stat
[0] = 0xff;
618 dev
->sc_msg
[0] = 0xff;
621 while ((*dev
->sci_bus_csr
& (SCI_BUS_REQ
|SCI_BUS_BSY
)) ==
624 QPRINTF((">CSR:%02x<", *dev
->sci_bus_csr
));
625 if ((*dev
->sci_bus_csr
& SCI_BUS_REQ
) == 0) {
628 phase
= SCI_PHASE(*dev
->sci_bus_csr
);
632 if (sci_ixfer_out (dev
, xs
->cmdlen
, (u_char
*) xs
->cmd
, phase
))
634 phase
= xs
->xs_control
& XS_CTL_DATA_IN
? DATA_IN_PHASE
: DATA_OUT_PHASE
;
640 /* XXX use psuedo DMA if available */
641 if (count
>= 128 && dev
->dma_xfer_in
)
642 (*dev
->dma_xfer_in
)(dev
, count
, addr
, phase
);
644 sci_ixfer_in (dev
, count
, addr
, phase
);
645 phase
= STATUS_PHASE
;
651 /* XXX use psuedo DMA if available */
652 if (count
>= 128 && dev
->dma_xfer_out
)
653 (*dev
->dma_xfer_out
)(dev
, count
, addr
, phase
);
655 if (sci_ixfer_out (dev
, count
, addr
, phase
))
657 phase
= STATUS_PHASE
;
661 dev
->sc_msg
[0] = 0xff;
662 sci_ixfer_in (dev
, 1, dev
->sc_msg
,phase
);
663 dev
->sc_flags
&= ~SCI_SELECTED
;
664 while (*dev
->sci_bus_csr
& SCI_BUS_BSY
);
669 phase
= STATUS_PHASE
;
673 sci_ixfer_in (dev
, 1, dev
->sc_stat
, phase
);
674 phase
= MESG_IN_PHASE
;
681 printf("sci: unexpected phase %d in icmd from %d\n",
690 QPRINTF(("=STS:%02x=", dev
->sc_stat
[0]));