134506Skarels /* 235514Sbostic * Copyright (c) 1986 The Regents of the University of California. 335514Sbostic * All rights reserved. 435514Sbostic * 5*44534Sbostic * %sccs.include.redist.c% 635514Sbostic * 7*44534Sbostic * @(#)ik.c 7.6 (Berkeley) 06/28/90 834506Skarels */ 930222Ssam 1030222Ssam #include "ik.h" 1130222Ssam #if NIK > 0 1230222Ssam /* 1330222Ssam * PS300/IKON DR-11W Device Driver. 1430222Ssam */ 1530222Ssam #include "param.h" 1630222Ssam #include "buf.h" 1730222Ssam #include "cmap.h" 1830222Ssam #include "conf.h" 1930222Ssam #include "dkstat.h" 2030222Ssam #include "map.h" 2130222Ssam #include "systm.h" 2230222Ssam #include "user.h" 2330222Ssam #include "vmmac.h" 2430222Ssam #include "proc.h" 2530222Ssam #include "kernel.h" 2630228Ssam #include "syslog.h" 2730222Ssam 2830222Ssam #include "../tahoe/mtpr.h" 2930222Ssam #include "../tahoe/pte.h" 3030222Ssam 3130222Ssam #include "../tahoevba/vbavar.h" 3230222Ssam #include "../tahoevba/ikreg.h" 3330222Ssam #include "../tahoevba/psreg.h" 3430222Ssam #include "../tahoevba/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 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 */ 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*/ 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*/ 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 19030222Ssam ikread(dev, uio) 19130286Ssam dev_t dev; 19230286Ssam struct uio *uio; 19330222Ssam { 19430222Ssam 19530286Ssam return (ikrw(dev, uio, B_READ)); 19630222Ssam } 19730222Ssam 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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*/ 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