1*30344Ssam /* ik.c 1.5 86/12/23 */ 230222Ssam 330222Ssam #include "ik.h" 430222Ssam #if NIK > 0 530222Ssam /* 630222Ssam * PS300/IKON DR-11W Device Driver. 730222Ssam */ 830222Ssam #include "param.h" 930222Ssam #include "buf.h" 1030222Ssam #include "cmap.h" 1130222Ssam #include "conf.h" 1230222Ssam #include "dir.h" 1330222Ssam #include "dkstat.h" 1430222Ssam #include "map.h" 1530222Ssam #include "systm.h" 1630222Ssam #include "user.h" 1730222Ssam #include "vmmac.h" 1830222Ssam #include "proc.h" 1930222Ssam #include "uio.h" 2030222Ssam #include "kernel.h" 2130228Ssam #include "syslog.h" 2230222Ssam 2330222Ssam #include "../tahoe/mtpr.h" 2430222Ssam #include "../tahoe/pte.h" 2530222Ssam 2630222Ssam #include "../tahoevba/vbavar.h" 2730222Ssam #include "../tahoevba/ikreg.h" 2830222Ssam #include "../tahoevba/psreg.h" 2930222Ssam #include "../tahoevba/psproto.h" 3030222Ssam 3130286Ssam int ikprobe(), ikattach(), iktimer(); 3230286Ssam struct vba_device *ikinfo[NIK]; 3330286Ssam long ikstd[] = { 0 }; 3430286Ssam struct vba_driver ikdriver = { ikprobe, 0, ikattach, 0, ikstd, "ik", ikinfo }; 3530222Ssam 3630286Ssam #define splik() spl4() 3730222Ssam /* 3830222Ssam * Devices are organized in pairs with the odd valued 3930222Ssam * device being used for ``diagnostic'' purposes. That 4030222Ssam * is diagnostic devices don't get auto-attach'd and 4130222Ssam * detach'd on open-close. 4230222Ssam */ 4330286Ssam #define IKUNIT(dev) (minor(dev) >> 1) 4430286Ssam #define IKDIAG(dev) (minor(dev) & 01) /* is a diagnostic unit */ 4530222Ssam 4630286Ssam struct ik_softc { 4730286Ssam uid_t is_uid; /* uid of open processes */ 4830286Ssam u_short is_timeout; /* current timeout (seconds) */ 4930286Ssam u_short is_error; /* internal error codes */ 5030286Ssam u_short is_flags; 5130286Ssam #define IKF_ATTACHED 0x1 /* unit is attached (not used yet) */ 5230286Ssam union { 5330286Ssam u_short w[2]; 5430286Ssam u_long l; 5530286Ssam } is_nameaddr; /* address of last symbol lookup */ 56*30344Ssam caddr_t is_buf[PS_MAXDMA];/* i/o buffer XXX */ 5730222Ssam } ik_softc[NIK]; 5830222Ssam 5930286Ssam struct buf iktab[NIK]; /* unit command queue headers */ 6030286Ssam struct buf rikbuf[NIK]; /* buffers for read/write operations */ 6130286Ssam struct buf cikbuf[NIK]; /* buffers for control operations */ 6230222Ssam 6330222Ssam /* buf overlay definitions */ 6430286Ssam #define b_command b_resid 6530222Ssam 6630286Ssam int ikdiotimo = PS_DIOTIMO; /* dio polling timeout */ 6730286Ssam int iktimeout = PS_TIMEOUT; /* attention/dma timeout (in hz) */ 6830222Ssam 6930222Ssam ikprobe(reg, vi) 7030286Ssam caddr_t reg; 7130222Ssam struct vba_device *vi; 7230222Ssam { 7330286Ssam register int br, cvec; /* r12, r11 */ 7430222Ssam register struct ikdevice *ik; 7530222Ssam 7630294Ssam #ifdef lint 7730294Ssam br = 0; cvec = br; br = cvec; 7830294Ssam ikintr(0); 7930294Ssam #endif 8030286Ssam if (badaddr(reg, 2)) 8130286Ssam return (0); 8230222Ssam ik = (struct ikdevice *)reg; 8330222Ssam ik->ik_vec = --vi->ui_hd->vh_lastiv; 8430286Ssam /* 85*30344Ssam * Use extended non-privileged address modifier 86*30344Ssam * to avoid address overlap with 24-bit devices. 8730286Ssam */ 8830286Ssam ik->ik_mod = 0xf1; /* address modifier */ 8930286Ssam /* 9030286Ssam * Try and reset the PS300. Since this 9130286Ssam * won't work if it's powered off, we 9230286Ssam * can't use sucess/failure to decide 9330286Ssam * if the device is present. 9430286Ssam */ 9530222Ssam br = 0; 9630286Ssam (void) psreset(ik, IKCSR_IENA); 9730286Ssam if (br == 0) /* XXX */ 9830222Ssam br = 0x18, cvec = ik->ik_vec; /* XXX */ 9930286Ssam return (sizeof (struct ikdevice)); 10030222Ssam } 10130222Ssam 10230222Ssam /* 10330222Ssam * Perform a ``hard'' reset. 10430222Ssam */ 10530222Ssam psreset(ik, iena) 10630286Ssam register struct ikdevice *ik; 10730222Ssam { 10830222Ssam 10930286Ssam ik->ik_csr = IKCSR_MCLR|iena; 11030286Ssam DELAY(10000); 11130286Ssam ik->ik_csr = IKCSR_FNC3|iena; 11230286Ssam if (!iena) 11330286Ssam return (dioread(ik) == PS_RESET); 11430286Ssam return (1); 11530222Ssam } 11630222Ssam 11730222Ssam ikattach(vi) 11830286Ssam struct vba_device *vi; 11930222Ssam { 12030222Ssam 12130286Ssam ik_softc[vi->ui_unit].is_uid = -1; 12230222Ssam } 12330222Ssam 12430222Ssam /* 12530222Ssam * Open a PS300 and attach. We allow multiple 12630222Ssam * processes with the same uid to share a unit. 12730222Ssam */ 12830222Ssam /*ARGSUSED*/ 12930222Ssam ikopen(dev, flag) 13030286Ssam dev_t dev; 13130286Ssam int flag; 13230222Ssam { 13330286Ssam register int unit = IKUNIT(dev); 13430286Ssam register struct ik_softc *sc; 13530286Ssam struct vba_device *vi; 13630286Ssam struct ikdevice *ik; 13730286Ssam int reset; 13830222Ssam 13930286Ssam if (unit >= NIK || (vi = ikinfo[unit]) == 0 || vi->ui_alive == 0) 14030286Ssam return (ENXIO); 14130286Ssam sc = &ik_softc[unit]; 14230294Ssam if (sc->is_uid != (uid_t)-1 && sc->is_uid != u.u_uid) 14330286Ssam return (EBUSY); 14430294Ssam if (sc->is_uid == (uid_t)-1) { 14530286Ssam sc->is_timeout = 0; 14630294Ssam timeout(iktimer, (caddr_t)unit, hz); 14730286Ssam /* 14830286Ssam * Perform PS300 attach for first process. 14930286Ssam */ 15030286Ssam if (!IKDIAG(dev)) { 15130286Ssam reset = 0; 15230286Ssam again: 15330286Ssam if (ikcommand(dev, PS_ATTACH, 1)) { 15430286Ssam /* 15530286Ssam * If attach fails, perform a hard 15630286Ssam * reset once, then retry the command. 15730286Ssam */ 15830286Ssam ik = (struct ikdevice *)ikinfo[unit]->ui_addr; 15930286Ssam if (!reset++ && psreset(ik, 0)) 16030286Ssam goto again; 16130294Ssam untimeout(iktimer, (caddr_t)unit); 16230286Ssam return (EIO); 16330286Ssam } 16430286Ssam } 16530286Ssam sc->is_uid = u.u_uid; 16630286Ssam } 16730286Ssam return (0); 16830222Ssam } 16930222Ssam 17030222Ssam /*ARGSUSED*/ 17130222Ssam ikclose(dev, flag) 17230286Ssam dev_t dev; 17330286Ssam int flag; 17430222Ssam { 17530286Ssam int unit = IKUNIT(dev); 17630222Ssam register struct ik_softc *sc = &ik_softc[unit]; 17730222Ssam 17830286Ssam if (!IKDIAG(dev)) 17930286Ssam (void) ikcommand(dev, PS_DETACH, 1); /* auto detach */ 18030286Ssam sc->is_uid = -1; 18130294Ssam untimeout(iktimer, (caddr_t)unit); 18230222Ssam } 18330222Ssam 18430222Ssam ikread(dev, uio) 18530286Ssam dev_t dev; 18630286Ssam struct uio *uio; 18730222Ssam { 18830222Ssam 18930286Ssam return (ikrw(dev, uio, B_READ)); 19030222Ssam } 19130222Ssam 19230222Ssam ikwrite(dev, uio) 19330286Ssam dev_t dev; 19430286Ssam struct uio *uio; 19530222Ssam { 19630222Ssam 19730286Ssam return (ikrw(dev, uio, B_WRITE)); 19830222Ssam } 19930222Ssam 20030222Ssam /* 20130222Ssam * Take read/write request and perform physical i/o 20230222Ssam * transaction with PS300. This involves constructing 20330222Ssam * a physical i/o request vector based on the uio 20430222Ssam * vector, performing the dma, and, finally, moving 20530222Ssam * the data to it's final destination (because of CCI 20630222Ssam * VERSAbus bogosities). 20730222Ssam */ 20830222Ssam ikrw(dev, uio, rw) 20930286Ssam dev_t dev; 21030286Ssam register struct uio *uio; 21130286Ssam int rw; 21230222Ssam { 21330286Ssam int error, unit = IKUNIT(dev), s, wrcmd; 21430286Ssam register struct buf *bp; 21530286Ssam register struct iovec *iov; 21630286Ssam register struct psalist *ap; 21730286Ssam struct ik_softc *sc = &ik_softc[unit]; 21830222Ssam 21930286Ssam if (unit >= NIK) 22030286Ssam return (ENXIO); 22130286Ssam bp = &rikbuf[unit]; 22230286Ssam error = 0, iov = uio->uio_iov, wrcmd = PS_WRPHY; 22330286Ssam for (; !error && uio->uio_iovcnt; iov++, uio->uio_iovcnt--) { 22430286Ssam /* 22530286Ssam * Hack way to set PS300 address w/o doing an lseek 22630286Ssam * and specify write physical w/ refresh synchronization. 22730286Ssam */ 22830286Ssam if (iov->iov_len == 0) { 22930286Ssam if ((int)iov->iov_base&PSIO_SYNC) 23030286Ssam wrcmd = PS_WRPHY_SYNC; 23130286Ssam uio->uio_offset = (int)iov->iov_base & ~PSIO_SYNC; 23230286Ssam continue; 23330286Ssam } 23430286Ssam if (iov->iov_len > PS_MAXDMA) { 23530286Ssam sc->is_error = PSERROR_INVALBC, error = EINVAL; 23630286Ssam continue; 23730286Ssam } 23830286Ssam if ((int)uio->uio_offset&01) { 23930286Ssam sc->is_error = PSERROR_BADADDR, error = EINVAL; 24030286Ssam continue; 24130286Ssam } 24230286Ssam s = splbio(); 24330286Ssam while (bp->b_flags&B_BUSY) { 24430286Ssam bp->b_flags |= B_WANTED; 24530286Ssam sleep((caddr_t)bp, PRIBIO+1); 24630286Ssam } 24730286Ssam splx(s); 24830286Ssam bp->b_flags = B_BUSY | rw; 24930286Ssam /* 25030286Ssam * Construct address descriptor in buffer. 25130286Ssam */ 25230286Ssam ap = (struct psalist *)sc->is_buf; 25330286Ssam ap->nblocks = 1; 25430286Ssam /* work-around dr300 word swapping */ 25530286Ssam ap->addr[0] = uio->uio_offset & 0xffff; 25630286Ssam ap->addr[1] = uio->uio_offset >> 16; 25730286Ssam ap->wc = (iov->iov_len + 1) >> 1; 25830286Ssam if (rw == B_WRITE) { 25930286Ssam error = copyin(iov->iov_base, (caddr_t)&ap[1], 26030294Ssam (unsigned)iov->iov_len); 26130286Ssam if (!error) 26230286Ssam error = ikcommand(dev, wrcmd, 26330286Ssam iov->iov_len + sizeof (*ap)); 26430286Ssam } else { 26530286Ssam caddr_t cp; 26630286Ssam int len; 26730222Ssam 26830286Ssam error = ikcommand(dev, PS_RDPHY, sizeof (*ap)); 26930286Ssam cp = (caddr_t)&ap[1], len = iov->iov_len; 27030286Ssam for (; len > 0; len -= NBPG, cp += NBPG) 27130286Ssam mtpr(P1DC, cp); 27230286Ssam if (!error) 27330286Ssam error = copyout((caddr_t)&ap[1], iov->iov_base, 27430294Ssam (unsigned)iov->iov_len); 27530286Ssam } 27630286Ssam (void) splbio(); 27730286Ssam if (bp->b_flags&B_WANTED) 27830286Ssam wakeup((caddr_t)bp); 27930286Ssam splx(s); 28030286Ssam uio->uio_resid -= iov->iov_len; 28130286Ssam uio->uio_offset += iov->iov_len; 28230286Ssam bp->b_flags &= ~(B_BUSY|B_WANTED); 28330286Ssam } 28430286Ssam return (error); 28530222Ssam } 28630222Ssam 28730222Ssam /* 28830222Ssam * Perform a PS300 command. 28930222Ssam */ 29030222Ssam ikcommand(dev, com, count) 29130286Ssam dev_t dev; 29230286Ssam int com, count; 29330222Ssam { 29430286Ssam register struct buf *bp; 29530286Ssam register int s; 29630222Ssam 29730286Ssam bp = &cikbuf[IKUNIT(dev)]; 29830286Ssam s = splik(); 29930286Ssam while (bp->b_flags&B_BUSY) { 30030286Ssam if (bp->b_flags&B_DONE) 30130286Ssam break; 30230286Ssam bp->b_flags |= B_WANTED; 30330286Ssam sleep((caddr_t)bp, PRIBIO); 30430286Ssam } 30530286Ssam bp->b_flags = B_BUSY|B_READ; 30630286Ssam splx(s); 30730286Ssam bp->b_dev = dev; 30830286Ssam bp->b_command = com; 30930286Ssam bp->b_bcount = count; 31030286Ssam ikstrategy(bp); 31130286Ssam biowait(bp); 31230286Ssam if (bp->b_flags&B_WANTED) 31330286Ssam wakeup((caddr_t)bp); 31430286Ssam bp->b_flags &= B_ERROR; 31530286Ssam return (geterror(bp)); 31630222Ssam } 31730222Ssam 31830222Ssam /* 31930222Ssam * Physio strategy routine 32030222Ssam */ 32130222Ssam ikstrategy(bp) 32230286Ssam register struct buf *bp; 32330222Ssam { 32430286Ssam register struct buf *dp; 32530222Ssam 32630286Ssam /* 32730286Ssam * Put request at end of controller queue. 32830286Ssam */ 32930286Ssam dp = &iktab[IKUNIT(bp->b_dev)]; 33030286Ssam bp->av_forw = NULL; 33130286Ssam (void) splik(); 33230286Ssam if (dp->b_actf != NULL) { 33330286Ssam dp->b_actl->av_forw = bp; 33430286Ssam dp->b_actl = bp; 33530286Ssam } else 33630286Ssam dp->b_actf = dp->b_actl = bp; 33730286Ssam if (!dp->b_active) 33830286Ssam ikstart(dp); 33930286Ssam (void) spl0(); 34030222Ssam } 34130222Ssam 34230222Ssam /* 34330222Ssam * Start the next command on the controller's queue. 34430222Ssam */ 34530222Ssam ikstart(dp) 34630286Ssam register struct buf *dp; 34730222Ssam { 34830286Ssam register struct buf *bp; 34930286Ssam register struct ikdevice *ik; 35030286Ssam register struct ik_softc *sc; 35130286Ssam u_short bc, csr; 35230286Ssam u_int addr; 35330286Ssam int unit; 35430222Ssam 35530222Ssam loop: 35630286Ssam /* 35730286Ssam * Pull a request off the controller queue 35830286Ssam */ 35930286Ssam if ((bp = dp->b_actf) == NULL) { 36030286Ssam dp->b_active = 0; 36130286Ssam return; 36230286Ssam } 36330286Ssam /* 36430286Ssam * Mark controller busy and process this request. 36530286Ssam */ 36630286Ssam dp->b_active = 1; 36730286Ssam unit = IKUNIT(bp->b_dev); 36830286Ssam sc = &ik_softc[unit]; 36930286Ssam ik = (struct ikdevice *)ikinfo[unit]->ui_addr; 37030294Ssam switch ((int)bp->b_command) { 37130222Ssam 37230286Ssam case PS_ATTACH: /* logical unit attach */ 37330286Ssam case PS_DETACH: /* logical unit detach */ 37430286Ssam case PS_LOOKUP: /* name lookup */ 37530286Ssam case PS_RDPHY: /* physical i/o read */ 37630286Ssam case PS_WRPHY: /* physical i/o write */ 37730286Ssam case PS_WRPHY_SYNC: /* physical i/o write w/ sync */ 37830286Ssam /* 37930286Ssam * Handshake command and, optionally, 38030286Ssam * byte count and byte swap flag. 38130286Ssam */ 38230294Ssam if (sc->is_error = diowrite(ik, (u_short)bp->b_command)) 38330286Ssam goto bad; 38430286Ssam if (bp->b_command < PS_DETACH) { 38530294Ssam if (sc->is_error = diowrite(ik, (u_short)bp->b_bcount)) 38630286Ssam goto bad; 38730294Ssam if (sc->is_error = diowrite(ik, (u_short)0 /* !swab */)) 38830286Ssam goto bad; 38930286Ssam } 39030286Ssam /* 39130286Ssam * Set timeout and wait for an attention interrupt. 39230286Ssam */ 39330286Ssam sc->is_timeout = iktimeout; 39430286Ssam return; 39530222Ssam 39630286Ssam case PS_DMAOUT: /* dma data host->PS300 */ 39730286Ssam bc = bp->b_bcount; 39830286Ssam csr = IKCSR_CYCLE; 39930286Ssam break; 40030222Ssam 40130286Ssam case PS_DMAIN: /* dma data PS300->host */ 40230286Ssam bc = bp->b_bcount; 40330286Ssam csr = IKCSR_CYCLE|IKCSR_FNC1; 40430286Ssam break; 40530222Ssam 40630286Ssam default: 40730286Ssam log(LOG_ERR, "ik%d: bad cmd %x\n", unit, bp->b_command); 40830286Ssam sc->is_error = PSERROR_BADCMD; 40930286Ssam goto bad; 41030286Ssam } 41130286Ssam /* initiate dma transfer */ 41230294Ssam addr = vtoph((struct proc *)0, (unsigned)sc->is_buf); 41330286Ssam ik->ik_bahi = addr >> 17; 41430286Ssam ik->ik_balo = (addr >> 1) & 0xffff; 41530286Ssam ik->ik_wc = ((bc + 1) >> 1) - 1; /* round & convert */ 41630286Ssam ik->ik_pulse = IKPULSE_RATTF|IKPULSE_RDMAF; 41730286Ssam sc->is_timeout = iktimeout; 41830286Ssam ik->ik_csr = IKCSR_IENA|IKCSR_GO|csr; 41930286Ssam return; 42030222Ssam bad: 42130286Ssam bp->b_flags |= B_ERROR; 42230286Ssam dp->b_actf = bp->av_forw; /* remove from queue */ 42330286Ssam biodone(bp); 42430286Ssam goto loop; 42530222Ssam } 42630222Ssam 42730222Ssam #define FETCHWORD(i) { \ 42830286Ssam v = dioread(ik); \ 42930286Ssam if (v == -1) { \ 43030286Ssam sc->is_error = PSERROR_NAMETIMO; \ 43130286Ssam goto bad; \ 43230286Ssam } \ 43330286Ssam sc->is_nameaddr.w[i] = v; \ 43430222Ssam } 43530222Ssam 43630222Ssam /* 43730222Ssam * Process a device interrupt. 43830222Ssam */ 43930222Ssam ikintr(ikon) 44030286Ssam int ikon; 44130222Ssam { 44230286Ssam register struct ikdevice *ik; 44330286Ssam register struct buf *bp, *dp; 44430286Ssam struct ik_softc *sc; 44530286Ssam register u_short data; 44630294Ssam int v; 44730222Ssam 44830286Ssam /* should go by controller, but for now... */ 44930286Ssam if (ikinfo[ikon] == 0) 45030286Ssam return; 45130286Ssam ik = (struct ikdevice *)ikinfo[ikon]->ui_addr; 45230286Ssam /* 45330286Ssam * Discard all non-attention interrupts. The 45430286Ssam * interrupts we're throwing away should all be 45530286Ssam * associated with DMA completion. 45630286Ssam */ 45730286Ssam data = ik->ik_data; 45830286Ssam if ((ik->ik_csr&(IKCSR_ATTF|IKCSR_STATC)) != IKCSR_ATTF) { 45930286Ssam ik->ik_pulse = IKPULSE_RATTF|IKPULSE_RDMAF|IKPULSE_SIENA; 46030286Ssam return; 46130286Ssam } 46230286Ssam /* 46330286Ssam * Fetch attention code immediately. 46430286Ssam */ 46530286Ssam ik->ik_csr = IKCSR_RATTF|IKCSR_RDMAF|IKCSR_FNC1; 46630286Ssam ik->ik_pulse = IKPULSE_FNC2; 46730286Ssam /* 46830286Ssam * Get device and block structures, and a pointer 46930286Ssam * to the vba_device for the device. We receive an 47030286Ssam * unsolicited interrupt whenever the PS300 is power 47130286Ssam * cycled (so ignore it in that case). 47230286Ssam */ 47330286Ssam dp = &iktab[ikon]; 47430286Ssam if ((bp = dp->b_actf) == NULL) { 47530286Ssam if (PS_CODE(data) != PS_RESET) /* power failure */ 47630286Ssam log(LOG_WARNING, "ik%d: spurious interrupt, code %x\n", 47730286Ssam ikon, data); 47830286Ssam goto enable; 47930286Ssam } 48030286Ssam sc = &ik_softc[IKUNIT(bp->b_dev)]; 48130286Ssam sc->is_timeout = 0; /* disable timer */ 48230286Ssam switch (PS_CODE(data)) { 48330222Ssam 48430286Ssam case PS_LOOKUP: /* name lookup */ 48530286Ssam if (data == PS_LOOKUP) { /* dma name */ 48630286Ssam bp->b_command = PS_DMAOUT; 48730286Ssam goto opcont; 48830286Ssam } 48930286Ssam if (data == PS_DMAOK(PS_LOOKUP)) { 49030286Ssam /* reenable interrupt and wait for address */ 49130286Ssam sc->is_timeout = iktimeout; 49230286Ssam goto enable; 49330286Ssam } 49430286Ssam /* 49530286Ssam * Address should be present, extract it one 49630286Ssam * word at a time from the PS300 (yech). 49730286Ssam */ 49830286Ssam if (data != PS_ADROK(PS_LOOKUP)) 49930286Ssam goto bad; 50030286Ssam FETCHWORD(0); 50130286Ssam FETCHWORD(1); 50230286Ssam goto opdone; 50330222Ssam 50430286Ssam case PS_WRPHY_SYNC: /* physical i/o write w/ sync */ 50530286Ssam if (data == PS_WRPHY_SYNC) { /* start dma transfer */ 50630286Ssam bp->b_command = PS_DMAOUT; 50730286Ssam goto opcont; 50830286Ssam } 50930286Ssam if (data != PS_DMAOK(PS_WRPHY_SYNC)) 51030286Ssam goto bad; 51130286Ssam goto opdone; 51230222Ssam 51330286Ssam case PS_WRPHY: /* physical i/o write */ 51430286Ssam if (data == PS_WRPHY) { /* start dma transfer */ 51530286Ssam bp->b_command = PS_DMAOUT; 51630286Ssam goto opcont; 51730286Ssam } 51830286Ssam if (data != PS_DMAOK(PS_WRPHY)) 51930286Ssam goto bad; 52030286Ssam goto opdone; 52130222Ssam 52230286Ssam case PS_ATTACH: /* attach unit */ 52330286Ssam case PS_DETACH: /* detach unit */ 52430286Ssam case PS_ABORT: /* abort code from ps300 */ 52530286Ssam if (data != bp->b_command) 52630286Ssam goto bad; 52730286Ssam goto opdone; 52830222Ssam 52930286Ssam case PS_RDPHY: /* physical i/o read */ 53030286Ssam if (data == PS_RDPHY) { /* dma address list */ 53130286Ssam bp->b_command = PS_DMAOUT; 53230286Ssam goto opcont; 53330286Ssam } 53430286Ssam if (data == PS_ADROK(PS_RDPHY)) { 53530286Ssam /* collect read byte count and start dma */ 53630286Ssam bp->b_bcount = dioread(ik); 53730286Ssam if (bp->b_bcount == -1) 53830286Ssam goto bad; 53930286Ssam bp->b_command = PS_DMAIN; 54030286Ssam goto opcont; 54130286Ssam } 54230286Ssam if (data == PS_DMAOK(PS_RDPHY)) 54330286Ssam goto opdone; 54430286Ssam goto bad; 54530286Ssam } 54630222Ssam bad: 54730286Ssam sc->is_error = data; 54830286Ssam bp->b_flags |= B_ERROR; 54930222Ssam opdone: 55030286Ssam dp->b_actf = bp->av_forw; /* remove from queue */ 55130286Ssam biodone(bp); 55230222Ssam opcont: 55330286Ssam ikstart(dp); 55430222Ssam enable: 55530286Ssam ik->ik_pulse = IKPULSE_SIENA; /* explicitly reenable */ 55630222Ssam } 55730222Ssam 55830222Ssam /* 55930222Ssam * Watchdog timer. 56030222Ssam */ 56130222Ssam iktimer(unit) 56230286Ssam int unit; 56330222Ssam { 56430286Ssam register struct ik_softc *sc = &ik_softc[unit]; 56530222Ssam 56630286Ssam if (sc->is_timeout && --sc->is_timeout == 0) { 56730286Ssam register struct buf *dp, *bp; 56830286Ssam int s; 56930222Ssam 57030286Ssam log(LOG_ERR, "ik%d: timeout\n", unit); 57130286Ssam s = splik(); 57230286Ssam /* should abort current command */ 57330286Ssam dp = &iktab[unit]; 57430286Ssam if (bp = dp->b_actf) { 57530286Ssam sc->is_error = PSERROR_CMDTIMO; 57630286Ssam bp->b_flags |= B_ERROR; 57730286Ssam dp->b_actf = bp->av_forw; /* remove from queue */ 57830286Ssam biodone(bp); 57930286Ssam ikstart(dp); 58030286Ssam } 58130286Ssam splx(s); 58230286Ssam } 58330294Ssam timeout(iktimer, (caddr_t)unit, hz); 58430222Ssam } 58530222Ssam 58630222Ssam /* 58730222Ssam * Handshake read from DR300. 58830222Ssam */ 58930222Ssam dioread(ik) 59030286Ssam register struct ikdevice *ik; 59130222Ssam { 59230294Ssam register int t; 59330286Ssam u_short data; 59430222Ssam 59530294Ssam for (t = ikdiotimo; t > 0; t--) 59630286Ssam if ((ik->ik_csr&(IKCSR_ATTF|IKCSR_STATC)) == IKCSR_ATTF) { 59730286Ssam data = ik->ik_data; 59830286Ssam ik->ik_csr = IKCSR_RATTF|IKCSR_RDMAF|IKCSR_FNC1; 59930286Ssam ik->ik_pulse = IKPULSE_FNC2; 60030286Ssam return (data); 60130286Ssam } 60230286Ssam return (-1); 60330222Ssam } 60430222Ssam 60530222Ssam /* 60630222Ssam * Handshake write to DR300. 60730222Ssam * 60830222Ssam * Interrupts are enabled before completing the work 60930222Ssam * so the caller should either be at splik or be 61030222Ssam * prepared to take the interrupt immediately. 61130222Ssam */ 61230222Ssam diowrite(ik, v) 61330286Ssam register struct ikdevice *ik; 61430286Ssam u_short v; 61530222Ssam { 61630294Ssam register int t; 61730286Ssam register u_short csr; 61830222Ssam 61930222Ssam top: 62030286Ssam /* 62130286Ssam * Deposit data and generate dr300 attention 62230286Ssam */ 62330286Ssam ik->ik_data = v; 62430286Ssam ik->ik_csr = IKCSR_RDMAF|IKCSR_RATTF; 62530286Ssam ik->ik_pulse = IKPULSE_FNC2; 62630294Ssam for (t = ikdiotimo; t > 0; t--) { 62730286Ssam csr = ik->ik_csr; 62830286Ssam #define IKCSR_DONE (IKCSR_STATA|IKCSR_STATC) 62930286Ssam if ((csr&IKCSR_DONE) == IKCSR_DONE) { 63030286Ssam /* 63130286Ssam * Done, complete handshake by notifying dr300. 63230286Ssam */ 63330286Ssam ik->ik_csr = IKCSR_IENA; /* ~IKCSR_FNC1 */ 63430286Ssam ik->ik_pulse = IKPULSE_FNC2; 63530286Ssam return (0); 63630286Ssam } 63730286Ssam /* beware of potential deadlock with dioread */ 63830286Ssam if ((csr&(IKCSR_ATTF|IKCSR_STATC)) == IKCSR_ATTF) 63930286Ssam goto top; 64030286Ssam } 64130286Ssam ik->ik_csr = IKCSR_IENA; 64230286Ssam return (PSERROR_DIOTIMO); 64330222Ssam } 64430222Ssam 64530222Ssam /*ARGSUSED*/ 64630222Ssam ikioctl(dev, cmd, data, flag) 64730286Ssam dev_t dev; 64830286Ssam int cmd; 64930286Ssam caddr_t data; 65030286Ssam int flag; 65130222Ssam { 65230286Ssam int error = 0, unit = IKUNIT(dev), s; 65330286Ssam register struct ik_softc *sc = &ik_softc[unit]; 65430222Ssam 65530286Ssam switch (cmd) { 65630222Ssam 65730286Ssam case PSIOGETERROR: /* get error code for last operation */ 65830286Ssam *(int *)data = sc->is_error; 65930286Ssam break; 66030222Ssam 66130286Ssam case PSIOLOOKUP: { /* PS300 name lookup */ 66230286Ssam register struct pslookup *lp = (struct pslookup *)data; 66330286Ssam register struct buf *bp; 66430222Ssam 66530286Ssam if (lp->pl_len > PS_MAXNAMELEN) 66630286Ssam return (EINVAL); 66730286Ssam bp = &rikbuf[unit]; 66830286Ssam s = splbio(); 66930286Ssam while (bp->b_flags&B_BUSY) { 67030286Ssam bp->b_flags |= B_WANTED; 67130286Ssam sleep((caddr_t)bp, PRIBIO+1); 67230286Ssam } 67330286Ssam splx(s); 67430286Ssam bp->b_flags = B_BUSY | B_WRITE; 67530294Ssam error = copyin(lp->pl_name, sc->is_buf, (unsigned)lp->pl_len); 67630286Ssam if (error == 0) { 67730286Ssam if (lp->pl_len&1) 67830286Ssam sc->is_buf[lp->pl_len] = '\0'; 67930286Ssam error = ikcommand(dev, PS_LOOKUP, lp->pl_len); 68030286Ssam } 68130286Ssam s = splbio(); 68230286Ssam if (bp->b_flags&B_WANTED) 68330286Ssam wakeup((caddr_t)bp); 68430286Ssam splx(s); 68530286Ssam bp->b_flags &= ~(B_BUSY|B_WANTED); 68630286Ssam lp->pl_addr = sc->is_nameaddr.l; 68730286Ssam break; 68830286Ssam } 68930286Ssam default: 69030286Ssam return (ENOTTY); 69130286Ssam } 69230286Ssam return (error); 69330222Ssam } 69430222Ssam #endif 695