xref: /openbsd/sys/dev/isa/uha_isa.c (revision e5dd7070)
1 /*	$OpenBSD: uha_isa.c,v 1.13 2017/09/08 05:36:52 deraadt Exp $	*/
2 /*	$NetBSD: uha_isa.c,v 1.5 1996/10/21 22:41:21 thorpej Exp $	*/
3 
4 /*
5  * Copyright (c) 1994, 1996 Charles M. Hannum.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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 Charles M. Hannum.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/device.h>
36 #include <sys/kernel.h>
37 #include <uvm/uvm_extern.h>
38 
39 #include <machine/bus.h>
40 #include <machine/intr.h>
41 
42 #include <scsi/scsi_all.h>
43 #include <scsi/scsiconf.h>
44 
45 #include <dev/isa/isavar.h>
46 #include <dev/isa/isadmavar.h>
47 
48 #include <dev/ic/uhareg.h>
49 #include <dev/ic/uhavar.h>
50 
51 #define	UHA_ISA_IOSIZE	16
52 
53 int	uha_isa_probe(struct device *, void *, void *);
54 void	uha_isa_attach(struct device *, struct device *, void *);
55 
56 struct cfattach uha_isa_ca = {
57 	sizeof(struct uha_softc), uha_isa_probe, uha_isa_attach
58 };
59 
60 #define KVTOPHYS(x)	vtophys((vaddr_t)(x))
61 
62 int u14_find(bus_space_tag_t, bus_space_handle_t, struct uha_softc *);
63 void u14_start_mbox(struct uha_softc *, struct uha_mscp *);
64 int u14_poll(struct uha_softc *, struct scsi_xfer *, int);
65 int u14_intr(void *);
66 void u14_init(struct uha_softc *);
67 
68 /*
69  * Check the slots looking for a board we recognise
70  * If we find one, note its address (slot) and call
71  * the actual probe routine to check it out.
72  */
73 int
74 uha_isa_probe(parent, match, aux)
75 	struct device *parent;
76 	void *match, *aux;
77 {
78 	struct isa_attach_args *ia = aux;
79 	struct uha_softc sc;
80 	bus_space_tag_t iot = ia->ia_iot;
81 	bus_space_handle_t ioh;
82 	int rv;
83 
84 	if (bus_space_map(iot, ia->ia_iobase, UHA_ISA_IOSIZE, 0, &ioh))
85 		return (0);
86 
87 	rv = u14_find(iot, ioh, &sc);
88 
89 	bus_space_unmap(iot, ioh, UHA_ISA_IOSIZE);
90 
91 	if (rv) {
92 		if (ia->ia_irq != -1 && ia->ia_irq != sc.sc_irq)
93 			return (0);
94 		if (ia->ia_drq != -1 && ia->ia_drq != sc.sc_drq)
95 			return (0);
96 		ia->ia_irq = sc.sc_irq;
97 		ia->ia_drq = sc.sc_drq;
98 		ia->ia_msize = 0;
99 		ia->ia_iosize = UHA_ISA_IOSIZE;
100 	}
101 	return (rv);
102 }
103 
104 /*
105  * Attach all the sub-devices we can find
106  */
107 void
108 uha_isa_attach(parent, self, aux)
109 	struct device *parent, *self;
110 	void *aux;
111 {
112 	struct isa_attach_args *ia = aux;
113 	struct uha_softc *sc = (void *)self;
114 	bus_space_tag_t iot = ia->ia_iot;
115 	bus_space_handle_t ioh;
116 	isa_chipset_tag_t ic = ia->ia_ic;
117 
118 	printf("\n");
119 
120 	if (bus_space_map(iot, ia->ia_iobase, UHA_ISA_IOSIZE, 0, &ioh))
121 		panic("uha_attach: bus_space_map failed!");
122 
123 	sc->sc_iot = iot;
124 	sc->sc_ioh = ioh;
125 	if (!u14_find(iot, ioh, sc))
126 		panic("uha_attach: u14_find failed!");
127 
128 	if (sc->sc_drq != -1)
129 		isadma_cascade(sc->sc_drq);
130 
131 	sc->sc_ih = isa_intr_establish(ic, sc->sc_irq, IST_EDGE, IPL_BIO,
132 	    u14_intr, sc, sc->sc_dev.dv_xname);
133 	if (sc->sc_ih == NULL) {
134 		printf("%s: couldn't establish interrupt\n",
135 		    sc->sc_dev.dv_xname);
136 		return;
137 	}
138 
139 	/* Save function pointers for later use. */
140 	sc->start_mbox = u14_start_mbox;
141 	sc->poll = u14_poll;
142 	sc->init = u14_init;
143 
144 	uha_attach(sc);
145 }
146 
147 /*
148  * Start the board, ready for normal operation
149  */
150 int
151 u14_find(iot, ioh, sc)
152 	bus_space_tag_t iot;
153 	bus_space_handle_t ioh;
154 	struct uha_softc *sc;
155 {
156 	u_int16_t model, config;
157 	int irq, drq;
158 	int resetcount = 4000;	/* 4 secs? */
159 
160 	model = (bus_space_read_1(iot, ioh, U14_ID + 0) << 8) |
161 		(bus_space_read_1(iot, ioh, U14_ID + 1) << 0);
162 	if ((model & 0xfff0) != 0x5640)
163 		return (0);
164 
165 	config = (bus_space_read_1(iot, ioh, U14_CONFIG + 0) << 8) |
166 		 (bus_space_read_1(iot, ioh, U14_CONFIG + 1) << 0);
167 
168 	switch (model & 0x000f) {
169 	case 0x0000:
170 		switch (config & U14_DMA_MASK) {
171 		case U14_DMA_CH5:
172 			drq = 5;
173 			break;
174 		case U14_DMA_CH6:
175 			drq = 6;
176 			break;
177 		case U14_DMA_CH7:
178 			drq = 7;
179 			break;
180 		default:
181 			printf("u14_find: illegal drq setting %x\n",
182 			    config & U14_DMA_MASK);
183 			return (0);
184 		}
185 		break;
186 	case 0x0001:
187 		/* This is a 34f, and doesn't need an ISA DMA channel. */
188 		drq = -1;
189 		break;
190 	default:
191 		printf("u14_find: unknown model %x\n", model);
192 		return (0);
193 	}
194 
195 	switch (config & U14_IRQ_MASK) {
196 	case U14_IRQ10:
197 		irq = 10;
198 		break;
199 	case U14_IRQ11:
200 		irq = 11;
201 		break;
202 	case U14_IRQ14:
203 		irq = 14;
204 		break;
205 	case U14_IRQ15:
206 		irq = 15;
207 		break;
208 	default:
209 		printf("u14_find: illegal irq setting %x\n",
210 		    config & U14_IRQ_MASK);
211 		return (0);
212 	}
213 
214 	bus_space_write_1(iot, ioh, U14_LINT, UHA_ASRST);
215 
216 	while (--resetcount) {
217 		if (bus_space_read_1(iot, ioh, U14_LINT))
218 			break;
219 		delay(1000);	/* 1 mSec per loop */
220 	}
221 	if (!resetcount) {
222 		printf("u14_find: board timed out during reset\n");
223 		return (0);
224 	}
225 
226 	/* if we want to fill in softc, do so now */
227 	if (sc != NULL) {
228 		sc->sc_irq = irq;
229 		sc->sc_drq = drq;
230 		sc->sc_scsi_dev = config & U14_HOSTID_MASK;
231 	}
232 
233 	return (1);
234 }
235 
236 /*
237  * Function to send a command out through a mailbox
238  */
239 void
240 u14_start_mbox(sc, mscp)
241 	struct uha_softc *sc;
242 	struct uha_mscp *mscp;
243 {
244 	bus_space_tag_t iot = sc->sc_iot;
245 	bus_space_handle_t ioh = sc->sc_ioh;
246 	int spincount = 100000;	/* 1s should be enough */
247 
248 	while (--spincount) {
249 		if ((bus_space_read_1(iot, ioh, U14_LINT) & U14_LDIP) == 0)
250 			break;
251 		delay(100);
252 	}
253 	if (!spincount)
254 		panic("%s: uha_start_mbox, board not responding",
255 		    sc->sc_dev.dv_xname);
256 
257 	bus_space_write_4(iot, ioh, U14_OGMPTR, KVTOPHYS(mscp));
258 	if (mscp->flags & MSCP_ABORT)
259 		bus_space_write_1(iot, ioh, U14_LINT, U14_ABORT);
260 	else
261 		bus_space_write_1(iot, ioh, U14_LINT, U14_OGMFULL);
262 
263 	if ((mscp->xs->flags & SCSI_POLL) == 0)
264 		timeout_add_msec(&mscp->xs->stimeout, mscp->timeout);
265 }
266 
267 /*
268  * Function to poll for command completion when in poll mode.
269  *
270  *	wait = timeout in msec
271  */
272 int
273 u14_poll(sc, xs, count)
274 	struct uha_softc *sc;
275 	struct scsi_xfer *xs;
276 	int count;
277 {
278 	bus_space_tag_t iot = sc->sc_iot;
279 	bus_space_handle_t ioh = sc->sc_ioh;
280 
281 	while (count) {
282 		/*
283 		 * If we had interrupts enabled, would we
284 		 * have got an interrupt?
285 		 */
286 		if (bus_space_read_1(iot, ioh, U14_SINT) & U14_SDIP)
287 			u14_intr(sc);
288 		if (xs->flags & ITSDONE)
289 			return (0);
290 		delay(1000);
291 		count--;
292 	}
293 	return (1);
294 }
295 
296 /*
297  * Catch an interrupt from the adaptor
298  */
299 int
300 u14_intr(arg)
301 	void *arg;
302 {
303 	struct uha_softc *sc = arg;
304 	bus_space_tag_t iot = sc->sc_iot;
305 	bus_space_handle_t ioh = sc->sc_ioh;
306 	struct uha_mscp *mscp;
307 	u_char uhastat;
308 	u_long mboxval;
309 
310 #ifdef	UHADEBUG
311 	printf("%s: uhaintr ", sc->sc_dev.dv_xname);
312 #endif /*UHADEBUG */
313 
314 	if ((bus_space_read_1(iot, ioh, U14_SINT) & U14_SDIP) == 0)
315 		return (0);
316 
317 	for (;;) {
318 		/*
319 		 * First get all the information and then
320 		 * acknowledge the interrupt
321 		 */
322 		uhastat = bus_space_read_1(iot, ioh, U14_SINT);
323 		mboxval = bus_space_read_4(iot, ioh, U14_ICMPTR);
324 		/* XXX Send an ABORT_ACK instead? */
325 		bus_space_write_1(iot, ioh, U14_SINT, U14_ICM_ACK);
326 
327 #ifdef	UHADEBUG
328 		printf("status = 0x%x ", uhastat);
329 #endif /*UHADEBUG*/
330 
331 		/*
332 		 * Process the completed operation
333 		 */
334 		mscp = uha_mscp_phys_kv(sc, mboxval);
335 		if (!mscp) {
336 			printf("%s: BAD MSCP RETURNED!\n",
337 			    sc->sc_dev.dv_xname);
338 			continue;	/* whatever it was, it'll timeout */
339 		}
340 
341 		timeout_del(&mscp->xs->stimeout);
342 		uha_done(sc, mscp);
343 
344 		if ((bus_space_read_1(iot, ioh, U14_SINT) & U14_SDIP) == 0)
345 			return (1);
346 	}
347 }
348 
349 void
350 u14_init(sc)
351 	struct uha_softc *sc;
352 {
353 	bus_space_tag_t iot = sc->sc_iot;
354 	bus_space_handle_t ioh = sc->sc_ioh;
355 
356 	/* make sure interrupts are enabled */
357 #ifdef UHADEBUG
358 	printf("u14_init: lmask=%02x, smask=%02x\n",
359 	    bus_space_read_1(iot, ioh, U14_LMASK),
360 	    bus_space_read_1(iot, ioh, U14_SMASK));
361 #endif
362 	bus_space_write_1(iot, ioh, U14_LMASK, 0xd1);	/* XXX */
363 	bus_space_write_1(iot, ioh, U14_SMASK, 0x91);	/* XXX */
364 }
365