Commit | Line | Data |
---|---|---|
5db86c85 | 1 | /* |
e699d09f | 2 | * @(#)ik.c 7.1 (Berkeley) %G% |
5db86c85 | 3 | */ |
6fcffbdd SL |
4 | |
5 | #include "ik.h" | |
6 | #if NIK > 0 | |
7 | /* | |
8 | * PS300/IKON DR-11W Device Driver. | |
9 | */ | |
10 | #include "param.h" | |
11 | #include "buf.h" | |
12 | #include "cmap.h" | |
13 | #include "conf.h" | |
14 | #include "dir.h" | |
15 | #include "dkstat.h" | |
16 | #include "map.h" | |
17 | #include "systm.h" | |
18 | #include "user.h" | |
19 | #include "vmmac.h" | |
20 | #include "proc.h" | |
21 | #include "uio.h" | |
22 | #include "kernel.h" | |
e1111228 | 23 | #include "syslog.h" |
6fcffbdd SL |
24 | |
25 | #include "../tahoe/mtpr.h" | |
26 | #include "../tahoe/pte.h" | |
27 | ||
28 | #include "../tahoevba/vbavar.h" | |
29 | #include "../tahoevba/ikreg.h" | |
30 | #include "../tahoevba/psreg.h" | |
31 | #include "../tahoevba/psproto.h" | |
32 | ||
93d65f53 SL |
33 | int ikprobe(), ikattach(), iktimer(); |
34 | struct vba_device *ikinfo[NIK]; | |
35 | long ikstd[] = { 0 }; | |
36 | struct vba_driver ikdriver = { ikprobe, 0, ikattach, 0, ikstd, "ik", ikinfo }; | |
6fcffbdd | 37 | |
93d65f53 | 38 | #define splik() spl4() |
6fcffbdd SL |
39 | /* |
40 | * Devices are organized in pairs with the odd valued | |
41 | * device being used for ``diagnostic'' purposes. That | |
42 | * is diagnostic devices don't get auto-attach'd and | |
43 | * detach'd on open-close. | |
44 | */ | |
93d65f53 SL |
45 | #define IKUNIT(dev) (minor(dev) >> 1) |
46 | #define IKDIAG(dev) (minor(dev) & 01) /* is a diagnostic unit */ | |
47 | ||
48 | struct ik_softc { | |
49 | uid_t is_uid; /* uid of open processes */ | |
50 | u_short is_timeout; /* current timeout (seconds) */ | |
51 | u_short is_error; /* internal error codes */ | |
52 | u_short is_flags; | |
53 | #define IKF_ATTACHED 0x1 /* unit is attached (not used yet) */ | |
54 | union { | |
55 | u_short w[2]; | |
56 | u_long l; | |
57 | } is_nameaddr; /* address of last symbol lookup */ | |
7ea0073c | 58 | caddr_t is_buf[PS_MAXDMA];/* i/o buffer XXX */ |
6fcffbdd SL |
59 | } ik_softc[NIK]; |
60 | ||
93d65f53 SL |
61 | struct buf iktab[NIK]; /* unit command queue headers */ |
62 | struct buf rikbuf[NIK]; /* buffers for read/write operations */ | |
63 | struct buf cikbuf[NIK]; /* buffers for control operations */ | |
6fcffbdd SL |
64 | |
65 | /* buf overlay definitions */ | |
93d65f53 | 66 | #define b_command b_resid |
6fcffbdd | 67 | |
93d65f53 SL |
68 | int ikdiotimo = PS_DIOTIMO; /* dio polling timeout */ |
69 | int iktimeout = PS_TIMEOUT; /* attention/dma timeout (in hz) */ | |
6fcffbdd SL |
70 | |
71 | ikprobe(reg, vi) | |
93d65f53 | 72 | caddr_t reg; |
6fcffbdd SL |
73 | struct vba_device *vi; |
74 | { | |
93d65f53 | 75 | register int br, cvec; /* r12, r11 */ |
6fcffbdd SL |
76 | register struct ikdevice *ik; |
77 | ||
9d61b7ff SL |
78 | #ifdef lint |
79 | br = 0; cvec = br; br = cvec; | |
80 | ikintr(0); | |
81 | #endif | |
93d65f53 SL |
82 | if (badaddr(reg, 2)) |
83 | return (0); | |
6fcffbdd SL |
84 | ik = (struct ikdevice *)reg; |
85 | ik->ik_vec = --vi->ui_hd->vh_lastiv; | |
93d65f53 | 86 | /* |
7ea0073c SL |
87 | * Use extended non-privileged address modifier |
88 | * to avoid address overlap with 24-bit devices. | |
93d65f53 SL |
89 | */ |
90 | ik->ik_mod = 0xf1; /* address modifier */ | |
91 | /* | |
92 | * Try and reset the PS300. Since this | |
93 | * won't work if it's powered off, we | |
94 | * can't use sucess/failure to decide | |
95 | * if the device is present. | |
96 | */ | |
6fcffbdd | 97 | br = 0; |
93d65f53 SL |
98 | (void) psreset(ik, IKCSR_IENA); |
99 | if (br == 0) /* XXX */ | |
6fcffbdd | 100 | br = 0x18, cvec = ik->ik_vec; /* XXX */ |
93d65f53 | 101 | return (sizeof (struct ikdevice)); |
6fcffbdd SL |
102 | } |
103 | ||
104 | /* | |
105 | * Perform a ``hard'' reset. | |
106 | */ | |
107 | psreset(ik, iena) | |
93d65f53 | 108 | register struct ikdevice *ik; |
6fcffbdd SL |
109 | { |
110 | ||
93d65f53 SL |
111 | ik->ik_csr = IKCSR_MCLR|iena; |
112 | DELAY(10000); | |
113 | ik->ik_csr = IKCSR_FNC3|iena; | |
114 | if (!iena) | |
115 | return (dioread(ik) == PS_RESET); | |
116 | return (1); | |
6fcffbdd SL |
117 | } |
118 | ||
119 | ikattach(vi) | |
93d65f53 | 120 | struct vba_device *vi; |
6fcffbdd | 121 | { |
6fcffbdd | 122 | |
93d65f53 | 123 | ik_softc[vi->ui_unit].is_uid = -1; |
6fcffbdd SL |
124 | } |
125 | ||
126 | /* | |
127 | * Open a PS300 and attach. We allow multiple | |
128 | * processes with the same uid to share a unit. | |
129 | */ | |
130 | /*ARGSUSED*/ | |
131 | ikopen(dev, flag) | |
93d65f53 SL |
132 | dev_t dev; |
133 | int flag; | |
6fcffbdd | 134 | { |
93d65f53 SL |
135 | register int unit = IKUNIT(dev); |
136 | register struct ik_softc *sc; | |
137 | struct vba_device *vi; | |
138 | struct ikdevice *ik; | |
139 | int reset; | |
140 | ||
141 | if (unit >= NIK || (vi = ikinfo[unit]) == 0 || vi->ui_alive == 0) | |
142 | return (ENXIO); | |
143 | sc = &ik_softc[unit]; | |
9d61b7ff | 144 | if (sc->is_uid != (uid_t)-1 && sc->is_uid != u.u_uid) |
93d65f53 | 145 | return (EBUSY); |
9d61b7ff | 146 | if (sc->is_uid == (uid_t)-1) { |
93d65f53 | 147 | sc->is_timeout = 0; |
9d61b7ff | 148 | timeout(iktimer, (caddr_t)unit, hz); |
93d65f53 SL |
149 | /* |
150 | * Perform PS300 attach for first process. | |
151 | */ | |
152 | if (!IKDIAG(dev)) { | |
153 | reset = 0; | |
154 | again: | |
155 | if (ikcommand(dev, PS_ATTACH, 1)) { | |
156 | /* | |
157 | * If attach fails, perform a hard | |
158 | * reset once, then retry the command. | |
159 | */ | |
160 | ik = (struct ikdevice *)ikinfo[unit]->ui_addr; | |
161 | if (!reset++ && psreset(ik, 0)) | |
162 | goto again; | |
9d61b7ff | 163 | untimeout(iktimer, (caddr_t)unit); |
93d65f53 SL |
164 | return (EIO); |
165 | } | |
166 | } | |
167 | sc->is_uid = u.u_uid; | |
168 | } | |
169 | return (0); | |
6fcffbdd SL |
170 | } |
171 | ||
172 | /*ARGSUSED*/ | |
173 | ikclose(dev, flag) | |
93d65f53 SL |
174 | dev_t dev; |
175 | int flag; | |
6fcffbdd | 176 | { |
93d65f53 | 177 | int unit = IKUNIT(dev); |
6fcffbdd SL |
178 | register struct ik_softc *sc = &ik_softc[unit]; |
179 | ||
93d65f53 SL |
180 | if (!IKDIAG(dev)) |
181 | (void) ikcommand(dev, PS_DETACH, 1); /* auto detach */ | |
182 | sc->is_uid = -1; | |
9d61b7ff | 183 | untimeout(iktimer, (caddr_t)unit); |
6fcffbdd SL |
184 | } |
185 | ||
186 | ikread(dev, uio) | |
93d65f53 SL |
187 | dev_t dev; |
188 | struct uio *uio; | |
6fcffbdd SL |
189 | { |
190 | ||
93d65f53 | 191 | return (ikrw(dev, uio, B_READ)); |
6fcffbdd SL |
192 | } |
193 | ||
194 | ikwrite(dev, uio) | |
93d65f53 SL |
195 | dev_t dev; |
196 | struct uio *uio; | |
6fcffbdd SL |
197 | { |
198 | ||
93d65f53 | 199 | return (ikrw(dev, uio, B_WRITE)); |
6fcffbdd SL |
200 | } |
201 | ||
202 | /* | |
203 | * Take read/write request and perform physical i/o | |
204 | * transaction with PS300. This involves constructing | |
205 | * a physical i/o request vector based on the uio | |
206 | * vector, performing the dma, and, finally, moving | |
207 | * the data to it's final destination (because of CCI | |
208 | * VERSAbus bogosities). | |
209 | */ | |
210 | ikrw(dev, uio, rw) | |
93d65f53 SL |
211 | dev_t dev; |
212 | register struct uio *uio; | |
213 | int rw; | |
6fcffbdd | 214 | { |
93d65f53 SL |
215 | int error, unit = IKUNIT(dev), s, wrcmd; |
216 | register struct buf *bp; | |
217 | register struct iovec *iov; | |
218 | register struct psalist *ap; | |
219 | struct ik_softc *sc = &ik_softc[unit]; | |
220 | ||
221 | if (unit >= NIK) | |
222 | return (ENXIO); | |
223 | bp = &rikbuf[unit]; | |
224 | error = 0, iov = uio->uio_iov, wrcmd = PS_WRPHY; | |
225 | for (; !error && uio->uio_iovcnt; iov++, uio->uio_iovcnt--) { | |
226 | /* | |
227 | * Hack way to set PS300 address w/o doing an lseek | |
228 | * and specify write physical w/ refresh synchronization. | |
229 | */ | |
230 | if (iov->iov_len == 0) { | |
231 | if ((int)iov->iov_base&PSIO_SYNC) | |
232 | wrcmd = PS_WRPHY_SYNC; | |
233 | uio->uio_offset = (int)iov->iov_base & ~PSIO_SYNC; | |
234 | continue; | |
235 | } | |
236 | if (iov->iov_len > PS_MAXDMA) { | |
237 | sc->is_error = PSERROR_INVALBC, error = EINVAL; | |
238 | continue; | |
239 | } | |
240 | if ((int)uio->uio_offset&01) { | |
241 | sc->is_error = PSERROR_BADADDR, error = EINVAL; | |
242 | continue; | |
243 | } | |
244 | s = splbio(); | |
245 | while (bp->b_flags&B_BUSY) { | |
246 | bp->b_flags |= B_WANTED; | |
247 | sleep((caddr_t)bp, PRIBIO+1); | |
248 | } | |
249 | splx(s); | |
250 | bp->b_flags = B_BUSY | rw; | |
251 | /* | |
252 | * Construct address descriptor in buffer. | |
253 | */ | |
254 | ap = (struct psalist *)sc->is_buf; | |
255 | ap->nblocks = 1; | |
256 | /* work-around dr300 word swapping */ | |
257 | ap->addr[0] = uio->uio_offset & 0xffff; | |
258 | ap->addr[1] = uio->uio_offset >> 16; | |
259 | ap->wc = (iov->iov_len + 1) >> 1; | |
260 | if (rw == B_WRITE) { | |
261 | error = copyin(iov->iov_base, (caddr_t)&ap[1], | |
9d61b7ff | 262 | (unsigned)iov->iov_len); |
93d65f53 SL |
263 | if (!error) |
264 | error = ikcommand(dev, wrcmd, | |
265 | iov->iov_len + sizeof (*ap)); | |
266 | } else { | |
267 | caddr_t cp; | |
268 | int len; | |
269 | ||
270 | error = ikcommand(dev, PS_RDPHY, sizeof (*ap)); | |
271 | cp = (caddr_t)&ap[1], len = iov->iov_len; | |
272 | for (; len > 0; len -= NBPG, cp += NBPG) | |
273 | mtpr(P1DC, cp); | |
274 | if (!error) | |
275 | error = copyout((caddr_t)&ap[1], iov->iov_base, | |
9d61b7ff | 276 | (unsigned)iov->iov_len); |
93d65f53 SL |
277 | } |
278 | (void) splbio(); | |
279 | if (bp->b_flags&B_WANTED) | |
280 | wakeup((caddr_t)bp); | |
281 | splx(s); | |
282 | uio->uio_resid -= iov->iov_len; | |
283 | uio->uio_offset += iov->iov_len; | |
284 | bp->b_flags &= ~(B_BUSY|B_WANTED); | |
285 | } | |
286 | return (error); | |
6fcffbdd SL |
287 | } |
288 | ||
289 | /* | |
290 | * Perform a PS300 command. | |
291 | */ | |
292 | ikcommand(dev, com, count) | |
93d65f53 SL |
293 | dev_t dev; |
294 | int com, count; | |
6fcffbdd | 295 | { |
93d65f53 SL |
296 | register struct buf *bp; |
297 | register int s; | |
298 | ||
299 | bp = &cikbuf[IKUNIT(dev)]; | |
300 | s = splik(); | |
301 | while (bp->b_flags&B_BUSY) { | |
302 | if (bp->b_flags&B_DONE) | |
303 | break; | |
304 | bp->b_flags |= B_WANTED; | |
305 | sleep((caddr_t)bp, PRIBIO); | |
306 | } | |
307 | bp->b_flags = B_BUSY|B_READ; | |
308 | splx(s); | |
309 | bp->b_dev = dev; | |
310 | bp->b_command = com; | |
311 | bp->b_bcount = count; | |
312 | ikstrategy(bp); | |
313 | biowait(bp); | |
314 | if (bp->b_flags&B_WANTED) | |
315 | wakeup((caddr_t)bp); | |
316 | bp->b_flags &= B_ERROR; | |
317 | return (geterror(bp)); | |
6fcffbdd SL |
318 | } |
319 | ||
320 | /* | |
321 | * Physio strategy routine | |
322 | */ | |
323 | ikstrategy(bp) | |
93d65f53 | 324 | register struct buf *bp; |
6fcffbdd | 325 | { |
93d65f53 SL |
326 | register struct buf *dp; |
327 | ||
328 | /* | |
329 | * Put request at end of controller queue. | |
330 | */ | |
331 | dp = &iktab[IKUNIT(bp->b_dev)]; | |
332 | bp->av_forw = NULL; | |
333 | (void) splik(); | |
334 | if (dp->b_actf != NULL) { | |
335 | dp->b_actl->av_forw = bp; | |
336 | dp->b_actl = bp; | |
337 | } else | |
338 | dp->b_actf = dp->b_actl = bp; | |
339 | if (!dp->b_active) | |
340 | ikstart(dp); | |
341 | (void) spl0(); | |
6fcffbdd SL |
342 | } |
343 | ||
344 | /* | |
345 | * Start the next command on the controller's queue. | |
346 | */ | |
347 | ikstart(dp) | |
93d65f53 | 348 | register struct buf *dp; |
6fcffbdd | 349 | { |
93d65f53 SL |
350 | register struct buf *bp; |
351 | register struct ikdevice *ik; | |
352 | register struct ik_softc *sc; | |
93d65f53 SL |
353 | u_short bc, csr; |
354 | u_int addr; | |
355 | int unit; | |
6fcffbdd SL |
356 | |
357 | loop: | |
93d65f53 SL |
358 | /* |
359 | * Pull a request off the controller queue | |
360 | */ | |
361 | if ((bp = dp->b_actf) == NULL) { | |
362 | dp->b_active = 0; | |
363 | return; | |
364 | } | |
365 | /* | |
366 | * Mark controller busy and process this request. | |
367 | */ | |
368 | dp->b_active = 1; | |
369 | unit = IKUNIT(bp->b_dev); | |
370 | sc = &ik_softc[unit]; | |
371 | ik = (struct ikdevice *)ikinfo[unit]->ui_addr; | |
9d61b7ff | 372 | switch ((int)bp->b_command) { |
93d65f53 SL |
373 | |
374 | case PS_ATTACH: /* logical unit attach */ | |
375 | case PS_DETACH: /* logical unit detach */ | |
376 | case PS_LOOKUP: /* name lookup */ | |
377 | case PS_RDPHY: /* physical i/o read */ | |
378 | case PS_WRPHY: /* physical i/o write */ | |
379 | case PS_WRPHY_SYNC: /* physical i/o write w/ sync */ | |
380 | /* | |
381 | * Handshake command and, optionally, | |
382 | * byte count and byte swap flag. | |
383 | */ | |
9d61b7ff | 384 | if (sc->is_error = diowrite(ik, (u_short)bp->b_command)) |
93d65f53 SL |
385 | goto bad; |
386 | if (bp->b_command < PS_DETACH) { | |
9d61b7ff | 387 | if (sc->is_error = diowrite(ik, (u_short)bp->b_bcount)) |
93d65f53 | 388 | goto bad; |
9d61b7ff | 389 | if (sc->is_error = diowrite(ik, (u_short)0 /* !swab */)) |
93d65f53 SL |
390 | goto bad; |
391 | } | |
392 | /* | |
393 | * Set timeout and wait for an attention interrupt. | |
394 | */ | |
395 | sc->is_timeout = iktimeout; | |
396 | return; | |
397 | ||
398 | case PS_DMAOUT: /* dma data host->PS300 */ | |
399 | bc = bp->b_bcount; | |
400 | csr = IKCSR_CYCLE; | |
401 | break; | |
402 | ||
403 | case PS_DMAIN: /* dma data PS300->host */ | |
404 | bc = bp->b_bcount; | |
405 | csr = IKCSR_CYCLE|IKCSR_FNC1; | |
406 | break; | |
407 | ||
408 | default: | |
409 | log(LOG_ERR, "ik%d: bad cmd %x\n", unit, bp->b_command); | |
410 | sc->is_error = PSERROR_BADCMD; | |
411 | goto bad; | |
412 | } | |
413 | /* initiate dma transfer */ | |
9d61b7ff | 414 | addr = vtoph((struct proc *)0, (unsigned)sc->is_buf); |
93d65f53 SL |
415 | ik->ik_bahi = addr >> 17; |
416 | ik->ik_balo = (addr >> 1) & 0xffff; | |
417 | ik->ik_wc = ((bc + 1) >> 1) - 1; /* round & convert */ | |
418 | ik->ik_pulse = IKPULSE_RATTF|IKPULSE_RDMAF; | |
419 | sc->is_timeout = iktimeout; | |
420 | ik->ik_csr = IKCSR_IENA|IKCSR_GO|csr; | |
421 | return; | |
6fcffbdd | 422 | bad: |
93d65f53 SL |
423 | bp->b_flags |= B_ERROR; |
424 | dp->b_actf = bp->av_forw; /* remove from queue */ | |
425 | biodone(bp); | |
426 | goto loop; | |
6fcffbdd SL |
427 | } |
428 | ||
429 | #define FETCHWORD(i) { \ | |
93d65f53 SL |
430 | v = dioread(ik); \ |
431 | if (v == -1) { \ | |
432 | sc->is_error = PSERROR_NAMETIMO; \ | |
433 | goto bad; \ | |
434 | } \ | |
435 | sc->is_nameaddr.w[i] = v; \ | |
6fcffbdd SL |
436 | } |
437 | ||
438 | /* | |
439 | * Process a device interrupt. | |
440 | */ | |
441 | ikintr(ikon) | |
93d65f53 | 442 | int ikon; |
6fcffbdd | 443 | { |
93d65f53 SL |
444 | register struct ikdevice *ik; |
445 | register struct buf *bp, *dp; | |
446 | struct ik_softc *sc; | |
447 | register u_short data; | |
9d61b7ff | 448 | int v; |
93d65f53 SL |
449 | |
450 | /* should go by controller, but for now... */ | |
451 | if (ikinfo[ikon] == 0) | |
452 | return; | |
453 | ik = (struct ikdevice *)ikinfo[ikon]->ui_addr; | |
454 | /* | |
455 | * Discard all non-attention interrupts. The | |
456 | * interrupts we're throwing away should all be | |
457 | * associated with DMA completion. | |
458 | */ | |
459 | data = ik->ik_data; | |
460 | if ((ik->ik_csr&(IKCSR_ATTF|IKCSR_STATC)) != IKCSR_ATTF) { | |
461 | ik->ik_pulse = IKPULSE_RATTF|IKPULSE_RDMAF|IKPULSE_SIENA; | |
462 | return; | |
463 | } | |
464 | /* | |
465 | * Fetch attention code immediately. | |
466 | */ | |
467 | ik->ik_csr = IKCSR_RATTF|IKCSR_RDMAF|IKCSR_FNC1; | |
468 | ik->ik_pulse = IKPULSE_FNC2; | |
469 | /* | |
470 | * Get device and block structures, and a pointer | |
471 | * to the vba_device for the device. We receive an | |
472 | * unsolicited interrupt whenever the PS300 is power | |
473 | * cycled (so ignore it in that case). | |
474 | */ | |
475 | dp = &iktab[ikon]; | |
476 | if ((bp = dp->b_actf) == NULL) { | |
477 | if (PS_CODE(data) != PS_RESET) /* power failure */ | |
478 | log(LOG_WARNING, "ik%d: spurious interrupt, code %x\n", | |
479 | ikon, data); | |
480 | goto enable; | |
481 | } | |
482 | sc = &ik_softc[IKUNIT(bp->b_dev)]; | |
483 | sc->is_timeout = 0; /* disable timer */ | |
484 | switch (PS_CODE(data)) { | |
485 | ||
486 | case PS_LOOKUP: /* name lookup */ | |
487 | if (data == PS_LOOKUP) { /* dma name */ | |
488 | bp->b_command = PS_DMAOUT; | |
489 | goto opcont; | |
490 | } | |
491 | if (data == PS_DMAOK(PS_LOOKUP)) { | |
492 | /* reenable interrupt and wait for address */ | |
493 | sc->is_timeout = iktimeout; | |
494 | goto enable; | |
495 | } | |
496 | /* | |
497 | * Address should be present, extract it one | |
498 | * word at a time from the PS300 (yech). | |
499 | */ | |
500 | if (data != PS_ADROK(PS_LOOKUP)) | |
501 | goto bad; | |
502 | FETCHWORD(0); | |
503 | FETCHWORD(1); | |
504 | goto opdone; | |
505 | ||
506 | case PS_WRPHY_SYNC: /* physical i/o write w/ sync */ | |
507 | if (data == PS_WRPHY_SYNC) { /* start dma transfer */ | |
508 | bp->b_command = PS_DMAOUT; | |
509 | goto opcont; | |
510 | } | |
511 | if (data != PS_DMAOK(PS_WRPHY_SYNC)) | |
512 | goto bad; | |
513 | goto opdone; | |
514 | ||
515 | case PS_WRPHY: /* physical i/o write */ | |
516 | if (data == PS_WRPHY) { /* start dma transfer */ | |
517 | bp->b_command = PS_DMAOUT; | |
518 | goto opcont; | |
519 | } | |
520 | if (data != PS_DMAOK(PS_WRPHY)) | |
521 | goto bad; | |
522 | goto opdone; | |
523 | ||
524 | case PS_ATTACH: /* attach unit */ | |
525 | case PS_DETACH: /* detach unit */ | |
526 | case PS_ABORT: /* abort code from ps300 */ | |
527 | if (data != bp->b_command) | |
528 | goto bad; | |
529 | goto opdone; | |
530 | ||
531 | case PS_RDPHY: /* physical i/o read */ | |
532 | if (data == PS_RDPHY) { /* dma address list */ | |
533 | bp->b_command = PS_DMAOUT; | |
534 | goto opcont; | |
535 | } | |
536 | if (data == PS_ADROK(PS_RDPHY)) { | |
537 | /* collect read byte count and start dma */ | |
538 | bp->b_bcount = dioread(ik); | |
539 | if (bp->b_bcount == -1) | |
540 | goto bad; | |
541 | bp->b_command = PS_DMAIN; | |
542 | goto opcont; | |
543 | } | |
544 | if (data == PS_DMAOK(PS_RDPHY)) | |
545 | goto opdone; | |
546 | goto bad; | |
547 | } | |
6fcffbdd | 548 | bad: |
93d65f53 SL |
549 | sc->is_error = data; |
550 | bp->b_flags |= B_ERROR; | |
6fcffbdd | 551 | opdone: |
93d65f53 SL |
552 | dp->b_actf = bp->av_forw; /* remove from queue */ |
553 | biodone(bp); | |
6fcffbdd | 554 | opcont: |
93d65f53 | 555 | ikstart(dp); |
6fcffbdd | 556 | enable: |
93d65f53 | 557 | ik->ik_pulse = IKPULSE_SIENA; /* explicitly reenable */ |
6fcffbdd SL |
558 | } |
559 | ||
560 | /* | |
561 | * Watchdog timer. | |
562 | */ | |
563 | iktimer(unit) | |
93d65f53 | 564 | int unit; |
6fcffbdd | 565 | { |
93d65f53 SL |
566 | register struct ik_softc *sc = &ik_softc[unit]; |
567 | ||
568 | if (sc->is_timeout && --sc->is_timeout == 0) { | |
569 | register struct buf *dp, *bp; | |
570 | int s; | |
571 | ||
572 | log(LOG_ERR, "ik%d: timeout\n", unit); | |
573 | s = splik(); | |
574 | /* should abort current command */ | |
575 | dp = &iktab[unit]; | |
576 | if (bp = dp->b_actf) { | |
577 | sc->is_error = PSERROR_CMDTIMO; | |
578 | bp->b_flags |= B_ERROR; | |
579 | dp->b_actf = bp->av_forw; /* remove from queue */ | |
580 | biodone(bp); | |
581 | ikstart(dp); | |
582 | } | |
583 | splx(s); | |
584 | } | |
9d61b7ff | 585 | timeout(iktimer, (caddr_t)unit, hz); |
6fcffbdd SL |
586 | } |
587 | ||
588 | /* | |
589 | * Handshake read from DR300. | |
590 | */ | |
591 | dioread(ik) | |
93d65f53 | 592 | register struct ikdevice *ik; |
6fcffbdd | 593 | { |
9d61b7ff | 594 | register int t; |
93d65f53 SL |
595 | u_short data; |
596 | ||
9d61b7ff | 597 | for (t = ikdiotimo; t > 0; t--) |
93d65f53 SL |
598 | if ((ik->ik_csr&(IKCSR_ATTF|IKCSR_STATC)) == IKCSR_ATTF) { |
599 | data = ik->ik_data; | |
600 | ik->ik_csr = IKCSR_RATTF|IKCSR_RDMAF|IKCSR_FNC1; | |
601 | ik->ik_pulse = IKPULSE_FNC2; | |
602 | return (data); | |
603 | } | |
604 | return (-1); | |
6fcffbdd SL |
605 | } |
606 | ||
607 | /* | |
608 | * Handshake write to DR300. | |
609 | * | |
610 | * Interrupts are enabled before completing the work | |
611 | * so the caller should either be at splik or be | |
612 | * prepared to take the interrupt immediately. | |
613 | */ | |
614 | diowrite(ik, v) | |
93d65f53 SL |
615 | register struct ikdevice *ik; |
616 | u_short v; | |
6fcffbdd | 617 | { |
9d61b7ff | 618 | register int t; |
93d65f53 | 619 | register u_short csr; |
6fcffbdd SL |
620 | |
621 | top: | |
93d65f53 SL |
622 | /* |
623 | * Deposit data and generate dr300 attention | |
624 | */ | |
625 | ik->ik_data = v; | |
626 | ik->ik_csr = IKCSR_RDMAF|IKCSR_RATTF; | |
627 | ik->ik_pulse = IKPULSE_FNC2; | |
9d61b7ff | 628 | for (t = ikdiotimo; t > 0; t--) { |
93d65f53 SL |
629 | csr = ik->ik_csr; |
630 | #define IKCSR_DONE (IKCSR_STATA|IKCSR_STATC) | |
631 | if ((csr&IKCSR_DONE) == IKCSR_DONE) { | |
632 | /* | |
633 | * Done, complete handshake by notifying dr300. | |
634 | */ | |
635 | ik->ik_csr = IKCSR_IENA; /* ~IKCSR_FNC1 */ | |
636 | ik->ik_pulse = IKPULSE_FNC2; | |
637 | return (0); | |
638 | } | |
639 | /* beware of potential deadlock with dioread */ | |
640 | if ((csr&(IKCSR_ATTF|IKCSR_STATC)) == IKCSR_ATTF) | |
641 | goto top; | |
642 | } | |
643 | ik->ik_csr = IKCSR_IENA; | |
644 | return (PSERROR_DIOTIMO); | |
6fcffbdd SL |
645 | } |
646 | ||
647 | /*ARGSUSED*/ | |
648 | ikioctl(dev, cmd, data, flag) | |
93d65f53 SL |
649 | dev_t dev; |
650 | int cmd; | |
651 | caddr_t data; | |
652 | int flag; | |
6fcffbdd | 653 | { |
93d65f53 SL |
654 | int error = 0, unit = IKUNIT(dev), s; |
655 | register struct ik_softc *sc = &ik_softc[unit]; | |
656 | ||
657 | switch (cmd) { | |
658 | ||
659 | case PSIOGETERROR: /* get error code for last operation */ | |
660 | *(int *)data = sc->is_error; | |
661 | break; | |
662 | ||
663 | case PSIOLOOKUP: { /* PS300 name lookup */ | |
664 | register struct pslookup *lp = (struct pslookup *)data; | |
665 | register struct buf *bp; | |
666 | ||
667 | if (lp->pl_len > PS_MAXNAMELEN) | |
668 | return (EINVAL); | |
669 | bp = &rikbuf[unit]; | |
670 | s = splbio(); | |
671 | while (bp->b_flags&B_BUSY) { | |
672 | bp->b_flags |= B_WANTED; | |
673 | sleep((caddr_t)bp, PRIBIO+1); | |
674 | } | |
675 | splx(s); | |
676 | bp->b_flags = B_BUSY | B_WRITE; | |
5db86c85 MK |
677 | error = copyin(lp->pl_name, (caddr_t)sc->is_buf, |
678 | (unsigned)lp->pl_len); | |
93d65f53 SL |
679 | if (error == 0) { |
680 | if (lp->pl_len&1) | |
681 | sc->is_buf[lp->pl_len] = '\0'; | |
682 | error = ikcommand(dev, PS_LOOKUP, lp->pl_len); | |
683 | } | |
684 | s = splbio(); | |
685 | if (bp->b_flags&B_WANTED) | |
686 | wakeup((caddr_t)bp); | |
687 | splx(s); | |
688 | bp->b_flags &= ~(B_BUSY|B_WANTED); | |
689 | lp->pl_addr = sc->is_nameaddr.l; | |
690 | break; | |
691 | } | |
692 | default: | |
693 | return (ENOTTY); | |
694 | } | |
695 | return (error); | |
6fcffbdd SL |
696 | } |
697 | #endif |