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