1 /* $NetBSD: cosc.c,v 1.15 2009/03/14 21:04:01 dsl Exp $ */
4 * Copyright (c) 1996 Mark Brinicombe
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Mark Brinicombe
18 * for the NetBSD Project.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * from: asc.c,v 1.8 1996/06/12 20:46:58 mark Exp
38 * Driver for the MCS Connect 32 SCSI 2 card with AM53C94 SCSI controller.
40 * Thanks to Mike <mcsmike@knipp.de> at MCS for loaning a card.
41 * Thanks to Andreas Gandor <andi@knipp.de> for some technical information
44 #include <sys/cdefs.h>
45 __KERNEL_RCSID(0, "$NetBSD: cosc.c,v 1.15 2009/03/14 21:04:01 dsl Exp $");
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/kernel.h>
50 #include <sys/device.h>
52 #include <uvm/uvm_extern.h>
54 #include <dev/scsipi/scsi_all.h>
55 #include <dev/scsipi/scsipi_all.h>
56 #include <dev/scsipi/scsiconf.h>
57 #include <machine/bootconfig.h>
58 #include <machine/io.h>
59 #include <machine/intr.h>
60 #include <arm/arm32/katelib.h>
61 #include <acorn32/podulebus/podulebus.h>
62 #include <acorn32/podulebus/escreg.h>
63 #include <acorn32/podulebus/escvar.h>
64 #include <acorn32/podulebus/coscreg.h>
65 #include <acorn32/podulebus/coscvar.h>
66 #include <dev/podulebus/podules.h>
68 void coscattach(struct device
*, struct device
*, void *);
69 int coscmatch(struct device
*, struct cfdata
*, void *);
71 CFATTACH_DECL(cosc
, sizeof(struct cosc_softc
),
72 coscmatch
, coscattach
, NULL
, NULL
);
74 int cosc_intr(void *);
75 int cosc_setup_dma(struct esc_softc
*, void *, int, int);
76 int cosc_build_dma_chain(struct esc_softc
*, struct esc_dma_chain
*, void *,
78 int cosc_need_bump(struct esc_softc
*, void *, int);
79 void cosc_led(struct esc_softc
*, int);
80 void cosc_set_dma_adr(struct esc_softc
*, void *);
81 void cosc_set_dma_tc(struct esc_softc
*, unsigned int);
82 void cosc_set_dma_mode(struct esc_softc
*, int);
89 coscmatch(struct device
*pdp
, struct cfdata
*cf
, void *auxp
)
91 struct podule_attach_args
*pa
= (struct podule_attach_args
*)auxp
;
93 /* Look for the card */
95 if (pa
->pa_product
== PODULE_CONNECT32
)
98 /* Old versions of the ROM on this card could have the wrong ID */
100 if (pa
->pa_product
== PODULE_ACORN_SCSI
&&
101 strncmp(pa
->pa_podule
->description
, "MCS", 3) == 0)
109 coscattach(struct device
*pdp
, struct device
*dp
, void *auxp
)
111 struct cosc_softc
*sc
= (struct cosc_softc
*)dp
;
112 struct podule_attach_args
*pa
;
113 cosc_regmap_p rp
= &sc
->sc_regmap
;
116 pa
= (struct podule_attach_args
*)auxp
;
118 if (pa
->pa_podule_number
== -1)
119 panic("Podule has disappeared !");
121 sc
->sc_podule_number
= pa
->pa_podule_number
;
122 sc
->sc_podule
= pa
->pa_podule
;
123 podules
[sc
->sc_podule_number
].attached
= 1;
127 if (pa
->pa_podule
->manufacturer
== MANUFACTURER_ACORN
128 && pa
->pa_podule
->product
== PODULE_ACORN_SCSI
)
129 printf(" Faulty expansion card identity\n");
131 sc
->sc_iobase
= (vu_char
*)sc
->sc_podule
->fast_base
;
133 /* Select page zero (so we can see the config info) */
135 sc
->sc_iobase
[COSC_PAGE_REGISTER
] = 0;
137 rp
->chipreset
= (vu_char
*)&dummy
[0];
138 rp
->inten
= (vu_char
*)&dummy
[1];
139 rp
->status
= (vu_char
*)&dummy
[2];
140 rp
->term
= &sc
->sc_iobase
[COSC_TERMINATION_CONTROL
];
141 rp
->led
= (vu_char
*)&dummy
[4];
142 esc
= &sc
->sc_iobase
[COSC_ESCOFFSET_BASE
];
144 rp
->esc
.esc_tc_low
= &esc
[COSC_ESCOFFSET_TCL
];
145 rp
->esc
.esc_tc_mid
= &esc
[COSC_ESCOFFSET_TCM
];
146 rp
->esc
.esc_fifo
= &esc
[COSC_ESCOFFSET_FIFO
];
147 rp
->esc
.esc_command
= &esc
[COSC_ESCOFFSET_COMMAND
];
148 rp
->esc
.esc_dest_id
= &esc
[COSC_ESCOFFSET_DESTID
];
149 rp
->esc
.esc_timeout
= &esc
[COSC_ESCOFFSET_TIMEOUT
];
150 rp
->esc
.esc_syncper
= &esc
[COSC_ESCOFFSET_PERIOD
];
151 rp
->esc
.esc_syncoff
= &esc
[COSC_ESCOFFSET_OFFSET
];
152 rp
->esc
.esc_config1
= &esc
[COSC_ESCOFFSET_CONFIG1
];
153 rp
->esc
.esc_clkconv
= &esc
[COSC_ESCOFFSET_CLOCKCONV
];
154 rp
->esc
.esc_test
= &esc
[COSC_ESCOFFSET_TEST
];
155 rp
->esc
.esc_config2
= &esc
[COSC_ESCOFFSET_CONFIG2
];
156 rp
->esc
.esc_config3
= &esc
[COSC_ESCOFFSET_CONFIG3
];
157 rp
->esc
.esc_config4
= &esc
[COSC_ESCOFFSET_CONFIG4
];
158 rp
->esc
.esc_tc_high
= &esc
[COSC_ESCOFFSET_TCH
];
159 rp
->esc
.esc_fifo_bot
= &esc
[COSC_ESCOFFSET_FIFOBOTTOM
];
161 *rp
->esc
.esc_command
= ESC_CMD_RESET_CHIP
;
163 *rp
->esc
.esc_command
= ESC_CMD_NOP
;
165 /* See if we recognise the controller */
167 switch (*rp
->esc
.esc_tc_high
) {
172 printf(" Unknown controller (%02x)", *rp
->esc
.esc_tc_high
);
176 /* Set termination power */
178 if (sc
->sc_iobase
[COSC_CONFIG_TERMINATION
] & COSC_CONFIG_TERMINATION_ON
) {
179 printf(" termpwr on");
180 sc
->sc_iobase
[COSC_TERMINATION_CONTROL
] = COSC_TERMINATION_ON
;
182 printf(" termpwr off");
183 sc
->sc_iobase
[COSC_TERMINATION_CONTROL
] = COSC_TERMINATION_OFF
;
186 /* Don't know what this is for */
192 byte
= sc
->sc_iobase
[COSC_REGISTER_01
];
194 for (loop
= 0; loop
< 8; ++loop
) {
195 if (sc
->sc_iobase
[COSC_REGISTER_00
] & 0x01)
198 printf(" byte=%02x", byte
);
202 * Control register 4 is an AMD special (not on FAS216)
204 * The powerdown and glitch eater facilities could be useful
205 * Use the podule configuration for this register
208 sc
->sc_softc
.sc_config4
= sc
->sc_iobase
[COSC_CONFIG_CONTROL_REG4
];
210 sc
->sc_softc
.sc_esc
= (esc_regmap_p
)rp
;
211 /* sc->sc_softc.sc_spec = &sc->sc_specific;*/
213 sc
->sc_softc
.sc_led
= cosc_led
;
214 sc
->sc_softc
.sc_setup_dma
= cosc_setup_dma
;
215 sc
->sc_softc
.sc_build_dma_chain
= cosc_build_dma_chain
;
216 sc
->sc_softc
.sc_need_bump
= cosc_need_bump
;
218 sc
->sc_softc
.sc_clock_freq
= 40; /* Connect32 runs at 40MHz */
219 sc
->sc_softc
.sc_timeout
= 250; /* Set default timeout to 250ms */
220 sc
->sc_softc
.sc_config_flags
= ESC_NO_DMA
;
221 sc
->sc_softc
.sc_host_id
= sc
->sc_iobase
[COSC_CONFIG_CONTROL_REG1
] & ESC_DEST_ID_MASK
;
223 printf(" hostid=%d", sc
->sc_softc
.sc_host_id
);
227 get_bootconf_option(boot_args
, "coscpoll",
228 BOOTOPT_TYPE_BOOLEAN
, &cosc_poll
);
232 sc
->sc_softc
.sc_adapter
.adapt_flags
|= SCSIPI_ADAPT_POLL_ONLY
;
236 sc
->sc_softc
.sc_bump_sz
= PAGE_SIZE
;
237 sc
->sc_softc
.sc_bump_pa
= 0x0;
239 escinitialize((struct esc_softc
*)sc
);
241 sc
->sc_softc
.sc_adapter
.adapt_dev
= &sc
->sc_softc
.sc_dev
;
242 sc
->sc_softc
.sc_adapter
.adapt_nchannels
= 1;
243 sc
->sc_softc
.sc_adapter
.adapt_openings
= 7;
244 sc
->sc_softc
.sc_adapter
.adapt_max_periph
= 1;
245 sc
->sc_softc
.sc_adapter
.adapt_ioctl
= NULL
;
246 sc
->sc_softc
.sc_adapter
.adapt_minphys
= esc_minphys
;
247 sc
->sc_softc
.sc_adapter
.adapt_request
= esc_scsi_request
;
249 sc
->sc_softc
.sc_channel
.chan_adapter
= &sc
->sc_softc
.sc_adapter
;
250 sc
->sc_softc
.sc_channel
.chan_bustype
= &scsi_bustype
;
251 sc
->sc_softc
.sc_channel
.chan_channel
= 0;
252 sc
->sc_softc
.sc_channel
.chan_ntargets
= 8;
253 sc
->sc_softc
.sc_channel
.chan_nluns
= 8;
254 sc
->sc_softc
.sc_channel
.chan_id
= sc
->sc_softc
.sc_host_id
;
256 /* initialise the card */
258 *rp
->inten
= (COSC_POLL
?0:1);
262 sc
->sc_softc
.sc_ih
.ih_func
= cosc_intr
;
263 sc
->sc_softc
.sc_ih
.ih_arg
= &sc
->sc_softc
;
264 sc
->sc_softc
.sc_ih
.ih_level
= IPL_BIO
;
265 sc
->sc_softc
.sc_ih
.ih_name
= "scsi: cosc";
266 sc
->sc_softc
.sc_ih
.ih_maskaddr
= sc
->sc_podule
->irq_addr
;
267 sc
->sc_softc
.sc_ih
.ih_maskbits
= sc
->sc_podule
->irq_mask
;
273 evcnt_attach_dynamic(&sc
->sc_intrcnt
, EVCNT_TYPE_INTR
, NULL
,
274 device_xname(dp
), "intr");
275 sc
->sc_ih
= podulebus_irq_establish(pa
->pa_ih
, IPL_BIO
,
276 cosc_intr
, sc
, &sc
->sc_intrcnt
);
277 if (sc
->sc_ih
== NULL
)
278 panic("%s: Cannot install IRQ handler",
284 /* attach all scsi units on us */
285 config_found(dp
, &sc
->sc_softc
.sc_channel
, scsiprint
);
289 /* Turn on/off led */
292 cosc_led(struct esc_softc
*sc
, int mode
)
296 rp
= (cosc_regmap_p
)sc
->sc_esc
;
301 if (sc
->sc_led_status
)
304 /* *rp->led = (sc->sc_led_status?1:0);*/
311 struct esc_softc
*dev
= arg
;
315 rp
= (cosc_regmap_p
)dev
->sc_esc
;
317 printf("cosc_intr:%08x %02x\n", (u_int
)rp
->esc
.esc_status
, *rp
->esc
.esc_status
);
319 if (*rp
->esc
.esc_status
& ESC_STAT_INTERRUPT_PENDING
) {
322 dev
->sc_status
= *rp
->esc
.esc_status
;
323 dev
->sc_interrupt
= *rp
->esc
.esc_interrupt
;
325 if (dev
->sc_interrupt
& ESC_INT_RESELECTED
) {
326 dev
->sc_resel
[0] = *rp
->esc
.esc_fifo
;
327 dev
->sc_resel
[1] = *rp
->esc
.esc_fifo
;
332 } while((*rp
->esc
.esc_status
& ESC_STAT_INTERRUPT_PENDING
)
336 return(0); /* Pass interrupt on down the chain */
340 /* Load transfer address into dma register */
343 cosc_set_dma_adr(struct esc_softc
*sc
, void *ptr
)
345 printf("cosc_set_dma_adr(sc = 0x%08x, ptr = 0x%08x)\n", (u_int
)sc
, (u_int
)ptr
);
350 /* Set DMA transfer counter */
353 cosc_set_dma_tc(struct esc_softc
*sc
, unsigned int len
)
355 printf("cosc_set_dma_tc(sc, len = 0x%08x)", len
);
357 /* Set the transfer size on the SCSI controller */
359 *sc
->sc_esc
->esc_tc_low
= len
; len
>>= 8;
360 *sc
->sc_esc
->esc_tc_mid
= len
; len
>>= 8;
361 *sc
->sc_esc
->esc_tc_high
= len
;
368 cosc_set_dma_mode(struct esc_softc
*sc
, int mode
)
370 printf("cosc_set_dma_mode(sc, mode = %d)", mode
);
374 /* Initialize DMA for transfer */
377 cosc_setup_dma(struct esc_softc
*sc
, void *ptr
, int len
, int mode
)
379 /* printf("cosc_setup_dma(sc, ptr = 0x%08x, len = 0x%08x, mode = 0x%08x)\n", (u_int)ptr, len, mode);*/
385 /* Check if address and len is ok for DMA transfer */
388 cosc_need_bump(struct esc_softc
*sc
, void *ptr
, int len
)
405 /* Interrupt driven routines */
408 cosc_build_dma_chain(struct esc_softc
*sc
, struct esc_dma_chain
*chain
, void *p
, int l
)
410 printf("cosc_build_dma_chain()\n");