xref: /openbsd/sys/dev/eisa/uha_eisa.c (revision 471aeecf)
1 /*	$OpenBSD: uha_eisa.c,v 1.16 2022/04/06 18:59:28 naddy Exp $	*/
2 /*	$NetBSD: uha_eisa.c,v 1.5 1996/10/21 22:31:07 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/eisa/eisavar.h>
46 #include <dev/eisa/eisadevs.h>
47 
48 #include <dev/ic/uhareg.h>
49 #include <dev/ic/uhavar.h>
50 
51 #define	UHA_EISA_SLOT_OFFSET	0xc80
52 #define	UHA_EISA_IOSIZE		0x020
53 
54 int	uha_eisa_match(struct device *, void *, void *);
55 void	uha_eisa_attach(struct device *, struct device *, void *);
56 
57 const struct cfattach uha_eisa_ca = {
58 	sizeof(struct uha_softc), uha_eisa_match, uha_eisa_attach
59 };
60 
61 #define KVTOPHYS(x)	vtophys((vaddr_t)(x))
62 
63 int u24_find(bus_space_tag_t, bus_space_handle_t, struct uha_softc *);
64 void u24_start_mbox(struct uha_softc *, struct uha_mscp *);
65 int u24_poll(struct uha_softc *, struct scsi_xfer *, int);
66 int u24_intr(void *);
67 void u24_init(struct uha_softc *);
68 
69 /*
70  * Check the slots looking for a board we recognise
71  * If we find one, note its address (slot) and call
72  * the actual probe routine to check it out.
73  */
74 int
uha_eisa_match(struct device * parent,void * match,void * aux)75 uha_eisa_match(struct device *parent, void *match, void *aux)
76 {
77 	struct eisa_attach_args *ea = aux;
78 	bus_space_tag_t iot = ea->ea_iot;
79 	bus_space_handle_t ioh;
80 	int rv;
81 
82 	/* must match one of our known ID strings */
83 	if (strncmp(ea->ea_idstring, "USC024", 6))
84 		return (0);
85 
86 	if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) +
87 	    UHA_EISA_SLOT_OFFSET, UHA_EISA_IOSIZE, 0, &ioh))
88 		return (0);
89 
90 	rv = u24_find(iot, ioh, NULL);
91 
92 	bus_space_unmap(iot, ioh, UHA_EISA_IOSIZE);
93 
94 	return (rv);
95 }
96 
97 /*
98  * Attach all the sub-devices we can find
99  */
100 void
uha_eisa_attach(struct device * parent,struct device * self,void * aux)101 uha_eisa_attach(struct device *parent, struct device *self, void *aux)
102 {
103 	struct eisa_attach_args *ea = aux;
104 	struct uha_softc *sc = (void *)self;
105 	bus_space_tag_t iot = ea->ea_iot;
106 	bus_space_handle_t ioh;
107 	eisa_chipset_tag_t ec = ea->ea_ec;
108 	eisa_intr_handle_t ih;
109 	const char *model, *intrstr;
110 
111 	if (!strncmp(ea->ea_idstring, "USC024", 6))
112 		model = EISA_PRODUCT_USC0240;
113 	else
114 		model = "unknown model!";
115 	printf(": %s\n", model);
116 
117 	if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) +
118 	    UHA_EISA_SLOT_OFFSET, UHA_EISA_IOSIZE, 0, &ioh))
119 		panic("uha_attach: can't map I/O addresses");
120 
121 	sc->sc_iot = iot;
122 	sc->sc_ioh = ioh;
123 	if (!u24_find(iot, ioh, sc))
124 		panic("uha_attach: u24_find failed!");
125 
126 	if (eisa_intr_map(ec, sc->sc_irq, &ih)) {
127 		printf("%s: couldn't map interrupt (%d)\n",
128 		    sc->sc_dev.dv_xname, sc->sc_irq);
129 		return;
130 	}
131 	intrstr = eisa_intr_string(ec, ih);
132 	sc->sc_ih = eisa_intr_establish(ec, ih, IST_LEVEL, IPL_BIO,
133 	    u24_intr, sc, sc->sc_dev.dv_xname);
134 	if (sc->sc_ih == NULL) {
135 		printf("%s: couldn't establish interrupt",
136 		    sc->sc_dev.dv_xname);
137 		if (intrstr != NULL)
138 			printf(" at %s", intrstr);
139 		printf("\n");
140 		return;
141 	}
142 	printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
143 
144 	/* Save function pointers for later use. */
145 	sc->start_mbox = u24_start_mbox;
146 	sc->poll = u24_poll;
147 	sc->init = u24_init;
148 
149 	uha_attach(sc);
150 }
151 
152 int
u24_find(bus_space_tag_t iot,bus_space_handle_t ioh,struct uha_softc * sc)153 u24_find(bus_space_tag_t iot, bus_space_handle_t ioh, struct uha_softc *sc)
154 {
155 	u_int8_t config0, config1, config2;
156 	int irq, drq;
157 	int resetcount = 4000;	/* 4 secs? */
158 
159 	config0 = bus_space_read_1(iot, ioh, U24_CONFIG + 0);
160 	config1 = bus_space_read_1(iot, ioh, U24_CONFIG + 1);
161 	config2 = bus_space_read_1(iot, ioh, U24_CONFIG + 2);
162 	if ((config0 & U24_MAGIC1) == 0 ||
163 	    (config1 & U24_MAGIC2) == 0)
164 		return (0);
165 
166 	drq = -1;
167 
168 	switch (config0 & U24_IRQ_MASK) {
169 	case U24_IRQ10:
170 		irq = 10;
171 		break;
172 	case U24_IRQ11:
173 		irq = 11;
174 		break;
175 	case U24_IRQ14:
176 		irq = 14;
177 		break;
178 	case U24_IRQ15:
179 		irq = 15;
180 		break;
181 	default:
182 		printf("u24_find: illegal irq setting %x\n",
183 		    config0 & U24_IRQ_MASK);
184 		return (0);
185 	}
186 
187 	bus_space_write_1(iot, ioh, U24_LINT, UHA_ASRST);
188 
189 	while (--resetcount) {
190 		if (bus_space_read_1(iot, ioh, U24_LINT))
191 			break;
192 		delay(1000);	/* 1 mSec per loop */
193 	}
194 	if (!resetcount) {
195 		printf("u24_find: board timed out during reset\n");
196 		return (0);
197 	}
198 
199 	/* if we want to fill in softc, do so now */
200 	if (sc != NULL) {
201 		sc->sc_irq = irq;
202 		sc->sc_drq = drq;
203 		sc->sc_scsi_dev = config2 & U24_HOSTID_MASK;
204 	}
205 
206 	return (1);
207 }
208 
209 void
u24_start_mbox(struct uha_softc * sc,struct uha_mscp * mscp)210 u24_start_mbox(struct uha_softc *sc, struct uha_mscp *mscp)
211 {
212 	bus_space_tag_t iot = sc->sc_iot;
213 	bus_space_handle_t ioh = sc->sc_ioh;
214 	int spincount = 100000;	/* 1s should be enough */
215 
216 	while (--spincount) {
217 		if ((bus_space_read_1(iot, ioh, U24_LINT) & U24_LDIP) == 0)
218 			break;
219 		delay(100);
220 	}
221 	if (!spincount)
222 		panic("%s: uha_start_mbox, board not responding",
223 		    sc->sc_dev.dv_xname);
224 
225 	bus_space_write_4(iot, ioh, U24_OGMPTR, KVTOPHYS(mscp));
226 	if (mscp->flags & MSCP_ABORT)
227 		bus_space_write_1(iot, ioh, U24_OGMCMD, 0x80);
228 	else
229 		bus_space_write_1(iot, ioh, U24_OGMCMD, 0x01);
230 	bus_space_write_1(iot, ioh, U24_LINT, U24_OGMFULL);
231 
232 	if ((mscp->xs->flags & SCSI_POLL) == 0)
233 		timeout_add_msec(&mscp->xs->stimeout, mscp->timeout);
234 }
235 
236 int
u24_poll(struct uha_softc * sc,struct scsi_xfer * xs,int count)237 u24_poll(struct uha_softc *sc, struct scsi_xfer *xs, int count)
238 {
239 	bus_space_tag_t iot = sc->sc_iot;
240 	bus_space_handle_t ioh = sc->sc_ioh;
241 	int s;
242 
243 	while (count) {
244 		/*
245 		 * If we had interrupts enabled, would we
246 		 * have got an interrupt?
247 		 */
248 		if (bus_space_read_1(iot, ioh, U24_SINT) & U24_SDIP) {
249 			s = splbio();
250 			u24_intr(sc);
251 			splx(s);
252 		}
253 		if (xs->flags & ITSDONE)
254 			return (0);
255 		delay(1000);
256 		count--;
257 	}
258 	return (1);
259 }
260 
261 int
u24_intr(void * arg)262 u24_intr(void *arg)
263 {
264 	struct uha_softc *sc = arg;
265 	bus_space_tag_t iot = sc->sc_iot;
266 	bus_space_handle_t ioh = sc->sc_ioh;
267 	struct uha_mscp *mscp;
268 	u_char uhastat;
269 	u_long mboxval;
270 
271 #ifdef	UHADEBUG
272 	printf("%s: uhaintr ", sc->sc_dev.dv_xname);
273 #endif /*UHADEBUG */
274 
275 	if ((bus_space_read_1(iot, ioh, U24_SINT) & U24_SDIP) == 0)
276 		return (0);
277 
278 	for (;;) {
279 		/*
280 		 * First get all the information and then
281 		 * acknowledge the interrupt
282 		 */
283 		uhastat = bus_space_read_1(iot, ioh, U24_SINT);
284 		mboxval = bus_space_read_4(iot, ioh, U24_ICMPTR);
285 		bus_space_write_1(iot, ioh, U24_SINT, U24_ICM_ACK);
286 		bus_space_write_1(iot, ioh, U24_ICMCMD, 0);
287 
288 #ifdef	UHADEBUG
289 		printf("status = 0x%x ", uhastat);
290 #endif /*UHADEBUG*/
291 
292 		/*
293 		 * Process the completed operation
294 		 */
295 		mscp = uha_mscp_phys_kv(sc, mboxval);
296 		if (!mscp) {
297 			printf("%s: BAD MSCP RETURNED!\n",
298 			    sc->sc_dev.dv_xname);
299 			continue;	/* whatever it was, it'll timeout */
300 		}
301 		timeout_del(&mscp->xs->stimeout);
302 		uha_done(sc, mscp);
303 
304 		if ((bus_space_read_1(iot, ioh, U24_SINT) & U24_SDIP) == 0)
305 			return (1);
306 	}
307 }
308 
309 void
u24_init(struct uha_softc * sc)310 u24_init(struct uha_softc *sc)
311 {
312 	bus_space_tag_t iot = sc->sc_iot;
313 	bus_space_handle_t ioh = sc->sc_ioh;
314 
315 	/* free OGM and ICM */
316 	bus_space_write_1(iot, ioh, U24_OGMCMD, 0);
317 	bus_space_write_1(iot, ioh, U24_ICMCMD, 0);
318 	/* make sure interrupts are enabled */
319 #ifdef UHADEBUG
320 	printf("u24_init: lmask=%02x, smask=%02x\n",
321 	    bus_space_read_1(iot, ioh, U24_LMASK),
322 	    bus_space_read_1(iot, ioh, U24_SMASK));
323 #endif
324 	bus_space_write_1(iot, ioh, U24_LMASK, 0xd2);	/* XXX */
325 	bus_space_write_1(iot, ioh, U24_SMASK, 0x92);	/* XXX */
326 }
327