134506Skarels /*
235514Sbostic * Copyright (c) 1986 The Regents of the University of California.
335514Sbostic * All rights reserved.
435514Sbostic *
544534Sbostic * %sccs.include.redist.c%
635514Sbostic *
7*45798Sbostic * @(#)ik.c 7.7 (Berkeley) 12/16/90
834506Skarels */
930222Ssam
1030222Ssam #include "ik.h"
1130222Ssam #if NIK > 0
1230222Ssam /*
1330222Ssam * PS300/IKON DR-11W Device Driver.
1430222Ssam */
15*45798Sbostic #include "sys/param.h"
16*45798Sbostic #include "sys/buf.h"
17*45798Sbostic #include "sys/cmap.h"
18*45798Sbostic #include "sys/conf.h"
19*45798Sbostic #include "sys/dkstat.h"
20*45798Sbostic #include "sys/map.h"
21*45798Sbostic #include "sys/systm.h"
22*45798Sbostic #include "sys/user.h"
23*45798Sbostic #include "sys/vmmac.h"
24*45798Sbostic #include "sys/proc.h"
25*45798Sbostic #include "sys/kernel.h"
26*45798Sbostic #include "sys/syslog.h"
2730222Ssam
28*45798Sbostic #include "../include/mtpr.h"
29*45798Sbostic #include "../include/pte.h"
3030222Ssam
31*45798Sbostic #include "../vba/vbavar.h"
32*45798Sbostic #include "../vba/ikreg.h"
33*45798Sbostic #include "../vba/psreg.h"
34*45798Sbostic #include "../vba/psproto.h"
3530222Ssam
3630286Ssam int ikprobe(), ikattach(), iktimer();
3730286Ssam struct vba_device *ikinfo[NIK];
3830286Ssam long ikstd[] = { 0 };
3930286Ssam struct vba_driver ikdriver = { ikprobe, 0, ikattach, 0, ikstd, "ik", ikinfo };
4030222Ssam
4130286Ssam #define splik() spl4()
4230222Ssam /*
4330222Ssam * Devices are organized in pairs with the odd valued
4430222Ssam * device being used for ``diagnostic'' purposes. That
4530222Ssam * is diagnostic devices don't get auto-attach'd and
4630222Ssam * detach'd on open-close.
4730222Ssam */
4830286Ssam #define IKUNIT(dev) (minor(dev) >> 1)
4930286Ssam #define IKDIAG(dev) (minor(dev) & 01) /* is a diagnostic unit */
5030222Ssam
5130286Ssam struct ik_softc {
5230286Ssam uid_t is_uid; /* uid of open processes */
5330286Ssam u_short is_timeout; /* current timeout (seconds) */
5430286Ssam u_short is_error; /* internal error codes */
5530286Ssam u_short is_flags;
5630286Ssam #define IKF_ATTACHED 0x1 /* unit is attached (not used yet) */
5730286Ssam union {
5830286Ssam u_short w[2];
5930286Ssam u_long l;
6030286Ssam } is_nameaddr; /* address of last symbol lookup */
6130344Ssam caddr_t is_buf[PS_MAXDMA];/* i/o buffer XXX */
6230222Ssam } ik_softc[NIK];
6330222Ssam
6430286Ssam struct buf iktab[NIK]; /* unit command queue headers */
6530286Ssam struct buf rikbuf[NIK]; /* buffers for read/write operations */
6630286Ssam struct buf cikbuf[NIK]; /* buffers for control operations */
6730222Ssam
6830222Ssam /* buf overlay definitions */
6930286Ssam #define b_command b_resid
7030222Ssam
7130286Ssam int ikdiotimo = PS_DIOTIMO; /* dio polling timeout */
7230286Ssam int iktimeout = PS_TIMEOUT; /* attention/dma timeout (in hz) */
7330222Ssam
ikprobe(reg,vi)7430222Ssam ikprobe(reg, vi)
7530286Ssam caddr_t reg;
7630222Ssam struct vba_device *vi;
7730222Ssam {
7830286Ssam register int br, cvec; /* r12, r11 */
7930222Ssam register struct ikdevice *ik;
8030222Ssam
8130294Ssam #ifdef lint
8230294Ssam br = 0; cvec = br; br = cvec;
8330294Ssam ikintr(0);
8430294Ssam #endif
8530286Ssam if (badaddr(reg, 2))
8630286Ssam return (0);
8730222Ssam ik = (struct ikdevice *)reg;
8830222Ssam ik->ik_vec = --vi->ui_hd->vh_lastiv;
8930286Ssam /*
9030344Ssam * Use extended non-privileged address modifier
9130344Ssam * to avoid address overlap with 24-bit devices.
9230286Ssam */
9330286Ssam ik->ik_mod = 0xf1; /* address modifier */
9430286Ssam /*
9530286Ssam * Try and reset the PS300. Since this
9630286Ssam * won't work if it's powered off, we
9730286Ssam * can't use sucess/failure to decide
9830286Ssam * if the device is present.
9930286Ssam */
10030222Ssam br = 0;
10130286Ssam (void) psreset(ik, IKCSR_IENA);
10230286Ssam if (br == 0) /* XXX */
10330222Ssam br = 0x18, cvec = ik->ik_vec; /* XXX */
10430286Ssam return (sizeof (struct ikdevice));
10530222Ssam }
10630222Ssam
10730222Ssam /*
10830222Ssam * Perform a ``hard'' reset.
10930222Ssam */
psreset(ik,iena)11030222Ssam psreset(ik, iena)
11130286Ssam register struct ikdevice *ik;
11230222Ssam {
11330222Ssam
11430286Ssam ik->ik_csr = IKCSR_MCLR|iena;
11530286Ssam DELAY(10000);
11630286Ssam ik->ik_csr = IKCSR_FNC3|iena;
11730286Ssam if (!iena)
11830286Ssam return (dioread(ik) == PS_RESET);
11930286Ssam return (1);
12030222Ssam }
12130222Ssam
12230222Ssam ikattach(vi)
12330286Ssam struct vba_device *vi;
12430222Ssam {
12530222Ssam
12630286Ssam ik_softc[vi->ui_unit].is_uid = -1;
12730222Ssam }
12830222Ssam
12930222Ssam /*
13030222Ssam * Open a PS300 and attach. We allow multiple
13130222Ssam * processes with the same uid to share a unit.
13230222Ssam */
13330222Ssam /*ARGSUSED*/
ikopen(dev,flag)13430222Ssam ikopen(dev, flag)
13530286Ssam dev_t dev;
13630286Ssam int flag;
13730222Ssam {
13830286Ssam register int unit = IKUNIT(dev);
13930286Ssam register struct ik_softc *sc;
14030286Ssam struct vba_device *vi;
14130286Ssam struct ikdevice *ik;
14230286Ssam int reset;
14330222Ssam
14430286Ssam if (unit >= NIK || (vi = ikinfo[unit]) == 0 || vi->ui_alive == 0)
14530286Ssam return (ENXIO);
14630286Ssam sc = &ik_softc[unit];
14730294Ssam if (sc->is_uid != (uid_t)-1 && sc->is_uid != u.u_uid)
14830286Ssam return (EBUSY);
14930294Ssam if (sc->is_uid == (uid_t)-1) {
15030286Ssam sc->is_timeout = 0;
15130294Ssam timeout(iktimer, (caddr_t)unit, hz);
15230286Ssam /*
15330286Ssam * Perform PS300 attach for first process.
15430286Ssam */
15530286Ssam if (!IKDIAG(dev)) {
15630286Ssam reset = 0;
15730286Ssam again:
15830286Ssam if (ikcommand(dev, PS_ATTACH, 1)) {
15930286Ssam /*
16030286Ssam * If attach fails, perform a hard
16130286Ssam * reset once, then retry the command.
16230286Ssam */
16330286Ssam ik = (struct ikdevice *)ikinfo[unit]->ui_addr;
16430286Ssam if (!reset++ && psreset(ik, 0))
16530286Ssam goto again;
16630294Ssam untimeout(iktimer, (caddr_t)unit);
16730286Ssam return (EIO);
16830286Ssam }
16930286Ssam }
17030286Ssam sc->is_uid = u.u_uid;
17130286Ssam }
17230286Ssam return (0);
17330222Ssam }
17430222Ssam
17530222Ssam /*ARGSUSED*/
ikclose(dev,flag)17630222Ssam ikclose(dev, flag)
17730286Ssam dev_t dev;
17830286Ssam int flag;
17930222Ssam {
18030286Ssam int unit = IKUNIT(dev);
18130222Ssam register struct ik_softc *sc = &ik_softc[unit];
18230222Ssam
18330286Ssam if (!IKDIAG(dev))
18430286Ssam (void) ikcommand(dev, PS_DETACH, 1); /* auto detach */
18530286Ssam sc->is_uid = -1;
18630294Ssam untimeout(iktimer, (caddr_t)unit);
18740735Skarels return (0);
18830222Ssam }
18930222Ssam
ikread(dev,uio)19030222Ssam ikread(dev, uio)
19130286Ssam dev_t dev;
19230286Ssam struct uio *uio;
19330222Ssam {
19430222Ssam
19530286Ssam return (ikrw(dev, uio, B_READ));
19630222Ssam }
19730222Ssam
ikwrite(dev,uio)19830222Ssam ikwrite(dev, uio)
19930286Ssam dev_t dev;
20030286Ssam struct uio *uio;
20130222Ssam {
20230222Ssam
20330286Ssam return (ikrw(dev, uio, B_WRITE));
20430222Ssam }
20530222Ssam
20630222Ssam /*
20730222Ssam * Take read/write request and perform physical i/o
20830222Ssam * transaction with PS300. This involves constructing
20930222Ssam * a physical i/o request vector based on the uio
21030222Ssam * vector, performing the dma, and, finally, moving
21130222Ssam * the data to it's final destination (because of CCI
21230222Ssam * VERSAbus bogosities).
21330222Ssam */
ikrw(dev,uio,rw)21430222Ssam ikrw(dev, uio, rw)
21530286Ssam dev_t dev;
21630286Ssam register struct uio *uio;
21730286Ssam int rw;
21830222Ssam {
21930286Ssam int error, unit = IKUNIT(dev), s, wrcmd;
22030286Ssam register struct buf *bp;
22130286Ssam register struct iovec *iov;
22230286Ssam register struct psalist *ap;
22330286Ssam struct ik_softc *sc = &ik_softc[unit];
22430222Ssam
22530286Ssam if (unit >= NIK)
22630286Ssam return (ENXIO);
22730286Ssam bp = &rikbuf[unit];
22830286Ssam error = 0, iov = uio->uio_iov, wrcmd = PS_WRPHY;
22930286Ssam for (; !error && uio->uio_iovcnt; iov++, uio->uio_iovcnt--) {
23030286Ssam /*
23130286Ssam * Hack way to set PS300 address w/o doing an lseek
23230286Ssam * and specify write physical w/ refresh synchronization.
23330286Ssam */
23430286Ssam if (iov->iov_len == 0) {
23530286Ssam if ((int)iov->iov_base&PSIO_SYNC)
23630286Ssam wrcmd = PS_WRPHY_SYNC;
23730286Ssam uio->uio_offset = (int)iov->iov_base & ~PSIO_SYNC;
23830286Ssam continue;
23930286Ssam }
24030286Ssam if (iov->iov_len > PS_MAXDMA) {
24130286Ssam sc->is_error = PSERROR_INVALBC, error = EINVAL;
24230286Ssam continue;
24330286Ssam }
24430286Ssam if ((int)uio->uio_offset&01) {
24530286Ssam sc->is_error = PSERROR_BADADDR, error = EINVAL;
24630286Ssam continue;
24730286Ssam }
24830286Ssam s = splbio();
24930286Ssam while (bp->b_flags&B_BUSY) {
25030286Ssam bp->b_flags |= B_WANTED;
25130286Ssam sleep((caddr_t)bp, PRIBIO+1);
25230286Ssam }
25330286Ssam splx(s);
25430286Ssam bp->b_flags = B_BUSY | rw;
25530286Ssam /*
25630286Ssam * Construct address descriptor in buffer.
25730286Ssam */
25830286Ssam ap = (struct psalist *)sc->is_buf;
25930286Ssam ap->nblocks = 1;
26030286Ssam /* work-around dr300 word swapping */
26130286Ssam ap->addr[0] = uio->uio_offset & 0xffff;
26230286Ssam ap->addr[1] = uio->uio_offset >> 16;
26330286Ssam ap->wc = (iov->iov_len + 1) >> 1;
26430286Ssam if (rw == B_WRITE) {
26530286Ssam error = copyin(iov->iov_base, (caddr_t)&ap[1],
26630294Ssam (unsigned)iov->iov_len);
26730286Ssam if (!error)
26830286Ssam error = ikcommand(dev, wrcmd,
26930286Ssam iov->iov_len + sizeof (*ap));
27030286Ssam } else {
27130286Ssam caddr_t cp;
27230286Ssam int len;
27330222Ssam
27430286Ssam error = ikcommand(dev, PS_RDPHY, sizeof (*ap));
27530286Ssam cp = (caddr_t)&ap[1], len = iov->iov_len;
27630286Ssam for (; len > 0; len -= NBPG, cp += NBPG)
27730286Ssam mtpr(P1DC, cp);
27830286Ssam if (!error)
27930286Ssam error = copyout((caddr_t)&ap[1], iov->iov_base,
28030294Ssam (unsigned)iov->iov_len);
28130286Ssam }
28230286Ssam (void) splbio();
28330286Ssam if (bp->b_flags&B_WANTED)
28430286Ssam wakeup((caddr_t)bp);
28530286Ssam splx(s);
28630286Ssam uio->uio_resid -= iov->iov_len;
28730286Ssam uio->uio_offset += iov->iov_len;
28830286Ssam bp->b_flags &= ~(B_BUSY|B_WANTED);
28930286Ssam }
29030286Ssam return (error);
29130222Ssam }
29230222Ssam
29330222Ssam /*
29430222Ssam * Perform a PS300 command.
29530222Ssam */
ikcommand(dev,com,count)29630222Ssam ikcommand(dev, com, count)
29730286Ssam dev_t dev;
29830286Ssam int com, count;
29930222Ssam {
30030286Ssam register struct buf *bp;
30130286Ssam register int s;
30237772Smckusick int error;
30330222Ssam
30430286Ssam bp = &cikbuf[IKUNIT(dev)];
30530286Ssam s = splik();
30630286Ssam while (bp->b_flags&B_BUSY) {
30730286Ssam if (bp->b_flags&B_DONE)
30830286Ssam break;
30930286Ssam bp->b_flags |= B_WANTED;
31030286Ssam sleep((caddr_t)bp, PRIBIO);
31130286Ssam }
31230286Ssam bp->b_flags = B_BUSY|B_READ;
31330286Ssam splx(s);
31430286Ssam bp->b_dev = dev;
31530286Ssam bp->b_command = com;
31630286Ssam bp->b_bcount = count;
31730286Ssam ikstrategy(bp);
31837772Smckusick error = biowait(bp);
31930286Ssam if (bp->b_flags&B_WANTED)
32030286Ssam wakeup((caddr_t)bp);
32130286Ssam bp->b_flags &= B_ERROR;
32237772Smckusick return (error);
32330222Ssam }
32430222Ssam
32530222Ssam /*
32630222Ssam * Physio strategy routine
32730222Ssam */
ikstrategy(bp)32830222Ssam ikstrategy(bp)
32930286Ssam register struct buf *bp;
33030222Ssam {
33130286Ssam register struct buf *dp;
33230222Ssam
33330286Ssam /*
33430286Ssam * Put request at end of controller queue.
33530286Ssam */
33630286Ssam dp = &iktab[IKUNIT(bp->b_dev)];
33730286Ssam bp->av_forw = NULL;
33830286Ssam (void) splik();
33930286Ssam if (dp->b_actf != NULL) {
34030286Ssam dp->b_actl->av_forw = bp;
34130286Ssam dp->b_actl = bp;
34230286Ssam } else
34330286Ssam dp->b_actf = dp->b_actl = bp;
34430286Ssam if (!dp->b_active)
34530286Ssam ikstart(dp);
34630286Ssam (void) spl0();
34730222Ssam }
34830222Ssam
34930222Ssam /*
35030222Ssam * Start the next command on the controller's queue.
35130222Ssam */
ikstart(dp)35230222Ssam ikstart(dp)
35330286Ssam register struct buf *dp;
35430222Ssam {
35530286Ssam register struct buf *bp;
35630286Ssam register struct ikdevice *ik;
35730286Ssam register struct ik_softc *sc;
35830286Ssam u_short bc, csr;
35930286Ssam u_int addr;
36030286Ssam int unit;
36130222Ssam
36230222Ssam loop:
36330286Ssam /*
36430286Ssam * Pull a request off the controller queue
36530286Ssam */
36630286Ssam if ((bp = dp->b_actf) == NULL) {
36730286Ssam dp->b_active = 0;
36830286Ssam return;
36930286Ssam }
37030286Ssam /*
37130286Ssam * Mark controller busy and process this request.
37230286Ssam */
37330286Ssam dp->b_active = 1;
37430286Ssam unit = IKUNIT(bp->b_dev);
37530286Ssam sc = &ik_softc[unit];
37630286Ssam ik = (struct ikdevice *)ikinfo[unit]->ui_addr;
37730294Ssam switch ((int)bp->b_command) {
37830222Ssam
37930286Ssam case PS_ATTACH: /* logical unit attach */
38030286Ssam case PS_DETACH: /* logical unit detach */
38130286Ssam case PS_LOOKUP: /* name lookup */
38230286Ssam case PS_RDPHY: /* physical i/o read */
38330286Ssam case PS_WRPHY: /* physical i/o write */
38430286Ssam case PS_WRPHY_SYNC: /* physical i/o write w/ sync */
38530286Ssam /*
38630286Ssam * Handshake command and, optionally,
38730286Ssam * byte count and byte swap flag.
38830286Ssam */
38930294Ssam if (sc->is_error = diowrite(ik, (u_short)bp->b_command))
39030286Ssam goto bad;
39130286Ssam if (bp->b_command < PS_DETACH) {
39230294Ssam if (sc->is_error = diowrite(ik, (u_short)bp->b_bcount))
39330286Ssam goto bad;
39430294Ssam if (sc->is_error = diowrite(ik, (u_short)0 /* !swab */))
39530286Ssam goto bad;
39630286Ssam }
39730286Ssam /*
39830286Ssam * Set timeout and wait for an attention interrupt.
39930286Ssam */
40030286Ssam sc->is_timeout = iktimeout;
40130286Ssam return;
40230222Ssam
40330286Ssam case PS_DMAOUT: /* dma data host->PS300 */
40430286Ssam bc = bp->b_bcount;
40530286Ssam csr = IKCSR_CYCLE;
40630286Ssam break;
40730222Ssam
40830286Ssam case PS_DMAIN: /* dma data PS300->host */
40930286Ssam bc = bp->b_bcount;
41030286Ssam csr = IKCSR_CYCLE|IKCSR_FNC1;
41130286Ssam break;
41230222Ssam
41330286Ssam default:
41430286Ssam log(LOG_ERR, "ik%d: bad cmd %x\n", unit, bp->b_command);
41530286Ssam sc->is_error = PSERROR_BADCMD;
41630286Ssam goto bad;
41730286Ssam }
41830286Ssam /* initiate dma transfer */
41930294Ssam addr = vtoph((struct proc *)0, (unsigned)sc->is_buf);
42030286Ssam ik->ik_bahi = addr >> 17;
42130286Ssam ik->ik_balo = (addr >> 1) & 0xffff;
42230286Ssam ik->ik_wc = ((bc + 1) >> 1) - 1; /* round & convert */
42330286Ssam ik->ik_pulse = IKPULSE_RATTF|IKPULSE_RDMAF;
42430286Ssam sc->is_timeout = iktimeout;
42530286Ssam ik->ik_csr = IKCSR_IENA|IKCSR_GO|csr;
42630286Ssam return;
42730222Ssam bad:
42830286Ssam bp->b_flags |= B_ERROR;
42930286Ssam dp->b_actf = bp->av_forw; /* remove from queue */
43030286Ssam biodone(bp);
43130286Ssam goto loop;
43230222Ssam }
43330222Ssam
43430222Ssam #define FETCHWORD(i) { \
43530286Ssam v = dioread(ik); \
43630286Ssam if (v == -1) { \
43730286Ssam sc->is_error = PSERROR_NAMETIMO; \
43830286Ssam goto bad; \
43930286Ssam } \
44030286Ssam sc->is_nameaddr.w[i] = v; \
44130222Ssam }
44230222Ssam
44330222Ssam /*
44430222Ssam * Process a device interrupt.
44530222Ssam */
ikintr(ikon)44630222Ssam ikintr(ikon)
44730286Ssam int ikon;
44830222Ssam {
44930286Ssam register struct ikdevice *ik;
45030286Ssam register struct buf *bp, *dp;
45130286Ssam struct ik_softc *sc;
45230286Ssam register u_short data;
45330294Ssam int v;
45430222Ssam
45530286Ssam /* should go by controller, but for now... */
45630286Ssam if (ikinfo[ikon] == 0)
45730286Ssam return;
45830286Ssam ik = (struct ikdevice *)ikinfo[ikon]->ui_addr;
45930286Ssam /*
46030286Ssam * Discard all non-attention interrupts. The
46130286Ssam * interrupts we're throwing away should all be
46230286Ssam * associated with DMA completion.
46330286Ssam */
46430286Ssam data = ik->ik_data;
46530286Ssam if ((ik->ik_csr&(IKCSR_ATTF|IKCSR_STATC)) != IKCSR_ATTF) {
46630286Ssam ik->ik_pulse = IKPULSE_RATTF|IKPULSE_RDMAF|IKPULSE_SIENA;
46730286Ssam return;
46830286Ssam }
46930286Ssam /*
47030286Ssam * Fetch attention code immediately.
47130286Ssam */
47230286Ssam ik->ik_csr = IKCSR_RATTF|IKCSR_RDMAF|IKCSR_FNC1;
47330286Ssam ik->ik_pulse = IKPULSE_FNC2;
47430286Ssam /*
47530286Ssam * Get device and block structures, and a pointer
47630286Ssam * to the vba_device for the device. We receive an
47730286Ssam * unsolicited interrupt whenever the PS300 is power
47830286Ssam * cycled (so ignore it in that case).
47930286Ssam */
48030286Ssam dp = &iktab[ikon];
48130286Ssam if ((bp = dp->b_actf) == NULL) {
48230286Ssam if (PS_CODE(data) != PS_RESET) /* power failure */
48330286Ssam log(LOG_WARNING, "ik%d: spurious interrupt, code %x\n",
48430286Ssam ikon, data);
48530286Ssam goto enable;
48630286Ssam }
48730286Ssam sc = &ik_softc[IKUNIT(bp->b_dev)];
48830286Ssam sc->is_timeout = 0; /* disable timer */
48930286Ssam switch (PS_CODE(data)) {
49030222Ssam
49130286Ssam case PS_LOOKUP: /* name lookup */
49230286Ssam if (data == PS_LOOKUP) { /* dma name */
49330286Ssam bp->b_command = PS_DMAOUT;
49430286Ssam goto opcont;
49530286Ssam }
49630286Ssam if (data == PS_DMAOK(PS_LOOKUP)) {
49730286Ssam /* reenable interrupt and wait for address */
49830286Ssam sc->is_timeout = iktimeout;
49930286Ssam goto enable;
50030286Ssam }
50130286Ssam /*
50230286Ssam * Address should be present, extract it one
50330286Ssam * word at a time from the PS300 (yech).
50430286Ssam */
50530286Ssam if (data != PS_ADROK(PS_LOOKUP))
50630286Ssam goto bad;
50730286Ssam FETCHWORD(0);
50830286Ssam FETCHWORD(1);
50930286Ssam goto opdone;
51030222Ssam
51130286Ssam case PS_WRPHY_SYNC: /* physical i/o write w/ sync */
51230286Ssam if (data == PS_WRPHY_SYNC) { /* start dma transfer */
51330286Ssam bp->b_command = PS_DMAOUT;
51430286Ssam goto opcont;
51530286Ssam }
51630286Ssam if (data != PS_DMAOK(PS_WRPHY_SYNC))
51730286Ssam goto bad;
51830286Ssam goto opdone;
51930222Ssam
52030286Ssam case PS_WRPHY: /* physical i/o write */
52130286Ssam if (data == PS_WRPHY) { /* start dma transfer */
52230286Ssam bp->b_command = PS_DMAOUT;
52330286Ssam goto opcont;
52430286Ssam }
52530286Ssam if (data != PS_DMAOK(PS_WRPHY))
52630286Ssam goto bad;
52730286Ssam goto opdone;
52830222Ssam
52930286Ssam case PS_ATTACH: /* attach unit */
53030286Ssam case PS_DETACH: /* detach unit */
53130286Ssam case PS_ABORT: /* abort code from ps300 */
53230286Ssam if (data != bp->b_command)
53330286Ssam goto bad;
53430286Ssam goto opdone;
53530222Ssam
53630286Ssam case PS_RDPHY: /* physical i/o read */
53730286Ssam if (data == PS_RDPHY) { /* dma address list */
53830286Ssam bp->b_command = PS_DMAOUT;
53930286Ssam goto opcont;
54030286Ssam }
54130286Ssam if (data == PS_ADROK(PS_RDPHY)) {
54230286Ssam /* collect read byte count and start dma */
54330286Ssam bp->b_bcount = dioread(ik);
54430286Ssam if (bp->b_bcount == -1)
54530286Ssam goto bad;
54630286Ssam bp->b_command = PS_DMAIN;
54730286Ssam goto opcont;
54830286Ssam }
54930286Ssam if (data == PS_DMAOK(PS_RDPHY))
55030286Ssam goto opdone;
55130286Ssam goto bad;
55230286Ssam }
55330222Ssam bad:
55430286Ssam sc->is_error = data;
55530286Ssam bp->b_flags |= B_ERROR;
55630222Ssam opdone:
55730286Ssam dp->b_actf = bp->av_forw; /* remove from queue */
55830286Ssam biodone(bp);
55930222Ssam opcont:
56030286Ssam ikstart(dp);
56130222Ssam enable:
56230286Ssam ik->ik_pulse = IKPULSE_SIENA; /* explicitly reenable */
56330222Ssam }
56430222Ssam
56530222Ssam /*
56630222Ssam * Watchdog timer.
56730222Ssam */
iktimer(unit)56830222Ssam iktimer(unit)
56930286Ssam int unit;
57030222Ssam {
57130286Ssam register struct ik_softc *sc = &ik_softc[unit];
57230222Ssam
57330286Ssam if (sc->is_timeout && --sc->is_timeout == 0) {
57430286Ssam register struct buf *dp, *bp;
57530286Ssam int s;
57630222Ssam
57730286Ssam log(LOG_ERR, "ik%d: timeout\n", unit);
57830286Ssam s = splik();
57930286Ssam /* should abort current command */
58030286Ssam dp = &iktab[unit];
58130286Ssam if (bp = dp->b_actf) {
58230286Ssam sc->is_error = PSERROR_CMDTIMO;
58330286Ssam bp->b_flags |= B_ERROR;
58430286Ssam dp->b_actf = bp->av_forw; /* remove from queue */
58530286Ssam biodone(bp);
58630286Ssam ikstart(dp);
58730286Ssam }
58830286Ssam splx(s);
58930286Ssam }
59030294Ssam timeout(iktimer, (caddr_t)unit, hz);
59130222Ssam }
59230222Ssam
59330222Ssam /*
59430222Ssam * Handshake read from DR300.
59530222Ssam */
dioread(ik)59630222Ssam dioread(ik)
59730286Ssam register struct ikdevice *ik;
59830222Ssam {
59930294Ssam register int t;
60030286Ssam u_short data;
60130222Ssam
60230294Ssam for (t = ikdiotimo; t > 0; t--)
60330286Ssam if ((ik->ik_csr&(IKCSR_ATTF|IKCSR_STATC)) == IKCSR_ATTF) {
60430286Ssam data = ik->ik_data;
60530286Ssam ik->ik_csr = IKCSR_RATTF|IKCSR_RDMAF|IKCSR_FNC1;
60630286Ssam ik->ik_pulse = IKPULSE_FNC2;
60730286Ssam return (data);
60830286Ssam }
60930286Ssam return (-1);
61030222Ssam }
61130222Ssam
61230222Ssam /*
61330222Ssam * Handshake write to DR300.
61430222Ssam *
61530222Ssam * Interrupts are enabled before completing the work
61630222Ssam * so the caller should either be at splik or be
61730222Ssam * prepared to take the interrupt immediately.
61830222Ssam */
diowrite(ik,v)61930222Ssam diowrite(ik, v)
62030286Ssam register struct ikdevice *ik;
62130286Ssam u_short v;
62230222Ssam {
62330294Ssam register int t;
62430286Ssam register u_short csr;
62530222Ssam
62630222Ssam top:
62730286Ssam /*
62830286Ssam * Deposit data and generate dr300 attention
62930286Ssam */
63030286Ssam ik->ik_data = v;
63130286Ssam ik->ik_csr = IKCSR_RDMAF|IKCSR_RATTF;
63230286Ssam ik->ik_pulse = IKPULSE_FNC2;
63330294Ssam for (t = ikdiotimo; t > 0; t--) {
63430286Ssam csr = ik->ik_csr;
63530286Ssam #define IKCSR_DONE (IKCSR_STATA|IKCSR_STATC)
63630286Ssam if ((csr&IKCSR_DONE) == IKCSR_DONE) {
63730286Ssam /*
63830286Ssam * Done, complete handshake by notifying dr300.
63930286Ssam */
64030286Ssam ik->ik_csr = IKCSR_IENA; /* ~IKCSR_FNC1 */
64130286Ssam ik->ik_pulse = IKPULSE_FNC2;
64230286Ssam return (0);
64330286Ssam }
64430286Ssam /* beware of potential deadlock with dioread */
64530286Ssam if ((csr&(IKCSR_ATTF|IKCSR_STATC)) == IKCSR_ATTF)
64630286Ssam goto top;
64730286Ssam }
64830286Ssam ik->ik_csr = IKCSR_IENA;
64930286Ssam return (PSERROR_DIOTIMO);
65030222Ssam }
65130222Ssam
65230222Ssam /*ARGSUSED*/
ikioctl(dev,cmd,data,flag)65330222Ssam ikioctl(dev, cmd, data, flag)
65430286Ssam dev_t dev;
65530286Ssam int cmd;
65630286Ssam caddr_t data;
65730286Ssam int flag;
65830222Ssam {
65930286Ssam int error = 0, unit = IKUNIT(dev), s;
66030286Ssam register struct ik_softc *sc = &ik_softc[unit];
66130222Ssam
66230286Ssam switch (cmd) {
66330222Ssam
66430286Ssam case PSIOGETERROR: /* get error code for last operation */
66530286Ssam *(int *)data = sc->is_error;
66630286Ssam break;
66730222Ssam
66830286Ssam case PSIOLOOKUP: { /* PS300 name lookup */
66930286Ssam register struct pslookup *lp = (struct pslookup *)data;
67030286Ssam register struct buf *bp;
67130222Ssam
67230286Ssam if (lp->pl_len > PS_MAXNAMELEN)
67330286Ssam return (EINVAL);
67430286Ssam bp = &rikbuf[unit];
67530286Ssam s = splbio();
67630286Ssam while (bp->b_flags&B_BUSY) {
67730286Ssam bp->b_flags |= B_WANTED;
67830286Ssam sleep((caddr_t)bp, PRIBIO+1);
67930286Ssam }
68030286Ssam splx(s);
68130286Ssam bp->b_flags = B_BUSY | B_WRITE;
68234506Skarels error = copyin(lp->pl_name, (caddr_t)sc->is_buf,
68334506Skarels (unsigned)lp->pl_len);
68430286Ssam if (error == 0) {
68530286Ssam if (lp->pl_len&1)
68630286Ssam sc->is_buf[lp->pl_len] = '\0';
68730286Ssam error = ikcommand(dev, PS_LOOKUP, lp->pl_len);
68830286Ssam }
68930286Ssam s = splbio();
69030286Ssam if (bp->b_flags&B_WANTED)
69130286Ssam wakeup((caddr_t)bp);
69230286Ssam splx(s);
69330286Ssam bp->b_flags &= ~(B_BUSY|B_WANTED);
69430286Ssam lp->pl_addr = sc->is_nameaddr.l;
69530286Ssam break;
69630286Ssam }
69730286Ssam default:
69830286Ssam return (ENOTTY);
69930286Ssam }
70030286Ssam return (error);
70130222Ssam }
70230222Ssam #endif
703