138623Skarels /* 238623Skarels * Datakit driver 338623Skarels * KMC assistance, with or without DR11C 4*45181Skarels * @(#)dkit_kmc.c 1.3 (Berkeley) 09/03/90 538623Skarels */ 638623Skarels 738623Skarels #include "dkitkmc.h" 838623Skarels #if NDKITKMC>0 938623Skarels 1038623Skarels #include "datakit.h" 1138623Skarels 1238623Skarels #include "../machine/pte.h" 1338623Skarels #include "param.h" 1438623Skarels #include "syslog.h" 1538623Skarels #include "time.h" 1638623Skarels #include "kernel.h" 1738623Skarels #include "buf.h" 1838623Skarels #include "mbuf.h" 1938623Skarels #include "errno.h" 2038623Skarels #include "socket.h" 2138623Skarels #include "../net/if.h" 2238623Skarels #include "../vaxif/if_uba.h" 2338623Skarels #include "../vaxuba/ubareg.h" 2438623Skarels #include "../vaxuba/ubavar.h" 2538623Skarels 2638623Skarels #include "dkit.h" 2738623Skarels #include "dkkmc.h" 2838623Skarels #include "dk.h" 2938623Skarels 3038625Skarels #define KMXSMALL 0 3138625Skarels #define KMXBIG 1 3238625Skarels 3338623Skarels #define MONITOR 1 3438623Skarels 3538623Skarels #ifdef MONITOR 3638623Skarels static int dummy ; 3738623Skarels int *DKP = &dummy ; 3838623Skarels #define M_ON(a) *DKP |= (a) 3938623Skarels #define M_OFF(a) *DKP &= ~(a) 4038623Skarels #define M_TRACE(a) *DKP |= (a);*DKP &= ~(a) 4138623Skarels 4238623Skarels #define Mxmit 01 4338623Skarels #define Mrecv 02 4438623Skarels #define Mkint 04 4538623Skarels #define Mint 010 4638623Skarels #define Mcmd 020 4738623Skarels 4838623Skarels #else 4938623Skarels #define M_ON(a) 5038623Skarels #define M_OFF(a) 5138623Skarels #define M_TRACE(a) 5238623Skarels #endif 5338623Skarels 5438623Skarels extern int dk_nchan; 5538623Skarels 5638623Skarels struct dkchan dkit[NDATAKIT]; 5738623Skarels 5838623Skarels #define DKNCMDB 20 5938623Skarels #define DKNSTB 20 6038623Skarels 6138623Skarels int dkk_ncmd = DKNCMDB; 6238623Skarels struct dkkin dkkcmdbuf[DKNCMDB]; 6338623Skarels int dkk_nstat = DKNSTB; 6438623Skarels struct dkkin dkkstat[DKNSTB]; 6538623Skarels char dkkbuf[16*1024]; 6638623Skarels int dkubmbuf; 6738623Skarels 6838623Skarels static struct kdevice *dkkaddr; 6938623Skarels 7038623Skarels /* 7138623Skarels * initial information to the KMC 7238623Skarels */ 7338623Skarels struct dkinit { 7438623Skarels caddr_t cmdaddr; /* command buffer */ 7538623Skarels caddr_t stataddr; /* status buffer */ 7638623Skarels caddr_t bufaddr ; /* kmc workspace */ 7738623Skarels caddr_t csraddr; /* for KMC/DR DR register address */ 7838623Skarels } dkkmcinit; 7938623Skarels 8038623Skarels /* 8138623Skarels * structure of data in first mbuf on chain (type DKM_HDR) 8238623Skarels * 8338623Skarels */ 8438623Skarels struct mpacket { 8538623Skarels short mp_len; /* Total length left */ 8638623Skarels char mp_ctl; /* Control character */ 8738623Skarels int mp_eob; /* Send end-of-block indicator */ 8838623Skarels int (*mp_endfcn)(); /* End-action function */ 8938623Skarels caddr_t mp_endparm; /* Parameter to above function */ 9038623Skarels }; 9138623Skarels 9238623Skarels 9338623Skarels /* 9438623Skarels * The circular buffer, cmdbuf, is used to pass command to kmc: 9538623Skarels * while the circular buffer statbuf is used to report status. 9638623Skarels * There are 8 control and status registers (csr) accessible to 9738623Skarels * both cpu and kmc. 9838623Skarels * Csr4-csr5 are used to indicate the head and tail respectively 9938623Skarels * of the cmdbuf. Likewise, csr6-csr7 for statbuf. 10038623Skarels * At initialization time, the cpu and kmc would agree on the beginning 10138623Skarels * address of both buffers and their sizes. 10238623Skarels */ 10338623Skarels #define csr0 dkkaddr->un.bsel.bsel0 /* kmc state */ 10438623Skarels #define csr1 dkkaddr->un.bsel.bsel1 10538623Skarels #define csr2 dkkaddr->un.bsel.bsel2 /* used at init time, to pass */ 10638623Skarels #define csr3 dkkaddr->un.bsel.bsel3 /* addresses to the kmc */ 10738623Skarels #define csr4 dkkaddr->un.bsel.bsel4 /* head cmdbuf */ 10838623Skarels #define csr5 dkkaddr->un.bsel.bsel5 /* tail cmdbuf */ 10938623Skarels #define csr6 dkkaddr->un.bsel.bsel6 /* head statbuf */ 11038623Skarels #define csr7 dkkaddr->un.bsel.bsel7 /* tail statbuf */ 11138623Skarels 11238623Skarels 11338623Skarels /* 11438623Skarels * kmc device registers 11538623Skarels */ 11638623Skarels struct kdevice { 11738623Skarels union { 11838623Skarels struct { short sel0, sel2, sel4, sel6;} wsel ; 11938623Skarels struct { char bsel0, bsel1, bsel2, bsel3; 12038623Skarels char bsel4, bsel5, bsel6, bsel7; } bsel ; 12138623Skarels } un; 12238623Skarels }; 12338623Skarels 12438623Skarels 12538623Skarels /* 12638623Skarels * For the moment, only support one kmc (kmc0) 12738623Skarels * More need be done for multiple kmc's 12838623Skarels */ 12938623Skarels 13038623Skarels int dkdebug = 512 ; 13138623Skarels int dkactive = 0 ; 13238623Skarels int dkbindex ; 13338623Skarels static int kseqchk = 0; /* used to check seq. #'s in statbuf */ 13438623Skarels static int dkpanic = 0; /* # of dk_close(0)'s in this run */ 13538623Skarels static int kseq = 0; /* # kmc responses mod 0377 */ 13638623Skarels static int pseq = 0; 13738623Skarels 13838623Skarels static struct dkkin *cmd4; /* dkkcmdbuf[csr4] pointer */ 13938623Skarels static struct dkkin *stat7; /* dkkstat[csr7] pointer */ 14038623Skarels 14138623Skarels int dkk_cnt ; 14238623Skarels static struct uba_device *ui; 14338623Skarels 14438623Skarels dkkmc_attach(kui) struct uba_device *kui; 14538623Skarels { 14638623Skarels ui = kui; 14738623Skarels dkk_cnt = kui->ui_unit; 14838623Skarels } 14938623Skarels 15038623Skarels dk_init() 15138623Skarels { 15238623Skarels int t, kt ; 15338623Skarels extern dkkint() ; 15438623Skarels 15538623Skarels /* 15638623Skarels * On the first open of the hardware interface 15738623Skarels */ 15838623Skarels if (!ui) return -ENXIO; 15938623Skarels if (kmcset((dkk_cnt)<<6,03,dkkint)) { 16038623Skarels /* debug */ log(LOG_ERR, "dkkmcinit bad: kmcset failed\n"); 16138623Skarels return -1; 16238623Skarels } 16338623Skarels dkkaddr = ((struct kdevice *) ui->ui_addr); 16438623Skarels 16538623Skarels /* if csr0 != 0, then error 16638623Skarels else pass the address of struct init 16738623Skarels in csr2~4 and set csr0 to 1 */ 16838623Skarels 16938623Skarels if ((csr0 & 3) != 0) { 17038623Skarels /* debug */ log(LOG_ERR, "dkkmcinit: csr0 != 0\n"); 17138623Skarels return EIO; 17238623Skarels } 17338623Skarels 17438623Skarels /* Map UBA registers to point to our stuff */ 17538623Skarels kt = dk_ubainit(); 17638623Skarels if (kt == 0) { 17738623Skarels log(LOG_ERR, "dkkmcinit: no uba resources\n"); 17838623Skarels return ENOBUFS; 17938623Skarels } 18038623Skarels 18138623Skarels /* Address of DR11-C (if any) */ 18238623Skarels t = ui->ui_flags & ~03 ; 18338623Skarels dkkmcinit.csraddr = (caddr_t) ((t<<16) + 3) ; /* bits 17 + 18 must be 1 */ 18438623Skarels 18538623Skarels /* append new init info here, if it is needed */ 18638623Skarels 187*45181Skarels dkkaddr->un.wsel.sel2 = (short)(UBAI_ADDR(kt) & 0xFFFF);/* bits 0-15 */ 188*45181Skarels dkkaddr->un.bsel.bsel4 = (char)(UBAI_ADDR(kt) >> 16); /* bits 16-17 */ 18938623Skarels 19038623Skarels csr0 = 1; /* tell KMC to read csr2 */ 19138623Skarels kseq = 0 ; 19238623Skarels 19338623Skarels cmd4 = &dkkcmdbuf[0] ; /* driver's pointers into cmdbuf and statbuf */ 19438623Skarels stat7 = &dkkstat[0] ; 19538623Skarels dkactive = 1 ; 19638623Skarels return 0 ; 19738623Skarels } 19838623Skarels 19938623Skarels int dk_ubaed = 0; 20038623Skarels 20138623Skarels dk_ubainit() 20238623Skarels { 20338623Skarels int t; 20438623Skarels static int kt; 20538623Skarels 20638623Skarels if (dk_ubaed) { 20738623Skarels if (dkdebug < dk_nchan) 20838623Skarels log(LOG_ERR, "dk_ubainit: reinit\n"); 20938623Skarels return kt; 21038623Skarels } 21138623Skarels dk_ubaed = 1; 21238623Skarels 21338623Skarels /* Initialization buffer */ 21438623Skarels kt = uballoc(ui->ui_ubanum, (caddr_t) &dkkmcinit, sizeof dkkmcinit, UBA_CANTWAIT); 21538623Skarels if (kt == 0) return 0; 21638623Skarels 21738623Skarels /* Command input buffer */ 21838623Skarels t = uballoc(ui->ui_ubanum, (caddr_t) dkkcmdbuf, sizeof dkkcmdbuf, UBA_CANTWAIT) ; 21938623Skarels if (t == 0) return 0; 220*45181Skarels dkkmcinit.cmdaddr = (caddr_t)((UBAI_ADDR(t)<<16) | ((UBAI_ADDR(t)>>16))); /* must swap bytes for unibus */ 22138623Skarels 22238623Skarels /* Status out buffer */ 22338623Skarels t = uballoc(ui->ui_ubanum, (caddr_t) dkkstat, sizeof dkkstat, UBA_CANTWAIT); 22438623Skarels if (t == 0) return 0; 225*45181Skarels dkkmcinit.stataddr = (caddr_t)((UBAI_ADDR(t)<<16) | (UBAI_ADDR(t)>>16)); 22638623Skarels 22738623Skarels /* KMC buffer */ 22838623Skarels dkubmbuf = uballoc(ui->ui_ubanum, (caddr_t) dkkbuf, sizeof dkkbuf, UBA_CANTWAIT); 229*45181Skarels if (dkubmbuf == 0) return 0; 230*45181Skarels dkkmcinit.bufaddr = (caddr_t) ((UBAI_ADDR(dkubmbuf)<<16) | 231*45181Skarels (UBAI_ADDR(dkubmbuf)>>16)); 23238623Skarels if (dkdebug < dk_nchan) 23338623Skarels log(LOG_ERR, "dk_ubainit: bufaddr %x mapped %x\n", (caddr_t)dkkbuf, 23438623Skarels dkubmbuf); 23538623Skarels 23638623Skarels return kt; 23738623Skarels } 23838623Skarels 23938623Skarels dk_open(chan, supfcn) 24038623Skarels register chan ; 24138623Skarels int (*supfcn)() ; 24238623Skarels { 24338623Skarels register struct dkchan *dkp; 24438623Skarels register s ; 24538623Skarels extern dkkint() ; 24638623Skarels extern int commchan; 24738623Skarels int init; 24838623Skarels 24938623Skarels if (chan >= dk_nchan) 25038623Skarels return -ENXIO ; 25138623Skarels if (dkactive == -1) /* fail request if reset is in progress */ 25238623Skarels return(-ENETRESET) ; 25338623Skarels dkp = &dkit[chan] ; 25438623Skarels s = splimp() ; 25538623Skarels /* 25638623Skarels * Channel 0 (0-3 in ISN) is reserved for maintenance. 25738623Skarels * An open on channel 0 is interpreted as a request 25838623Skarels * for an unused channel. Channel 1 (4 in ISN or RADIAN) 25938623Skarels * is the common supervisory channel. 26038623Skarels */ 26138623Skarels if (chan == 0) { 26238623Skarels chan = commchan+1; /* Start above commchan */ 26338623Skarels while (1) { 26438623Skarels dkp = &dkit[chan] ; 26538623Skarels if (dkp->dk_state == 0) 26638623Skarels break ; 26738623Skarels chan++ ; 26838623Skarels if (chan >= dk_nchan) { 26938623Skarels splx(s) ; 27038623Skarels return -EADDRNOTAVAIL ; 27138623Skarels } 27238623Skarels } 27338623Skarels } 27438623Skarels splx(s) ; 27538623Skarels 27638623Skarels if (dkactive == 0) 27738623Skarels if ((init = dk_init()) < 0) 27838623Skarels return init ; 27938623Skarels 28038623Skarels /* 28138623Skarels * On first use of a channel, we must 28238623Skarels * allocate per-channel UBA resource for transmit. 28338623Skarels * Some day, when we convert the receivers to use mbufs, 28438623Skarels * we'll do the same for reads. 28538623Skarels * Note that these resources can't easily be freed (I think). 28638623Skarels */ 28738623Skarels if (!dkp->dk_uba.ifu_uba) { 28838623Skarels dkp->dk_uba.ifu_flags = UBA_CANTWAIT; 28938623Skarels if (if_ubaminit(&dkp->dk_uba.ifu_info, ui->ui_ubanum, 0, 29038623Skarels btoc(CLBYTES), 29138623Skarels &dkp->dk_uba.ifu_r, 0, 29238623Skarels &dkp->dk_uba.ifu_xmt, 1) == 0) { 29338623Skarels log(LOG_ERR, "dkkmc: no ubamap for channel %d\n", chan); 29438623Skarels return -ENOBUFS; 29538623Skarels } 29638623Skarels dkp->dk_outq.ifq_maxlen = 20; 29738623Skarels } 29838623Skarels 29938623Skarels /* 30038623Skarels * Finish setting up dkp struct. 30138623Skarels */ 30238623Skarels if ((dkp->dk_state & DK_OPEN) ==0) { 30338625Skarels dkcmd(KC_XINIT, chan, (caddr_t)0, (unsigned) 0, KMXBIG, 0); 30438623Skarels flushall(dkp, 0); 30538623Skarels dkp->dk_state |= DK_OPEN; 30638625Skarels dkp->dk_state &= ~(DK_LINGR | DK_RESET); 30738623Skarels dkactive++ ; 30838623Skarels } 30938623Skarels dkp->dk_supfcn = supfcn ; 31038623Skarels return chan ; 31138623Skarels } 31238623Skarels 31338623Skarels 31438623Skarels /* 31538623Skarels * Close a channel: 31638623Skarels */ 31738623Skarels 31838623Skarels dk_close(chan) 31938623Skarels { 32038623Skarels register struct dkchan *dkp; 32138623Skarels register s ; 32238623Skarels int init; 32338623Skarels 32438623Skarels if (dkkaddr == 0) return(-ENODEV); /* if no init, can't close */ 32538623Skarels /* ie: can't do dkmaint */ 32638623Skarels 32738623Skarels s = splimp() ; 32838623Skarels dkp = &dkit[chan] ; 32938623Skarels if (chan == 0) { 33038623Skarels for (dkp = &dkit[1]; dkp < &dkit[dk_nchan]; dkp++) { 33138623Skarels if (dkp->dk_state & (DK_OPEN|DK_BUSY|DK_RCV)) { 33238623Skarels dkp->dk_state |= DK_RESET ; 33338623Skarels flushall(dkp, 0) ; 33438623Skarels dkp->dk_state = DK_RESET ; 33538623Skarels } 33638623Skarels } 33738623Skarels dkpanic++ ; 33838623Skarels kseq = 0 ; 33938623Skarels pseq = 0 ; 34038623Skarels #ifdef notdef 34138623Skarels if(dkubmbuf){ /* only deallocate mem if still allocated */ 34238623Skarels ubarelse(ui->ui_ubanum, &dkubmbuf); 34338623Skarels dkubmbuf = NULL; 34438623Skarels } 34538623Skarels #endif 34638623Skarels /* wait for protocols to close channels */ 34738623Skarels dkactive = -1 ; 34838623Skarels DELAY(4 * hz) ; 34938623Skarels /* do a dk_free for all channels */ 35038623Skarels for (dkp = &dkit[1]; dkp < &dkit[dk_nchan]; dkp++) { 35138623Skarels dkp->dk_state &= ~DK_LINGR ; 35238623Skarels } 35338623Skarels dkactive = 0 ; 35438623Skarels csr0 = 0 ; /* set kmc to idle mode */ 35538623Skarels if ((init = dk_init()) < 0) { 35638623Skarels splx(s) ; 35738623Skarels return init ; 35838623Skarels } 35938623Skarels } else { 36038623Skarels flushall(dkp, 0) ; 36138623Skarels dkp->dk_state = DK_LINGR ; /* set while UNIXP protocol 36238623Skarels closes up channel with DK */ 36338623Skarels } 36438623Skarels splx(s) ; 36538623Skarels return 0; 36638623Skarels } 36738623Skarels 36838623Skarels 36938623Skarels 37038623Skarels 37138623Skarels /* 37238623Skarels * Close phase 2 - mark available for reassignment 37338623Skarels */ 37438623Skarels dk_free(chan) 37538623Skarels { 37638623Skarels if (chan > dkdebug) 37738623Skarels log(LOG_ERR, "dk_free %d\n", chan) ; 37838625Skarels dkit[chan].dk_state &= ~(DK_LINGR | DK_RESET); 37938623Skarels } 38038623Skarels 38138623Skarels 38238623Skarels /* 38338623Skarels * Reset a channel 38438623Skarels * prevents further I/O until close 38538623Skarels */ 38638623Skarels dk_reset(chan) 38738623Skarels { 38838623Skarels register struct dkchan *dkp ; 38938623Skarels register s ; 39038623Skarels 39138623Skarels if (chan > dkdebug) 39238623Skarels log(LOG_ERR, "dk_reset %d\n", chan) ; 39338623Skarels s = splimp() ; 39438623Skarels dkp = &dkit[chan] ; 39538623Skarels dkp->dk_state |= DK_RESET ; 39638623Skarels flushall(dkp, 0) ; 39738623Skarels splx(s) ; 39838623Skarels } 39938623Skarels 40038623Skarels 40138623Skarels 40238623Skarels /* 40338623Skarels * Xmit a short control (interrupt) packet (max 2 bytes) 40438623Skarels */ 40538623Skarels dk_xint(chan, intr) 40638623Skarels { 40738623Skarels register s ; 40838623Skarels 40938623Skarels s = splimp() ; 41038623Skarels dkcmd(KC_SOI, chan, (caddr_t)0, (unsigned) intr, 0, 0) ; 41138623Skarels splx(s) ; 41238623Skarels return 0 ; 41338623Skarels } 41438623Skarels 41538623Skarels 41638623Skarels /* 41738623Skarels * Adjust window size 41838623Skarels */ 41938623Skarels /*ARGSUSED*/ 42038623Skarels dk_winsize(chan, win) 42138623Skarels struct diocxwin *win; 42238623Skarels { 42338623Skarels return EINVAL; /* For now... */ 42438623Skarels } 42538623Skarels 42638623Skarels 42738623Skarels 42838623Skarels /* 42938623Skarels * Xmit data on a channel 43038623Skarels */ 43138623Skarels dk_xmit(chan, m, eob, ctlchar, endfcn, endparm) 43238623Skarels struct mbuf *m ; 43338623Skarels int (*endfcn)() ; 43438623Skarels caddr_t endparm ; 43538623Skarels { 43638623Skarels register struct dkchan *dkp ; 43738623Skarels short s ; 43838623Skarels register struct mpacket *mbp ; 43938623Skarels register struct mbuf *mb; 44038623Skarels int len; 44138623Skarels 44238623Skarels M_ON(Mxmit) ; 44338623Skarels s = splimp() ; 44438623Skarels dkp = &dkit[chan] ; 44538623Skarels if ((dkp->dk_state & DK_RESET) || (mb = m_get(M_DONTWAIT,DKMT_HDR)) == NULL) { 44638623Skarels m_freem(m); 44738623Skarels splx(s) ; 44838623Skarels return 0 ; 44938623Skarels } 45038623Skarels 45138623Skarels mb->m_len = 0; 45238623Skarels mbp = mtod(mb, struct mpacket *); 45338623Skarels mbp->mp_endfcn = endfcn ; 45438623Skarels mbp->mp_endparm = endparm ; 45538623Skarels mbp->mp_eob = eob; 45638623Skarels mbp->mp_ctl = ctlchar; 45738623Skarels 45838623Skarels if ((dkp->dk_state & DK_BUSY) == 0) { 45938623Skarels dkp->dk_state |= DK_BUSY ; 46038623Skarels dkp->dk_obuf = mbp ; 46138623Skarels mb->m_next = NULL; 46238623Skarels len = if_wubaput(&dkp->dk_uba, m); 46338623Skarels dkcmd(KC_SEND, chan, (caddr_t) UBAI_ADDR(dkp->dk_uba.ifu_w.ifrw_info), 46438623Skarels (unsigned) len, eob ? SBOT : SBOTM, ctlchar) ; 46538623Skarels splx(s) ; 46638623Skarels M_OFF(Mxmit) ; 46738623Skarels return dkp->dk_state ; 46838623Skarels } 46938623Skarels 47038623Skarels mb->m_next = m; 47138623Skarels if (IF_QFULL(&dkp->dk_outq)) { 47238623Skarels IF_DROP(&dkp->dk_outq); 47338623Skarels m_freem(mb); 47438623Skarels } 47538623Skarels else 47638623Skarels IF_ENQUEUE(&dkp->dk_outq, mb); 47738623Skarels splx(s) ; 47838623Skarels M_OFF(Mxmit) ; 47938623Skarels return dkp->dk_state ; 48038623Skarels } 48138623Skarels 48238623Skarels /* 48338623Skarels * Receive into a block buffer 48438623Skarels */ 48538623Skarels dk_recv(chan, addr, len, mode, endfcn, endparm) 48638623Skarels int len; 48738623Skarels int (*endfcn)() ; 48838623Skarels caddr_t addr, endparm ; 48938623Skarels { 49038623Skarels register struct dkchan *dkp ; 49138623Skarels int s; 49238623Skarels 49338623Skarels s = splimp() ; 49438623Skarels M_ON(Mrecv) ; 49538623Skarels dkp = &dkit[chan] ; 49638623Skarels if (dkp->dk_state & (DK_RCV | DK_RESET)) { 49738623Skarels splx(s) ; 49838623Skarels return(0) ; 49938623Skarels } 50038623Skarels dkp->dk_ubmbase = uballoc(ui->ui_ubanum, addr, len, UBA_CANTWAIT); 50138623Skarels if (dkp->dk_ubmbase == NULL) { 50238623Skarels splx(s) ; 50338623Skarels return(0) ; 50438623Skarels } 50538623Skarels dkp->dk_state |= DK_RCV ; 50638623Skarels dkp->dk_endfcn = endfcn ; 50738623Skarels dkp->dk_endparm = endparm ; 50838623Skarels dkp->dk_rlen = len; 50938623Skarels dkcmd(KC_RCVB, chan, (caddr_t) UBAI_ADDR(dkp->dk_ubmbase), (unsigned) len, mode&0377, mode>>8); 51038623Skarels M_OFF(Mrecv) ; 51138623Skarels splx(s); 51238623Skarels return dkp->dk_state ; 51338623Skarels } 51438623Skarels 51538623Skarels /* Abort pending receive */ 51638623Skarels 51738623Skarels 51838623Skarels dk_rabort(chan, nendfcn, nendparm) 51938623Skarels int (*nendfcn)() ; 52038623Skarels caddr_t nendparm; 52138623Skarels { 52238623Skarels register struct dkchan *dkp ; 52338623Skarels register s ; 52438623Skarels 52538623Skarels dkp = &dkit[chan] ; 52638623Skarels s = splimp() ; 52738623Skarels if (dkp->dk_state & DK_RCV) { /* cancel outstanding receive */ 52838623Skarels dkcmd(KC_RCVB, chan, (caddr_t)0, (unsigned) 0, 0, 0) ; 52938623Skarels dkp->dk_endfcn = nendfcn ; 53038623Skarels dkp->dk_endparm = nendparm ; 53138623Skarels } 53238623Skarels splx(s) ; 53338623Skarels return dkp->dk_state ; 53438623Skarels } 53538623Skarels 53638623Skarels 53738623Skarels 53838623Skarels dk_status(chan) 53938623Skarels { 54038623Skarels if (chan >= dk_nchan) 54138623Skarels return 0 ; 54238623Skarels return dkit[chan].dk_state ; 54338623Skarels } 54438623Skarels 54538623Skarels 54638623Skarels /* 54738623Skarels * Various control commands to KMC 54838623Skarels */ 54938623Skarels dk_cmd(chan, cmd) 55038623Skarels { 55138623Skarels register struct dkchan *dkp ; 55238623Skarels register s ; 55338623Skarels 55438623Skarels dkp = &dkit[chan] ; 55538623Skarels if (cmd & (DKC_XINIT|DKC_FLUSH)) { 55638623Skarels /*for either command do the same thing: 55738623Skarels * reinit the transmitter and flush any pending output. 55838623Skarels * NOTE: for the kmc, there is no response to XINIT 55938623Skarels * and no send complete for flush 56038623Skarels */ 56138623Skarels s = splimp() ; 56238625Skarels dkcmd(KC_XINIT, chan, (caddr_t)0, (unsigned) 0, KMXBIG, 0) ; 56338623Skarels flushall(dkp, -1) ; 56438623Skarels dkcmd(KC_CMD, chan, (caddr_t)0, (unsigned) DKC_FLUSH, 0, 0) ; 56538623Skarels splx(s); 56638623Skarels cmd &= ~(DKC_XINIT|DKC_FLUSH) ; 56738623Skarels } 56838623Skarels if (cmd) 56938623Skarels dkcmd(KC_CMD, chan, (caddr_t)0, (unsigned) cmd, 0, 0) ; 57038623Skarels } 57138623Skarels 57238623Skarels 57338623Skarels /* 57438623Skarels * Note that flushall is often recursive when a tty driver 57538623Skarels * is involved. 57638623Skarels */ 57738623Skarels 57838623Skarels static 57938623Skarels flushall(dkp, rwflag) 58038623Skarels register struct dkchan *dkp ; 58138623Skarels { 58238623Skarels register s ; 58338623Skarels register struct mpacket *mbp ; 58438623Skarels int (*endfcn)(); 58538623Skarels 58638623Skarels s = splimp() ; 58738623Skarels if ((dkp->dk_state & DK_RCV) && (rwflag >= 0)) { 58838623Skarels dkcmd(KC_RCVB, dkp-dkit, (caddr_t)0, (unsigned) 0, 0, 0) ; 58938623Skarels dkp->dk_state &= ~DK_RCV ; 59038623Skarels if (dkp->dk_ubmbase) { 59138623Skarels ubarelse(ui->ui_ubanum, &dkp->dk_ubmbase); 59238623Skarels dkp->dk_ubmbase = NULL; 59338623Skarels } 59438623Skarels if (endfcn = dkp->dk_endfcn) { 59538623Skarels dkp->dk_endfcn = NULL ; 59638623Skarels (*endfcn)(dkp->dk_endparm, dkp-dkit, dkp->dk_rlen, DKR_ABORT, 0) ; 59738623Skarels } 59838623Skarels } 59938623Skarels 60038623Skarels /* flush all writes current and pending */ 60138623Skarels 60238623Skarels if ((dkp->dk_state & DK_BUSY) && (rwflag <= 0)) { 60338623Skarels register struct mbuf *m ; 60438623Skarels 60538623Skarels /* flush current write */ 60638623Skarels if (mbp = dkp->dk_obuf) { 60738623Skarels dkp->dk_obuf = NULL; 60838623Skarels if (endfcn = mbp->mp_endfcn) { 60938623Skarels mbp->mp_endfcn = NULL; 61038623Skarels (endfcn)(mbp->mp_endparm, dkp-dkit); 61138623Skarels } 61238623Skarels m_free(dtom(mbp)); 61338623Skarels } 61438623Skarels /* flush any pending writes which may be queued up */ 61538623Skarels while (1) { 61638623Skarels IF_DEQUEUE(&dkp->dk_outq, m); 61738623Skarels if (!m) break; 61838623Skarels mbp = mtod(m, struct mpacket *); 61938623Skarels if (endfcn = mbp->mp_endfcn) { 62038623Skarels mbp->mp_endfcn = NULL; 62138623Skarels (endfcn)(mbp->mp_endparm, dkp-dkit); 62238623Skarels } 62338623Skarels m_freem(m); 62438623Skarels } 62538623Skarels /* mark channel as not busy */ 62638623Skarels dkp->dk_state &= ~DK_BUSY ; 62738623Skarels } 62838623Skarels if ((dkp->dk_state & DK_OPEN) && (rwflag >= 0)) { 62938623Skarels dkcmd(KC_CLOSE, dkp-dkit, (caddr_t)0, (unsigned) 0, 0, 0) ; 63038623Skarels if (dkp->dk_state & DK_BUSY){ 63138623Skarels mbp = dkp->dk_obuf; 63238623Skarels dkp->dk_obuf = NULL; 63338623Skarels if (endfcn = mbp->mp_endfcn) { 63438623Skarels mbp->mp_endfcn = NULL; 63538623Skarels (endfcn)(mbp->mp_endparm, dkp-dkit); 63638623Skarels } 63738623Skarels m_free(dtom(mbp)); 63838623Skarels dkp->dk_state &= ~DK_BUSY ; 63938623Skarels } 64038623Skarels } 64138623Skarels splx(s) ; 64238623Skarels } 64338623Skarels 64438623Skarels 64538623Skarels short dup_count = 0; /* counter for number of duplicate sends */ 64638623Skarels 64738623Skarels /* 64838623Skarels * Routine to handle interrupts from the KMC 64938623Skarels * 65038623Skarels * This routine is called when 65138623Skarels * the KMC generates an unsolicited interrupt (VEC4 == 1) 65238623Skarels * 65338623Skarels * These interrupts are used by the KMC to notify dkit_kmc.c 65438623Skarels * of events such as output buffer completions 65538623Skarels * csr6 & csr7 point to dkkstat 65638623Skarels */ 65738623Skarels dkkint() 65838623Skarels { 65938623Skarels register struct dkchan *dkp; 66038623Skarels register struct dkkin *sp; 66138623Skarels register chan; 66238623Skarels struct mpacket *mbp ; 66338623Skarels int (*endfcn)(); 66438623Skarels 66538623Skarels M_ON(Mkint) ; 66638623Skarels 66738623Skarels chan = csr0 ; /* temp for cc -O bug */ 66838623Skarels if((chan & 01) == 1) /* 1 or 3 -> ignore */ 66938623Skarels return; 67038623Skarels sp = stat7 ; /* next response to be processed */ 67138623Skarels while (csr6 != csr7) { 67238623Skarels if (kseqchk) 67338623Skarels if ((((sp->k_chan >> 8)&0377) != kseq) || 67438623Skarels (((sp->k_type >> 8)&0377) != kseq)) { 67538623Skarels log(LOG_ERR, "dkkint: kseq %x chan %d type %x\n", 67638623Skarels kseq, sp->k_chan, sp->k_type) ; 67738623Skarels goto reset ; 67838623Skarels } 67938623Skarels kseq = (kseq + 1) & 0377 ; 68038623Skarels sp->k_addr = pseq ; 68138623Skarels pseq++ ; 68238623Skarels chan = sp->k_chan & 0377 ; /* mask off seq. # */ 68338623Skarels dkp = &dkit[chan]; 68438623Skarels if (chan > dkdebug) { 68538623Skarels log(LOG_ERR, " dkkint: head %d tail %d", csr6, csr7) ; 68638623Skarels log(LOG_ERR, " type %x chan %d len %d mode %x ctl %x\n", sp->k_type&0377, sp->k_chan&0377, sp->k_len, sp->k_mode, sp->k_ctl) ; 68738623Skarels } 68838623Skarels switch(sp->k_type & 0377) { 68938623Skarels case KS_CNTL: 69038623Skarels if (dkp->dk_supfcn) 69138623Skarels (*dkp->dk_supfcn)(chan, sp->k_ctl) ; 69238623Skarels break ; 69338623Skarels case KS_EOI: 69438623Skarels break ; 69538623Skarels case KS_SEND: 69638623Skarels mbp = dkp->dk_obuf ; 69738623Skarels if (mbp == NULL) { 69838623Skarels if (dkp->dk_state & (DK_RESET|DK_LINGR)) 69938623Skarels break; /* flushall was already called */ 70038623Skarels log(LOG_ERR, "dkkint: xbufout chan %d state %x\n", chan, dkp->dk_state) ; 70138623Skarels log(LOG_ERR, "head %d tail %d", csr6, csr7) ; 70238623Skarels log(LOG_ERR, " type %x len %d mode %x ctl %x\n", 70338623Skarels sp->k_type&0377, sp->k_len, sp->k_mode, sp->k_ctl) ; 70438623Skarels break ; 70538623Skarels } 70638623Skarels dkp->dk_state &= ~DK_BUSY; 70738623Skarels dkp->dk_obuf = NULL ; 70838623Skarels if (endfcn = mbp->mp_endfcn) { 70938623Skarels mbp->mp_endfcn = NULL; 71038623Skarels (endfcn)(mbp->mp_endparm, chan) ; 71138623Skarels } 71238623Skarels m_free(dtom(mbp)) ; 71338623Skarels if (dkp->dk_uba.ifu_xtofree) { 71438623Skarels m_freem(dkp->dk_uba.ifu_xtofree); 71538623Skarels dkp->dk_uba.ifu_xtofree = 0; 71638623Skarels } 71738623Skarels if (dkp->dk_outq.ifq_head) 71838623Skarels dkstart(dkp) ; 71938623Skarels break; 72038623Skarels case KS_RDB: 72138623Skarels if (((dkp->dk_state & DK_RCV) == 0) && dkp->dk_endfcn) { 72238623Skarels log(LOG_ERR, "dkkint: rbufin chan %d state %x\n", chan, dkp->dk_state) ; 72338623Skarels log(LOG_ERR, " head %d tail %d\n", csr6, csr7) ; 72438623Skarels log(LOG_ERR, " type %x len %d mode %x ctl %x\n", 72538623Skarels sp->k_type&0377, sp->k_len, sp->k_mode, sp->k_ctl) ; 72638623Skarels 72738623Skarels if (sp->k_ctl) 72838623Skarels break ; 72938623Skarels else { 73038623Skarels stat7 = sp ; /* save it for dump */ 73138623Skarels csr0 = 3 ; /* stop KMC */ 73238623Skarels panic("") ; /* KMC probably wrote 73338623Skarels into a mbuf we don't own */ 73438623Skarels } 73538623Skarels } 73638623Skarels dkp->dk_state &= ~DK_RCV ; 73738623Skarels if (dkp->dk_ubmbase) { 73838623Skarels ubarelse(ui->ui_ubanum, &dkp->dk_ubmbase); 73938623Skarels dkp->dk_ubmbase = NULL; 74038623Skarels } 74138623Skarels if (endfcn = dkp->dk_endfcn) { 74238623Skarels dkp->dk_endfcn = NULL; 74338623Skarels (endfcn)(dkp->dk_endparm, chan, sp->k_len, sp->k_mode, sp->k_ctl) ; 74438623Skarels } 74538623Skarels break; 74638623Skarels case KS_ERR: 74738623Skarels log(LOG_ERR, "dkkint: err : chan %d, code %x\nchead: %d, ctail: %d, rhead: %d, rtail: %d\n", 74838623Skarels chan, sp->k_len, csr4, csr5, csr6, csr7); 74938623Skarels 75038623Skarels /* if error is duplicate send, only close that chan, */ 75138623Skarels /* not the whole interface */ 75238623Skarels 75338623Skarels if (sp->k_len == E_DUP) { 75438623Skarels dup_count++; 75538623Skarels if (dkp->dk_state & DK_OPEN) { 75638623Skarels dk_reset(chan); 75738623Skarels } 75838623Skarels break; 75938623Skarels } 76038623Skarels reset: 76138623Skarels (void) dk_close(0) ; 76238623Skarels return ; 76338623Skarels default: 76438623Skarels log(LOG_ERR, "dkkint: chan %d, type %x, len %d, ctl %x, mode %x\n", 76538623Skarels chan, sp->k_type&0377, sp->k_len, sp->k_ctl, sp->k_mode); 76638623Skarels goto reset ; 76738623Skarels } /* end switch */ 76838623Skarels 76938623Skarels if (csr7 == dkk_nstat-1) { 77038623Skarels csr7 = 0 ; 77138623Skarels sp = &dkkstat[0] ; 77238623Skarels } else { 77338623Skarels csr7++ ; 77438623Skarels sp++ ; 77538623Skarels } 77638623Skarels 77738623Skarels } /* end while */ 77838623Skarels stat7 = sp ; 77938623Skarels M_OFF(Mkint) ; 78038623Skarels } 78138623Skarels 78238623Skarels /* 78338623Skarels * Start (Restart) transmission on the given line 78438623Skarels */ 78538623Skarels dkstart(dkp) 78638623Skarels register struct dkchan *dkp; 78738623Skarels { 78838623Skarels register struct mpacket *mbp; 78938623Skarels register struct mbuf *m; 79038623Skarels int len; 79138623Skarels 79238623Skarels /* 79338623Skarels * If it is currently active, just return 79438623Skarels */ 79538623Skarels if (dkp->dk_state&DK_BUSY) 79638623Skarels return; 79738623Skarels 79838623Skarels IF_DEQUEUE(&dkp->dk_outq, m); 79938623Skarels if (!m) 80038623Skarels return; 80138623Skarels mbp = mtod(m, struct mpacket *); 80238623Skarels 80338623Skarels dkp->dk_state |= DK_BUSY ; 80438623Skarels dkp->dk_obuf = mbp ; 80538623Skarels len = if_wubaput(&dkp->dk_uba, m->m_next); 80638623Skarels dkcmd(KC_SEND, dkp-dkit, (caddr_t) UBAI_ADDR(dkp->dk_uba.ifu_w.ifrw_info), 80738623Skarels (unsigned) len, mbp->mp_eob ? SBOT : SBOTM, mbp->mp_ctl) ; 80838623Skarels } 80938623Skarels 81038623Skarels /* 81138623Skarels * Put command in dkkcmdbuf which is pointed by csr4~5 81238623Skarels */ 81338623Skarels dkcmd(type, chan, addr, len, mode, ctl) 81438623Skarels int type, chan; 81538623Skarels caddr_t addr ; 81638623Skarels unsigned len ; 81738623Skarels { 81838623Skarels register struct dkkin *sp; 81938623Skarels register s; 82038623Skarels register next; 82138625Skarels register loop; 82238623Skarels struct timeval tv1, tv2; 82338623Skarels 82438623Skarels M_ON(Mcmd) ; 82538623Skarels s = csr0 ; 82638623Skarels if ((s & 3) != 2) 82738623Skarels return; 82838623Skarels 82938623Skarels s = splimp(); 83038623Skarels next = (csr4+1)%dkk_ncmd; 83138625Skarels loop = 0; 83238625Skarels while (csr5 == next) { 83338625Skarels /* give it a chance to empty the buffer */ 83438625Skarels if (loop++>10000000) { 83538625Skarels log(LOG_ERR, "KMC DIED, restart\n"); 83638625Skarels dk_close(0); 83738625Skarels splx(s); 83838625Skarels return; 83938625Skarels } 84038625Skarels log(LOG_ERR, "KMC cmd overrun for %ld\n", loop); 84138623Skarels } 84238623Skarels 84338623Skarels sp = cmd4 ; 84438623Skarels sp->k_type = type | ((pseq&0177)<<9) ; 84538623Skarels sp->k_chan = chan | ((kseq&0377)<<8) ; 84638623Skarels sp->k_addr = ((int)addr << 16) + ((int)addr >> 16) ; 84738623Skarels sp->k_len = len ; 84838623Skarels sp->k_mode = mode ; 84938623Skarels sp->k_ctl = ctl ; 85038623Skarels pseq++ ; 85138623Skarels 85238623Skarels csr4 = next; 85338623Skarels cmd4 = &dkkcmdbuf[next]; 85438623Skarels 85538623Skarels if (chan > dkdebug) { 85638623Skarels log(LOG_ERR, " dkcmd: head %d, tail %d", csr4, csr5); 85738623Skarels log(LOG_ERR, " type %x, chan %d, addr %x, len %d", 85838623Skarels type, chan, addr, len); 85938623Skarels log(LOG_ERR, " mode %x, ctl %x\n", mode, ctl); 86038623Skarels } 86138623Skarels splx(s) ; 86238623Skarels M_OFF(Mcmd) ; 86338623Skarels } 86438623Skarels 86538623Skarels #endif 866