1 /* $OpenBSD: uha_isa.c,v 1.15 2022/04/06 18:59:29 naddy 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 const 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
uha_isa_probe(struct device * parent,void * match,void * aux)74 uha_isa_probe(struct device *parent, void *match, void *aux)
75 {
76 struct isa_attach_args *ia = aux;
77 struct uha_softc sc;
78 bus_space_tag_t iot = ia->ia_iot;
79 bus_space_handle_t ioh;
80 int rv;
81
82 if (bus_space_map(iot, ia->ia_iobase, UHA_ISA_IOSIZE, 0, &ioh))
83 return (0);
84
85 rv = u14_find(iot, ioh, &sc);
86
87 bus_space_unmap(iot, ioh, UHA_ISA_IOSIZE);
88
89 if (rv) {
90 if (ia->ia_irq != -1 && ia->ia_irq != sc.sc_irq)
91 return (0);
92 if (ia->ia_drq != -1 && ia->ia_drq != sc.sc_drq)
93 return (0);
94 ia->ia_irq = sc.sc_irq;
95 ia->ia_drq = sc.sc_drq;
96 ia->ia_msize = 0;
97 ia->ia_iosize = UHA_ISA_IOSIZE;
98 }
99 return (rv);
100 }
101
102 /*
103 * Attach all the sub-devices we can find
104 */
105 void
uha_isa_attach(struct device * parent,struct device * self,void * aux)106 uha_isa_attach(struct device *parent, struct device *self, void *aux)
107 {
108 struct isa_attach_args *ia = aux;
109 struct uha_softc *sc = (void *)self;
110 bus_space_tag_t iot = ia->ia_iot;
111 bus_space_handle_t ioh;
112 isa_chipset_tag_t ic = ia->ia_ic;
113
114 printf("\n");
115
116 if (bus_space_map(iot, ia->ia_iobase, UHA_ISA_IOSIZE, 0, &ioh))
117 panic("uha_attach: bus_space_map failed!");
118
119 sc->sc_iot = iot;
120 sc->sc_ioh = ioh;
121 if (!u14_find(iot, ioh, sc))
122 panic("uha_attach: u14_find failed!");
123
124 if (sc->sc_drq != -1)
125 isadma_cascade(sc->sc_drq);
126
127 sc->sc_ih = isa_intr_establish(ic, sc->sc_irq, IST_EDGE, IPL_BIO,
128 u14_intr, sc, sc->sc_dev.dv_xname);
129 if (sc->sc_ih == NULL) {
130 printf("%s: couldn't establish interrupt\n",
131 sc->sc_dev.dv_xname);
132 return;
133 }
134
135 /* Save function pointers for later use. */
136 sc->start_mbox = u14_start_mbox;
137 sc->poll = u14_poll;
138 sc->init = u14_init;
139
140 uha_attach(sc);
141 }
142
143 /*
144 * Start the board, ready for normal operation
145 */
146 int
u14_find(bus_space_tag_t iot,bus_space_handle_t ioh,struct uha_softc * sc)147 u14_find(bus_space_tag_t iot, bus_space_handle_t ioh, struct uha_softc *sc)
148 {
149 u_int16_t model, config;
150 int irq, drq;
151 int resetcount = 4000; /* 4 secs? */
152
153 model = (bus_space_read_1(iot, ioh, U14_ID + 0) << 8) |
154 (bus_space_read_1(iot, ioh, U14_ID + 1) << 0);
155 if ((model & 0xfff0) != 0x5640)
156 return (0);
157
158 config = (bus_space_read_1(iot, ioh, U14_CONFIG + 0) << 8) |
159 (bus_space_read_1(iot, ioh, U14_CONFIG + 1) << 0);
160
161 switch (model & 0x000f) {
162 case 0x0000:
163 switch (config & U14_DMA_MASK) {
164 case U14_DMA_CH5:
165 drq = 5;
166 break;
167 case U14_DMA_CH6:
168 drq = 6;
169 break;
170 case U14_DMA_CH7:
171 drq = 7;
172 break;
173 default:
174 printf("u14_find: illegal drq setting %x\n",
175 config & U14_DMA_MASK);
176 return (0);
177 }
178 break;
179 case 0x0001:
180 /* This is a 34f, and doesn't need an ISA DMA channel. */
181 drq = -1;
182 break;
183 default:
184 printf("u14_find: unknown model %x\n", model);
185 return (0);
186 }
187
188 switch (config & U14_IRQ_MASK) {
189 case U14_IRQ10:
190 irq = 10;
191 break;
192 case U14_IRQ11:
193 irq = 11;
194 break;
195 case U14_IRQ14:
196 irq = 14;
197 break;
198 case U14_IRQ15:
199 irq = 15;
200 break;
201 default:
202 printf("u14_find: illegal irq setting %x\n",
203 config & U14_IRQ_MASK);
204 return (0);
205 }
206
207 bus_space_write_1(iot, ioh, U14_LINT, UHA_ASRST);
208
209 while (--resetcount) {
210 if (bus_space_read_1(iot, ioh, U14_LINT))
211 break;
212 delay(1000); /* 1 mSec per loop */
213 }
214 if (!resetcount) {
215 printf("u14_find: board timed out during reset\n");
216 return (0);
217 }
218
219 /* if we want to fill in softc, do so now */
220 if (sc != NULL) {
221 sc->sc_irq = irq;
222 sc->sc_drq = drq;
223 sc->sc_scsi_dev = config & U14_HOSTID_MASK;
224 }
225
226 return (1);
227 }
228
229 /*
230 * Function to send a command out through a mailbox
231 */
232 void
u14_start_mbox(struct uha_softc * sc,struct uha_mscp * mscp)233 u14_start_mbox(struct uha_softc *sc, struct uha_mscp *mscp)
234 {
235 bus_space_tag_t iot = sc->sc_iot;
236 bus_space_handle_t ioh = sc->sc_ioh;
237 int spincount = 100000; /* 1s should be enough */
238
239 while (--spincount) {
240 if ((bus_space_read_1(iot, ioh, U14_LINT) & U14_LDIP) == 0)
241 break;
242 delay(100);
243 }
244 if (!spincount)
245 panic("%s: uha_start_mbox, board not responding",
246 sc->sc_dev.dv_xname);
247
248 bus_space_write_4(iot, ioh, U14_OGMPTR, KVTOPHYS(mscp));
249 if (mscp->flags & MSCP_ABORT)
250 bus_space_write_1(iot, ioh, U14_LINT, U14_ABORT);
251 else
252 bus_space_write_1(iot, ioh, U14_LINT, U14_OGMFULL);
253
254 if ((mscp->xs->flags & SCSI_POLL) == 0)
255 timeout_add_msec(&mscp->xs->stimeout, mscp->timeout);
256 }
257
258 /*
259 * Function to poll for command completion when in poll mode.
260 *
261 * wait = timeout in msec
262 */
263 int
u14_poll(struct uha_softc * sc,struct scsi_xfer * xs,int count)264 u14_poll(struct uha_softc *sc, struct scsi_xfer *xs, int count)
265 {
266 bus_space_tag_t iot = sc->sc_iot;
267 bus_space_handle_t ioh = sc->sc_ioh;
268
269 while (count) {
270 /*
271 * If we had interrupts enabled, would we
272 * have got an interrupt?
273 */
274 if (bus_space_read_1(iot, ioh, U14_SINT) & U14_SDIP)
275 u14_intr(sc);
276 if (xs->flags & ITSDONE)
277 return (0);
278 delay(1000);
279 count--;
280 }
281 return (1);
282 }
283
284 /*
285 * Catch an interrupt from the adaptor
286 */
287 int
u14_intr(void * arg)288 u14_intr(void *arg)
289 {
290 struct uha_softc *sc = arg;
291 bus_space_tag_t iot = sc->sc_iot;
292 bus_space_handle_t ioh = sc->sc_ioh;
293 struct uha_mscp *mscp;
294 u_char uhastat;
295 u_long mboxval;
296
297 #ifdef UHADEBUG
298 printf("%s: uhaintr ", sc->sc_dev.dv_xname);
299 #endif /*UHADEBUG */
300
301 if ((bus_space_read_1(iot, ioh, U14_SINT) & U14_SDIP) == 0)
302 return (0);
303
304 for (;;) {
305 /*
306 * First get all the information and then
307 * acknowledge the interrupt
308 */
309 uhastat = bus_space_read_1(iot, ioh, U14_SINT);
310 mboxval = bus_space_read_4(iot, ioh, U14_ICMPTR);
311 /* XXX Send an ABORT_ACK instead? */
312 bus_space_write_1(iot, ioh, U14_SINT, U14_ICM_ACK);
313
314 #ifdef UHADEBUG
315 printf("status = 0x%x ", uhastat);
316 #endif /*UHADEBUG*/
317
318 /*
319 * Process the completed operation
320 */
321 mscp = uha_mscp_phys_kv(sc, mboxval);
322 if (!mscp) {
323 printf("%s: BAD MSCP RETURNED!\n",
324 sc->sc_dev.dv_xname);
325 continue; /* whatever it was, it'll timeout */
326 }
327
328 timeout_del(&mscp->xs->stimeout);
329 uha_done(sc, mscp);
330
331 if ((bus_space_read_1(iot, ioh, U14_SINT) & U14_SDIP) == 0)
332 return (1);
333 }
334 }
335
336 void
u14_init(struct uha_softc * sc)337 u14_init(struct uha_softc *sc)
338 {
339 bus_space_tag_t iot = sc->sc_iot;
340 bus_space_handle_t ioh = sc->sc_ioh;
341
342 /* make sure interrupts are enabled */
343 #ifdef UHADEBUG
344 printf("u14_init: lmask=%02x, smask=%02x\n",
345 bus_space_read_1(iot, ioh, U14_LMASK),
346 bus_space_read_1(iot, ioh, U14_SMASK));
347 #endif
348 bus_space_write_1(iot, ioh, U14_LMASK, 0xd1); /* XXX */
349 bus_space_write_1(iot, ioh, U14_SMASK, 0x91); /* XXX */
350 }
351