From 5d02de29ba95047c4e7cf238585df1accaf56eda Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Sat, 13 Nov 1993 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1993-11-13 --- pc/adaptec.c | 505 --------------------- pc/bbmalloc.c | 62 ++- pc/clock.c | 1 - pc/devether.c | 592 +++++-------------------- pc/devincon.c | 1140 ------------------------------------------------ pc/ether.h | 169 ------- pc/ether503.c | 346 --------------- pc/ether509.c | 208 +++++---- pc/etherif.h | 29 ++ pc/fault386.c | 3 +- pc/fns.h | 3 + pc/kbd.c | 32 +- pc/l.s | 14 + pc/main.c | 6 +- pc/mmu.c | 35 +- pc/screen.c | 309 +++++++++++++ pc/trap.c | 126 ++++-- pc/ultrastor.c | 484 -------------------- 18 files changed, 752 insertions(+), 3312 deletions(-) delete mode 100644 pc/adaptec.c delete mode 100644 pc/devincon.c delete mode 100644 pc/ether.h delete mode 100644 pc/ether503.c create mode 100644 pc/etherif.h create mode 100644 pc/screen.c delete mode 100644 pc/ultrastor.c diff --git a/pc/adaptec.c b/pc/adaptec.c deleted file mode 100644 index 8c9ff7088a0f647ee23303676b07fd855a581563..0000000000000000000000000000000000000000 --- a/pc/adaptec.c +++ /dev/null @@ -1,505 +0,0 @@ -/* - * Adaptec AHA-154[02][BC] Intelligent Host Adapter. - * Needs work: - * handle multiple controllers; - * set options from user-level; - * split out to handle ultrastor too; - */ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "io.h" -#include "../port/error.h" - -#include "ureg.h" - -enum { - NCtlr = 1, - NTarget = 8, /* targets per controller */ - - Port = 0x330, /* factory defaults: I/O port */ - CtlrID = 7, /* adapter SCSI id */ - Irq = 11, /* interrupt request level */ -}; - -enum { /* registers */ - Rc = 0, /* WO: control */ - Rs = 0, /* RO: status */ - Rcdo = 1, /* WO: command/data out */ - Rdi = 1, /* RO: data in */ - Rif = 2, /* RO: interrupt flags */ -}; - -enum { /* Rc */ - Scrst = 0x10, /* SCSI bus reset */ - Irst = 0x20, /* interrupt reset */ - Srst = 0x40, /* soft reset */ - Hrst = 0x80, /* hard reset */ -}; - -enum { /* Rs */ - Invdcmd = 0x01, /* invalid host adapter command */ - Df = 0x04, /* data in port full */ - Cdf = 0x08, /* command/data port full */ - Idle = 0x10, /* SCSI host adapter idle */ - Init = 0x20, /* mailbox initialisation required */ - Diagf = 0x40, /* internal diagnostic failure */ - Stst = 0x80, /* self testing in progress */ -}; - -enum { /* Rcdo */ - Cnop = 0x00, /* no operation */ - Cmbinit = 0x01, /* mailbox initialisation */ - Cstart = 0x02, /* start SCSI command */ - Cbios = 0x03, /* start PC/AT BIOS command */ - Cinquiry = 0x04, /* adapter inquiry */ - Cmboie = 0x05, /* enable mailbox out available interrupt */ - Cselection = 0x06, /* set selection timeout */ - Cbuson = 0x07, /* set bus-on time */ - Cbusoff = 0x08, /* set bus-off time */ - Ctransfer = 0x09, /* set transfer speed */ - Cdevices = 0x0A, /* return installed devices */ - Cconfiguration = 0x0B, /* return configuration data */ - Ctenable = 0x0C, /* enable target mode */ - Csetup = 0x0D, /* return setup data */ - Cwbuff = 0x1A, /* write adapter channel 2 buffer */ - Crbuff = 0x1B, /* read adapter channel 2 buffer */ - Cwfifo = 0x1C, /* write adapter FIFO buffer */ - Crfifo = 0x1D, /* read adapter FIFO buffer */ - Cecho = 0x1F, /* ECHO command data */ - Cdiag = 0x20, /* adapter diagnostic */ - Coptions = 0x21, /* set host adapter options */ -}; - -enum { /* Rif */ - Mbif = 0x01, /* mailbox in full */ - Mboa = 0x02, /* mailbox out available */ - Hacc = 0x04, /* host adapter command complete */ - Scrd = 0x08, /* SCSI reset detected */ - Ai = 0x80, /* any interrupt */ -}; - -typedef struct { - uchar cmd; /* command */ - uchar msb; /* CCB pointer MSB */ - uchar mid; /* CCB pointer MID */ - uchar lsb; /* CCB pointer LSB */ -} Mbox; - -enum { /* mailbox commands */ - Mbfree = 0x00, /* mailbox is free */ - - Mbostart = 0x01, /* start SCSI or adapter command */ - Mboabort = 0x02, /* abort SCSI or adapter command */ - - Mbiok = 0x01, /* CCB completed without error */ - Mbiabort = 0x02, /* CCB aborted by host */ - Mbinx = 0x03, /* aborted CCB not found */ - Mbierror = 0x04, /* CCB completed with error */ -}; - -typedef struct { - uchar op; /* command control block operation code */ - uchar ctl; /* address and direction control */ - uchar cmdlen; /* SCSI command length */ - uchar reqlen; /* request sense allocation length */ - uchar datalen[3]; /* data length (MSB, MID, LSB) */ - uchar dataptr[3]; /* data pointer (MSB, MID, LSB) */ - uchar linkptr[3]; /* link pointer (MSB, MID, LSB) */ - uchar linkid; /* command linking identifier */ - uchar hastat; /* host adapter status */ - uchar tarstat; /* target device status */ - uchar reserved[2]; - uchar cs[12+0xFF]; /* SCSI command and sense bytes */ -} Ccb; - -enum { /* op */ - OInitiator = 0x00, /* initiator CCB */ - OTarget = 0x01, /* target CCB */ - Osg = 0x02, /* initiator CCB with scatter/gather */ - Ordl = 0x03, /* initiator CCB, residual data length returned */ - Osgrdl = 0x04, /* initiator CCB, both of the above */ - Obdr = 0x81, /* bus device reset */ -}; - -enum { /* ctl */ - CCBdatain = 0x08, /* inbound data transfer, length is checked */ - CCBdataout = 0x10, /* outbound data transfer, length is checked */ -}; - -enum { /* hastat */ - Eok = 0x00, /* no host adapter detected error */ - Etimeout = 0x11, /* selection timeout */ - Elength = 0x12, /* data over/under run */ - Ebusfree = 0x13, /* unexpected bus free */ - Ephase = 0x14, /* target bus phase sequence error */ - Eopcode = 0x16, /* invalid CCB opcode */ - Elink = 0x17, /* linked CCB does not have same LUN */ - Edirection = 0x18, /* invalid target direction received from host */ - Eduplicate = 0x19, /* duplicate CCB received in target mode */ - Esegment = 0x1A, /* invalid CCB or segment list parameter */ -}; - -enum { /* tarstat */ - Sgood = 0x00, /* good status */ - Scheck = 0x02, /* check status */ - Sbusy = 0x08, /* LUN busy */ -}; - -typedef struct Target Target; -typedef struct Ctlr Ctlr; - -struct Target { - QLock; - Rendez; - - Ccb ccb; - ulong paddr; /* physical address of ccb */ - uchar *sense; /* address of returned sense data */ - - int done; - Target *active; /* link on active list */ -}; - -struct Ctlr { - Lock; - - ulong port; /* I/O port */ - ulong id; /* adapter SCSI id */ - - uchar cmd[5]; /* adapter command out */ - uchar cmdlen; /* adapter command out length */ - uchar data[256]; /* adapter command data in */ - uchar datalen; /* adapter command data in length */ - - Mbox mb[NTarget+NTarget]; /* mailbox out + mailbox in */ - - Mbox *mbox; /* current mailbox out index into mb */ - Mbox *mbix; /* current mailbox in index into mb */ - - Target target[NTarget]; - Target *active; /* link on active list */ -}; - -static Ctlr softctlr[NCtlr]; - -/* - * Issue a command to the controller. The command and its length is - * contained in ctlr->cmd and ctlr->cmdlen. If any data is to be - * returned, ctlr->datalen should be non-0, and the returned data will - * be placed in ctlr->data. - * If we see Hacc set, bail out, we'll process - * the invalid command at interrupt time. - */ -static void -issue(Ctlr *ctlr) -{ - int len; - - len = 0; - while(len < ctlr->cmdlen){ - if((inb(ctlr->port+Rs) & Cdf) == 0){ - outb(ctlr->port+Rcdo, ctlr->cmd[len]); - len++; - } - - if(inb(ctlr->port+Rif) & Hacc) - return; - } - - if(ctlr->datalen){ - len = 0; - while(len < ctlr->datalen){ - if(inb(ctlr->port+Rs) & Df){ - ctlr->data[len] = inb(ctlr->port+Rdi); - len++; - } - - if(inb(ctlr->port+Rif) & Hacc) - return; - } - } -} - -static int -done(void *arg) -{ - return ((Target*)arg)->done; -} - -static int -scsiio(int bus, Scsi *p, int rw) -{ - Ctlr *ctlr; - Target *tp; - ushort status; - ulong len, s; - - /* - * Wait for the target to become free, - * then set it up. The Adaptec will allow us to - * queue multiple transactions per target, but - * gives no guarantee about ordering, so we just - * allow one per target. - */ - ctlr = &softctlr[bus]; - tp = &ctlr->target[p->target]; - - qlock(tp); - if(waserror()){ - qunlock(tp); - nexterror(); - } - - /* - * If this is a request-sense and we have valid sense data - * from the last command, return it immediately. - * A pox on these weird enum names and the WD33C93A status - * codes. - */ - if(p->cmd.base[0] == ScsiExtsens && tp->sense){ - len = 8+tp->sense[7]; - memmove(p->data.ptr, tp->sense, len); - p->data.ptr += len; - tp->sense = 0; - - qunlock(tp); - poperror(); - return 0x6000; - } - tp->sense = 0; - - /* - * Fill in the ccb. - */ - tp->ccb.op = Ordl; - tp->ccb.ctl = (p->target<<5)|p->lun; - - len = p->cmd.lim - p->cmd.base; - tp->ccb.cmdlen = len; - memmove(tp->ccb.cs, p->cmd.base, len); - - tp->ccb.reqlen = 0xFF; - - len = p->data.lim - p->data.base; - tp->ccb.datalen[0] = (len>>16) & 0xFF; - tp->ccb.datalen[1] = (len>>8) & 0xFF; - tp->ccb.datalen[2] = len; - if(len == 0) - tp->ccb.ctl |= CCBdataout|CCBdatain; - else if(rw == ScsiIn) - tp->ccb.ctl |= CCBdatain; - else - tp->ccb.ctl |= CCBdataout; - - len = PADDR(p->data.base); - tp->ccb.dataptr[0] = (len>>16) & 0xFF; - tp->ccb.dataptr[1] = (len>>8) & 0xFF; - tp->ccb.dataptr[2] = len; - - tp->ccb.linkptr[0] = tp->ccb.linkptr[1] = tp->ccb.linkptr[2] = 0; - tp->ccb.linkid = 0; - - tp->ccb.hastat = tp->ccb.tarstat = 0; - tp->ccb.reserved[0] = tp->ccb.reserved[1] = 0; - - /* - * Link the target onto the beginning of the - * ctlr active list and start the request. - * The interrupt routine has to be able to take - * requests off the queue in any order. - */ - s = splhi(); - if(active.machs > 1) - lock(ctlr); - - tp->done = 0; - tp->active = ctlr->active; - ctlr->active = tp; - - ctlr->mbox->msb = (tp->paddr>>16) & 0xFF; - ctlr->mbox->mid = (tp->paddr>>8) & 0xFF; - ctlr->mbox->lsb = tp->paddr & 0xFF; - ctlr->mbox->cmd = Mbostart; - - ctlr->cmd[0] = Cstart; - ctlr->cmdlen = 1; - ctlr->datalen = 0; - issue(ctlr); - - ctlr->mbox++; - if(ctlr->mbox >= &ctlr->mb[NTarget]) - ctlr->mbox = ctlr->mb; - - if(active.machs > 1) - unlock(ctlr); - splx(s); - - /* - * Wait for the request to complete - * and return the status. - */ - tsleep(tp, done, tp, 60*5*1000); - if(done(tp) == 0) - print("adaptec%d: timeout cmd=#%2.2ux\n", p->target, tp->ccb.cs[0]); - - if((status = (tp->ccb.hastat<<8)) == 0) - status = 0x6000; - status |= tp->ccb.tarstat; - len = (tp->ccb.datalen[0]<<16)|(tp->ccb.datalen[1]<<8)|tp->ccb.datalen[2]; - p->data.ptr = p->data.lim - len; - - /* - * If the command returned sense data, keep a note - * of where it is for a subsequent request-sense command. - */ - if(tp->ccb.tarstat == Scheck && tp->ccb.hastat == Eok) - tp->sense = &tp->ccb.cs[tp->ccb.cmdlen]; - - qunlock(tp); - poperror(); - - return status; -} - -static int -aha1542exec(Scsi *p, int rw) -{ - Ctlr *ctlr = &softctlr[0]; - - if(ctlr->port == 0) - error(Enodev); - if(p->target == CtlrID) - return 0x6002; - - return p->status = scsiio(0, p, rw); -} - -static void -interrupt(Ureg *ur) -{ - Ctlr *ctlr = &softctlr[0]; - uchar rif, rs; - Target *tp, **l; - ulong paddr; - - USED(ur); - - if(active.machs > 1) - lock(ctlr); - - /* - * Save and clear the interrupt(s). The only - * interrupts expected are Hacc, which we ignore, - * and Mbif which means something completed. - */ - rif = inb(ctlr->port+Rif); - rs = inb(ctlr->port+Rs); - outb(ctlr->port+Rc, Irst); - if(rif & ~(Ai|Hacc|Mbif)) - print("adaptec%d: interrupt #%2.2ux\n", 0, rif); - if((rif & Hacc) && (rs & Invdcmd)) - print("adaptec%d: invdcmd #%2.2ux, len %d\n", 0, ctlr->cmd[0], ctlr->cmdlen); - - /* - * Look for something in the mail. - * If there is, try to find the recipient from the - * ccb address, take it off the active list and - * wakeup whoever. - */ - while(ctlr->mbix->cmd){ - paddr = (ctlr->mbix->msb<<16)|(ctlr->mbix->mid<<8)|ctlr->mbix->lsb; - l = &ctlr->active; - for(tp = *l; tp; tp = tp->active){ - if(tp->paddr == paddr) - break; - l = &tp->active; - } - if(tp == 0) - panic("adaptec%d: no target for ccb #%lux\n", 0, paddr); - *l = tp->active; - - ctlr->mbix->cmd = 0; - - tp->done = 1; - wakeup(tp); - - ctlr->mbix++; - if(ctlr->mbix >= &ctlr->mb[NTarget+NTarget]) - ctlr->mbix = &ctlr->mb[NTarget]; - } - - if(active.machs > 1) - unlock(ctlr); -} - -static void -reset(Ctlr *ctlr, ulong port, ulong id) -{ - ulong paddr; - int i; - - /* - * Initialise the software controller and set the board - * scanning the mailboxes. - * Need code here to tidy things up if we're - * resetting after being active. - */ - memset(ctlr, 0, sizeof(Ctlr)); - ctlr->port = port; - ctlr->id = id; - for(i = 0; i < NTarget; i++){ - ctlr->target[i].paddr = PADDR(&ctlr->target[i].ccb); - ctlr->mbox = ctlr->mb; - ctlr->mbix = &ctlr->mb[NTarget]; - } - - ctlr->cmd[0] = Cmbinit; - paddr = PADDR(ctlr->mb); - ctlr->cmd[1] = NTarget; - ctlr->cmd[2] = (paddr>>16) & 0xFF; - ctlr->cmd[3] = (paddr>>8) & 0xFF; - ctlr->cmd[4] = paddr & 0xFF; - ctlr->cmdlen = 5; - ctlr->datalen = 0; - issue(ctlr); -} - -static ISAConf aha1542 = { - "aha1542", - Port, - Irq, - 0, - 0, -}; - -int (* -aha1542reset(void))(Scsi*, int) -{ - ISAConf *isa = &aha1542; - - /* - * See if we have any configuration info. - * Only one controller for now. - */ - if(isaconfig("scsi", 0, &aha1542) == 0) - return 0; - - /* - * Attempt to hard-reset the board and reset - * the SCSI bus. If the board state doesn't settle to - * idle with mailbox initialisation required, either - * it isn't an Adaptec or it's broken. - */ - outb(isa->port+Rc, Hrst|Scrst); - delay(500); - if(inb(isa->port+Rs) != (Init|Idle)) - return 0; - - setvec(Int0vec+isa->irq, interrupt); - reset(&softctlr[0], isa->port, CtlrID); - - return aha1542exec; -} diff --git a/pc/bbmalloc.c b/pc/bbmalloc.c index f216af964a4d112913363f2496a24f6b57326dfc..08d6aef6f0522c38f4b3bc1548227c3872c377cb 100644 --- a/pc/bbmalloc.c +++ b/pc/bbmalloc.c @@ -5,24 +5,31 @@ #include "fns.h" #include "io.h" +#define LINEWORDS (0) + /* * Allocate memory for use in kernel bitblts. + * The allocated memory must have a flushed instruction + * cache, and the data cache must be flushed by bbdflush(). + * To avoid the need for frequent cache flushes, the memory + * is allocated out of an arena, and the i-cache is only + * flushed when it has to be reused * * This code will have to be interlocked if we ever get * a multiprocessor with a bitmapped display. */ -/* a 0->3 bitblt can take 800 longs */ +/* a 0->3 bitblt can take 900 words */ enum { narena=2, /* put interrupt time stuff in separate arena */ nbbarena=4096 /* number of words in an arena */ }; -static ulong *bbarena[narena]; -static ulong *bbcur[narena]; -static ulong *bblast[narena]; +static ulong bbarena[narena][nbbarena+LINEWORDS]; +static ulong *bbcur[narena] = {&bbarena[0][0], &bbarena[1][0]}; +static ulong *bblast[narena] = {0, 0}; -#define INTENABLED(v) ((v)&(1<<9)) +#define INTLEVEL(v) (((v)&(1<<9)) == 0) void * bbmalloc(int nbytes) { @@ -32,52 +39,43 @@ bbmalloc(int nbytes) nw = nbytes/sizeof(long); s = splhi(); - a = INTENABLED(s) ? 0 : 1; - if(bbcur[a] + nw > bbarena[a] + nbbarena) + a = INTLEVEL(s)? 1 : 0; + if(bbcur[a] + nw > &bbarena[a][nbbarena]) ans = bbarena[a]; else ans = bbcur[a]; - bbcur[a] = ans + nw; - bblast[a] = ans; + bbcur[a] = ans + nw + (LINEWORDS); splx(s); - return ans; -} - -void -bbinit(void) -{ - int i; - if(bbarena[0]) - return; - for(i = 0; i < narena; i++){ - bbarena[i] = xalloc(nbbarena * sizeof(long)); - bbcur[i] = bbarena[i]; - bblast[i] = 0; - } + bblast[a] = ans; + return ans; } - void bbfree(void *p, int n) { int a, s; s = splhi(); - a = INTENABLED(s) ? 0 : 1; + a = INTLEVEL(s)? 1 : 0; if(p == bblast[a]) - bbcur[a] = (ulong *)(((char *)bblast[a]) + n); + bbcur[a] = (ulong *)(((char *)bblast[a]) + n + LINEWORDS*sizeof(long)); splx(s); } -void -bbdflush(void *p, int n) -{ - USED(p, n); -} - int bbonstack(void) { + /*if(u) + return 1;*/ return 0; } + +void +bbexec(void (*memstart)(void), int len, int onstack) +{ + memstart(); + if(onstack) + return; + bbfree(memstart, len); +} diff --git a/pc/clock.c b/pc/clock.c index 190bcc22eadb5f61859f1f0a981a959e16e5e6a1..b49a6b55f11fe55f0cff8bc69da439d063174a20 100644 --- a/pc/clock.c +++ b/pc/clock.c @@ -88,7 +88,6 @@ clock(Ureg *ur) m->ticks++; checkalarms(); - uartclock(); mouseclock(); /* diff --git a/pc/devether.c b/pc/devether.c index e972e4d3fe5234587fd0743d74a76f89299045fa..3940785040bbcba9183d27f5f43497d90cdf519f 100644 --- a/pc/devether.c +++ b/pc/devether.c @@ -3,46 +3,42 @@ #include "mem.h" #include "dat.h" #include "fns.h" -#include "../port/error.h" #include "io.h" -#include "devtab.h" +#include "ureg.h" +#include "../port/error.h" +#include "../port/netif.h" -#include "ether.h" +#include "etherif.h" -/* - * Half-arsed attempt at a general top-level - * ethernet driver. Needs work: - * handle multiple controllers - * much tidying - * set ethernet address - * need a ctl file passed down to card drivers - * so we can set options. - */ -extern Card ether8003, ether503, ether2000; -extern Card ether509; +static Ether *ether[MaxEther]; -/* - * The ordering here is important for those cards - * using the DP8390 (WD8003, 3Com503 and NE2000) as - * attempting to determine if a card is a NE2000 - * cannot be done passively, so it must be last to - * prevent scrogging one of the others. - */ -static Card *cards[] = { - ðer8003, - ðer503, - ðer2000, +void +etherinit(void) +{ +} - ðer509, - 0 -}; +Chan* +etherattach(char *spec) +{ + ulong ctlrno; + char *p; + Chan *c; -enum { - NCtlr = 1, -}; + ctlrno = 0; + if(spec && *spec){ + ctlrno = strtoul(spec, &p, 0); + if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther)) + error(Ebadarg); + } + if(ether[ctlrno] == 0) + error(Enodev); -/*static */struct Ctlr *softctlr[NCtlr]; -static int nctlr; + c = devattach('l', spec); + c->dev = ctlrno; + if(ether[ctlrno]->attach) + (*ether[ctlrno]->attach)(ether[ctlrno]); + return c; +} Chan* etherclone(Chan *c, Chan *nc) @@ -53,530 +49,164 @@ etherclone(Chan *c, Chan *nc) int etherwalk(Chan *c, char *name) { - return netwalk(c, name, &softctlr[0]->net); + return netifwalk(ether[c->dev], c, name); } void etherstat(Chan *c, char *dp) { - netstat(c, dp, &softctlr[0]->net); + netifstat(ether[c->dev], c, dp); } Chan* etheropen(Chan *c, int omode) { - return netopen(c, omode, &softctlr[0]->net); + return netifopen(ether[c->dev], c, omode); } void ethercreate(Chan *c, char *name, int omode, ulong perm) { USED(c, name, omode, perm); - error(Eperm); } void etherclose(Chan *c) { - if(c->stream) - streamclose(c); + netifclose(ether[c->dev], c); } long -etherread(Chan *c, void *a, long n, ulong offset) +etherread(Chan *c, void *buf, long n, ulong offset) { - return netread(c, a, n, offset, &softctlr[0]->net); -} - -long -etherwrite(Chan *c, char *a, long n, ulong offset) -{ - USED(offset); - return streamwrite(c, a, n, 0); + return netifread(ether[c->dev], c, buf, n, offset); } void etherremove(Chan *c) { USED(c); - error(Eperm); } void etherwstat(Chan *c, char *dp) { - netwstat(c, dp, &softctlr[0]->net); + netifwstat(ether[c->dev], c, dp); } -static int -isobuf(void *arg) -{ - Ctlr *ctlr = arg; - - return ctlr->tb[ctlr->th].owner == Host; -} - -static void -etheroput(Queue *q, Block *bp) +long +etherwrite(Chan *c, void *buf, long n, ulong offset) { - Ctlr *ctlr; - Type *type; - Etherpkt *pkt; - RingBuf *ring; - int len, n, s; - Block *nbp; + Ether *ctlr; - type = q->ptr; - ctlr = type->ctlr; - if(bp->type == M_CTL){ - qlock(ctlr); - if(streamparse("connect", bp)){ - if(type->type == -1) - ctlr->all--; - type->type = strtol((char*)bp->rptr, 0, 0); - if(type->type == -1) - ctlr->all++; - } - else if(streamparse("promiscuous", bp)) { - type->prom = 1; - ctlr->prom++; - if(ctlr->prom == 1) - (*ctlr->card.mode)(ctlr, 1); - } - qunlock(ctlr); - freeb(bp); - return; - } + USED(offset); + if(n > ETHERMAXTU) + error(Ebadarg); + ctlr = ether[c->dev]; - /* - * Give packet a local address, return upstream if destined for - * this machine. - */ - if(BLEN(bp) < ETHERHDRSIZE && (bp = pullup(bp, ETHERHDRSIZE)) == 0) - return; - pkt = (Etherpkt*)bp->rptr; - memmove(pkt->s, ctlr->ea, sizeof(ctlr->ea)); - if(memcmp(ctlr->ea, pkt->d, sizeof(ctlr->ea)) == 0){ - len = blen(bp); - if(bp = expandb(bp, len >= ETHERMINTU ? len: ETHERMINTU)){ - putq(&ctlr->lbq, bp); - wakeup(&ctlr->rr); - } - return; - } - if(memcmp(ctlr->ba, pkt->d, sizeof(ctlr->ba)) == 0 || ctlr->prom || ctlr->all){ - len = blen(bp); - nbp = copyb(bp, len); - if(nbp = expandb(nbp, len >= ETHERMINTU ? len: ETHERMINTU)){ - nbp->wptr = nbp->rptr+len; - putq(&ctlr->lbq, nbp); - wakeup(&ctlr->rr); - } - } + if(NETTYPE(c->qid.path) != Ndataqid) + return netifwrite(ctlr, c, buf, n); - /* - * Only one transmitter at a time. - */ qlock(&ctlr->tlock); if(waserror()){ qunlock(&ctlr->tlock); - freeb(bp); nexterror(); } - - /* - * Wait till we get an output buffer. - * should try to restart. - */ - if(isobuf(ctlr) == 0){ - tsleep(&ctlr->tr, isobuf, ctlr, 3*1000); - if(isobuf(ctlr) == 0){ - qunlock(&ctlr->tlock); - freeb(bp); - poperror(); - return; - } - } - - ring = &ctlr->tb[ctlr->th]; - - /* - * Copy message into buffer. - */ - len = 0; - for(nbp = bp; nbp; nbp = nbp->next){ - if(sizeof(Etherpkt) - len >= (n = BLEN(nbp))){ - memmove(ring->pkt+len, nbp->rptr, n); - len += n; - } - if(bp->flags & S_DELIM) - break; - } - - /* - * Pad the packet (zero the pad). - */ - if(len < ETHERMINTU){ - memset(ring->pkt+len, 0, ETHERMINTU-len); - len = ETHERMINTU; - } - - /* - * Set up the transmit buffer and - * start the transmission. - */ - s = splhi(); - ring->len = len; - ring->owner = Interface; - ctlr->th = NEXT(ctlr->th, ctlr->ntb); - (*ctlr->card.transmit)(ctlr); - splx(s); - - qunlock(&ctlr->tlock); - freeb(bp); + n = (*ctlr->write)(ctlr, buf, n); poperror(); -} - -/* - * Open an ether line discipline. - */ -static void -etherstopen(Queue *q, Stream *s) -{ - Ctlr *ctlr = softctlr[0]; - Type *type; - - type = &ctlr->type[s->id]; - RD(q)->ptr = WR(q)->ptr = type; - type->type = 0; - type->q = RD(q); - type->inuse = 1; - type->ctlr = ctlr; -} + qunlock(&ctlr->tlock); -/* - * Close ether line discipline. - * - * The locking is to synchronize changing the ethertype with - * sending packets up the stream on interrupts. - */ -static int -isclosed(void *arg) -{ - return ((Type*)arg)->q == 0; + return n; } static void -etherstclose(Queue *q) +etherintr(Ureg *ur) { - Type *type = (Type*)(q->ptr); - Ctlr *ctlr = type->ctlr; - - if(type->prom){ - qlock(ctlr); - ctlr->prom--; - if(ctlr->prom == 0) - (*ctlr->card.mode)(ctlr, 0); - qunlock(ctlr); - } - if(type->type == -1){ - qlock(ctlr); - ctlr->all--; - qunlock(ctlr); - } + int i, irq; /* - * Mark as closing and wait for kproc - * to close us. + * Call all ethernet interrupt routines on this IRQ. + * Might be better if setvec() took an argument which + * was passed down to the interrupt routine when + * called. This would let us easily distinguish multiple + * controllers. A hack by any other name... */ - lock(&ctlr->clock); - type->clist = ctlr->clist; - ctlr->clist = type; - unlock(&ctlr->clock); - wakeup(&ctlr->rr); - sleep(&type->cr, isclosed, type); - - type->type = 0; - type->prom = 0; - type->inuse = 0; - netdisown(type); - type->ctlr = 0; -} - -static Qinfo info = { - nullput, - etheroput, - etherstopen, - etherstclose, - "ether" -}; - -static int -clonecon(Chan *c) -{ - Ctlr *ctlr = softctlr[0]; - Type *type; - - USED(c); - for(type = ctlr->type; type < &ctlr->type[NType]; type++){ - qlock(type); - if(type->inuse || type->q){ - qunlock(type); - continue; - } - type->inuse = 1; - netown(type, u->p->user, 0); - qunlock(type); - return type - ctlr->type; + irq = ur->trap-Int0vec; + for(i = 0; i < MaxEther; i++){ + if(ether[i] && ether[i]->irq == irq) + (*ether[i]->interrupt)(ether[i]); } - exhausted("ether channels"); - return 0; -} - -static void -statsfill(Chan *c, char *p, int n) -{ - Ctlr *ctlr = softctlr[0]; - char buf[256]; - - USED(c); - sprint(buf, "in: %d\nout: %d\ncrc errs %d\noverflows: %d\nframe errs %d\nbuff errs: %d\noerrs %d\naddr: %.02x:%.02x:%.02x:%.02x:%.02x:%.02x\n", - ctlr->inpackets, ctlr->outpackets, ctlr->crcs, - ctlr->overflows, ctlr->frames, ctlr->buffs, ctlr->oerrs, - ctlr->ea[0], ctlr->ea[1], ctlr->ea[2], - ctlr->ea[3], ctlr->ea[4], ctlr->ea[5]); - strncpy(p, buf, n); } -static void -typefill(Chan *c, char *p, int n) -{ - char buf[16]; - Type *type; - - type = &softctlr[0]->type[STREAMID(c->qid.path)]; - sprint(buf, "%d", type->type); - strncpy(p, buf, n); -} - -static void -etherup(Ctlr *ctlr, Etherpkt *pkt, int len) -{ - int t; - Type *type; - Block *bp; - - t = (pkt->type[0]<<8)|pkt->type[1]; - for(type = &ctlr->type[0]; type < &ctlr->type[NType]; type++){ - - /* - * Check for open, the right type, and flow control. - */ - if(type->q == 0) - continue; - if(t != type->type && type->type != -1) - continue; - if(type->q->next->len > Streamhi) - continue; - - /* - * Only a trace channel gets packets destined for other machines. - */ - if(type->type != -1 && pkt->d[0] != 0xFF - && (*pkt->d != *ctlr->ea || memcmp(pkt->d, ctlr->ea, sizeof(pkt->d)))) - continue; - - if(waserror() == 0){ - bp = allocb(len); - memmove(bp->rptr, pkt, len); - bp->wptr += len; - bp->flags |= S_DELIM; - PUTNEXT(type->q, bp); - poperror(); - } - } -} - -static int -isinput(void *arg) -{ - Ctlr *ctlr = arg; - - return ctlr->lbq.first || ctlr->rb[ctlr->rh].owner == Host || ctlr->clist; -} - -static void -etherkproc(void *arg) -{ - Ctlr *ctlr = arg; - RingBuf *ring; - Block *bp; - Type *type; - - if(waserror()){ - print("%s noted\n", ctlr->name); - /* fix - if(ctlr->card.reset) - (*ctlr->card.reset)(ctlr); - */ - ctlr->kproc = 0; - nexterror(); - } - - for(;;){ - tsleep(&ctlr->rr, isinput, ctlr, 500); - if(ctlr->card.watch) - (*ctlr->card.watch)(ctlr); - - /* - * Process any internal loopback packets. - */ - while(bp = getq(&ctlr->lbq)){ - ctlr->inpackets++; - etherup(ctlr, (Etherpkt*)bp->rptr, BLEN(bp)); - freeb(bp); - } - - /* - * Process any received packets. - */ - while(ctlr->rb[ctlr->rh].owner == Host){ - ctlr->inpackets++; - ring = &ctlr->rb[ctlr->rh]; - etherup(ctlr, (Etherpkt*)ring->pkt, ring->len); - ring->owner = Interface; - ctlr->rh = NEXT(ctlr->rh, ctlr->nrb); - } - - /* - * Close Types requesting it. - */ - if(ctlr->clist){ - lock(&ctlr->clock); - for(type = ctlr->clist; type; type = type->clist){ - type->q = 0; - wakeup(&type->cr); - } - ctlr->clist = 0; - unlock(&ctlr->clock); - } - } -} +#define NCARD 32 +static struct { + char *type; + int (*reset)(Ether*); +} cards[NCARD+1]; -static void -etherintr(Ureg *ur) +void +addethercard(char *t, int (*r)(Ether*)) { - Ctlr *ctlr = softctlr[0]; + static int ncard; - USED(ur); - (*ctlr->card.intr)(ctlr); + if(ncard == NCARD) + panic("too many ether cards"); + cards[ncard].type = t; + cards[ncard].reset = r; + ncard++; } void etherreset(void) { - Ctlr *ctlr; - Card **card; - int i; + Ether *ctlr; + int i, n, ctlrno; + ulong irqmask; - if(nctlr >= NCtlr) - return; - if(softctlr[nctlr] == 0) - softctlr[nctlr] = xalloc(sizeof(Ctlr)); - ctlr = softctlr[nctlr]; - for(card = cards; *card; card++){ - memset(ctlr, 0, sizeof(Ctlr)); - ctlr->card = **card; - if((*ctlr->card.reset)(ctlr) == 0){ - ctlr->present = 1; + irqmask = 0; + for(ctlr = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){ + if(ctlr == 0) + ctlr = malloc(sizeof(Ether)); + memset(ctlr, 0, sizeof(Ether)); + if(isaconfig("ether", ctlrno, ctlr) == 0) + continue; + for(n = 0; cards[n].type; n++){ + if(strcmp(cards[n].type, ctlr->type)) + continue; + if((*cards[n].reset)(ctlr)) + break; /* * IRQ2 doesn't really exist, it's used to gang the interrupt * controllers together. A device set to IRQ2 will appear on * the second interrupt controller as IRQ9. + * If there are multiple controllers on the same IRQ, only + * call setvec() for one of them, etherintr() will scan through + * all the controllers looking for those at the IRQ it was + * called with. This is a hack, see the comments in etherintr(). */ - if(ctlr->card.irq == 2) - ctlr->card.irq = 9; - setvec(Int0vec + ctlr->card.irq, etherintr); - break; - } - } - if(ctlr->present == 0) - return; - - print("ether%d: %s: I/O addr %lux width %d addr %lux size %d irq %d:", - nctlr, ctlr->card.id, - ctlr->card.io, ctlr->card.bit16 ? 16: 8, ctlr->card.ramstart, - ctlr->card.ramstop-ctlr->card.ramstart, ctlr->card.irq); - for(i = 0; i < sizeof(ctlr->ea); i++) - print(" %2.2ux", ctlr->ea[i]); - print("\n"); - - nctlr++; - - if(ctlr->nrb == 0) - ctlr->nrb = Nrb; - ctlr->rb = xalloc(sizeof(RingBuf)*ctlr->nrb); - if(ctlr->ntb == 0) - ctlr->ntb = Ntb; - ctlr->tb = xalloc(sizeof(RingBuf)*ctlr->ntb); - - memset(ctlr->ba, 0xFF, sizeof(ctlr->ba)); - - ctlr->net.name = "ether"; - ctlr->net.nconv = NType; - ctlr->net.devp = &info; - ctlr->net.protop = 0; - ctlr->net.listen = 0; - ctlr->net.clone = clonecon; - ctlr->net.ninfo = 2; - ctlr->net.info[0].name = "stats"; - ctlr->net.info[0].fill = statsfill; - ctlr->net.info[1].name = "type"; - ctlr->net.info[1].fill = typefill; - for(i = 0; i < NType; i++) - netadd(&ctlr->net, &ctlr->type[i], i); -} - -void -etherinit(void) -{ - int ctlrno = 0; - Ctlr *ctlr = softctlr[ctlrno]; - int i; - - if(ctlr->present == 0) - return; - - ctlr->rh = 0; - ctlr->ri = 0; - for(i = 0; i < ctlr->nrb; i++) - ctlr->rb[i].owner = Interface; + if(ctlr->irq == 2) + ctlr->irq = 9; + if((irqmask & (1<irq)) == 0){ + setvec(Int0vec+ctlr->irq, etherintr); + irqmask |= 1<irq; + } - ctlr->th = 0; - ctlr->ti = 0; - for(i = 0; i < ctlr->ntb; i++) - ctlr->tb[i].owner = Host; -} + print("ether%d: %s: port %lux irq %d addr %lux size %d:", + ctlrno, ctlr->type, ctlr->port, ctlr->irq, ctlr->mem, ctlr->size); + for(i = 0; i < sizeof(ctlr->ea); i++) + print(" %2.2ux", ctlr->ea[i]); + print("\n"); -Chan* -etherattach(char *spec) -{ - int ctlrno = 0; - Ctlr *ctlr = softctlr[ctlrno]; + netifinit(ctlr, "ether", Ntypes, 32*1024); + ctlr->alen = Eaddrlen; + memmove(ctlr->addr, ctlr->ea, sizeof(ctlr->ea)); + memmove(ctlr->bcast, etherbcast, sizeof(etherbcast)); - if(ctlr->present == 0) - error(Enodev); - - /* - * Enable the interface - * and start the kproc. - */ - (*ctlr->card.attach)(ctlr); - if(ctlr->kproc == 0){ - sprint(ctlr->name, "ether%dkproc", ctlrno); - ctlr->kproc = 1; - kproc(ctlr->name, etherkproc, ctlr); + ether[ctlrno] = ctlr; + ctlr = 0; + } } - return devattach('l', spec); + if(ctlr) + free(ctlr); } diff --git a/pc/devincon.c b/pc/devincon.c deleted file mode 100644 index 65b8dfb1264920c1de987fbad2bcd0dfe03aec38..0000000000000000000000000000000000000000 --- a/pc/devincon.c +++ /dev/null @@ -1,1140 +0,0 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "../port/error.h" -#include "devtab.h" - -#include "io.h" - -/* Centronix parallel (printer) port */ - -typedef struct Lptinfo Lptinfo; - -struct Lptinfo -{ - int base; /* port number */ - int ivec; /* interrupt number */ -}; - -static Lptinfo lptinfo[] = { - 0x3bc, Parallelvec, /* lpt1 (safari) */ - 0x378, Parallelvec, /* lpt1 (`official') */ - 0x278, Int0vec+5, /* lpt2 (`official') */ -}; -#define NDEV (sizeof lptinfo/sizeof lptinfo[0]) - -extern int incondev; /* from config */ - -/* offsets, and bits in the registers */ -enum -{ - /* data latch register */ - Qdlr= 0x0, - /* printer status register */ - Qpsr= 0x1, - Fbusy= 0x80, - Fintbar= 0x40, - /* printer control register */ - Qpcr= 0x2, - Fie= 0x10, - Fsi= 0x08, - Finitbar= 0x04, - Faf= 0x02, - Fstrobe= 0x01, - - /* other `registers' */ - Qstats= 0x03, - Qdebug= 0x04 -}; - -/* - * af si dlr<7:0> - * 0 x xxxxxxxx wr ctl/data char (si is dcto) - * 1 0 xxxxxxxx wr cmd - * 1 1 xxxxxx00 rd ctl/data char - * 1 1 xxxxxx01 rd status - * 1 1 xxxxxx11 nop (multiplexer to normal state) - * - * psr<7:3> multiplexed as follows: - * - * bc7 bc6 bc5 bc4 bc3 - * rd, st- low bsy d8 d7 d6 d5 - * rd, st- high d4 d3 d2 d1 d0 - * other bsy int- - */ - -typedef struct Incon Incon; - -#define NOW (MACHP(0)->ticks*MS2HZ) - -#define DPRINT if(incondebug)kprint - -static void inconintr(Ureg *ur); - -enum { - Minstation= 2, /* lowest station # to poll */ - Maxstation= 15, /* highest station # to poll */ - Nincon= 1, /* number of incons */ - Nin= 32, /* Blocks in the input ring */ - Bsize= 128, /* size of an input ring block */ - Mfifo= 0xff /* a mask, must be 2^n-1, must be > Nin */ -}; - -struct Incon { - QLock; - - QLock xmit; /* transmit lock */ - QLock reslock; /* reset lock */ - int dev; /* base address of port */ - int station; /* station number */ - int state; /* chip state */ - Rendez r; /* output process */ - Rendez kr; /* input kernel process */ - ushort chan; /* current input channel */ - Queue *rq; /* read queue */ - int kstarted; /* true if kernel process started */ - - /* input blocks */ - - Block *inb[Nin]; - ushort wi; - ushort ri; - - /* statistics */ - - ulong overflow; /* overflow errors */ - ulong pack0; /* channel 0 */ - ulong crc; /* crc errors */ - ulong in; /* bytes in */ - ulong out; /* bytes out */ - ulong wait; /* wait time in milliseconds */ -}; - -Incon incon[Nincon]; - -/* - * chip state - */ -enum { - Selecting, - Selected, - Notliving, -}; - -/* - * internal chip registers - */ -#define sel_polln 0 -#define sel_station 1 -#define sel_poll0 2 -#define sel_rcv_cnt 3 -#define sel_rcv_tim 4 -#define sel_tx_cnt 5 - -/* - * CSR bits - */ -#define INCON_RUN 0x80 -#define INCON_STOP 0x00 -#define ENABLE_IRQ 0x40 -#define ENABLE_TX_IRQ 0x20 -#define INCON_ALIVE 0x80 -#define TX_FULL 0x10 -#define TX_EMPTY 0x08 -#define RCV_EMPTY 0x04 -#define OVERFLOW 0x02 -#define CRC_ERROR 0x01 - -/* - * polling constants - */ -#define HT_GNOT 0x30 -#define HT_UNIX 0x31 -#define ST_UNIX 0x04 -#define NCHAN 64 - -static void inconkproc(void*); - -/* - * incon stream module definition - */ -static void inconoput(Queue*, Block*); -static void inconstopen(Queue*, Stream*); -static void inconstclose(Queue*); -Qinfo inconinfo = -{ - nullput, - inconoput, - inconstopen, - inconstclose, - "incon" -}; - -int incondebug = 0; - -Dirtab incondir[]={ - "dlr", {Qdlr}, 1, 0666, - "psr", {Qpsr}, 5, 0444, - "pcr", {Qpcr}, 0, 0666, - "stats", {Qstats}, 0, 0444, - "debug", {Qdebug}, 0, 0666, -}; -#define NINCON (sizeof incondir/sizeof incondir[0]) - -static void -nop(void) -{ -} - -static int -slowinb(int x) -{ - nop(); - nop(); - return inb(x); -} - -static void -reset(int dev) /* hardware reset */ -{ - outb(dev+Qpcr, Finitbar); - outb(dev+Qpcr, 0); - outb(dev+Qpcr, Finitbar); -} - -static void -wrctl(int dev, int data) /* write control character */ -{ - outb(dev+Qpcr, Finitbar); /* no interrupts, please */ - outb(dev+Qdlr, data); - outb(dev+Qpcr, Finitbar|Fstrobe); - outb(dev+Qpcr, Finitbar|Fie); -} - -static void -wrdata(int dev, int data) /* write data character */ -{ - outb(dev+Qpcr, Finitbar|Fsi); - outb(dev+Qdlr, data); - outb(dev+Qpcr, Finitbar|Fsi|Fstrobe); - outb(dev+Qpcr, Finitbar|Fsi|Fie); -} - -static void -wrcmd(int dev, int data) /* write command */ -{ - outb(dev+Qpcr, Finitbar|Faf); - outb(dev+Qdlr, data); - outb(dev+Qpcr, Finitbar|Faf|Fstrobe); - outb(dev+Qpcr, Finitbar|Faf|Fie); -} - -static int -rdstatus(Incon *ip) /* read status */ -{ - int dev, data; - - dev = ip->dev; - - outb(dev+Qpcr, Finitbar|Faf|Fsi); - outb(dev+Qdlr, 0x01); - outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe); - data = (inb(dev+Qpsr)&0xf8)<<2; - outb(dev+Qpcr, Finitbar|Faf|Fsi); - data |= inb(dev+Qpsr)>>3; - if(data&(OVERFLOW|CRC_ERROR)){ - if(data&OVERFLOW) - ip->overflow++; - if(data&CRC_ERROR) - ip->crc++; - } - outb(dev+Qdlr, 0x03); - outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe); - outb(dev+Qpcr, Finitbar|Faf|Fsi|Fie); - - return data; -} - -static void -iwrcmd(int dev, int data) /* write command at interrupt level */ -{ - outb(dev+Qdlr, data); - outb(dev+Qpcr, Finitbar|Faf|Fstrobe); - outb(dev+Qpcr, Finitbar|Faf); -} - -static int -irdstatus(Incon *ip) /* read status at interrupt level */ -{ - int dev, data; - - dev = ip->dev; - - outb(dev+Qdlr, 0x01); - outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe); - data = (slowinb(dev+Qpsr)&0xf8)<<2; - outb(dev+Qpcr, Finitbar|Faf|Fsi); - data |= slowinb(dev+Qpsr)>>3; - if(data&(OVERFLOW|CRC_ERROR)){ - if(data&OVERFLOW) - ip->overflow++; - if(data&CRC_ERROR) - ip->crc++; - } - - return data; -} - -static int -irddata(int dev) /* read data at interrupt level */ -{ - int data; - - outb(dev+Qdlr, 0x00); - outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe); - data = (slowinb(dev+Qpsr)&0xf8)<<2; - outb(dev+Qpcr, Finitbar|Faf|Fsi); - data |= slowinb(dev+Qpsr)>>3; - - return data; -} - -static int -irdnext(int dev) /* read next data at interrupt level */ -{ - int data; - - outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe); - data = (inb(dev+Qpsr)&0xf8)<<2; - outb(dev+Qpcr, Finitbar|Faf|Fsi); - data |= inb(dev+Qpsr)>>3; - - return data; -} - -static void -irdnop(int dev, int pcr) /* read nop (mux reset) */ -{ - outb(dev+Qdlr, 0x03); - outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe); - outb(dev+Qpcr, pcr); -} - -int Irdnext(int); -#define irdnext Irdnext -/**/ - -/* - * set the incon parameters - */ -void -inconset(Incon *ip, int cnt, int del) -{ - int dev; - - if (cnt<1 || cnt>14 || del<1 || del>15) - error(Ebadarg); - - dev = ip->dev; - wrcmd(dev, sel_rcv_cnt | INCON_RUN); - wrdata(dev, cnt); - wrcmd(dev, sel_rcv_tim | INCON_RUN); - wrdata(dev, del); - wrcmd(dev, INCON_RUN | ENABLE_IRQ); -} - -/* - * parse a set request - */ -void -inconsetctl(Incon *ip, Block *bp) -{ - char *field[3]; - int n; - int del; - int cnt; - - del = 15; - n = getfields((char *)bp->rptr, field, 3, ' '); - switch(n){ - default: - freeb(bp); - error(Ebadarg); - case 2: - del = strtol(field[1], 0, 0); - if(del<0 || del>15){ - freeb(bp); - error(Ebadarg); - } - /* fall through */ - case 1: - cnt = strtol(field[0], 0, 0); - if(cnt<0 || cnt>15){ - freeb(bp); - error(Ebadarg); - } - } - inconset(ip, cnt, del); - freeb(bp); -} - -/* - * poll for a station number - */ -void -inconpoll(Incon *ip, int station) -{ - ulong timer; - int dev; - char *p; - - dev = ip->dev; - - /* - * get us to a known state - */ - ip->state = Notliving; - wrcmd(dev, INCON_STOP); - - /* - * try a station number - */ - wrcmd(dev, sel_station); - wrdata(dev, station); - wrcmd(dev, sel_poll0); - wrdata(dev, HT_GNOT); - wrcmd(dev, sel_rcv_cnt); - wrdata(dev, 3); - wrcmd(dev, sel_rcv_tim); - wrdata(dev, 15); - wrcmd(dev, sel_tx_cnt); - wrdata(dev, 1); - wrcmd(dev, sel_polln); - wrdata(dev, 0x00); - wrdata(dev, ST_UNIX); - wrdata(dev, NCHAN); - for(p = "gnot"; *p; p++) - wrdata(dev, *p); - wrctl(dev, 0); - - /* - * poll and wait for ready (or 1/4 second) - */ - ip->state = Selecting; - wrcmd(dev, INCON_RUN | ENABLE_IRQ); - timer = NOW + 250; - while (NOW < timer) { - nop(); - if(rdstatus(ip) & INCON_ALIVE){ - ip->station = station; - ip->state = Selected; - break; - } - } -} - -/* - * reset the chip and find a new station number - */ -void -inconrestart(Incon *ip) -{ - int i; - - if(!canqlock(&ip->reslock)) - return; - - /* - * poll for incon station numbers - */ - DPRINT("inconrestart\n"); - for(i = Minstation; i <= Maxstation; i++){ - inconpoll(ip, i); - if(ip->state == Selected) - break; - } - switch(ip->state) { - case Selecting: - DPRINT("incon[%d] not polled\n", ip-incon); - print("incon[%d] not polled\n", ip-incon); - break; - case Selected: - DPRINT("incon[%d] station %d\n", ip-incon, ip->station); - print("incon[%d] station %d\n", ip-incon, ip->station); - inconset(ip, 3, 15); - break; - default: - DPRINT("incon[%d] bollixed\n", ip-incon); - print("incon[%d] bollixed\n", ip-incon); - break; - } - qunlock(&ip->reslock); -} - -/* - * reset all incon chips. - */ - -void -inconreset(void) -{ - int i; - char *p; - - /* - * get incondev from p9rc - */ - p = getconf("incondev"); - if(p) - incondev = atoi(p); - - /* - * state is Selected if we used incon as the boot device - * i.e. we've already got a station number. - * state is Selecting if this is a first-time open. - */ -/* inconset(&incon[0], 3, 15); /**/ - for(i=0; i= Nincon) - error(Ebadarg); - ip = &incon[i]; - rdstatus(ip); - if(ip->state != Selected) - inconrestart(ip); - - c = devattach('i', spec); - c->dev = i; - c->qid.path = CHDIR; - c->qid.vers = 0; - return c; -} - -Chan* -inconclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int -inconwalk(Chan *c, char *name) -{ - return devwalk(c, name, incondir, NINCON, streamgen); -} - -void -inconstat(Chan *c, char *dp) -{ - devstat(c, dp, incondir, NINCON, streamgen); -} - -Chan* -inconopen(Chan *c, int omode) -{ - if(c->qid.path != CHDIR && c->qid.path >= Slowqid) - streamopen(c, &inconinfo); - c->mode = openmode(omode); - c->flag |= COPEN; - c->offset = 0; - return c; -} - -void -inconcreate(Chan *c, char *name, int omode, ulong perm) -{ - USED(c, name, omode, perm); - error(Eperm); -} - -void -inconclose(Chan *c) -{ - if(c->qid.path != CHDIR && c->qid.path >= Slowqid) - streamclose(c); -} - -long -inconread(Chan *c, void *buf, long n, ulong offset) -{ - char b[256]; - Incon *ip; - - if(c->qid.path == CHDIR) - return devdirread(c, buf, n, incondir, NINCON, streamgen); - ip = &incon[c->dev]; - switch(c->qid.path){ - default: - return streamread(c, buf, n); - case Qdlr: - case Qpsr: - case Qpcr: - sprint(b, "0x%2.2ux\n", inb(ip->dev + c->qid.path)); - break; - case Qstats: - sprint(b, "state: %d\nstation: %d\nin: %d\nout: %d\noverflow: %d\ncrc: %d\nwait: %d\n", - ip->state, ip->station, ip->in, ip->out, ip->overflow, ip->crc, ip->wait); - break; - case Qdebug: - sprint(b, "%d\n", incondebug); - break; - } - return readstr(offset, buf, n, b); -} - -long -inconwrite(Chan *c, void *buf, long n, ulong offset) -{ - char b[8]; - Incon *ip; - int data; - - USED(offset); - switch(c->qid.path){ - default: - return streamwrite(c, buf, n, 0); - case Qdlr: - case Qpcr: - case Qdebug: - break; - } - if(n > sizeof b-1) - n = sizeof b-1; - memmove(b, buf, n); - b[n] = 0; - data = strtoul(b, 0, 0); - switch(c->qid.path){ - default: - ip = &incon[c->dev]; - outb(ip->dev + c->qid.path, data); - break; - case Qdebug: - incondebug = data; - break; - } - return n; -} - -void -inconremove(Chan *c) -{ - USED(c); - error(Eperm); -} - -void -inconwstat(Chan *c, char *dp) -{ - USED(c, dp); - error(Eperm); -} - -/* - * the stream routines - */ - -/* - * kill off the kernel process - */ -static int -kNotliving(void *arg) -{ - Incon *ip; - - ip = (Incon *)arg; - return ip->kstarted == 0; -} - -static void -inconstclose(Queue * q) -{ - Incon *ip; - - ip = (Incon *)q->ptr; - qlock(ip); - ip->rq = 0; - qunlock(ip); - wakeup(&ip->kr); - sleep(&ip->r, kNotliving, ip); -} - -/* - * create the kernel process for input - * first wait for any old ones to die - */ -static void -inconstopen(Queue *q, Stream *s) -{ - Incon *ip; - char name[32]; - - ip = &incon[s->dev]; - sprint(name, "incon%d", s->dev); - q->ptr = q->other->ptr = ip; - wakeup(&ip->kr); - sleep(&ip->r, kNotliving, ip); - ip->rq = q; - kproc(name, inconkproc, ip); -} - -/* - * free all blocks of a message in `q', `bp' is the first block - * of the message - */ -static void -freemsg(Queue *q, Block *bp) -{ - for(; bp; bp = getq(q)){ - if(bp->flags & S_DELIM){ - freeb(bp); - return; - } - freeb(bp); - } -} - -static void -showpkt(char *str, int chan, int ctl, Block *bp, int i) -{ - int n; - - n = bp->wptr - bp->rptr; - kprint("%s(%d)%uo %d", str, chan, ctl, n); - if(n > 8) - n = 8; - for(; irptr[i]); - kprint("\n"); -} - -/* - * output a block - * - * the first 2 bytes of every message are the channel number, - * low order byte first. the third is a possible trailing control - * character. - */ -void -inconoput(Queue *q, Block *bp) -{ - int dev; - Incon *ip; - ulong end; - int status, chan, ctl; - int n, size; - - ip = (Incon *)q->ptr; - - if(bp->type != M_DATA){ - if(streamparse("inconset", bp)) - inconsetctl(ip, bp); - else - freeb(bp); - return; - } - if(BLEN(bp) < 3){ - bp = pullup(bp, 3); - if(bp == 0){ - print("inconoput pullup failed\n"); - return; - } - } - - /* - * get a whole message before handing bytes to the device - */ - if(!putq(q, bp)) - return; - - /* - * one transmitter at a time - */ - qlock(&ip->xmit); - dev = ip->dev; - - /* - * parse message - */ - bp = getq(q); - chan = bp->rptr[0] | (bp->rptr[1]<<8); - ctl = bp->rptr[2]; - bp->rptr += 3; - if(chan<=0) - print("bad channel %d\n", chan); - - if(incondebug){ - kprint("0x%.2ux ", rdstatus(ip)); - showpkt("->", chan, ctl, bp, 0); - } - - /* - * make sure there's an incon out there - */ - if(!(rdstatus(ip)&INCON_ALIVE) || ip->state==Notliving){ - DPRINT("inconoput: not ready"); - inconrestart(ip); - freemsg(q, bp); - qunlock(&ip->xmit); - return; - } - - /* - * send the 8 bit data - */ - for(;;){ - /* - * spin till there is room - */ - for(n=0, end = NOW+1000; (status=rdstatus(ip)) & TX_FULL; n++){ - nop(); /* make sure we don't optimize too much */ - if(NOW > end){ - print("incon output stuck 0 %.2ux\n", status); - freemsg(q, bp); - qunlock(&ip->xmit); - return; - } - } - ip->wait = (n + ip->wait)>>1; - - /* - * put in next packet - */ - n = bp->wptr - bp->rptr; - if(n > 16) - n = 16; - size = n; - wrctl(dev, chan); - ip->out += n; - while(n--){ - wrdata(dev, *bp->rptr++); - } - - /* - * get next block - */ - if(bp->rptr >= bp->wptr){ - if(bp->flags & S_DELIM){ - freeb(bp); - break; - } - freeb(bp); - bp = getq(q); - if(bp==0) - break; - } - - /* - * end packet - */ - wrctl(dev, 0); - } - - /* - * send the control byte if there is one - */ - if(ctl){ - if(size >= 16){ - wrctl(dev, 0); - for(end = NOW+1000; rdstatus(ip) & TX_FULL;){ - nop(); /* make sure we don't optimize too much */ - if(NOW > end){ - print("incon output stuck 1\n"); - freemsg(q, bp); - qunlock(&ip->xmit); - return; - } - } - wrctl(dev, chan); - } - if(rdstatus(ip) & TX_FULL) - print("inconfull\n"); - ip->out += 1; - wrctl(dev, ctl); - } - wrctl(dev, 0); - - qunlock(&ip->xmit); - return; -} - -/* - * return true if the raw fifo is non-empty - */ -static int -notempty(void *arg) -{ - Incon *ip; - - ip = (Incon *)arg; - return ip->ri!=ip->wi; -} - -/* - * Read bytes from the raw input circular buffer. - */ -static void -inconkproc(void *arg) -{ - Incon *ip; - Block *bp; - int i; - int locked; - - ip = (Incon *)arg; - ip->kstarted = 1; - - /* - * create a number of blocks for input - */ - for(i = 0; i < Nin; i++){ - bp = ip->inb[i] = allocb(Bsize); - bp->wptr += 3; - } - - locked = 0; - if(waserror()){ - if(locked) - qunlock(ip); - ip->kstarted = 0; - wakeup(&ip->r); - return; - } - - for(;;){ - /* - * sleep if input fifo empty - */ - sleep(&ip->kr, notempty, ip); - - /* - * die if the device is closed - */ - USED(locked); - qlock(ip); - locked = 1; - if(ip->rq == 0){ - qunlock(ip); - ip->kstarted = 0; - wakeup(&ip->r); - poperror(); - return; - } - - /* - * send blocks upstream and stage new blocks. - */ - while(ip->ri != ip->wi){ - bp = ip->inb[ip->ri]; - bp->flags |= S_DELIM; - ip->in += BLEN(bp); - PUTNEXT(ip->rq, bp); - bp = ip->inb[ip->ri] = allocb(Bsize); - bp->wptr += 3; - ip->ri = (ip->ri+1)%Nin; - } - USED(locked); - qunlock(ip); - locked = 0; - } -} - -/* - * drop a single packet - */ -static void -droppacket(int dev) -{ - if(irddata(dev) == 0) - return; - while(irdnext(dev)) - ; -} - -/* - * flush the input fifo - */ -static void -flushfifo(Incon *ip) -{ - while(!(irdstatus(ip) & RCV_EMPTY)) - droppacket(ip->dev); -} - -/* - * advance the queue. if we've run out of staged input blocks, - * drop the packet and return 0. otherwise return the next input - * block to fill. - */ -static Block * -nextin(Incon *ip, unsigned int c) -{ - Block *bp; - int next; - - bp = ip->inb[ip->wi]; - bp->rptr[0] = ip->chan; - bp->rptr[1] = ip->chan>>8; - bp->rptr[2] = c; - if(incondebug) - showpkt("<-", ip->chan, c, bp, 3); - - next = (ip->wi+1)%Nin; - if(next == ip->ri){ - bp->wptr = bp->rptr+3; - return bp; - } - ip->wi = next; - - return ip->inb[ip->wi]; -} - -/* - * read the packets from the device into the staged input blocks. - * we have to do this at interrupt tevel to turn off the interrupts. - */ -static void -rdpackets(Incon *ip) -{ - Block *bp; - unsigned int c; - int dev; - uchar *p; - int first = ip->wi; - - dev = ip->dev; - bp = ip->inb[ip->wi]; - if(bp==0){ - flushfifo(ip); - return; - } - p = bp->wptr; - while(!(irdstatus(ip) & RCV_EMPTY)){ - /* - * get channel number - */ - c = irddata(dev); - if(c == 0){ - droppacket(dev); - continue; - } - if(ip->chan != c){ - if(p - bp->rptr > 3){ - bp->wptr = p; - bp = nextin(ip, 0); - p = bp->wptr; - } - ip->chan = c; - } - - /* - * null byte marks end of packet - */ - while(c = irdnext(dev)){ /* assign = */ - if((c & 0x100) == 0){ - /* - * control byte ends block - */ - bp->wptr = p; - bp = nextin(ip, c); - p = bp->wptr; - }else{ - /* - * data byte, put in local buffer - */ - *p++ = c; - } - } - - /* - * pass a block on if it doesn't have room for one more - * packet. this way we don't have to check per byte. - */ - if(p + 16 > bp->lim){ - bp->wptr = p; - bp = nextin(ip, 0); - p = bp->wptr; - } - } - bp->wptr = p; - if(bp->wptr != bp->rptr+3) - nextin(ip, 0); - - if(first != ip->wi)/**/ - wakeup(&ip->kr); -} - -/* - * Receive an incon interrupt. One entry point - * for all types of interrupt. Until we figure out - * how to use more than one incon, this routine only - * is for incon[0]. - */ -static void -inconintr(Ureg *ur) -{ - uchar status; - int pcr; - Incon *ip; - - USED(ur); - ip = &incon[0]; - pcr = inb(ip->dev+Qpcr); - if(!(pcr & Fie)) - return; - status = irdstatus(ip); - if(incondebug){ - kprint("pcr=%2.2x status=%2.2x\n", pcr, status); - if(pcr & Fstrobe) - kprint("YIKES!!\n"); - } - if(!(status & RCV_EMPTY)) - rdpackets(ip); - - /* see if it died underneath us */ - if(!(status&INCON_ALIVE)){ - switch(ip->state){ - case Selected: - iwrcmd(ip->dev, INCON_STOP); - DPRINT("Incon died\n"); - print("Incon died\n"); - break; - case Selecting: - DPRINT("rejected\n"); - print("rejected\n"); - break; - default: - iwrcmd(ip->dev, INCON_STOP); - DPRINT("state was %d\n", ip->state); - break; - } - ip->state = Notliving; - } - irdnop(ip->dev, pcr); -} diff --git a/pc/ether.h b/pc/ether.h deleted file mode 100644 index d4fcf00ae96b96ce795b5352f532ca0003997513..0000000000000000000000000000000000000000 --- a/pc/ether.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * All the goo for PC ethernet cards. - */ -typedef struct Card Card; -typedef struct RingBuf RingBuf; -typedef struct Type Type; -typedef struct Ctlr Ctlr; - -/* - * Hardware interface. - */ -struct Card { - ISAConf; - - int (*reset)(Ctlr*); - void (*init)(Ctlr*); - void (*attach)(Ctlr*); - void (*mode)(Ctlr*, int); - - void *(*read)(Ctlr*, void*, ulong, ulong); - void *(*write)(Ctlr*, ulong, void*, ulong); - - void (*receive)(Ctlr*); - void (*transmit)(Ctlr*); - void (*intr)(Ctlr*); - void (*watch)(Ctlr*); - void (*overflow)(Ctlr*); - - uchar bit16; /* true if a 16 bit interface */ - uchar ram; /* true if card has shared memory */ - - ulong dp8390; /* I/O address of 8390 (if any) */ - ulong data; /* I/O data port if no shared memory */ - uchar nxtpkt; /* software bndry */ - uchar tstart; /* 8390 ring addresses */ - uchar pstart; - uchar pstop; -}; - -/* - * Software ring buffer. - */ -struct RingBuf { - uchar owner; - uchar busy; /* unused */ - ushort len; - uchar pkt[sizeof(Etherpkt)]; -}; - -enum { - Host = 0, /* buffer owned by host */ - Interface = 1, /* buffer owned by card */ - - Nrb = 16, /* default number of receive buffers */ - Ntb = 4, /* default number of transmit buffers */ -}; - -/* - * One per ethernet packet type. - */ -struct Type { - QLock; - Netprot; /* stat info */ - int type; /* ethernet type */ - int prom; /* promiscuous mode */ - Queue *q; - int inuse; - Ctlr *ctlr; - - Rendez cr; /* rendezvous for close */ - Type *clist; /* close list */ -}; - -enum { - NType = 9, /* types/card */ -}; - -/* - * Software controller. - */ -struct Ctlr { - QLock; - int ctlrno; - Ctlr *next; - - Card card; /* hardware info */ - int present; - int debug; - - ushort nrb; /* number of software receive buffers */ - ushort ntb; /* number of software transmit buffers */ - RingBuf *rb; /* software receive buffers */ - RingBuf *tb; /* software transmit buffers */ - - uchar ea[6]; /* ethernet address */ - uchar ba[6]; /* broadcast address */ - - Rendez rr; /* rendezvous for a receive buffer */ - ushort rh; /* first receive buffer belonging to host */ - ushort ri; /* first receive buffer belonging to card */ - - Rendez tr; /* rendezvous for a transmit buffer */ - QLock tlock; /* semaphore on th */ - ushort th; /* first transmit buffer belonging to host */ - ushort ti; /* first transmit buffer belonging to card */ - int tbusy; /* transmitter is busy */ - - Type type[NType]; - int all; /* number of channels listening to all packets */ - Type *clist; /* channels waiting to close */ - Lock clock; /* lock for clist */ - int prom; /* number of promiscuous channels */ - int kproc; /* true if kproc started */ - char name[NAMELEN]; /* name of kproc */ - Network net; - - Queue lbq; /* software loopback packet queue */ - - int inpackets; - int outpackets; - int crcs; /* input crc errors */ - int oerrs; /* output errors */ - int frames; /* framing errors */ - int overflows; /* packet overflows */ - int buffs; /* buffering errors */ -}; - -#define NEXT(x, l) (((x)+1)%(l)) -#define HOWMANY(x, y) (((x)+((y)-1))/(y)) -#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y)) - -/* - * The Western Digital 8003 and 8013 series, the NE2000 - * and the 3Com 503 all use the DP8390 Network Interface - * Chip. - */ -extern void dp8390reset(Ctlr*); -extern void dp8390attach(Ctlr*); -extern void dp8390mode(Ctlr*, int); -extern void dp8390getea(Ctlr*); -extern void dp8390setea(Ctlr*); -extern void *dp8390read(Ctlr*, void*, ulong, ulong); -extern void *dp8390write(Ctlr*, ulong, void*, ulong); -extern void dp8390receive(Ctlr*); -extern void dp8390transmit(Ctlr*); -extern void dp8390intr(Ctlr*); -extern void dp8390watch(Ctlr*); -extern void dp8390overflow(Ctlr*); - -extern void dp8390debug(Ctlr*); - -/* - * The DP8390 needs some time between successive - * chip selects, so we need special I/O routines. - * See l.s. - * These routines only need to be used for accessing - * the chip registers. Data I/O, either through - * remote DMA or shared memory, can use the normal - * routines. - */ -extern int dp8390inb(ulong); -extern void dp8390outb(ulong, uchar); - -enum { - Dp8390BufSz = 256, /* hardware ring buffer size */ -}; - - -extern void addethercard(char*, int (*)(Ctlr*)); diff --git a/pc/ether503.c b/pc/ether503.c deleted file mode 100644 index 563702cc7f7f8d42bf9e7f36c707e682e17522f9..0000000000000000000000000000000000000000 --- a/pc/ether503.c +++ /dev/null @@ -1,346 +0,0 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "../port/error.h" -#include "io.h" -#include "devtab.h" - -#include "ether.h" - -/* - * 3Com 503 (EtherLink II). - * This driver doesn't work under load, the card gets blasted by - * overwrite-warning interrupts and eventually just hangs. Always clearing - * the Ovw bit in the DP8390 Isr along with the Rxe and Prx bits stops - * the overwrite-warning interrupts, but the card eventually hangs anyway. - * I really don't understand why this card doesn't work, - * there is plenty of evidence that other systems manage to use it. - * The only good thing about this driver is that both shared - * memory and polled I/O work (given the above restraints), although - * the polled I/O should be tuned. - */ -enum { /* Gate Array Registers */ - Pstr = 0x400, /* Page Start Register */ - Pspr = 0x401, /* Page Stop Register */ - Dqtr = 0x402, /* Drq Timer Register */ - Bcfr = 0x403, /* Base Configuration Register */ - Pcfr = 0x404, /* EPROM Configuration Register */ - Gacfr = 0x405, /* GA Configuration Register */ - Ctrl = 0x406, /* Control Register */ - Streg = 0x407, /* Status Register */ - Idcfr = 0x408, /* Interrupt/DMA Configuration Register */ - Damsb = 0x409, /* DMA Address Register MSB */ - Dalsb = 0x40A, /* DMA Address Register LSB */ - Vptr2 = 0x40B, /* Vector Pointer Register 2 */ - Vptr1 = 0x40C, /* Vector Pointer Register 1 */ - Vptr0 = 0x40D, /* Vector Pointer Register 0 */ - Rfmsb = 0x40E, /* Register File Access MSB */ - Rflsb = 0x40F, /* Register File Access LSB */ -}; - -enum { /* Pcfr */ - C8xxx = 0x10, /* memory address 0xC8000 */ - CCxxx = 0x20, /* memory address 0xCC000 */ - D8xxx = 0x40, /* memory address 0xD8000 */ - DCxxx = 0x80, /* memory address 0xDC000 */ -}; - -enum { /* Gacfr */ - Mbs0 = 0x01, /* memory bank select 0 */ - Mbs1 = 0x02, /* memory bank select 1 */ - Mbs2 = 0x04, /* memory bank select 2 */ - Rsel = 0x08, /* RAM select */ - Test = 0x10, /* test */ - Ows = 0x20, /* 0 wait state */ - Tcm = 0x40, /* terminal count mask */ - Nim = 0x80, /* MIC interrupt mask */ -}; - -enum { /* Ctrl */ - Rst = 0x01, /* software reset */ - Xsel = 0x02, /* transceiver select (BNC = 1, AUI = 0) */ - Ealo = 0x04, /* ethernet address low */ - Eahi = 0x08, /* ethernet address high */ - Share = 0x10, /* interrupt share */ - Dbsel = 0x20, /* double buffer select */ - Ddir = 0x40, /* DMA direction */ - Start = 0x80, /* DMA start */ -}; - -enum { /* Streg */ - Rev0 = 0x01, /* gate array revision bit 0 */ - Rev1 = 0x02, /* gate array revision bit 1 */ - Rev2 = 0x04, /* gate array revision bit 2 */ - Dip = 0x08, /* DMA in progress */ - Dtc = 0x10, /* DMA terminal count */ - Oflw = 0x20, /* overflow */ - Uflw = 0x40, /* underflow */ - Dprdy = 0x80, /* data port ready */ -}; - -enum { /* Idcfr */ - Drq1 = 0x01, /* DMA request 1 */ - Drq2 = 0x02, /* DMA request 2 */ - Drq3 = 0x04, /* DMA request 3 */ - Irq2 = 0x10, /* interrupt request 2 */ - Irq3 = 0x20, /* interrupt request 3 */ - Irq4 = 0x40, /* interrupt request 4 */ - Irq5 = 0x80, /* interrupt request 5 */ -}; - -enum { - RamOffset = 0x2000, /* where the card sees the shared memory */ -}; - -typedef struct { - ulong io; /* I/O base address */ - uchar irq; /* interrupt level */ - uchar bnc; /* use BNC connector */ -} Table; - -/* - * The only configuration info we can get from the card is the - * I/O base address and the shared-memory address. So let's make - * a little hard-wired configuration table. - */ -static Table table[] = { - { 0x300, Irq2, 0, }, /* external transceiver */ - { 0x310, Irq3, 0, }, - { 0x330, Irq4, 0, }, - { 0x350, Irq5, 0, }, - - { 0x250, Irq2, Xsel, }, /* BNC */ - { 0x280, Irq3, Xsel, }, - { 0x2A0, Irq4, Xsel, }, - { 0x2E0, Irq5, Xsel, }, - - { 0 }, -}; - - -static int -reset(Ctlr *ctlr) -{ - Table *tp; - int i; - uchar cfr; - - /* - * The Gate Array Ctrl register bits <3,2> determine what is - * mapped at the I/O base address. The options are the DP8390, - * PROM bytes 0-15 or PROM bytes 16-31. - * At power-on, the I/O base address contains PROM bytes 16-31. - */ - for(tp = table; ctlr->card.io = tp->io; tp++){ - /* - * Toggle the software reset bit, this should initialise the - * Ctrl register to 0x0A (Eahi|Xsel). - * Hopefully there is no other card at the gate-array address. - */ - outb(ctlr->card.io+Ctrl, Rst); - delay(1); - outb(ctlr->card.io+Ctrl, 0); - if(inb(ctlr->card.io+Ctrl) == (Eahi|Xsel)) - break; - } - if(ctlr->card.io == 0) - return -1; - - /* - * Map PROM bytes 0-15 to the I/O base address - * and read the ethernet address. - * When done, map the DP8390 at the I/O base address - * and set the transceiver type and irq. - */ - outb(ctlr->card.io+Ctrl, Ealo|Xsel); - for(i = 0; i < sizeof(ctlr->ea); i++) - ctlr->ea[i] = inb(ctlr->card.io+i); - - outb(ctlr->card.io+Gacfr, Nim|Tcm); - - outb(ctlr->card.io+Ctrl, 0|tp->bnc); - outb(ctlr->card.io+Idcfr, tp->irq); - - if(tp->irq == Irq2) - ctlr->card.irq = 2; - else if(tp->irq == Irq3) - ctlr->card.irq = 3; - else if(tp->irq == Irq4) - ctlr->card.irq = 4; - else if(tp->irq == Irq5) - ctlr->card.irq = 5; - else - return -1; - - /* - * Try to configure the shared memory. - * Assume this is an 8K card. - */ - ctlr->card.ram = 1; - cfr = inb(ctlr->card.io+Pcfr); - if(cfr & C8xxx) - ctlr->card.ramstart = KZERO|0xC8000; - else if(cfr & CCxxx) - ctlr->card.ramstart = KZERO|0xCC000; - else if(cfr & D8xxx) - ctlr->card.ramstart = KZERO|0xD8000; - else if(cfr & DCxxx) - ctlr->card.ramstart = KZERO|0xDC000; - else - ctlr->card.ram = 0; - - ctlr->card.ramstop = ctlr->card.ramstart + 8*1024; - - /* - * Finish initialising the gate-array. - * The Pstr and Pspr registers must be the same as those - * given to the DP8390. - * Gacfr is set to enable shared memory and block DMA - * interrupts. - */ - outb(ctlr->card.io+Pstr, ctlr->card.pstart); - outb(ctlr->card.io+Pspr, ctlr->card.pstop); - - outb(ctlr->card.io+Dqtr, 8); - outb(ctlr->card.io+Damsb, ctlr->card.tstart); - outb(ctlr->card.io+Dalsb, 0); - - outb(ctlr->card.io+Vptr2, 0xFF); - outb(ctlr->card.io+Vptr1, 0xFF); - outb(ctlr->card.io+Vptr0, 0x00); - - /* - * Finally, init the 8390, set the ethernet address - * and turn on the shared memory if any. - */ - ctlr->card.dp8390 = ctlr->card.io; - dp8390reset(ctlr); - dp8390setea(ctlr); - - if(ctlr->card.ram) - outb(ctlr->card.io+Gacfr, Tcm|Rsel|Mbs0); - else - outb(ctlr->card.io+Gacfr, Tcm); - - return 0; -} - -static void* -read(Ctlr *ctlr, void *to, ulong from, ulong len) -{ - uchar *addr, ctrl; - - /* - * If the interface has shared memory, just do a memmove. - * In this case, 'from' is an index into the shared memory. - * Due to 'hardware considerations', the memory is seen by - * the adapter at RamOffset, so we have to adjust. - */ - if(ctlr->card.ram) - return memmove(to, (void*)(ctlr->card.ramstart+from-RamOffset), len); - - /* - * Polled I/O. This should be tuned. - * Set up the dma registers and pump the fifo. - */ - outb(ctlr->card.io+Dalsb, from & 0xFF); - outb(ctlr->card.io+Damsb, (from>>8) & 0xFF); - ctrl = inb(ctlr->card.io+Ctrl); - outb(ctlr->card.io+Ctrl, Start|ctrl); - addr = to; - while(len){ - /* - * The fifo is 8 bytes deep, we have to wait - * until it's ready before stuffing it. - * The fifo is in its default configuration, - * so we can do word accesses. - */ - while((inb(ctlr->card.io+Streg) & Dprdy) == 0) - ; - if(len >= 8){ - inss(ctlr->card.io+Rfmsb, addr, 4); - addr += 8; - len -= 8; - } - else{ - insb(ctlr->card.io+Rfmsb, addr, len); - break; - } - } - outb(ctlr->card.io+Ctrl, ctrl); - return to; -} - -static void* -write(Ctlr *ctlr, ulong to, void *from, ulong len) -{ - uchar *addr, ctrl; - - /* - * See the comments in 'read()' above. - */ - if(ctlr->card.ram) - return memmove((void*)(ctlr->card.ramstart+to-RamOffset), from, len); - - outb(ctlr->card.io+Dalsb, to & 0xFF); - outb(ctlr->card.io+Damsb, (to>>8) & 0xFF); - ctrl = inb(ctlr->card.io+Ctrl); - outb(ctlr->card.io+Ctrl, Start|Ddir|ctrl); - addr = from; - while(len){ - while((inb(ctlr->card.io+Streg) & Dprdy) == 0) - ; - if(len >= 8){ - outss(ctlr->card.io+Rfmsb, addr, 4); - addr += 8; - len -= 8; - } - else{ - outsb(ctlr->card.io+Rfmsb, addr, len); - break; - } - } - outb(ctlr->card.io+Ctrl, ctrl); - return (void*)to; -} - -Card ether503 = { - "3Com503", /* ident */ - - reset, /* reset */ - 0, /* init */ - dp8390attach, /* attach */ - dp8390mode, /* mode */ - - read, /* read */ - write, /* write */ - - dp8390receive, /* receive */ - dp8390transmit, /* transmit */ - dp8390intr, /* interrupt */ - dp8390watch, /* watch */ - dp8390overflow, /* overflow */ - - 0, /* io */ - 0, /* irq */ - 0, /* bit16 */ - - 0, /* ram */ - 0, /* ramstart */ - 0, /* ramstop */ - - 0, /* dp8390 */ - 0, /* data */ - 0, /* software bndry */ - RamOffset/Dp8390BufSz, /* tstart */ - (RamOffset+0x600)/Dp8390BufSz, /* pstart */ - (RamOffset+8*1024)/Dp8390BufSz, /* pstop */ -}; - -void -ether503link(void) -{ - addethercard("3C503", ccc503reset); -} diff --git a/pc/ether509.c b/pc/ether509.c index cc28b2d40d2890f1d2562b21bbff540fb61df071..d31b97459bbd70a17e76209dee212c8e6661e540 100644 --- a/pc/ether509.c +++ b/pc/ether509.c @@ -3,11 +3,11 @@ #include "mem.h" #include "dat.h" #include "fns.h" -#include "../port/error.h" #include "io.h" -#include "devtab.h" +#include "../port/error.h" +#include "../port/netif.h" -#include "ether.h" +#include "etherif.h" enum { IDport = 0x0100, /* anywhere between 0x0100 and 0x01F0 */ @@ -87,11 +87,11 @@ enum { #define COMMAND(port, cmd, a) outs(port+Command, ((cmd)<<11)|(a)) static void -attach(Ctlr *ctlr) +attach(Ether *ether) { ulong port; - port = ctlr->card.port; + port = ether->port; /* * Set the receiver packet filter for our own and * and broadcast addresses, set the interrupt masks @@ -108,11 +108,11 @@ attach(Ctlr *ctlr) } static void -mode(Ctlr *ctlr, int on) +promiscuous(void *arg, int on) { ulong port; - port = ctlr->card.port; + port = ((Ether*)arg)->port; if(on) COMMAND(port, SetRxFilter, Promiscuous|Broadcast|MyEtherAddr); else @@ -120,14 +120,14 @@ mode(Ctlr *ctlr, int on) } static void -receive(Ctlr *ctlr) +receive(Ether *ether) { - ushort status; - RingBuf *rb; + ushort status, type; int len; ulong port; + Netfile *f, **fp, **ep; - port = ctlr->card.port; + port = ether->port; while(((status = ins(port+RxStatus)) & RxEmpty) == 0){ /* * If we had an error, log it and continue @@ -137,47 +137,44 @@ receive(Ctlr *ctlr) switch(status & RxErrMask){ case RxErrOverrun: /* Overrrun */ - ctlr->overflows++; + ether->overflows++; break; case RxErrOversize: /* Oversize Packet (>1514) */ case RxErrRunt: /* Runt Packet */ - ctlr->buffs++; + ether->buffs++; break; case RxErrFraming: /* Alignment (Framing) */ - ctlr->frames++; + ether->frames++; break; case RxErrCRC: /* CRC */ - ctlr->crcs++; + ether->crcs++; break; } } else { /* - * We have a packet. Read it into the next - * free ring buffer, if any. - * The CRC is already stripped off. + * We have a packet. Read it into the + * buffer. The CRC is already stripped off. + * Must read len bytes padded to a + * doubleword. We can pick them out 16-bits + * at a time (can try 32-bits at a time + * later). + insl(port+Fifo, ether->rpkt, HOWMANY(len, 4)); + */ + len = (status & RxByteMask); + inss(port+Fifo, ðer->rpkt, HOWMANY(len, 2)); + + /* + * Copy the packet to whoever wants it. */ - rb = &ctlr->rb[ctlr->ri]; - if(rb->owner == Interface){ - len = (status & RxByteMask); - rb->len = len; - - /* - * Must read len bytes padded to a - * doubleword. We can pick them out 16-bits - * at a time (can try 32-bits at a time - * later). - insl(port+Fifo, rb->pkt, HOWMANY(len, 4)); - */ - inss(port+Fifo, rb->pkt, HOWMANY(len, 2)); - - /* - * Update the ring. - */ - rb->owner = Host; - ctlr->ri = NEXT(ctlr->ri, ctlr->nrb); + type = (ether->rpkt.type[0]<<8)|ether->rpkt.type[1]; + ep = ðer->f[Ntypes]; + for(fp = ether->f; fp < ep; fp++) { + f = *fp; + if(f && (f->type == type || f->type < 0)) + qproduce(f->in, ðer->rpkt, len); } } @@ -191,46 +188,69 @@ receive(Ctlr *ctlr) } } -static void -transmit(Ctlr *ctlr) +static int +istxfifo(void *arg) { - RingBuf *tb; + Ether *ether; ushort len; ulong port; - port = ctlr->card.port; - for(tb = &ctlr->tb[ctlr->ti]; tb->owner == Interface; tb = &ctlr->tb[ctlr->ti]){ - /* - * If there's no room in the FIFO for this packet, - * set up an interrupt for when space becomes available. - * Output packet must be a multiple of 4 in length and - * we need 4 bytes for the preamble. - */ - len = ROUNDUP(tb->len, 4); - if(len+4 > ins(port+TxFreeBytes)){ - COMMAND(port, SetTxAvailable, len); - break; - } + ether = arg; + port = ether->port; + /* + * If there's no room in the FIFO for this packet, + * set up an interrupt for when space becomes available. + * Output packet must be a multiple of 4 in length and + * we need 4 bytes for the preamble. + * Assume here that when we are called (via tsleep) that + * we are safe from interrupts. + */ + len = ROUNDUP(ether->tlen, 4); + if(len+4 > ins(port+TxFreeBytes)){ + COMMAND(port, SetTxAvailable, len); + return 0; + } + return 1; +} - /* - * There's room, copy the packet to the FIFO and free - * the buffer back to the host. - */ - outs(port+Fifo, tb->len); - outs(port+Fifo, 0); - outss(port+Fifo, tb->pkt, len/2); - tb->owner = Host; - ctlr->ti = NEXT(ctlr->ti, ctlr->ntb); +static long +write(Ether *ether, void *buf, long n) +{ + ushort len; + ulong port; + +print("W|"); + port = ether->port; + ether->tlen = n; + len = ROUNDUP(ether->tlen, 4); + tsleep(ðer->tr, istxfifo, ether, 10000); + if(len+4 > ins(port+TxFreeBytes)){ + print("ether509: transmitter jammed\n"); + return 0; } + /* + * We know there's room, copy the packet to the FIFO. + * To save copying the packet into a local buffer just + * so we can set the source address, stuff the packet + * into the FIFO in 3 pieces. + * Transmission won't start until the entire packet is + * in the FIFO, so it's OK to fault here. + */ + outs(port+Fifo, ether->tlen); + outs(port+Fifo, 0); + outss(port+Fifo, buf, Eaddrlen/2); + outss(port+Fifo, ether->ea, Eaddrlen/2); + outss(port+Fifo, (uchar*)buf+2*Eaddrlen, (len-2*Eaddrlen)/2); + return n; } static ushort -getdiag(Ctlr *ctlr) +getdiag(Ether *ether) { ushort bytes; ulong port; - port = ctlr->card.port; + port = ether->port; COMMAND(port, SelectWindow, 4); bytes = ins(port+FIFOdiag); COMMAND(port, SelectWindow, 1); @@ -238,15 +258,16 @@ getdiag(Ctlr *ctlr) } static void -interrupt(Ctlr *ctlr) +interrupt(Ether *ether) { ushort status, diag; uchar txstatus, x; ulong port; - port = ctlr->card.port; + port = ether->port; status = ins(port+Status); +print("I%2.2ux|", status); if(status & Failure){ /* * Adapter failure, try to find out why. @@ -255,28 +276,25 @@ interrupt(Ctlr *ctlr) * need to retransmit? * This probably isn't right. */ - diag = getdiag(ctlr); + diag = getdiag(ether); print("ether509: status #%ux, diag #%ux\n", status, diag); if(diag & TxOverrun){ COMMAND(port, TxReset, 0); COMMAND(port, TxEnable, 0); + wakeup(ðer->tr); } if(diag & RxUnderrun){ COMMAND(port, RxReset, 0); - attach(ctlr); + attach(ether); } - if(diag & TxOverrun) - transmit(ctlr); - return; } if(status & RxComplete){ - receive(ctlr); - wakeup(&ctlr->rr); + receive(ether); status &= ~RxComplete; } @@ -297,17 +315,17 @@ interrupt(Ctlr *ctlr) if(txstatus & (TxJabber|TxUnderrun)) COMMAND(port, TxReset, 0); COMMAND(port, TxEnable, 0); - ctlr->oerrs++; + ether->oerrs++; } if(status & (TxAvailable|TxComplete)){ /* * Reset the Tx FIFO threshold. */ - if(status & TxAvailable) + if(status & TxAvailable){ COMMAND(port, AckIntr, TxAvailable); - transmit(ctlr); - wakeup(&ctlr->tr); + wakeup(ðer->tr); + } status &= ~(TxAvailable|TxComplete); } @@ -317,7 +335,7 @@ interrupt(Ctlr *ctlr) * Otherwise, acknowledge the interrupt. */ if(status & AllIntr) - panic("ether509 interrupt: #%lux, #%ux\n", status, getdiag(ctlr)); + panic("ether509 interrupt: #%lux, #%ux\n", status, getdiag(ether)); COMMAND(port, AckIntr, Latch); } @@ -349,17 +367,15 @@ idseq(void) /* * Get configuration parameters. */ -int -ccc509reset(Ctlr *ctlr) +static int +reset(Ether *ether) { int i, ea; ushort x, acr; ulong port; /* - * Do the little configuration dance. We only look - * at the first card that responds, if we ever have more - * than one we'll need to modify this sequence. + * Do the little configuration dance: * * 2. get to command state, reset, then return to command state */ @@ -408,8 +424,8 @@ ccc509reset(Ctlr *ctlr) * * Enable the adapter. */ - ctlr->card.port = (acr & 0x1F)*0x10 + 0x200; - port = ctlr->card.port; + ether->port = (acr & 0x1F)*0x10 + 0x200; + port = ether->port; outb(port+ConfigControl, 0x01); /* @@ -418,7 +434,7 @@ ccc509reset(Ctlr *ctlr) * The EEPROM command is 8bits, the lower 6 bits being * the address offset. */ - ctlr->card.irq = (ins(port+ResourceConfig)>>12) & 0x0F; + ether->irq = (ins(port+ResourceConfig)>>12) & 0x0F; for(ea = 0, i = 0; i < 3; i++, ea += 2){ while(ins(port+EEPROMcmd) & 0x8000) ; @@ -426,8 +442,8 @@ ccc509reset(Ctlr *ctlr) while(ins(port+EEPROMcmd) & 0x8000) ; x = ins(port+EEPROMdata); - ctlr->ea[ea] = (x>>8) & 0xFF; - ctlr->ea[ea+1] = x & 0xFF; + ether->ea[ea] = (x>>8) & 0xFF; + ether->ea[ea+1] = x & 0xFF; } /* @@ -438,7 +454,7 @@ ccc509reset(Ctlr *ctlr) */ COMMAND(port, SelectWindow, 2); for(i = 0; i < 6; i++) - outb(port+i, ctlr->ea[i]); + outb(port+i, ether->ea[i]); /* * Finished with window 2. @@ -458,12 +474,12 @@ ccc509reset(Ctlr *ctlr) /* * Set up the software configuration. */ - ctlr->card.reset = ccc509reset; - ctlr->card.attach = attach; - ctlr->card.mode = mode; - ctlr->card.transmit = transmit; - ctlr->card.intr = interrupt; - ctlr->card.bit16 = 1; + ether->attach = attach; + ether->write = write; + ether->interrupt = interrupt; + + ether->promiscuous = promiscuous; + ether->arg = ether; return 0; } @@ -471,5 +487,5 @@ ccc509reset(Ctlr *ctlr) void ether509link(void) { - addethercard("3C509", ccc509reset); + addethercard("3C509", reset); } diff --git a/pc/etherif.h b/pc/etherif.h new file mode 100644 index 0000000000000000000000000000000000000000..b2ea60c6f365ff67b627775dbcfb910ea17561d0 --- /dev/null +++ b/pc/etherif.h @@ -0,0 +1,29 @@ +enum { + MaxEther = 4, + Ntypes = 8, +}; + +typedef struct Ether Ether; +struct Ether { + ISAConf; /* hardware info */ + + void (*attach)(Ether*); /* filled in by reset routine */ + long (*write)(Ether*, void*, long); + void (*interrupt)(Ether*); + void *private; + + Etherpkt tpkt; /* transmit buffer */ + Etherpkt rpkt; /* receive buffer */ + + QLock tlock; /* lock for grabbing transmitter queue */ + Rendez tr; /* wait here for free xmit buffer */ + long tlen; /* length of data in tb for txfifo management */ + + Netif; +}; + +#define NEXT(x, l) (((x)+1)%(l)) +#define HOWMANY(x, y) (((x)+((y)-1))/(y)) +#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y)) + +extern void addethercard(char*, int(*)(Ether*)); diff --git a/pc/fault386.c b/pc/fault386.c index 04f6bf1f9ffa1b4a01fd492c3302cc110c9197d5..3fa6282ca3b7b6f75c1bee014e84e5906c264194 100644 --- a/pc/fault386.c +++ b/pc/fault386.c @@ -24,7 +24,7 @@ fault386(Ureg *ur) read = !(ur->ecode & 2); user = (ur->cs&0xffff) == UESEL; spllo(); -/* print("F%d:A#%lux:U%d:R%d|", up->pid, addr, user, read);/**/ +/*print("F%d:A#%lux:U%d:R%d|", up->pid, addr, user, read);/**/ n = fault(addr, read); if(n < 0){ if(user){ @@ -33,6 +33,7 @@ fault386(Ureg *ur) postnote(up, 1, buf, NDebug); return; } +print("fault: 0x%lux", addr); dumpregs(ur); panic("fault: 0x%lux", addr); } diff --git a/pc/fns.h b/pc/fns.h index d9e874d2d017c5bd24d86dbacd2aba9e0a8e195f..6d7d0708ef31ca7bc9d3b2f7ab2346f3bb15e950 100644 --- a/pc/fns.h +++ b/pc/fns.h @@ -63,6 +63,7 @@ long pcmread(int, int, void*, long, ulong); int pcmspecial(int); void pcmspecialclose(int); long pcmwrite(int, int, void*, long, ulong); +void prflush(void); void prhex(ulong); void procrestore(Proc*); void procsave(Proc*); @@ -91,3 +92,5 @@ void vgainit(void); #define getcallerpc(x) (*(ulong*)(x)) #define KADDR(a) ((void*)((ulong)(a)|KZERO)) #define PADDR(a) ((ulong)(a)&~KZERO) + +void NS16552special(int, int, Queue**, Queue**, int (*)(Queue*, int)); diff --git a/pc/kbd.c b/pc/kbd.c index b4f61ee727f90ef3f6031efea6bbe61d041fd570..4a3c8cad49c21250603ab5dc5cf1a918048f9489 100644 --- a/pc/kbd.c +++ b/pc/kbd.c @@ -115,11 +115,6 @@ uchar kbtabesc1[] = [0x58] No, No, No, No, No, No, No, No, }; -/* - * keyboard input q - */ -KIOQ kbdq; - static int keybuttons; static uchar ccc; static int shift; @@ -138,7 +133,8 @@ enum static void kbdintr(Ureg*); static void ctps2intr(Ureg*); -static int ps2mouseputc(IOQ*, int); + +extern int m3mouseputc(IOQ*, int); /* * wait for output no longer busy @@ -246,6 +242,8 @@ kbdinit(void) { int c; + kbdq = qopen(4*1024, 0, 0, 0); + setvec(Kbdvec, kbdintr); bigcursor(); @@ -287,9 +285,12 @@ serialmouse(int port, char *type, int setspeed) error(Ebadarg); /* set up /dev/eia0 as the mouse */ - uartspecial(port, 0, &mouseq, setspeed ? 1200 : 0); + if(setspeed) + setspeed = 1200; if(type && *type == 'M') - mouseq.putc = m3mouseputc; + NS16552special(port, setspeed, 0, 0, m3mouseputc); + else + NS16552special(port, setspeed, 0, 0, 0); mousetype = Mouseserial; } @@ -390,14 +391,13 @@ ps2mouse(void) * shift & left button is the same as middle button */ static int -ps2mouseputc(IOQ *q, int c) +ps2mouseputc(int c) { static short msg[3]; static int nb; static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 5, 2, 3, 6, 7 }; int buttons, dx, dy; - USED(q); /* not */ /* * check byte 0 for consistency */ @@ -508,7 +508,7 @@ kbdintr0(void) * if it's the mouse... */ if(s & Minready){ - ps2mouseputc(&mouseq, c); + ps2mouseputc(c); return 0; } @@ -579,9 +579,9 @@ kbdintr0(void) putit: lstate = 0; if(c != -1) - kbdputc(&kbdq, c); + kbdputc(kbdq, c); else for(i=0; immask = 1<machno; } -ulong garbage; - void ksetterm(char *f) { @@ -292,7 +290,7 @@ confinit(void) pcnt = 0; /* - * parse configuration args from dos file p9rc + * parse configuration args from dos file plan9.ini */ cp = BOOTARGS; /* where b.com leaves its config */ cp[BOOTARGSLEN-1] = 0; @@ -542,7 +540,7 @@ exit(int ispanic) up = 0; print("exiting\n"); if(ispanic){ - if(cpuflag) + if(cpuserver) delay(10000); else for(;;); diff --git a/pc/mmu.c b/pc/mmu.c index b3b66444dbdcb519e3aa08ffd311a9b44fe48ebf..21b62782402bd52c460f98b4f40371b57ec70b5a 100644 --- a/pc/mmu.c +++ b/pc/mmu.c @@ -104,10 +104,10 @@ struct static void taskswitch(ulong pagetbl, ulong stack) { - putcr3(pagetbl); tss.ss0 = KDSEL; tss.sp0 = stack; tss.cr3 = pagetbl; + putcr3(pagetbl); } /* @@ -166,11 +166,11 @@ mmuinit(void) */ memset(&tss, 0, sizeof(tss)); taskswitch(ktoppg.pa, BY2PG + (ulong)m); - puttr(TSSSEL); + puttr(TSSSEL);/**/ } /* - * Mark the mmu and tlb as inconsistent and call mapstack to fix it up. + * Mark the mmu and tlb as inconsistent and call mmuswitch to fix it up. */ void flushmmu(void) @@ -223,6 +223,32 @@ mmuswitch(Proc *p) taskswitch(ktoppg.pa, (ulong)(p->kstack+KSTACK)); } +void +simpleputpage(Page *pg) +{ + Rendez *r; + + if(pg->ref != 1) + panic("simpleputpage"); + + pg->ref = 0; + if(palloc.head){ + pg->next = palloc.head; + palloc.head->prev = pg; + } + else { + palloc.tail = pg; + pg->next = 0; + } + palloc.head = pg; + pg->prev = 0; + + palloc.freecol[pg->color]++; + r = &palloc.r[pg->color]; + if(r->p != 0) + wakeup(r); +} + /* * give all page table pages back to the free pool. This is called in sched() * with palloc locked. @@ -305,7 +331,8 @@ putmmu(ulong va, ulong pa, Page *pg) pt[BTMOFF(va)] = pa | PTEUSER; /* flush cached mmu entries */ - taskswitch(up->mmutop->pa, (ulong)up->kstack); + /*taskswitch(up->mmutop->pa, (ulong)(up->kstack+KSTACK));/**/ + putcr3(up->mmutop->pa);/**/ splx(s); } diff --git a/pc/screen.c b/pc/screen.c new file mode 100644 index 0000000000000000000000000000000000000000..3925a1d6b7660be65d2b939cad31d693dcc5a71e --- /dev/null +++ b/pc/screen.c @@ -0,0 +1,309 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +#include +#include +#include "screen.h" +#include "vga.h" + +/* + * CGA-only hack. + */ +/* imported */ +extern GSubfont defont0; +extern Cursor arrow; +extern GBitmap cursorback; + +/* exported */ +GSubfont *defont; +int islittle = 1; /* little endian bit ordering in bytes */ +GBitmap gscreen; + +/* local */ +static Lock vgalock; +static ulong colormap[256][3]; +static Rectangle mbb; + +/* + * reverse pixels into little endian order + */ +uchar revtab0[] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, +}; +uchar revtab1[] = { + 0x00, 0x40, 0x80, 0xc0, 0x10, 0x50, 0x90, 0xd0, + 0x20, 0x60, 0xa0, 0xe0, 0x30, 0x70, 0xb0, 0xf0, + 0x04, 0x44, 0x84, 0xc4, 0x14, 0x54, 0x94, 0xd4, + 0x24, 0x64, 0xa4, 0xe4, 0x34, 0x74, 0xb4, 0xf4, + 0x08, 0x48, 0x88, 0xc8, 0x18, 0x58, 0x98, 0xd8, + 0x28, 0x68, 0xa8, 0xe8, 0x38, 0x78, 0xb8, 0xf8, + 0x0c, 0x4c, 0x8c, 0xcc, 0x1c, 0x5c, 0x9c, 0xdc, + 0x2c, 0x6c, 0xac, 0xec, 0x3c, 0x7c, 0xbc, 0xfc, + 0x01, 0x41, 0x81, 0xc1, 0x11, 0x51, 0x91, 0xd1, + 0x21, 0x61, 0xa1, 0xe1, 0x31, 0x71, 0xb1, 0xf1, + 0x05, 0x45, 0x85, 0xc5, 0x15, 0x55, 0x95, 0xd5, + 0x25, 0x65, 0xa5, 0xe5, 0x35, 0x75, 0xb5, 0xf5, + 0x09, 0x49, 0x89, 0xc9, 0x19, 0x59, 0x99, 0xd9, + 0x29, 0x69, 0xa9, 0xe9, 0x39, 0x79, 0xb9, 0xf9, + 0x0d, 0x4d, 0x8d, 0xcd, 0x1d, 0x5d, 0x9d, 0xdd, + 0x2d, 0x6d, 0xad, 0xed, 0x3d, 0x7d, 0xbd, 0xfd, + 0x02, 0x42, 0x82, 0xc2, 0x12, 0x52, 0x92, 0xd2, + 0x22, 0x62, 0xa2, 0xe2, 0x32, 0x72, 0xb2, 0xf2, + 0x06, 0x46, 0x86, 0xc6, 0x16, 0x56, 0x96, 0xd6, + 0x26, 0x66, 0xa6, 0xe6, 0x36, 0x76, 0xb6, 0xf6, + 0x0a, 0x4a, 0x8a, 0xca, 0x1a, 0x5a, 0x9a, 0xda, + 0x2a, 0x6a, 0xaa, 0xea, 0x3a, 0x7a, 0xba, 0xfa, + 0x0e, 0x4e, 0x8e, 0xce, 0x1e, 0x5e, 0x9e, 0xde, + 0x2e, 0x6e, 0xae, 0xee, 0x3e, 0x7e, 0xbe, 0xfe, + 0x03, 0x43, 0x83, 0xc3, 0x13, 0x53, 0x93, 0xd3, + 0x23, 0x63, 0xa3, 0xe3, 0x33, 0x73, 0xb3, 0xf3, + 0x07, 0x47, 0x87, 0xc7, 0x17, 0x57, 0x97, 0xd7, + 0x27, 0x67, 0xa7, 0xe7, 0x37, 0x77, 0xb7, 0xf7, + 0x0b, 0x4b, 0x8b, 0xcb, 0x1b, 0x5b, 0x9b, 0xdb, + 0x2b, 0x6b, 0xab, 0xeb, 0x3b, 0x7b, 0xbb, 0xfb, + 0x0f, 0x4f, 0x8f, 0xcf, 0x1f, 0x5f, 0x9f, 0xdf, + 0x2f, 0x6f, 0xaf, 0xef, 0x3f, 0x7f, 0xbf, 0xff, +}; +uchar revtab2[] = { + 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, + 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, + 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, + 0x81, 0x91, 0xa1, 0xb1, 0xc1, 0xd1, 0xe1, 0xf1, + 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, + 0x82, 0x92, 0xa2, 0xb2, 0xc2, 0xd2, 0xe2, 0xf2, + 0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73, + 0x83, 0x93, 0xa3, 0xb3, 0xc3, 0xd3, 0xe3, 0xf3, + 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74, + 0x84, 0x94, 0xa4, 0xb4, 0xc4, 0xd4, 0xe4, 0xf4, + 0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75, + 0x85, 0x95, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, + 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76, + 0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, + 0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, + 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7, + 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78, + 0x88, 0x98, 0xa8, 0xb8, 0xc8, 0xd8, 0xe8, 0xf8, + 0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79, + 0x89, 0x99, 0xa9, 0xb9, 0xc9, 0xd9, 0xe9, 0xf9, + 0x0a, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a, 0x7a, + 0x8a, 0x9a, 0xaa, 0xba, 0xca, 0xda, 0xea, 0xfa, + 0x0b, 0x1b, 0x2b, 0x3b, 0x4b, 0x5b, 0x6b, 0x7b, + 0x8b, 0x9b, 0xab, 0xbb, 0xcb, 0xdb, 0xeb, 0xfb, + 0x0c, 0x1c, 0x2c, 0x3c, 0x4c, 0x5c, 0x6c, 0x7c, + 0x8c, 0x9c, 0xac, 0xbc, 0xcc, 0xdc, 0xec, 0xfc, + 0x0d, 0x1d, 0x2d, 0x3d, 0x4d, 0x5d, 0x6d, 0x7d, + 0x8d, 0x9d, 0xad, 0xbd, 0xcd, 0xdd, 0xed, 0xfd, + 0x0e, 0x1e, 0x2e, 0x3e, 0x4e, 0x5e, 0x6e, 0x7e, + 0x8e, 0x9e, 0xae, 0xbe, 0xce, 0xde, 0xee, 0xfe, + 0x0f, 0x1f, 0x2f, 0x3f, 0x4f, 0x5f, 0x6f, 0x7f, + 0x8f, 0x9f, 0xaf, 0xbf, 0xcf, 0xdf, 0xef, 0xff, +}; + +void +pixreverse(uchar *p, int len, int ldepth) +{ + uchar *e; + uchar *tab; + + switch(ldepth){ + case 0: + tab = revtab0; + break; + case 1: + tab = revtab1; + break; + case 2: + tab = revtab2; + break; + default: + return; + } + + for(e = p + len; p < e; p++) + *p = tab[*p]; +} + +static void +crout(int reg, int val) +{ + outb(CRX, reg); + outb(CR, val); +} + +void +screeninit(void) +{ + int i; + ulong *l; + + /* + * arrow is defined as a big endian + */ + pixreverse(arrow.set, 2*16, 0); + pixreverse(arrow.clr, 2*16, 0); + + /* + * swizzle the font longs. we do both byte and bit swizzling + * since the font is initialized with big endian longs. + */ + defont = &defont0; + l = defont->bits->base; + for(i = defont->bits->width*Dy(defont->bits->r); i > 0; i--, l++) + *l = (*l<<24) | ((*l>>8)&0x0000ff00) | ((*l<<8)&0x00ff0000) | (*l>>24); + pixreverse((uchar*)defont->bits->base, + defont->bits->width*BY2WD*Dy(defont->bits->r), 0); + + crout(0x0a, 0xff); /* turn off cursor */ + memset(CGASCREEN, 0, CGAWIDTH*CGAHEIGHT); +} + +static void +cgascreenputc(int c) +{ + int i; + static int color; + static int pos; + + if(c == '\n'){ + pos = pos/CGAWIDTH; + pos = (pos+1)*CGAWIDTH; + } else if(c == '\t'){ + i = 8 - ((pos/2)&7); + while(i-->0) + cgascreenputc(' '); + } else if(c == '\b'){ + if(pos >= 2) + pos -= 2; + cgascreenputc(' '); + pos -= 2; + } else { + CGASCREEN[pos++] = c; + CGASCREEN[pos++] = 2; /* green on black */ + } + if(pos >= CGAWIDTH*CGAHEIGHT){ + memmove(CGASCREEN, &CGASCREEN[CGAWIDTH], CGAWIDTH*(CGAHEIGHT-1)); + memset(&CGASCREEN[CGAWIDTH*(CGAHEIGHT-1)], 0, CGAWIDTH); + pos = CGAWIDTH*(CGAHEIGHT-1); + } +} + +void +screenputs(char *s, int n) +{ + while(n-- > 0) + cgascreenputc(*s++); +} + +/* + * collect changes to the 'soft' screen + */ +void +mbbrect(Rectangle r) +{ + if (r.min.x < mbb.min.x) + mbb.min.x = r.min.x; + if (r.min.y < mbb.min.y) + mbb.min.y = r.min.y; + if (r.max.x > mbb.max.x) + mbb.max.x = r.max.x; + if (r.max.y > mbb.max.y) + mbb.max.y = r.max.y; + mousescreenupdate(); +} + +void +hwcursset(ulong *s, ulong *c, int ox, int oy) +{ + USED(s, c, ox, oy); +} + +void +hwcursmove(int x, int y) +{ + USED(x, y); +} + +void +screenload(Rectangle r, uchar *data, int tl, int l) +{ + USED(r, data, tl, l); +} + +void +getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb) +{ + p &= (1<<(1<trap; - user = ((ur->cs)&0xffff)!=KESEL && v!=Syscallvec; + user = (ur->cs&0xffff) == UESEL; if(user) up->dbgreg = ur; +ur->cs &= 0xffff; +ur->ds &= 0xffff; +ur->es &= 0xffff; +ur->fs &= 0xffff; +ur->gs &= 0xffff; +if(user) ur->ss &= 0xffff; + /* * tell the 8259 that we're done with the * highest level interrupt (interrupts are still @@ -253,6 +261,7 @@ trap(Ureg *ur) if(v>=256 || (h = halloc.ivec[v]) == 0){ lasttrap = *ur; lastur = ur; +lastup = up; /* an old 386 generates these fairly often, no idea why */ if(v == 13) return; @@ -292,6 +301,8 @@ lastur = ur; splhi(); if(user && (up->procctl || up->nnote)) notify(ur); + +lastup = up; lasttrap = *ur; lastur = ur; } @@ -307,24 +318,31 @@ dumpregs2(Ureg *ur) else print("registers for kernel\n"); print("FLAGS=%lux TRAP=%lux ECODE=%lux CS=%lux PC=%lux", ur->flags, ur->trap, - ur->ecode, ur->cs&0xff, ur->pc); - print(" SS=%lux USP=%lux\n", ur->ss&0xff, ur->usp); + ur->ecode, ur->cs, ur->pc); + print(" SS=%lux USP=%lux\n", ur->ss, ur->usp); print(" AX %8.8lux BX %8.8lux CX %8.8lux DX %8.8lux\n", ur->ax, ur->bx, ur->cx, ur->dx); print(" SI %8.8lux DI %8.8lux BP %8.8lux\n", ur->si, ur->di, ur->bp); - print(" DS %4.4ux ES %4.4ux FS %4.4ux GS %4.4ux\n", - ur->ds&0xffff, ur->es&0xffff, ur->fs&0xffff, ur->gs&0xffff); + print(" DS %4.4lux ES %4.4lux FS %4.4lux GS %4.4lux\n", + ur->ds, ur->es, ur->fs, ur->gs); } void dumpregs(Ureg *ur) { + ulong *x; + + x = (ulong*)(ur+1); dumpregs2(ur); - print(" ur %lux\n", ur); + print(" magic %lux %lux %lux\n", x[0], x[1], x[2]); + print(" ur %lux up %lux\n", ur, up); dumpregs2(&lasttrap); - print(" lastur %lux\n", lastur); + print(" lastur %lux lastup %lux\n", lastur); +splhi(); +dumpstack(); +for(;;); } void @@ -332,49 +350,28 @@ dumpstack(void) { ulong l, v, i; extern ulong etext; + int lim; if(up == 0) return; i = 0; - for(l=(ulong)&l; l<(ulong)(up->kstack+BY2PG); l+=4){ + lim = 3; + for(l=(ulong)&l; l<(ulong)(up->kstack+BY2PG) && lim; l+=4){ v = *(ulong*)l; if(KTZERO < v && v < (ulong)&etext){ print("%lux ", v); i++; } - if(i == 4){ + if(i == 8){ i = 0; print("\n"); + lim--; } } } -long -execregs(ulong entry, ulong ssize, ulong nargs) -{ - ulong *sp; - Ureg *ur; - - sp = (ulong*)(USTKTOP - ssize); - *--sp = nargs; - - ur = up->dbgreg; - ur->usp = (ulong)sp; - ur->pc = entry; - return USTKTOP-BY2WD; /* address of user-level clock */ -} - -ulong -userpc(void) -{ - Ureg *ur; - - ur = (Ureg*)up->dbgreg; - return ur->pc; -} - /* * system calls */ @@ -573,6 +570,30 @@ noted(Ureg *ur, ulong arg0) } } +long +execregs(ulong entry, ulong ssize, ulong nargs) +{ + ulong *sp; + Ureg *ur; + + sp = (ulong*)(USTKTOP - ssize); + *--sp = nargs; + + ur = up->dbgreg; + ur->usp = (ulong)sp; + ur->pc = entry; + return USTKTOP-BY2WD; /* address of user-level clock */ +} + +ulong +userpc(void) +{ + Ureg *ur; + + ur = (Ureg*)up->dbgreg; + return ur->pc; +} + /* This routine must save the values of registers the user is not permitted to write * from devproc and the restore the saved values before returning */ @@ -592,6 +613,45 @@ setregisters(Ureg *xp, char *pureg, char *uva, int n) xp->ss = ss; } +static void +linkproc(void) +{ + spllo(); + (*up->kpfun)(up->kparg); +} + +void +kprocchild(Proc *p, void (*func)(void*), void *arg) +{ + p->sched.pc = (ulong)linkproc; + p->sched.sp = (ulong)p->kstack+KSTACK; + + p->kpfun = func; + p->kparg = arg; +} + +void +forkchild(Proc *p, Ureg *ur) +{ + Ureg *cur; + + /* + * We add 2*BY2Wd to the stack because we have to account for + * - the return PC + * - trap's argument (ur) + */ + p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD); + p->sched.pc = (ulong)forkret; + + cur = (Ureg*)(p->sched.sp+2*BY2WD); + memmove(cur, ur, sizeof(Ureg)); + cur->ax = 0; /* return value of syscall in child */ + + /* Things from bottom of syscall we never got to execute */ + p->psstate = 0; + p->insyscall = 0; +} + /* Give enough context in the ureg to produce a kernel stack for * a sleeping process */ diff --git a/pc/ultrastor.c b/pc/ultrastor.c deleted file mode 100644 index b1812378a0ae7e12a50bc517f1d913f305e4645d..0000000000000000000000000000000000000000 --- a/pc/ultrastor.c +++ /dev/null @@ -1,484 +0,0 @@ -/* - * Ultrastor [13]4f SCSI Host Adapter. - * Originally written by Charles Forsyth, forsyth@minster.york.ac.uk. - * Needs work: - * handle multiple controllers; - * set options from user-level; - * split out to handle adaptec too; - */ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "io.h" -#include "../port/error.h" - -#include "ureg.h" - -typedef struct Ctlr Ctlr; -typedef struct Mailbox Mailbox; -typedef struct Scatter Scatter; - -enum { - Nctl = 1, /* only support one */ - Nmbox = 8, /* number of Mailboxes; up to 16? */ - Nscatter = 33, /* s/g list limit fixed by Ultrastor controller */ - - Port = 0x330, /* factory defaults: I/O port */ - CtlrID = 7, /* adapter SCSI id */ - Irq = 14, /* interrupt request level */ -}; - -struct Scatter { - ulong start; /* physical address; Intel byte order */ - ulong len; /* length in bytes; Intel byte order */ -}; - -/* - * Ultrastor mailbox pointers point to one of these structures - */ -struct Mailbox { - uchar op; /* Adapter operation */ - uchar addr; /* lun, chan, scsi ID */ - uchar datap[4]; /* transfer data phys. pointer */ - uchar datalen[4]; /* transfer data length */ - uchar cmdlink[4]; /* command link phys. pointer */ - uchar linkid; /* SCSI command link ID */ - uchar nscatter; /* scatter/gather length (8 bytes per entry) */ - uchar senselen; /* length of sense data */ - uchar cmdlen; /* length of CDB */ - uchar cmd[12]; /* SCSI command */ - uchar adapterstatus; - uchar targetstatus; - uchar sensep[4]; /* sense data phys. pointer */ - - /* the remainder is used by software, not the device */ - uchar sensedata[64]; /* enough for AdapterInquiry data too */ - Scatter sglist[Nscatter]; - Rendez iodone; - int busy; /* interrupt pending */ - ulong physaddr; /* physical address of this Mailbox */ - int p9status; /* p9 status value */ - Mailbox *next; /* next Mailbox in free list */ -}; - -/* pack pointer as Intel order bytes (can simply assign) */ -#define PL(buf,p) (*(ulong*)(buf)=(ulong)(p)) - -enum { - /* bits in Mailbox.op[0] */ - /* 3 bit opcode */ - OpAdapter = 0x01, /* adapter command, not SCSI command */ - OpTarget = 0x02, /* SCSI command for device */ - OpReset = 0x04, /* device reset */ - /* 2 bit transfer direction */ - CmdDirection = 0<<3, /* transfer direction determined by SCSI command */ - DataIn = 1<<3, /* SCSI Data In */ - DataOut = 2<<3, /* SCSI Data Out */ - NoTransfer = 3<<3, - Nodiscon= 1<<5, /* disable disconnect */ - Usecache= 1<<6, /* use adapter cache (if available) */ - Scattered= 1<<7, /* transfer pointer refers to S/G list */ - - /* OpAdapter commands in Mailbox.cmd[0] */ - AdapterInquiry = 0x01, - AdapterSelftest = 0x02, - AdapterRead = 0x03, /* read adapter's buffer */ - AdapterWrite = 0x04, /* write to adapter's buffer */ - - /* IO port offsets and bits */ - AdapterMask = 0x00, /* local doorbell mask register */ - OGMIntEnable = 0x01, - SoftResetEnable = 0x40, - AdapterReady = 0xe1, /* adapter ready for work when all these set */ - AdapterIntr = 0x01, /* adapter interrupt/status; set by host, reset by adapter */ - SignalAdapter = 0x01, /* tell adapter to read OGMpointer */ - BusReset = 0x20, /* SCSI Bus Reset */ - SoftReset = 0x40, /* Adapter Soft Reset */ - HostMask = 0x02, /* host doorbell mask register */ - ICMIntEnable = 0x01, /* incoming mail enable */ - SIntEnable = 0x80, /* enable interrupt from HostIntr reg */ - HostIntr = 0x03, /* host doorbell interrupt/status; set by adapter, reset by host */ - IntPending = 0x80, /* interrupt pending for host */ - SignalHost = 0x01, /* Incoming Mail Interrupt */ - ProductID = 0x04, /* two byte product ID */ - Config1 = 0x06, - Config2 = 0x07, - OGMpointer = 0x08, /* pointer to Outgoing Mail */ - ICMpointer = 0x0c, /* pointer to Incoming Mail */ -}; - -#define OUT(c,v) outb(ctlr->io+(c), (v)) -#define IN(c) inb(ctlr->io+(c)) - -struct Ctlr { - Lock; - QLock; - int io; /* io port */ - int irq; /* interrupt vector */ - int dma; /* DMA channel */ - int ownid; /* adapter's SCSI ID */ - Mailbox mbox[Nmbox]; - Mailbox *free; /* next free Mailbox */ - Rendez mboxes; /* wait for free mbox */ - QLock mboxq; /* mutex for mboxes */ - Rendez ogm; /* wait for free OGM slot with Ctlr qlocked */ -}; - -static Ctlr ultra[Nctl]; - -int scsidebugs[8] = {0}; -int scsiownid = 7; - -static void -prmbox(Mailbox *m) -{ - int i; - - print("scsi %lx: op=%2.2x dir=%x cmd=%d [", m->physaddr, m->op&07, (m->op>>3)&3, m->cmdlen); - for(i=0; icmdlen; i++) - print(" %2.2x", m->cmd[i]); - print("] id=%d lun=%d chan=%d", m->addr&7, (m->addr>>5)&7, (m->addr>>3)&3); - print(" dlen=%lx dptr=%lx\n", *(long*)m->datalen, *(long*)m->datap); - print(" astat=%2.2x dstat=%2.2x sc=%d [", m->adapterstatus, m->targetstatus, m->nscatter); - for(i=0; inscatter; i++) - print(" %lx,%ld", m->sglist[i].start, m->sglist[i].len); - print("]\n"); - /*for(i=0; i<10; i++) - print(" %2.2x", m->sensedata[i]);*/ - print("\n"); -} - -static void -resetadapter(int busreset) -{ - Ctlr *ctlr = &ultra[0]; - int i; - - if(IN(AdapterMask) & SoftResetEnable){ - OUT(AdapterIntr, SoftReset|busreset); - for(i=50000; IN(AdapterIntr) & (SoftReset|busreset);) - if(--i<0) { - print("Ultrastor reset timed out\n"); - break; - } - } -} - -static void -freebox(Ctlr *ctlr, Mailbox *m) -{ - lock(ctlr); - if((m->next = ctlr->free) == 0) - wakeup(&ctlr->mboxes); - ctlr->free = m; - unlock(ctlr); -} - -static int -boxavail(void *a) -{ - return ((Ctlr*)a)->free != 0; -} - -static int -scatter(Scatter *list, void *va, ulong nb) -{ - char *p = (char *)va; - Scatter *sp = list; - int limit = Nscatter; - - for(; nb != 0; sp++){ - if(--limit < 0) - panic("Ultrastor I/O too scattered"); - sp->start = PADDR(p); - sp->len = BY2PG - (sp->start&(BY2PG-1)); /* the rest of that page */ - if(sp->len > nb) - sp->len = nb; - nb -= sp->len; - p += sp->len; - } - return sp - list; -} - -static int -isready(void *a) -{ - Ctlr *ctlr = (Ctlr*)a; - - return (IN(AdapterIntr) & SignalAdapter) == 0; -} - -static int -isdone(void *a) -{ - return ((Mailbox*)a)->busy == 0; -} - -static int -ultra14fexec(Scsi *p, int rflag) -{ - Ctlr *ctlr = &ultra[0]; - Mailbox *m; - long n; - uchar *cp; - - if (p == 0 || ctlr->io == 0) - return 0x0200; /* device not available */ - - /* - * get a free Mailbox and build an Ultrastor command - */ - while(lock(ctlr), (m = ctlr->free) == 0){ - unlock(ctlr); - qlock(&ctlr->mboxq); - if(waserror()){ - qunlock(&ctlr->mboxq); - nexterror(); - } - sleep(&ctlr->mboxes, boxavail, ctlr); - poperror(); - qunlock(&ctlr->mboxq); - } - ctlr->free = m->next; - unlock(ctlr); - p->rflag = rflag; - m->p9status = 0; - m->op = OpTarget | CmdDirection | Usecache; /* BUG? is it safe always to Usecache? */ - m->addr = p->target | (p->lun<<5); - if(p->cmd.lim - p->cmd.ptr > sizeof(m->cmd)) - panic("scsiexec"); - m->cmdlen = p->cmd.lim - p->cmd.ptr; - for(cp = m->cmd; p->cmd.ptr < p->cmd.lim;) - *cp++ = *p->cmd.ptr++; - n = p->data.lim - p->data.ptr; - if(n){ - PL(m->datap, PADDR(m->sglist)); - m->op |= Scattered; - m->nscatter = scatter(m->sglist, p->data.ptr, n); - } else { - m->nscatter = 0; /* controller will not allow s/g when n==0 */ - PL(m->datap, 0); - } - PL(m->datalen, n); - m->adapterstatus = 0; - m->targetstatus = 0; - - /* - * send the command to the host adapter - */ - while(lock(ctlr), IN(AdapterIntr) & SignalAdapter) { /* adapter busy: infrequent? */ - static int fred; - if(fred == 0){ - print("ultrastor busy\n"); - fred = 1; - } - unlock(ctlr); - qlock(ctlr); - if(waserror()) { - freebox(ctlr, m); - qunlock(ctlr); - nexterror(); - } - sleep(&ctlr->ogm, isready, ctlr); - poperror(); - qunlock(ctlr); - } - m->busy = 1; - outl(ctlr->io+OGMpointer, m->physaddr); - OUT(AdapterIntr, SignalAdapter); - unlock(ctlr); - - /* - * wait for reply - */ - while(waserror()) - ; /* could send MSCP abort request to adapter */ - while(m->busy) - sleep(&m->iodone, isdone, m); - poperror(); - p->status = m->p9status; - if(scsidebugs[2]) - prmbox(m); - if(p->status == 0x6000) - p->data.ptr = p->data.lim; /* can only assume no residue */ - freebox(ctlr, m); - return p->status; -} - -static void -scsimoan(char *msg, Mailbox *m) -{ - /*int i;*/ - - print("SCSI error: %s:", msg); - print("id=%d cmd=%2.2x status=%2.2x adapter=%2.2x", m->addr&7, m->cmd[0], m->targetstatus, m->adapterstatus); - /*print(" sense:"); - for(i=0; i<10; i++) - print(" %2.2x", m->sensedata[i]);*/ - print("\n"); -} - -static void -interrupt(Ureg *ur) -{ - Ctlr *ctlr = &ultra[0]; - Mailbox *m; - ulong pa; - - USED(ur); - if(ctlr->ogm.p && (IN(AdapterIntr) & SignalAdapter) == 0) - wakeup(&ctlr->ogm); - if((IN(HostIntr) & SignalHost) == 0) - return; /* no incoming mail */ - pa = inl(ctlr->io+ICMpointer); - OUT(HostIntr, SignalHost); /* release ICM slot */ - for(m = &ctlr->mbox[0]; m->physaddr != pa;) - if(++m >= &ctlr->mbox[Nmbox]) { - /* these sometimes happen in response to a scsi bus reset; ignore them */ - print("ultrastor: invalid ICM pointer #%lux\n", pa); - return; - } - if(scsidebugs[1]) - prmbox(m); - - m->p9status = 0x1000 | m->adapterstatus; - switch(m->adapterstatus){ - default: - scsimoan("adapter", m); - if(m->adapterstatus >= 0x92) /* ie, scsi command protocol error */ - resetadapter(BusReset); - /* might adapter reset be required in other cases? */ - break; - - case 0x91: /* selection timed out */ - m->p9status = 0x0200; - if(scsidebugs[0]) - scsimoan("timeout", m); - break; - - case 0xA3: - scsimoan("SCSI bus reset error", m); - break; - - case 0x00: - m->p9status = 0x6000 | m->targetstatus; - if(m->targetstatus && scsidebugs[0]) - scsimoan("device", m); - break; - } - m->busy = 0; - wakeup(&m->iodone); -} - -static ISAConf ultra14f = { - "ultra14f", - Port, - Irq, - 0, - 0, -}; - -static int irq[4] = { - 15, 14, 11, 10, -}; - -int (* -ultra14freset(void))(Scsi*, int) -{ - ISAConf *isa = &ultra14f; - Ctlr *ctlr = &ultra[0]; - Mailbox *m; - int i, model; - - /* - * See if we have any configuration info - * and check it is an Ultrastor [13]4f. - * Only one controller for now. - */ - if(isaconfig("scsi", 0, &ultra14f) == 0) - return 0; - memset(ctlr, 0, sizeof(Ctlr)); - ctlr->io = isa->port; - - if(IN(ProductID) != 0x56) - return 0; - model = IN(ProductID+1); - switch(model){ - - case 0x40: - model = 14; - break; - - case 0x41: - model = 34; - break; - - default: - return 0; - } - - i = IN(Config1); - ctlr->irq = irq[((i>>4)&03)]; - if(model == 14) - ctlr->dma = 5 + ((i>>6)&03); - ctlr->ownid = IN(Config2)&07; - /*print("Ultrastor %dF id %d io 0x%x irq %d dma %d\n", - model, ctlr->ownid, ctlr->io, ctlr->irq, ctlr->dma);*/ - - /* - * set the DMA controller to cascade mode for bus master - */ - switch(ctlr->dma){ - case 5: - outb(0xd6, 0xc1); outb(0xd4, 1); break; - case 6: - outb(0xd6, 0xc2); outb(0xd4, 2); break; - case 7: - outb(0xd6, 0xc3); outb(0xd4, 3); break; - } - - resetadapter(0); - ctlr->free = 0; - for(i=0; imbox[i]; - memset(m, 0, sizeof(*m)); - m->physaddr = PADDR(m); - PL(m->sensep, 0); /* DON'T collect sense data automatically: messes up scuzz? */ - m->senselen = 0; - m->next = ctlr->free; - ctlr->free = m; - } - - setvec(Int0vec+ctlr->irq, interrupt); - - /* - * issue AdapterInquiry command to check it's alive - * -- could check enquiry data - */ - OUT(HostMask, 0); /* mask interrupts */ - m = &ctlr->mbox[0]; - m->op = OpAdapter | CmdDirection; - m->addr = ctlr->ownid; - m->cmdlen = 1; - m->cmd[0] = AdapterInquiry; - PL(m->datap, PADDR(m->sensedata)); - PL(m->datalen, 38); - while(IN(AdapterIntr) & SignalAdapter) - ; - outl(ctlr->io+OGMpointer, m->physaddr); - OUT(AdapterIntr, SignalAdapter); - for(i=100000; (IN(HostIntr)&SignalHost)==0;) - if(--i < 0){ - print("No response to UltraStor Inquiry\n"); - ctlr->io = 0; - return 0; - } - OUT(HostIntr, SignalHost); - - OUT(HostMask, ICMIntEnable|SIntEnable); - scsiownid = ctlr->ownid; - - return ultra14fexec; -}