From e60967e8e7a82404ab9c2a0f5c5dab40ec217e7d Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Thu, 6 Jul 2000 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2000-07-06 --- alphapc/sd.h | 17 +- alphapc/sdata.c | 1842 +-------------------------------------------- alphapc/sdscsi.c | 387 +--------- ip/icmp.c | 144 ++-- ip/il.c | 67 +- ip/ip.c | 144 ++-- ip/netdevmedium.c | 8 +- ip/tcp.c | 129 ++-- ip/udp.c | 66 +- pc/i8253.c | 6 +- port/devcons.c | 12 + port/devsd.c | 61 +- port/lib.h | 1 + port/sd.h | 17 +- 14 files changed, 399 insertions(+), 2502 deletions(-) diff --git a/alphapc/sd.h b/alphapc/sd.h index 9093a20cbfcf3d7ec945ebedfa14bd3ad6f310f1..e0eb1675b358b3204ef6c860031d560b9ef1c96c 100644 --- a/alphapc/sd.h +++ b/alphapc/sd.h @@ -4,15 +4,20 @@ typedef struct SDev SDev; typedef struct SDifc SDifc; typedef struct SDpart SDpart; +typedef struct SDperm SDperm; typedef struct SDreq SDreq; typedef struct SDunit SDunit; -typedef struct SDpart { - ulong start; - ulong end; +typedef struct SDperm { char name[NAMELEN]; char user[NAMELEN]; ulong perm; +} SDperm; + +typedef struct SDpart { + ulong start; + ulong end; + SDperm; int valid; ulong vers; } SDpart; @@ -21,18 +26,20 @@ typedef struct SDunit { SDev* dev; int subno; uchar inquiry[256]; /* format follows SCSI spec */ - char name[NAMELEN]; + SDperm; Rendez rendez; QLock ctl; ulong sectors; ulong secsize; - SDpart* part; /* either nil or points at array of size SDnpart */ + SDpart* part; /* nil or array of size SDnpart */ ulong vers; + SDperm ctlperm; Lock rawinuse; /* really just a test-and-set */ int state; SDreq* req; + SDperm rawperm; } SDunit; typedef struct SDev { diff --git a/alphapc/sdata.c b/alphapc/sdata.c index ba26c96d54208cf9eb1826d15268162a082362f1..4058937581243feaf43110f4080187597fe8a97a 100644 --- a/alphapc/sdata.c +++ b/alphapc/sdata.c @@ -1,1841 +1 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "io.h" -#include "ureg.h" -#include "../port/error.h" - -#include "sd.h" - -extern SDifc sdataifc; - -enum { - DbgCONFIG = 0x01, /* detected drive config info */ - DbgIDENTIFY = 0x02, /* detected drive identify info */ - DbgSTATE = 0x04, /* dump state on panic */ - DbgPROBE = 0x08, /* trace device probing */ - DbgDEBUG = 0x80, /* the current problem... */ -}; -#define DEBUG (DbgDEBUG|DbgSTATE|DbgCONFIG) - -enum { /* I/O ports */ - Data = 0, - Error = 1, /* (read) */ - Features = 1, /* (write) */ - Count = 2, /* sector count */ - Ir = 2, /* interrupt reason (PACKET) */ - Sector = 3, /* sector number, LBA<7-0> */ - Cyllo = 4, /* cylinder low, LBA<15-8> */ - Bytelo = 4, /* byte count low (PACKET) */ - Cylhi = 5, /* cylinder high, LBA<23-16> */ - Bytehi = 5, /* byte count hi (PACKET) */ - Dh = 6, /* Device/Head, LBA<32-14> */ - Status = 7, /* (read) */ - Command = 7, /* (write) */ - - As = 2, /* Alternate Status (read) */ - Dc = 2, /* Device Control (write) */ -}; - -enum { /* Error */ - Med = 0x01, /* Media error */ - Ili = 0x01, /* command set specific (PACKET) */ - Nm = 0x02, /* No Media */ - Eom = 0x02, /* command set specific (PACKET) */ - Abrt = 0x04, /* Aborted command */ - Mcr = 0x08, /* Media Change Request */ - Idnf = 0x10, /* no user-accessible address */ - Mc = 0x20, /* Media Change */ - Unc = 0x40, /* Uncorrectable data error */ - Wp = 0x40, /* Write Protect */ - Icrc = 0x80, /* Interface CRC error */ -}; - -enum { /* Features */ - Dma = 0x01, /* data transfer via DMA (PACKET) */ - Ovl = 0x02, /* command overlapped (PACKET) */ -}; - -enum { /* Interrupt Reason */ - Cd = 0x01, /* Command/Data */ - Io = 0x02, /* I/O direction */ - Rel = 0x04, /* Bus Release */ -}; - -enum { /* Device/Head */ - Dev0 = 0xA0, /* Master */ - Dev1 = 0xB0, /* Slave */ - Lba = 0x40, /* LBA mode */ -}; - -enum { /* Status, Alternate Status */ - Err = 0x01, /* Error */ - Chk = 0x01, /* Check error (PACKET) */ - Drq = 0x08, /* Data Request */ - Dsc = 0x10, /* Device Seek Complete */ - Serv = 0x10, /* Service */ - Df = 0x20, /* Device Fault */ - Dmrd = 0x20, /* DMA ready (PACKET) */ - Drdy = 0x40, /* Device Ready */ - Bsy = 0x80, /* Busy */ -}; - -enum { /* Command */ - Cnop = 0x00, /* NOP */ - Cdr = 0x08, /* Device Reset */ - Crs = 0x20, /* Read Sectors */ - Cws = 0x30, /* Write Sectors */ - Cedd = 0x90, /* Execute Device Diagnostics */ - Cpkt = 0xA0, /* Packet */ - Cidpkt = 0xA1, /* Identify Packet Device */ - Crsm = 0xC4, /* Read Multiple */ - Cwsm = 0xC5, /* Write Multiple */ - Csm = 0xC6, /* Set Multiple */ - Crdq = 0xC7, /* Read DMA queued */ - Crd = 0xC8, /* Read DMA */ - Cwd = 0xCA, /* Write DMA */ - Cwdq = 0xCC, /* Write DMA queued */ - Cid = 0xEC, /* Identify Device */ - Csf = 0xEF, /* Set Features */ -}; - -enum { /* Device Control */ - Nien = 0x02, /* (not) Interrupt Enable */ - Srst = 0x04, /* Software Reset */ -}; - -enum { /* PCI Configuration Registers */ - Bmiba = 0x20, /* Bus Master Interface Base Address */ - Idetim = 0x40, /* IE Timing */ - Sidetim = 0x44, /* Slave IE Timing */ - Udmactl = 0x48, /* Ultra DMA/33 Control */ - Udmatim = 0x4A, /* Ultra DMA/33 Timing */ -}; - -enum { /* Bus Master IDE I/O Ports */ - Bmicx = 0, /* Command */ - Bmisx = 2, /* Status */ - Bmidtpx = 4, /* Descriptor Table Pointer */ -}; - -enum { /* Bmicx */ - Ssbm = 0x01, /* Start/Stop Bus Master */ - Rwcon = 0x08, /* Read/Write Control */ -}; - -enum { /* Bmisx */ - Bmidea = 0x01, /* Bus Master IDE Active */ - Idedmae = 0x02, /* IDE DMA Error (R/WC) */ - Ideints = 0x04, /* IDE Interrupt Status (R/WC) */ - Dma0cap = 0x20, /* Drive 0 DMA Capable */ - Dma1cap = 0x40, /* Drive 0 DMA Capable */ -}; -enum { /* Physical Region Descriptor */ - PrdEOT = 0x80000000, /* Bus Master IDE Active */ -}; - -enum { /* offsets into the identify info. */ - Iconfig = 0, /* general configuration */ - Ilcyl = 1, /* logical cylinders */ - Ilhead = 3, /* logical heads */ - Ilsec = 6, /* logical sectors per logical track */ - Iserial = 10, /* serial number */ - Ifirmware = 23, /* firmware revision */ - Imodel = 27, /* model number */ - Imaxrwm = 47, /* max. read/write multiple sectors */ - Icapabilities = 49, /* capabilities */ - Istandby = 50, /* device specific standby timer */ - Ipiomode = 51, /* PIO data transfer mode number */ - Ivalid = 53, - Iccyl = 54, /* cylinders if (valid&0x01) */ - Ichead = 55, /* heads if (valid&0x01) */ - Icsec = 56, /* sectors if (valid&0x01) */ - Iccap = 57, /* capacity if (valid&0x01) */ - Irwm = 59, /* read/write multiple */ - Ilba0 = 60, /* LBA size */ - Ilba1 = 61, /* LBA size */ - Imwdma = 63, /* multiword DMA mode */ - Iapiomode = 64, /* advanced PIO modes supported */ - Iminmwdma = 65, /* min. multiword DMA cycle time */ - Irecmwdma = 66, /* rec. multiword DMA cycle time */ - Iminpio = 67, /* min. PIO cycle w/o flow control */ - Iminiordy = 68, /* min. PIO cycle with IORDY */ - Ipcktbr = 71, /* time from PACKET to bus release */ - Iserbsy = 72, /* time from SERVICE to !Bsy */ - Iqdepth = 75, /* max. queue depth */ - Imajor = 80, /* major version number */ - Iminor = 81, /* minor version number */ - Icmdset0 = 82, /* command sets supported */ - Icmdset1 = 83, /* command sets supported */ - Icmdset2 = 84, /* command sets supported extension */ - Icmdset3 = 85, /* command sets enabled */ - Icmdset4 = 86, /* command sets enabled */ - Icmdset5 = 87, /* command sets enabled extension */ - Iudma = 88, /* ultra DMA mode */ - Ierase = 89, /* time for security erase */ - Ieerase = 90, /* time for enhanced security erase */ - Ipower = 91, /* current advanced power management */ - Irmsn = 127, /* removable status notification */ - Istatus = 128, /* security status */ -}; - -typedef struct Ctlr Ctlr; -typedef struct Drive Drive; - -typedef struct Prd { - ulong pa; /* Physical Base Address */ - int count; -} Prd; - -enum { - Nprd = SDmaxio/(64*1024)+2, -}; - -typedef struct Ctlr { - int cmdport; - int ctlport; - int irq; - int tbdf; - int bmiba; /* bus master interface base address */ - - Pcidev* pcidev; - void (*ienable)(Ctlr*); - SDev* sdev; - - Drive* drive[2]; - - Prd* prdt; /* physical region descriptor table */ - - QLock; /* current command */ - Drive* curdrive; - int command; /* last command issued (debugging) */ - Rendez; - int done; - - Lock; /* register access */ -} Ctlr; - -typedef struct Drive { - Ctlr* ctlr; - - int dev; - ushort info[256]; - int c; /* cylinder */ - int h; /* head */ - int s; /* sector */ - int sectors; /* total */ - int secsize; /* sector size */ - - int dma; /* DMA R/W possible */ - int dmactl; - int rwm; /* read/write multiple possible */ - int rwmctl; - - int pkt; /* PACKET device, length of pktcmd */ - uchar pktcmd[16]; - int pktdma; /* this PACKET command using dma */ - - uchar sense[18]; - uchar inquiry[48]; - - QLock; /* drive access */ - int command; /* current command */ - int write; - uchar* data; - int dlen; - uchar* limit; - int count; /* sectors */ - int block; /* R/W bytes per block */ - int status; - int error; -} Drive; - -static void -pc87415ienable(Ctlr* ctlr) -{ - Pcidev *p; - int x; - - p = ctlr->pcidev; - if(p == nil) - return; - - x = pcicfgr32(p, 0x40); - if(ctlr->cmdport == p->mem[0].bar) - x &= ~0x00000100; - else - x &= ~0x00000200; - pcicfgw32(p, 0x40, x); -} - -static void -atadumpstate(Drive* drive, uchar* cmd, int lba, int count) -{ - Prd *prd; - Pcidev *p; - Ctlr *ctlr; - int i, bmiba; - - if(!(DEBUG & DbgSTATE)){ - USED(drive, cmd, lba, count); - return; - } - - ctlr = drive->ctlr; - print("command %2.2uX\n", ctlr->command); - print("data %8.8p limit %8.8p dlen %d status %uX error %uX\n", - drive->data, drive->limit, drive->dlen, - drive->status, drive->error); - if(cmd != nil){ - print("lba %d -> %d, count %d -> %d (%d)\n", - (cmd[2]<<24)|(cmd[3]<<16)|(cmd[4]<<8)|cmd[5], lba, - (cmd[7]<<8)|cmd[8], count, drive->count); - } - if(!(inb(ctlr->ctlport+As) & Bsy)){ - for(i = 1; i < 7; i++) - print(" 0x%2.2uX", inb(ctlr->cmdport+i)); - print(" 0x%2.2uX\n", inb(ctlr->ctlport+As)); - } - if(drive->command == Cwd || drive->command == Crd){ - bmiba = ctlr->bmiba; - prd = ctlr->prdt; - print("bmicx %2.2uX bmisx %2.2uX prdt %8.8p\n", - inb(bmiba+Bmicx), inb(bmiba+Bmisx), prd); - for(;;){ - print("pa 0x%8.8luX count %8.8uX\n", - prd->pa, prd->count); - if(prd->count & PrdEOT) - break; - prd++; - } - } - if(ctlr->pcidev && ctlr->pcidev->vid == 0x8086){ - p = ctlr->pcidev; - print("0x40: %4.4uX 0x42: %4.4uX", - pcicfgr16(p, 0x40), pcicfgr16(p, 0x42)); - print("0x48: %2.2uX\n", pcicfgr8(p, 0x48)); - print("0x4A: %4.4uX\n", pcicfgr16(p, 0x4A)); - } -} - -static int -atadebug(int cmdport, int ctlport, char* fmt, ...) -{ - int i, n; - va_list arg; - char buf[PRINTSIZE]; - - if(!(DEBUG & DbgPROBE)){ - USED(cmdport, ctlport, fmt); - return 0; - } - - va_start(arg, fmt); - n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf; - va_end(arg); - - if(cmdport){ - if(buf[n-1] == '\n') - n--; - n += snprint(buf+n, PRINTSIZE-n, " ataregs 0x%uX:", - cmdport); - for(i = Features; i < Command; i++) - n += snprint(buf+n, PRINTSIZE-n, " 0x%2.2uX", - inb(cmdport+i)); - if(ctlport) - n += snprint(buf+n, PRINTSIZE-n, " 0x%2.2uX", - inb(ctlport+As)); - n += snprint(buf+n, PRINTSIZE-n, "\n"); - } - putstrn(buf, n); - - return n; -} - -static int -ataready(int cmdport, int ctlport, int dev, int reset, int ready, int micro) -{ - int as; - - atadebug(cmdport, ctlport, "ataready: dev %uX reset %uX ready %uX", - dev, reset, ready); - - for(;;){ - /* - * Wait for the controller to become not busy and - * possibly for a status bit to become true (usually - * Drdy). Must change to the appropriate device - * register set if necessary before testing for ready. - * Always run through the loop at least once so it - * can be used as a test for !Bsy. - */ - as = inb(ctlport+As); - if(as & reset) - ; - else if(dev){ - outb(cmdport+Dh, dev); - dev = 0; - } - else if(ready == 0 || (as & ready)){ - atadebug(0, 0, "ataready: %d 0x%2.2uX\n", micro, as); - return as; - } - - if(micro-- <= 0){ - atadebug(0, 0, "ataready: %d 0x%2.2uX\n", micro, as); - break; - } - microdelay(1); - } - atadebug(cmdport, ctlport, "ataready: timeout"); - - return -1; -} - -static int -atacsfenabled(Drive* drive, vlong csf) -{ - int cmdset, i, x; - - for(i = 0; i < 3; i++){ - x = (csf>>(16*i)) & 0xFFFF; - if(x == 0) - continue; - cmdset = drive->info[Icmdset3+i]; - if(cmdset == 0 || cmdset == 0xFFFF) - return 0; - return cmdset & x; - } - - return 0; -} - -static int -atasf(int cmdport, int ctlport, int dev, uchar* command) -{ - int as, i; - - if(ataready(cmdport, ctlport, dev, Bsy|Drq, Drdy, 108*1000) < 0) - return -1; - - for(i = Features; i < Dh; i++) - outb(cmdport+i, command[i]); - outb(cmdport+Command, Csf); - microdelay(100); - as = ataready(cmdport, ctlport, 0, Bsy, Drdy|Df|Err, 109*1000); - if(as < 0 || (as & (Df|Err))) - return -1; - return 0; -} - -static int -atarwmmode(Drive* drive, int cmdport, int ctlport, int dev) -{ - int as, maxrwm, rwm; - - maxrwm = (drive->info[Imaxrwm] & 0xFF); - if(maxrwm == 0) - return 0; - - /* - * Sometimes drives come up with the current count set - * to 0; if so, set a suitable value, otherwise believe - * the value in Irwm if the 0x100 bit is set. - */ - if(drive->info[Irwm] & 0x100) - rwm = (drive->info[Irwm] & 0xFF); - else - rwm = 0; - if(rwm == 0) - rwm = maxrwm; - if(rwm > 16) - rwm = 16; - if(ataready(cmdport, ctlport, dev, Bsy|Drq, Drdy, 102*1000) < 0) - return 0; - outb(cmdport+Count, rwm); - outb(cmdport+Command, Csm); - microdelay(1); - as = ataready(cmdport, ctlport, 0, Bsy, Drdy|Df|Err, 1000); - inb(cmdport+Status); - if(as < 0 || (as & (Df|Err))) - return 0; - - drive->rwm = rwm; - - return rwm; -} - -static int -atadmamode(Drive* drive) -{ - int dma; - - /* - * Check if any DMA mode enabled. - * Assumes the BIOS has picked and enabled the best. - * This is completely passive at the moment, no attempt is - * made to ensure the hardware is correctly set up. - */ - dma = drive->info[Imwdma] & 0x0707; - drive->dma = (dma>>8) & dma; - if(drive->dma == 0 && (drive->info[Ivalid] & 0x04)){ - dma = drive->info[Iudma] & 0x1F1F; - drive->dma = (dma>>8) & dma; - if(drive->dma) - drive->dma |= 'U'<<16; - } - - return dma; -} - -static int -ataidentify(int cmdport, int ctlport, int dev, int pkt, void* info) -{ - int as, command, drdy; - - if(pkt){ - command = Cidpkt; - drdy = 0; - } - else{ - command = Cid; - drdy = Drdy; - } - as = ataready(cmdport, ctlport, dev, Bsy|Drq, drdy, 103*1000); - if(as < 0) - return as; - outb(cmdport+Command, command); - microdelay(1); - - as = ataready(cmdport, ctlport, 0, Bsy, Drq|Err, 104*1000); - if(as < 0) - return -1; - if(as & Err) - return as; - - memset(info, 0, 512); - inss(cmdport+Data, info, 256); - inb(cmdport+Status); - - if(DEBUG & DbgIDENTIFY){ - int i; - ushort *sp; - - sp = (ushort*)info; - for(i = 0; i < 256; i++){ - if(i && (i%16) == 0) - print("\n"); - print("%4.4uX ", *sp); - sp++; - } - print("\n"); - } - - return 0; -} - -static Drive* -atadrive(int cmdport, int ctlport, int dev) -{ - ushort *sp; - Drive *drive; - int as, i, pkt; - uchar buf[512], *p; - - atadebug(0, 0, "identify: port 0x%uX dev 0x%2.2uX\n", cmdport, dev); - pkt = 1; -retry: - as = ataidentify(cmdport, ctlport, dev, pkt, buf); - if(as < 0) - return nil; - if(as & Err){ - if(pkt == 0) - return nil; - pkt = 0; - goto retry; - } - - if((drive = malloc(sizeof(Drive))) == nil) - return nil; - drive->dev = dev; - memmove(drive->info, buf, sizeof(drive->info)); - drive->sense[0] = 0x70; - drive->sense[7] = sizeof(drive->sense)-7; - - drive->inquiry[2] = 2; - drive->inquiry[3] = 2; - drive->inquiry[4] = sizeof(drive->inquiry)-4; - p = &drive->inquiry[8]; - sp = &drive->info[Imodel]; - for(i = 0; i < 20; i++){ - *p++ = *sp>>8; - *p++ = *sp++; - } - - drive->secsize = 512; - if((drive->info[Iconfig] & 0xC000) == 0x8000){ - if(drive->info[Iconfig] & 0x01) - drive->pkt = 16; - else - drive->pkt = 12; - } - else{ - if(drive->info[Ivalid] & 0x0001){ - drive->c = drive->info[Ilcyl]; - drive->h = drive->info[Ilhead]; - drive->s = drive->info[Ilsec]; - } - else{ - drive->c = drive->info[Iccyl]; - drive->h = drive->info[Ichead]; - drive->s = drive->info[Icsec]; - } - if(drive->info[Icapabilities] & 0x0200){ - drive->sectors = (drive->info[Ilba1]<<16) - |drive->info[Ilba0]; - drive->dev |= Lba; - } - else - drive->sectors = drive->c*drive->h*drive->s; - atarwmmode(drive, cmdport, ctlport, dev); - } - atadmamode(drive); - - if(DEBUG & DbgCONFIG){ - print("dev %2.2uX config %4.4uX capabilities %4.4uX", - dev, drive->info[Iconfig], drive->info[Icapabilities]); - print(" mwdma %4.4uX dma %8.8uX", - drive->info[Imwdma], drive->dma); - if(drive->info[Ivalid] & 0x04) - print(" udma %4.4uX", drive->info[Iudma]); - print(" rwm %ud\n", drive->rwm); - } - - return drive; -} - -static void -atasrst(int ctlport) -{ - /* - * Srst is a big stick and may cause problems if further - * commands are tried before the drives become ready again. - * Also, there will be problems here if overlapped commands - * are ever supported. - */ - microdelay(5); - outb(ctlport+Dc, Srst); - microdelay(5); - outb(ctlport+Dc, 0); - microdelay(2*1000); -} - -static SDev* -ataprobe(int cmdport, int ctlport, int irq) -{ - Ctlr* ctlr; - SDev *sdev; - Drive *drive; - int dev, error, rhi, rlo; - - if(ioalloc(cmdport, 8, 0, "atacmd") < 0) - return nil; - if(ioalloc(ctlport+As, 1, 0, "atactl") < 0){ - iofree(cmdport); - return nil; - } - - /* - * Try to detect a floating bus. - * Bsy should be cleared. If not, see if the cylinder registers - * are read/write capable. - * If the master fails, try the slave to catch slave-only - * configurations. - * There's no need to restore the tested registers as they will - * be reset on any detected drives by the Cedd command. - * All this indicates is that there is at least one drive on the - * controller; when the non-existent drive is selected in a - * single-drive configuration the registers of the existing drive - * are often seen, only command execution fails. - */ - dev = Dev0; - if(inb(ctlport+As) & Bsy){ - outb(cmdport+Dh, dev); - microdelay(1); -trydev1: - atadebug(cmdport, ctlport, "ataprobe bsy"); - outb(cmdport+Cyllo, 0xAA); - outb(cmdport+Cylhi, 0x55); - outb(cmdport+Sector, 0xFF); - rlo = inb(cmdport+Cyllo); - rhi = inb(cmdport+Cylhi); - if(rlo != 0xAA && (rlo == 0xFF || rhi != 0x55)){ - if(dev == Dev1){ -release: - iofree(cmdport); - iofree(ctlport+As); - return nil; - } - dev = Dev1; - if(ataready(cmdport, ctlport, dev, Bsy, 0, 20*1000) < 0) - goto trydev1; - } - } - - /* - * Disable interrupts on any detected controllers. - */ - outb(ctlport+Dc, Nien); -tryedd1: - if(ataready(cmdport, ctlport, dev, Bsy|Drq, 0, 105*1000) < 0){ - /* - * There's something there, but it didn't come up clean, - * so try hitting it with a big stick. The timing here is - * wrong but this is a last-ditch effort and it sometimes - * gets some marginal hardware back online. - */ - atasrst(ctlport); - if(ataready(cmdport, ctlport, dev, Bsy|Drq, 0, 106*1000) < 0) - goto release; - } - - /* - * Can only get here if controller is not busy. - * If there are drives Bsy will be set within 400nS, - * must wait 2mS before testing Status. - * Wait for the command to complete (6 seconds max). - */ - outb(cmdport+Command, Cedd); - delay(2); - if(ataready(cmdport, ctlport, dev, Bsy|Drq, 0, 6*1000*1000) < 0) - goto release; - - /* - * If bit 0 of the error register is set then the selected drive - * exists. This is enough to detect single-drive configurations. - * However, if the master exists there is no way short of executing - * a command to determine if a slave is present. - * It appears possible to get here testing Dev0 although it doesn't - * exist and the EDD won't take, so try again with Dev1. - */ - error = inb(cmdport+Error); - atadebug(cmdport, ctlport, "ataprobe: dev %uX", dev); - if((error & ~0x80) != 0x01){ - if(dev == Dev1) - goto release; - dev = Dev1; - goto tryedd1; - } - - /* - * At least one drive is known to exist, try to - * identify it. If that fails, don't bother checking - * any further. - * If the one drive found is Dev0 and the EDD command - * didn't indicate Dev1 doesn't exist, check for it. - */ - if((drive = atadrive(cmdport, ctlport, dev)) == nil) - goto release; - if((ctlr = malloc(sizeof(Ctlr))) == nil){ - free(drive); - goto release; - } - if((sdev = malloc(sizeof(SDev))) == nil){ - free(ctlr); - free(drive); - goto release; - } - drive->ctlr = ctlr; - if(dev == Dev0){ - ctlr->drive[0] = drive; - if(!(error & 0x80)){ - /* - * Always leave Dh pointing to a valid drive, - * otherwise a subsequent call to ataready on - * this controller may try to test a bogus Status. - * Ataprobe is the only place possibly invalid - * drives should be selected. - */ - drive = atadrive(cmdport, ctlport, Dev1); - if(drive != nil){ - drive->ctlr = ctlr; - ctlr->drive[1] = drive; - } - else{ - outb(cmdport+Dh, Dev0); - microdelay(1); - } - } - } - else - ctlr->drive[1] = drive; - - ctlr->cmdport = cmdport; - ctlr->ctlport = ctlport; - ctlr->irq = irq; - ctlr->tbdf = BUSUNKNOWN; - ctlr->command = Cedd; /* debugging */ - - sdev->ifc = &sdataifc; - sdev->ctlr = ctlr; - sdev->nunit = 2; - ctlr->sdev = sdev; - - return sdev; -} - -static int -atasetsense(Drive* drive, int status, int key, int asc, int ascq) -{ - drive->sense[2] = key; - drive->sense[12] = asc; - drive->sense[13] = ascq; - - return status; -} - -static int -atamodesense(Drive* drive, uchar* cmd) -{ - int len; - - /* - * Fake a vendor-specific request with page code 0, - * return the drive info. - */ - if((cmd[2] & 0x3F) != 0 && (cmd[2] & 0x3F) != 0x3F) - return atasetsense(drive, SDcheck, 0x05, 0x24, 0); - len = (cmd[7]<<8)|cmd[8]; - if(len == 0) - return SDok; - if(len < 8+sizeof(drive->info)) - return atasetsense(drive, SDcheck, 0x05, 0x1A, 0); - if(drive->data == nil || drive->dlen < len) - return atasetsense(drive, SDcheck, 0x05, 0x20, 1); - memset(drive->data, 0, 8); - drive->data[0] = sizeof(drive->info)>>8; - drive->data[1] = sizeof(drive->info); - memmove(drive->data+8, drive->info, sizeof(drive->info)); - drive->data += 8+sizeof(drive->info); - - return SDok; -} - -static void -atanop(Drive* drive, int subcommand) -{ - Ctlr* ctlr; - int as, cmdport, ctlport, timeo; - - /* - * Attempt to abort a command by using NOP. - * In response, the drive is supposed to set Abrt - * in the Error register, set (Drdy|Err) in Status - * and clear Bsy when done. However, some drives - * (e.g. ATAPI Zip) just go Bsy then clear Status - * when done, hence the timeout loop only on Bsy - * and the forced setting of drive->error. - */ - ctlr = drive->ctlr; - cmdport = ctlr->cmdport; - outb(cmdport+Features, subcommand); - outb(cmdport+Dh, drive->dev); - ctlr->command = Cnop; /* debugging */ - outb(cmdport+Command, Cnop); - - microdelay(1); - ctlport = ctlr->ctlport; - for(timeo = 0; timeo < 1000; timeo++){ - as = inb(ctlport+As); - if(!(as & Bsy)) - break; - microdelay(1); - } - drive->error |= Abrt; -} - -static void -ataabort(Drive* drive, int dolock) -{ - /* - * If NOP is available (packet commands) use it otherwise - * must try a software reset. - */ - if(dolock) - ilock(drive->ctlr); - if(atacsfenabled(drive, 0x0000000000004000LL)) - atanop(drive, 0); - else{ - atasrst(drive->ctlr->ctlport); - drive->error |= Abrt; - } - if(dolock) - iunlock(drive->ctlr); -} - -static int -atadmasetup(Drive* drive, int len) -{ - Prd *prd; - ulong pa; - Ctlr *ctlr; - int bmiba, bmisx, count; - - pa = PCIWADDR(drive->data); - if(pa & 0x03) - return -1; - ctlr = drive->ctlr; - prd = ctlr->prdt; - - /* - * Sometimes drives identify themselves as being DMA capable - * although they are not on a busmastering controller. - */ - if(prd == nil){ - drive->dmactl = 0; - return -1; - } - - for(;;){ - prd->pa = pa; - count = 64*1024 - (pa & 0xFFFF); - if(count >= len){ - prd->count = PrdEOT|(len & 0xFFFF); - break; - } - prd->count = count; - len -= count; - pa += count; - prd++; - } - - bmiba = ctlr->bmiba; - outl(bmiba+Bmidtpx, PCIWADDR(ctlr->prdt)); - if(drive->write) - outb(ctlr->bmiba+Bmicx, 0); - else - outb(ctlr->bmiba+Bmicx, Rwcon); - bmisx = inb(bmiba+Bmisx); - outb(bmiba+Bmisx, bmisx|Ideints|Idedmae); - - return 0; -} - -static void -atadmastart(Ctlr* ctlr, int write) -{ - if(write) - outb(ctlr->bmiba+Bmicx, Ssbm); - else - outb(ctlr->bmiba+Bmicx, Rwcon|Ssbm); -} - -static int -atadmastop(Ctlr* ctlr) -{ - int bmiba; - - bmiba = ctlr->bmiba; - outb(bmiba+Bmicx, inb(bmiba+Bmicx) & ~Ssbm); - - return inb(bmiba+Bmisx); -} - -static void -atadmainterrupt(Drive* drive, int count) -{ - Ctlr* ctlr; - int bmiba, bmisx; - - ctlr = drive->ctlr; - bmiba = ctlr->bmiba; - bmisx = inb(bmiba+Bmisx); - switch(bmisx & (Ideints|Idedmae|Bmidea)){ - case Bmidea: - /* - * Data transfer still in progress, nothing to do - * (this should never happen). - */ - return; - - case Ideints: - case Ideints|Bmidea: - /* - * Normal termination, tidy up. - */ - drive->data += count; - break; - - default: - /* - * What's left are error conditions (memory transfer - * problem) and the device is not done but the PRD is - * exhausted. For both cases must somehow tell the - * drive to abort. - */ - ataabort(drive, 0); - break; - } - atadmastop(ctlr); - ctlr->done = 1; -} - -static int -atapktiodone(void* arg) -{ - return ((Ctlr*)arg)->done; -} - -static void -atapktinterrupt(Drive* drive) -{ - Ctlr* ctlr; - int cmdport, len; - - ctlr = drive->ctlr; - cmdport = ctlr->cmdport; - switch(inb(cmdport+Ir) & (/*Rel|*/Io|Cd)){ - case Cd: - outss(cmdport+Data, drive->pktcmd, drive->pkt/2); - break; - - case 0: - len = (inb(cmdport+Bytehi)<<8)|inb(cmdport+Bytelo); - if(drive->data+len > drive->limit){ - atanop(drive, 0); - break; - } - outss(cmdport+Data, drive->data, len/2); - drive->data += len; - break; - - case Io: - len = (inb(cmdport+Bytehi)<<8)|inb(cmdport+Bytelo); - if(drive->data+len > drive->limit){ - atanop(drive, 0); - break; - } - inss(cmdport+Data, drive->data, len/2); - drive->data += len; - break; - - case Io|Cd: - if(drive->pktdma) - atadmainterrupt(drive, drive->dlen); - else - ctlr->done = 1; - break; - } -} - -static int -atapktio(Drive* drive, uchar* cmd, int clen) -{ - Ctlr *ctlr; - int as, cmdport, ctlport, len, r, timeo; - - if(cmd[0] == 0x5A && (cmd[2] & 0x3F) == 0) - return atamodesense(drive, cmd); - - r = SDok; - - drive->command = Cpkt; - memmove(drive->pktcmd, cmd, clen); - memset(drive->pktcmd+clen, 0, drive->pkt-clen); - drive->limit = drive->data+drive->dlen; - - ctlr = drive->ctlr; - cmdport = ctlr->cmdport; - ctlport = ctlr->ctlport; - - qlock(ctlr); - - if(ataready(cmdport, ctlport, drive->dev, Bsy|Drq, 0, 107*1000) < 0){ - qunlock(ctlr); - return -1; - } - - ilock(ctlr); - if(drive->dlen && drive->dmactl && !atadmasetup(drive, drive->dlen)) - drive->pktdma = Dma; - else - drive->pktdma = 0; - - outb(cmdport+Features, drive->pktdma); - outb(cmdport+Count, 0); - outb(cmdport+Sector, 0); - len = 16*drive->secsize; - outb(cmdport+Bytelo, len); - outb(cmdport+Bytehi, len>>8); - outb(cmdport+Dh, drive->dev); - ctlr->done = 0; - ctlr->curdrive = drive; - ctlr->command = Cpkt; /* debugging */ - if(drive->pktdma) - atadmastart(ctlr, drive->write); - outb(cmdport+Command, Cpkt); - - if((drive->info[Iconfig] & 0x0060) != 0x0020){ - microdelay(1); - as = ataready(cmdport, ctlport, 0, Bsy, Drq|Chk, 4*1000); - if(as < 0) - r = SDtimeout; - else if(as & Chk) - r = SDcheck; - else - atapktinterrupt(drive); - } - iunlock(ctlr); - - while(waserror()) - ; - if(!drive->pktdma) - sleep(ctlr, atapktiodone, ctlr); - else for(timeo = 0; !ctlr->done; timeo++){ - tsleep(ctlr, atapktiodone, ctlr, 1000); - if(ctlr->done) - break; - ilock(ctlr); - atadmainterrupt(drive, 0); - if(!drive->error && timeo > 10){ - ataabort(drive, 0); - atadmastop(ctlr); - drive->dmactl = 0; - drive->error |= Abrt; - } - if(drive->error){ - drive->status |= Chk; - ctlr->curdrive = nil; - } - iunlock(ctlr); - } - poperror(); - - qunlock(ctlr); - - if(drive->status & Chk) - r = SDcheck; - - return r; -} - -static int -atageniodone(void* arg) -{ - return ((Ctlr*)arg)->done; -} - -static int -atageniostart(Drive* drive, int lba) -{ - Ctlr *ctlr; - int as, c, cmdport, ctlport, h, len, s; - - if(drive->dev & Lba){ - c = (lba>>8) & 0xFFFF; - h = (lba>>24) & 0x0F; - s = lba & 0xFF; - } - else{ - c = lba/(drive->s*drive->h); - h = ((lba/drive->s) % drive->h); - s = (lba % drive->s) + 1; - } - - ctlr = drive->ctlr; - cmdport = ctlr->cmdport; - ctlport = ctlr->ctlport; - if(ataready(cmdport, ctlport, drive->dev, Bsy|Drq, 0, 101*1000) < 0) - return -1; - - ilock(ctlr); - if(drive->dmactl && !atadmasetup(drive, drive->count*drive->secsize)){ - if(drive->write) - drive->command = Cwd; - else - drive->command = Crd; - } - else if(drive->rwmctl){ - drive->block = drive->rwm*drive->secsize; - if(drive->write) - drive->command = Cwsm; - else - drive->command = Crsm; - } - else{ - drive->block = drive->secsize; - if(drive->write) - drive->command = Cws; - else - drive->command = Crs; - } - drive->limit = drive->data + drive->count*drive->secsize; - - outb(cmdport+Count, drive->count); - outb(cmdport+Sector, s); - outb(cmdport+Dh, drive->dev|h); - outb(cmdport+Cyllo, c); - outb(cmdport+Cylhi, c>>8); - ctlr->done = 0; - ctlr->curdrive = drive; - ctlr->command = drive->command; /* debugging */ - outb(cmdport+Command, drive->command); - - switch(drive->command){ - case Cws: - case Cwsm: - microdelay(1); - as = ataready(cmdport, ctlport, 0, Bsy, Drq|Err, 1000); - if(as < 0 || (as & Err)){ - iunlock(ctlr); - return -1; - } - len = drive->block; - if(drive->data+len > drive->limit) - len = drive->limit-drive->data; - outss(cmdport+Data, drive->data, len/2); - break; - - case Crd: - case Cwd: - atadmastart(ctlr, drive->write); - break; - } - iunlock(ctlr); - - return 0; -} - -static int -atagenioretry(Drive* drive) -{ - if(drive->dmactl) - drive->dmactl = 0; - else if(drive->rwmctl) - drive->rwmctl = 0; - else - return atasetsense(drive, SDcheck, 4, 8, drive->error); - - return SDretry; -} - -static int -atagenio(Drive* drive, uchar* cmd, int) -{ - uchar *p; - Ctlr *ctlr; - int count, lba, len; - - /* - * Map SCSI commands into ATA commands for discs. - * Fail any command with a LUN except INQUIRY which - * will return 'logical unit not supported'. - */ - if((cmd[1]>>5) && cmd[0] != 0x12) - return atasetsense(drive, SDcheck, 0x05, 0x25, 0); - - switch(cmd[0]){ - default: - return atasetsense(drive, SDcheck, 0x05, 0x20, 0); - - case 0x00: /* test unit ready */ - return SDok; - - case 0x03: /* request sense */ - if(cmd[4] < sizeof(drive->sense)) - len = cmd[4]; - else - len = sizeof(drive->sense); - if(drive->data && drive->dlen >= len){ - memmove(drive->data, drive->sense, len); - drive->data += len; - } - return SDok; - - case 0x12: /* inquiry */ - if(cmd[4] < sizeof(drive->inquiry)) - len = cmd[4]; - else - len = sizeof(drive->inquiry); - if(drive->data && drive->dlen >= len){ - memmove(drive->data, drive->inquiry, len); - drive->data += len; - } - return SDok; - - case 0x1B: /* start/stop unit */ - /* - * NOP for now, can use the power management feature - * set later. - */ - return SDok; - - case 0x25: /* read capacity */ - if((cmd[1] & 0x01) || cmd[2] || cmd[3]) - return atasetsense(drive, SDcheck, 0x05, 0x24, 0); - if(drive->data == nil || drive->dlen < 8) - return atasetsense(drive, SDcheck, 0x05, 0x20, 1); - /* - * Read capacity returns the LBA of the last sector. - */ - len = drive->sectors-1; - p = drive->data; - *p++ = len>>24; - *p++ = len>>16; - *p++ = len>>8; - *p++ = len; - len = drive->secsize; - *p++ = len>>24; - *p++ = len>>16; - *p++ = len>>8; - *p = len; - drive->data += 8; - return SDok; - - case 0x28: /* read */ - case 0x2A: /* write */ - break; - - case 0x5A: - return atamodesense(drive, cmd); - } - - ctlr = drive->ctlr; - lba = (cmd[2]<<24)|(cmd[3]<<16)|(cmd[4]<<8)|cmd[5]; - count = (cmd[7]<<8)|cmd[8]; - if(drive->data == nil) - return SDok; - if(drive->dlen < count*drive->secsize) - count = drive->dlen/drive->secsize; - qlock(ctlr); - while(count){ - if(count > 256) - drive->count = 256; - else - drive->count = count; - if(atageniostart(drive, lba)){ - ilock(ctlr); - atanop(drive, 0); - iunlock(ctlr); - qunlock(ctlr); - return atagenioretry(drive); - } - - while(waserror()) - ; - tsleep(ctlr, atageniodone, ctlr, 10*1000); - poperror(); - if(!ctlr->done){ - /* - * What should the above timeout be? In - * standby and sleep modes it could take as - * long as 30 seconds for a drive to respond. - * Very hard to get out of this cleanly. - */ - atadumpstate(drive, cmd, lba, count); - ataabort(drive, 1); - return atagenioretry(drive); - } - - if(drive->status & Err){ - qunlock(ctlr); - return atasetsense(drive, SDcheck, 4, 8, drive->error); - } - count -= drive->count; - lba += drive->count; - } - qunlock(ctlr); - - return SDok; -} - -static int -atario(SDreq* r) -{ - Ctlr *ctlr; - Drive *drive; - SDunit *unit; - uchar cmd10[10], *cmdp, *p; - int clen, reqstatus, status; - - unit = r->unit; - if((ctlr = unit->dev->ctlr) == nil || ctlr->drive[unit->subno] == nil){ - r->status = SDtimeout; - return SDtimeout; - } - drive = ctlr->drive[unit->subno]; - - /* - * Most SCSI commands can be passed unchanged except for - * the padding on the end. The few which require munging - * are not used internally. Mode select/sense(6) could be - * converted to the 10-byte form but it's not worth the - * effort. Read/write(6) are easy. - */ - switch(r->cmd[0]){ - case 0x08: /* read */ - case 0x0A: /* write */ - cmdp = cmd10; - memset(cmdp, 0, sizeof(cmd10)); - cmdp[0] = r->cmd[0]|0x20; - cmdp[1] = r->cmd[1] & 0xE0; - cmdp[5] = r->cmd[3]; - cmdp[4] = r->cmd[2]; - cmdp[3] = r->cmd[1] & 0x0F; - cmdp[8] = r->cmd[4]; - clen = sizeof(cmd10); - break; - - default: - cmdp = r->cmd; - clen = r->clen; - break; - } - - qlock(drive); -retry: - drive->write = r->write; - drive->data = r->data; - drive->dlen = r->dlen; - - drive->status = 0; - drive->error = 0; - if(drive->pkt) - status = atapktio(drive, cmdp, clen); - else - status = atagenio(drive, cmdp, clen); - if(status == SDretry){ - if(DbgDEBUG) - print("%s: retry: dma %8.8uX rwm %4.4uX\n", - unit->name, drive->dmactl, drive->rwmctl); - goto retry; - } - if(status == SDok){ - atasetsense(drive, SDok, 0, 0, 0); - if(drive->data){ - p = r->data; - r->rlen = drive->data - p; - } - else - r->rlen = 0; - } - else if(status == SDcheck && !(r->flags & SDnosense)){ - drive->write = 0; - memset(cmd10, 0, sizeof(cmd10)); - cmd10[0] = 0x03; - cmd10[1] = r->lun<<5; - cmd10[4] = sizeof(r->sense)-1; - drive->data = r->sense; - drive->dlen = sizeof(r->sense)-1; - drive->status = 0; - drive->error = 0; - if(drive->pkt) - reqstatus = atapktio(drive, cmd10, 6); - else - reqstatus = atagenio(drive, cmd10, 6); - if(reqstatus == SDok){ - r->flags |= SDvalidsense; - atasetsense(drive, SDok, 0, 0, 0); - } - } - qunlock(drive); - r->status = status; - if(status != SDok) - return status; - - /* - * Fix up any results. - * Many ATAPI CD-ROMs ignore the LUN field completely and - * return valid INQUIRY data. Patch the response to indicate - * 'logical unit not supported' if the LUN is non-zero. - */ - switch(cmdp[0]){ - case 0x12: /* inquiry */ - if((p = r->data) == nil) - break; - if((cmdp[1]>>5) && (!drive->pkt || (p[0] & 0x1F) == 0x05)) - p[0] = 0x7F; - /*FALLTHROUGH*/ - default: - break; - } - - return SDok; -} - -static void -atainterrupt(Ureg*, void* arg) -{ - Ctlr *ctlr; - Drive *drive; - int cmdport, len, status; - - ctlr = arg; - - ilock(ctlr); - if(inb(ctlr->ctlport+As) & Bsy){ - iunlock(ctlr); - if(DEBUG & DbgDEBUG) - print("IBsy+"); - return; - } - cmdport = ctlr->cmdport; - status = inb(cmdport+Status); - if((drive = ctlr->curdrive) == nil){ - iunlock(ctlr); - if((DEBUG & DbgDEBUG) && ctlr->command != Cedd) - print("Inil%2.2uX+", ctlr->command); - return; - } - - if(status & Err) - drive->error = inb(cmdport+Error); - else switch(drive->command){ - default: - drive->error = Abrt; - break; - - case Crs: - case Crsm: - if(!(status & Drq)){ - drive->error = Abrt; - break; - } - len = drive->block; - if(drive->data+len > drive->limit) - len = drive->limit-drive->data; - inss(cmdport+Data, drive->data, len/2); - drive->data += len; - if(drive->data >= drive->limit) - ctlr->done = 1; - break; - - case Cws: - case Cwsm: - len = drive->block; - if(drive->data+len > drive->limit) - len = drive->limit-drive->data; - drive->data += len; - if(drive->data >= drive->limit){ - ctlr->done = 1; - break; - } - if(!(status & Drq)){ - drive->error = Abrt; - break; - } - len = drive->block; - if(drive->data+len > drive->limit) - len = drive->limit-drive->data; - outss(cmdport+Data, drive->data, len/2); - break; - - case Cpkt: - atapktinterrupt(drive); - break; - - case Crd: - case Cwd: - atadmainterrupt(drive, drive->count*drive->secsize); - break; - } - iunlock(ctlr); - - if(drive->error){ - status |= Err; - ctlr->done = 1; - } - - if(ctlr->done){ - ctlr->curdrive = nil; - drive->status = status; - wakeup(ctlr); - } -} - -static SDev* -atapnp(void) -{ - Ctlr *ctlr; - Pcidev *p; - int channel, ispc87415, pi, r; - SDev *legacy[2], *sdev, *head, *tail; - - legacy[0] = legacy[1] = head = tail = nil; - if(sdev = ataprobe(0x1F0, 0x3F4, IrqATA0)){ - head = tail = sdev; - legacy[0] = sdev; - } - if(sdev = ataprobe(0x170, 0x374, IrqATA1)){ - if(head != nil) - tail->next = sdev; - else - head = sdev; - tail = sdev; - legacy[1] = sdev; - } - - p = nil; - while(p = pcimatch(p, 0, 0)){ - /* - * Look for devices with the correct class and sub-class - * code and known device and vendor ID; add native-mode - * channels to the list to be probed, save info for the - * compatibility mode channels. - * Note that the legacy devices should not be considered - * PCI devices by the interrupt controller. - * For both native and legacy, save info for busmastering - * if capable. - * Promise Ultra ATA/66 (PDC20262) appears to - * 1) give a sub-class of 'other mass storage controller' - * instead of 'IDE controller', regardless of whether it's - * the only controller or not; - * 2) put 0 in the programming interface byte (probably - * as a consequence of 1) above). - */ - if(p->ccrb != 0x01 || (p->ccru != 0x01 && p->ccru != 0x80)) - continue; - pi = p->ccrp; - ispc87415 = 0; - - switch((p->did<<16)|p->vid){ - default: - continue; - - case (0x0002<<16)|0x100B: /* NS PC87415 */ - /* - * Disable interrupts on both channels until - * after they are probed for drives. - * This must be called before interrupts are - * enabled because the IRQ may be shared. - */ - ispc87415 = 1; - pcicfgw32(p, 0x40, 0x00000300); - break; - case (0x1000<<16)|0x1042: /* PC-Tech RZ1000 */ - /* - * Turn off prefetch. Overkill, but cheap. - */ - r = pcicfgr32(p, 0x40); - r &= ~0x2000; - pcicfgw32(p, 0x40, r); - break; - case (0x4D38<<16)|0x105A: /* Promise PDC20262 */ - pi = 0x85; - break; - case (0x0640<<16)|0x1095: /* CMD 640B */ - /* - * Bugfix code here... - */ - break; - case (0x0646<<16)|0x1095: /* CMD 646 */ - case (0x0571<<16)|0x1106: /* VIA 82C686 */ - case (0x1230<<16)|0x8086: /* 82371FB (PIIX) */ - case (0x7010<<16)|0x8086: /* 82371SB (PIIX3) */ - case (0x7111<<16)|0x8086: /* 82371[AE]B (PIIX4[E]) */ - break; - } - - for(channel = 0; channel < 2; channel++){ - if(pi & (1<<(2*channel))){ - sdev = ataprobe(p->mem[0+2*channel].bar & ~0x01, - p->mem[1+2*channel].bar & ~0x01, - p->intl); - if(sdev == nil) - continue; - - ctlr = sdev->ctlr; - if(ispc87415) - ctlr->ienable = pc87415ienable; - - if(head != nil) - tail->next = sdev; - else - head = sdev; - tail = sdev; - ctlr->tbdf = p->tbdf; - } - else if((sdev = legacy[channel]) == nil) - continue; - else - ctlr = sdev->ctlr; - - ctlr->pcidev = p; - if(!(pi & 0x80)) - continue; - ctlr->bmiba = (p->mem[4].bar & ~0x01) + channel*8; - } - } - - return head; -} - -static SDev* -atalegacy(int port, int irq) -{ - return ataprobe(port, port+0x204, irq); -} - -static SDev* -ataid(SDev* sdev) -{ - int i; - Ctlr *ctlr; - - /* - * Legacy controllers are always 'C' and 'D' and if - * they exist and have drives will be first in the list. - * If there are no active legacy controllers, native - * controllers start at 'C'. - */ - if(sdev == nil) - return nil; - ctlr = sdev->ctlr; - if(ctlr->cmdport == 0x1F0 || ctlr->cmdport == 0x170) - i = 2; - else - i = 0; - while(sdev){ - if(sdev->ifc == &sdataifc){ - ctlr = sdev->ctlr; - if(ctlr->cmdport == 0x1F0) - sdev->idno = 'C'; - else if(ctlr->cmdport == 0x170) - sdev->idno = 'D'; - else{ - sdev->idno = 'C'+i; - i++; - } - snprint(sdev->name, NAMELEN, "sd%c", sdev->idno); - } - sdev = sdev->next; - } - - return nil; -} - -static int -ataenable(SDev* sdev) -{ - Ctlr *ctlr; - char name[NAMELEN]; - - ctlr = sdev->ctlr; - - if(ctlr->bmiba){ - if(ctlr->pcidev != nil) - pcisetbme(ctlr->pcidev); - ctlr->prdt = xspanalloc(Nprd*sizeof(Prd), 4, 4*1024); - } - snprint(name, NAMELEN, "%s (%s)", sdev->name, sdev->ifc->name); - intrenable(ctlr->irq, atainterrupt, ctlr, ctlr->tbdf, name); - outb(ctlr->ctlport+Dc, 0); - if(ctlr->ienable) - ctlr->ienable(ctlr); - - return 1; -} - -static int -atarctl(SDunit* unit, char* p, int l) -{ - int n; - Ctlr *ctlr; - Drive *drive; - - if((ctlr = unit->dev->ctlr) == nil || ctlr->drive[unit->subno] == nil) - return 0; - drive = ctlr->drive[unit->subno]; - - qlock(drive); - n = snprint(p, l, "config %4.4uX capabilities %4.4uX", - drive->info[Iconfig], drive->info[Icapabilities]); - if(drive->dma) - n += snprint(p+n, l-n, " dma %8.8uX dmactl %8.8uX", - drive->dma, drive->dmactl); - if(drive->rwm) - n += snprint(p+n, l-n, " rwm %ud rwmctl %ud", - drive->rwm, drive->rwmctl); - n += snprint(p+n, l-n, "\n"); - if(!unit->changed && unit->sectors){ - n += snprint(p+n, l-n, "geometry %ld %ld", - unit->sectors, unit->secsize); - if(drive->pkt == 0) - n += snprint(p+n, l-n, " %d %d %d", - drive->c, drive->h, drive->s); - n += snprint(p+n, l-n, "\n"); - } - qunlock(drive); - - return n; -} - -static int -atawctl(SDunit* unit, Cmdbuf* cb) -{ - Ctlr *ctlr; - Drive *drive; - - if((ctlr = unit->dev->ctlr) == nil || ctlr->drive[unit->subno] == nil) - return 0; - drive = ctlr->drive[unit->subno]; - - qlock(drive); - if(waserror()){ - qunlock(drive); - nexterror(); - } - - /* - * Dma and rwm control is passive at the moment, - * i.e. it is assumed that the hardware is set up - * correctly already either by the BIOS or when - * the drive was initially identified. - */ - if(strcmp(cb->f[0], "dma") == 0){ - if(cb->nf != 2 || drive->dma == 0) - error(Ebadctl); - if(strcmp(cb->f[1], "on") == 0) - drive->dmactl = drive->dma; - else if(strcmp(cb->f[1], "off") == 0) - drive->dmactl = 0; - else - error(Ebadctl); - } - else if(strcmp(cb->f[0], "rwm") == 0){ - if(cb->nf != 2 || drive->rwm == 0) - error(Ebadctl); - if(strcmp(cb->f[1], "on") == 0) - drive->rwmctl = drive->rwm; - else if(strcmp(cb->f[1], "off") == 0) - drive->rwmctl = 0; - else - error(Ebadctl); - } - else - error(Ebadctl); - qunlock(drive); - poperror(); - - return 0; -} - -SDifc sdataifc = { - "ata", /* name */ - - atapnp, /* pnp */ - atalegacy, /* legacy */ - ataid, /* id */ - ataenable, /* enable */ - nil, /* disable */ - - scsiverify, /* verify */ - scsionline, /* online */ - atario, /* rio */ - atarctl, /* rctl */ - atawctl, /* wctl */ - - scsibio, /* bio */ -}; +#include "../pc/sdata.c" diff --git a/alphapc/sdscsi.c b/alphapc/sdscsi.c index e98d038accc6f18db6705afb08b5cf286afa271d..dd38ec1f4e63bd3b5885c1cb16ae68791cc478c0 100644 --- a/alphapc/sdscsi.c +++ b/alphapc/sdscsi.c @@ -1,386 +1 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "io.h" -#include "ureg.h" -#include "../port/error.h" - -#include "sd.h" - -static int -scsitest(SDreq* r) -{ - r->write = 0; - memset(r->cmd, 0, sizeof(r->cmd)); - r->cmd[1] = r->lun<<5; - r->clen = 6; - r->data = nil; - r->dlen = 0; - r->flags = 0; - - r->status = ~0; - - return r->unit->dev->ifc->rio(r); -} - -int -scsiverify(SDunit* unit) -{ - SDreq *r; - int i, status; - uchar *inquiry; - - if((r = malloc(sizeof(SDreq))) == nil) - return 0; - if((inquiry = sdmalloc(sizeof(unit->inquiry))) == nil){ - free(r); - return 0; - } - r->unit = unit; - r->lun = 0; /* ??? */ - - memset(unit->inquiry, 0, sizeof(unit->inquiry)); - r->write = 0; - r->cmd[0] = 0x12; - r->cmd[1] = r->lun<<5; - r->cmd[4] = sizeof(unit->inquiry)-1; - r->clen = 6; - r->data = inquiry; - r->dlen = sizeof(unit->inquiry)-1; - r->flags = 0; - - r->status = ~0; - if(unit->dev->ifc->rio(r) != SDok){ - free(r); - return 0; - } - memmove(unit->inquiry, inquiry, r->dlen); - free(inquiry); - - SET(status); - for(i = 0; i < 3; i++){ - while((status = scsitest(r)) == SDbusy) - ; - if(status == SDok || status != SDcheck) - break; - if(!(r->flags & SDvalidsense)) - break; - if((r->sense[2] & 0x0F) != 0x02) - continue; - /* - * Unit is 'not ready'. - * If it needs an initialising command, set status - * so it will be spun-up below. - * If there's no medium, that's OK too, but don't - * try to spin it up. - */ - if(r->sense[12] == 0x04 && r->sense[13] == 0x02){ - status = SDok; - break; - } - if(r->sense[12] == 0x3A) - break; - } - - if(status == SDok){ - /* - * Try to ensure a direct-access device is spinning. - * Don't wait for completion, ignore the result. - */ - if((unit->inquiry[0] & 0x1F) == 0){ - memset(r->cmd, 0, sizeof(r->cmd)); - r->write = 0; - r->cmd[0] = 0x1B; - r->cmd[1] = (r->lun<<5)|0x01; - r->cmd[4] = 1; - r->clen = 6; - r->data = nil; - r->dlen = 0; - r->flags = 0; - - r->status = ~0; - unit->dev->ifc->rio(r); - } - } - free(r); - - if(status == SDok || status == SDcheck) - return 1; - return 0; -} - -static int -scsirio(SDreq* r) -{ - /* - * Perform an I/O request, returning - * -1 failure - * 0 ok - * 1 no medium present - * 2 retry - * The contents of r may be altered so the - * caller should re-initialise if necesary. - */ - r->status = ~0; - switch(r->unit->dev->ifc->rio(r)){ - default: - return -1; - case SDcheck: - if(!(r->flags & SDvalidsense)) - return -1; - switch(r->sense[2] & 0x0F){ - case 0x00: /* no sense */ - case 0x01: /* recovered error */ - return 2; - case 0x06: /* check condition */ - /* - * 0x28 - not ready to ready transition, - * medium may have changed. - * 0x29 - power on or some type of reset. - */ - if(r->sense[12] == 0x28 && r->sense[13] == 0) - return 2; - if(r->sense[12] == 0x29) - return 2; - return -1; - case 0x02: /* not ready */ - /* - * If no medium present, bail out. - * If unit is becoming ready, rather than not - * not ready, wait a little then poke it again. */ - if(r->sense[12] == 0x3A) - return 1; - if(r->sense[12] != 0x04 || r->sense[13] != 0x01) - return -1; - - while(waserror()) - ; - tsleep(&r->unit->rendez, return0, 0, 500); - poperror(); - scsitest(r); - return 2; - default: - return -1; - } - return -1; - case SDok: - return 0; - } - return -1; -} - -int -scsionline(SDunit* unit) -{ - SDreq *r; - uchar *p; - int ok, retries; - - if((r = malloc(sizeof(SDreq))) == nil) - return 0; - if((p = sdmalloc(8)) == nil){ - free(r); - return 0; - } - - ok = 0; - - r->unit = unit; - r->lun = 0; /* ??? */ - for(retries = 0; retries < 10; retries++){ - /* - * Read-capacity is mandatory for DA, WORM, CD-ROM and - * MO. It may return 'not ready' if type DA is not - * spun up, type MO or type CD-ROM are not loaded or just - * plain slow getting their act together after a reset. - */ - r->write = 0; - memset(r->cmd, 0, sizeof(r->cmd)); - r->cmd[0] = 0x25; - r->cmd[1] = r->lun<<5; - r->clen = 10; - r->data = p; - r->dlen = 8; - r->flags = 0; - - r->status = ~0; - switch(scsirio(r)){ - default: - break; - case 0: - unit->sectors = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3]; - /* - * Read-capacity returns the LBA of the last sector, - * therefore the number of sectors must be incremented. - */ - unit->sectors++; - unit->secsize = (p[4]<<24)|(p[5]<<16)|(p[6]<<8)|p[7]; - - /* - * Some ATAPI CD readers lie about the block size. - * Since we don't read audio via this interface - * it's okay to always fudge this. - */ - if(unit->secsize == 2352) - unit->secsize = 2048; - ok = 1; - break; - case 1: - ok = 1; - break; - case 2: - continue; - } - break; - } - free(p); - free(r); - - if(ok) - return ok+retries; - else - return 0; -} - -int -scsiexec(SDunit* unit, int write, uchar* cmd, int clen, void* data, int* dlen) -{ - SDreq *r; - int status; - - if((r = malloc(sizeof(SDreq))) == nil) - return SDmalloc; - r->unit = unit; - r->lun = cmd[1]>>5; /* ??? */ - r->write = write; - memmove(r->cmd, cmd, clen); - r->clen = clen; - r->data = data; - if(dlen) - r->dlen = *dlen; - r->flags = 0; - - r->status = ~0; - - /* - * Call the device-specific I/O routine. - * There should be no calls to 'error()' below this - * which percolate back up. - */ - switch(status = unit->dev->ifc->rio(r)){ - case SDok: - if(dlen) - *dlen = r->rlen; - /*FALLTHROUGH*/ - case SDcheck: - /*FALLTHROUGH*/ - default: - /* - * It's more complicated than this. There are conditions - * which are 'ok' but for which the returned status code - * is not 'SDok'. - * Also, not all conditions require a reqsense, might - * need to do a reqsense here and make it available to the - * caller somehow. - * - * MaƱana. - */ - break; - } - sdfree(r); - - return status; -} - -long -scsibio(SDunit* unit, int lun, int write, void* data, long nb, long bno) -{ - SDreq *r; - long rlen; - - if((r = malloc(sizeof(SDreq))) == nil) - error(Enomem); - r->unit = unit; - r->lun = lun; -again: - r->write = write; - if(write == 0) - r->cmd[0] = 0x28; - else - r->cmd[0] = 0x2A; - r->cmd[1] = (lun<<5); - r->cmd[2] = bno>>24; - r->cmd[3] = bno>>16; - r->cmd[4] = bno>>8; - r->cmd[5] = bno; - r->cmd[6] = 0; - r->cmd[7] = nb>>8; - r->cmd[8] = nb; - r->cmd[9] = 0; - r->clen = 10; - r->data = data; - r->dlen = nb*unit->secsize; - r->flags = 0; - - r->status = ~0; - switch(scsirio(r)){ - default: - rlen = -1; - break; - case 0: - rlen = r->rlen; - break; - case 2: - rlen = -1; - if(!(r->flags & SDvalidsense)) - break; - switch(r->sense[2] & 0x0F){ - default: - break; - case 0x06: /* check condition */ - /* - * Check for a removeable media change. - * If so, mark it by zapping the geometry info - * to force an online request. - */ - if(r->sense[12] != 0x28 || r->sense[13] != 0) - break; - if(unit->inquiry[1] & 0x80) - unit->sectors = 0; - break; - case 0x02: /* not ready */ - /* - * If unit is becoming ready, - * rather than not not ready, try again. - */ - if(r->sense[12] == 0x04 && r->sense[13] == 0x01) - goto again; - break; - } - break; - } - free(r); - - return rlen; -} - -SDev* -scsiid(SDev* sdev, SDifc* ifc) -{ - static char idno[16] = "0123456789abcdef"; - static char *p = idno; - - while(sdev){ - if(sdev->ifc == ifc){ - sdev->idno = *p++; - snprint(sdev->name, NAMELEN, "sd%c", sdev->idno); - if(p >= &idno[sizeof(idno)]) - break; - } - sdev = sdev->next; - } - - return nil; -} +#include "../pc/sdscsi.c" diff --git a/ip/icmp.c b/ip/icmp.c index 7df64cfbf11dc95a73c5f188bf3aeaf5538e48b3..3285e615b03eec696f6059d7181c866ad5919a08 100644 --- a/ip/icmp.c +++ b/ip/icmp.c @@ -30,7 +30,7 @@ enum { /* Packet Types */ EchoReply = 0, Unreachable = 3, SrcQuench = 4, - Redirect = 4, + Redirect = 5, EchoRequest = 8, TimeExceed = 11, InParmProblem = 12, @@ -40,56 +40,61 @@ enum { /* Packet Types */ InfoReply = 16, AddrMaskRequest = 17, AddrMaskReply = 18, + Maxtype = 18, }; +char *icmpnames[Maxtype+1] = +{ +[EchoReply] "EchoReply", +[Unreachable] "Unreachable", +[SrcQuench] "SrcQuench", +[Redirect] "Redirect", +[EchoRequest] "EchoRequest", +[TimeExceed] "TimeExceed", +[InParmProblem] "InParmProblem", +[Timestamp] "Timestamp", +[TimestampReply] "TimestampReply", +[InfoRequest] "InfoRequest", +[InfoReply] "InfoReply", +[AddrMaskRequest] "AddrMaskRequest", +[AddrMaskReply ] "AddrMaskReply ", +}; + enum { IP_ICMPPROTO = 1, ICMP_IPSIZE = 20, ICMP_HDRSIZE = 8, }; -typedef struct Icmpstats Icmpstats; -struct Icmpstats +enum +{ + InMsgs, + InErrors, + OutMsgs, + CsumErrs, + LenErrs, + HlenErrs, + + Nstats, +}; + +static char *statnames[Nstats] = { - ulong icmpInMsgs; - ulong icmpInErrors; -// ulong icmpInDestUnreachs; -// ulong icmpInTimeExcds; -// ulong icmpInParmProbs; -// ulong icmpInSrcQuenchs; -// ulong icmpInRedirects; -// ulong icmpInEchos; -// ulong icmpInEchoReps; -// ulong icmpInTimestamps; -// ulong icmpInTimestampReps; -// ulong icmpInAddrMasks; -// ulong icmpInAddrMaskReps; - ulong icmpOutMsgs; - ulong icmpOutErrors; -// ulong icmpOutDestUnreachs; -// ulong icmpOutTimeExcds; -// ulong icmpOutParmProbs; -// ulong icmpOutSrcQuenchs; -// ulong icmpOutRedirects; -// ulong icmpOutEchos; -// ulong icmpOutEchoReps; -// ulong icmpOutTimestamps; -// ulong icmpOutTimestampReps; -// ulong icmpOutAddrMasks; -// ulong icmpOutAddrMaskReps; +[InMsgs] "InMsgs", +[InErrors] "InErrors", +[OutMsgs] "OutMsgs", +[CsumErrs] "CsumErrs", +[LenErrs] "LenErrs", +[HlenErrs] "HlenErrs", }; typedef struct Icmppriv Icmppriv; struct Icmppriv { - /* MIB Counters */ - Icmpstats istats; + ulong stats[Nstats]; - /* non-MIB stats */ - ulong csumerr; /* checksum errors */ - ulong lenerr; /* short packet */ - ulong hlenerr; /* short header */ + /* message counts */ ulong in[Maxtype+1]; ulong out[Maxtype+1]; }; @@ -170,7 +175,7 @@ icmpkick(Conv *c, int l) hnputs(p->icmpid, c->lport); memset(p->cksum, 0, sizeof(p->cksum)); hnputs(p->cksum, ptclcsum(bp, ICMP_IPSIZE, blocklen(bp) - ICMP_IPSIZE)); - ipriv->istats.icmpOutMsgs++; + ipriv->stats[OutMsgs]++; ipoput(c->p->f, bp, 0, c->ttl, c->tos); } @@ -196,7 +201,6 @@ icmpttlexceeded(Fs *f, uchar *ia, Block *bp) hnputs(np->seq, 0); memset(np->cksum, 0, sizeof(np->cksum)); hnputs(np->cksum, ptclcsum(nbp, ICMP_IPSIZE, blocklen(nbp) - ICMP_IPSIZE)); -/* stats.out[TimeExceed]++; */ ipoput(f, nbp, 0, MAXTTL, DFLTTOS); } @@ -235,7 +239,6 @@ icmpnoconv(Fs *f, Block *bp) hnputs(np->seq, 0); memset(np->cksum, 0, sizeof(np->cksum)); hnputs(np->cksum, ptclcsum(nbp, ICMP_IPSIZE, blocklen(nbp) - ICMP_IPSIZE)); -/* stats.out[Unreachable]++; */ ipoput(f, nbp, 0, MAXTTL, DFLTTOS); } @@ -304,27 +307,27 @@ icmpiput(Proto *icmp, uchar*, Block *bp) ipriv = icmp->priv; - ipriv->istats.icmpInMsgs++; + ipriv->stats[InMsgs]++; p = (Icmp *)bp->rp; netlog(icmp->f, Logicmp, "icmpiput %d %d\n", p->type, p->code); n = blocklen(bp); if(n < ICMP_IPSIZE+ICMP_HDRSIZE){ - ipriv->istats.icmpInErrors++; - ipriv->hlenerr++; + ipriv->stats[InErrors]++; + ipriv->stats[HlenErrs]++; netlog(icmp->f, Logicmp, "icmp hlen %d\n", n); goto raise; } iplen = nhgets(p->length); if(iplen > n || (iplen % 1)){ - ipriv->lenerr++; - ipriv->istats.icmpInErrors++; + ipriv->stats[LenErrs]++; + ipriv->stats[InErrors]++; netlog(icmp->f, Logicmp, "icmp length %d\n", iplen); goto raise; } if(ptclcsum(bp, ICMP_IPSIZE, iplen - ICMP_IPSIZE)){ - ipriv->istats.icmpInErrors++; - ipriv->csumerr++; + ipriv->stats[InErrors]++; + ipriv->stats[CsumErrs]++; netlog(icmp->f, Logicmp, "icmp checksum error\n"); goto raise; } @@ -345,7 +348,7 @@ icmpiput(Proto *icmp, uchar*, Block *bp) bp->rp += ICMP_IPSIZE+ICMP_HDRSIZE; if(blocklen(bp) < 8){ - ipriv->lenerr++; + ipriv->stats[LenErrs]++; goto raise; } p = (Icmp *)bp->rp; @@ -364,7 +367,7 @@ icmpiput(Proto *icmp, uchar*, Block *bp) bp->rp += ICMP_IPSIZE+ICMP_HDRSIZE; if(blocklen(bp) < 8){ - ipriv->lenerr++; + ipriv->stats[LenErrs]++; goto raise; } p = (Icmp *)bp->rp; @@ -414,37 +417,22 @@ icmpadvise(Proto *icmp, Block *bp, char *msg) int icmpstats(Proto *icmp, char *buf, int len) { - Icmppriv *ipriv; - - ipriv = icmp->priv; - - return snprint(buf,len,"%lud %lud %lud %lud %lud %lud %lud %lud %lud %lud %lud %lud %lud %lud %lud %lud %lud %lud %lud %lud %lud %lud %lud %lud %lud %lud", - ipriv->istats.icmpInMsgs, - ipriv->istats.icmpInErrors, - ipriv->in[Unreachable], - ipriv->in[TimeExceed], - ipriv->in[InParmProblem], - ipriv->in[SrcQuench], - ipriv->in[Redirect], - ipriv->in[EchoRequest], - ipriv->in[EchoReply], - ipriv->in[Timestamp], - ipriv->in[TimestampReply], - ipriv->in[AddrMaskRequest], - ipriv->in[AddrMaskReply], - ipriv->istats.icmpOutMsgs, - ipriv->istats.icmpOutErrors, - ipriv->out[Unreachable], - ipriv->out[TimeExceed], - ipriv->out[InParmProblem], - ipriv->out[SrcQuench], - ipriv->out[Redirect], - ipriv->out[EchoRequest], - ipriv->out[EchoReply], - ipriv->out[Timestamp], - ipriv->out[TimestampReply], - ipriv->out[AddrMaskRequest], - ipriv->out[AddrMaskReply]); + Icmppriv *priv; + char *p, *e; + int i; + + priv = icmp->priv; + p = buf; + e = p+len; + for(i = 0; i < Nstats; i++) + p = seprint(p, e, "%s: %lud\n", statnames[i], priv->stats[i]); + for(i = 0; i <= Maxtype; i++){ + if(icmpnames[i]) + p = seprint(p, e, "%s: %lud %lud\n", icmpnames[i], priv->in[i], priv->out[i]); + else + p = seprint(p, e, "%d: %lud %lud\n", i, priv->in[i], priv->out[i]); + } + return p - buf; } void diff --git a/ip/il.c b/ip/il.c index 33ec6df9a770f9fe1550bafddccc2a1c328808d7..e76545426a71e83b153b2548a5f6951dac391df4 100644 --- a/ip/il.c +++ b/ip/il.c @@ -149,12 +149,39 @@ struct Ilhdr uchar ilack[4]; /* Acked sequence */ }; +enum +{ + InMsgs, + OutMsgs, + CsumErrs, /* checksum errors */ + HlenErrs, /* header length error */ + LenErrs, /* short packet */ + OutOfOrder, /* out of order */ + Retrans, /* retransmissions */ + DupMsg, + DupBytes, + + Nstats, +}; + +static char *statnames[] = +{ +[InMsgs] "InMsgs", +[OutMsgs] "OutMsgs", +[CsumErrs] "CsumErrs", +[HlenErrs] "HlenErr", +[LenErrs] "LenErrs", +[OutOfOrder] "OutOfOrder", +[Retrans] "Retrans", +[DupMsg] "DupMsg", +[DupBytes] "DupBytes", +}; typedef struct Ilpriv Ilpriv; struct Ilpriv { + ulong stats[Nstats]; - /* non-MIB stats */ ulong csumerr; /* checksum errors */ ulong hlenerr; /* header length error */ ulong lenerr; /* short packet */ @@ -289,10 +316,13 @@ ilkick(Conv *c, int l) ulong id, ack; Block *bp; Fs *f; + Ilpriv *priv; + USED(l); f = c->p->f; + priv = c->p->priv; ic = (Ilcb*)c->ptcl; bp = qget(c->wq); @@ -355,6 +385,7 @@ ilkick(Conv *c, int l) if(later(msec, ic->timeout, nil)) ilsettimeout(ic); ipoput(f, bp, 0, c->ttl, c->tos); + priv->stats[OutMsgs]++; } static void @@ -367,17 +398,16 @@ ilcreate(Conv *c) int ilxstats(Proto *il, char *buf, int len) { - int n; - Ilpriv *ipriv; - - ipriv = il->priv; + Ilpriv *priv; + char *p, *e; + int i; - n = snprint(buf, len, - "il: csum %lud hlen %lud len %lud order %lud rexmit %lud", - ipriv->csumerr, ipriv->hlenerr, ipriv->lenerr, ipriv->order, ipriv->rexmit); - n += snprint(buf+n, len-n, " dupp %lud dupb %lud\n", - ipriv->dup, ipriv->dupb); - return n; + priv = il->priv; + p = buf; + e = p+len; + for(i = 0; i < Nstats; i++) + p = seprint(p, e, "%s: %lud\n", statnames[i], priv->stats[i]); + return p - buf; } void @@ -492,14 +522,14 @@ iliput(Proto *il, uchar*, Block *bp) plen = blocklen(bp); if(plen < IL_IPSIZE+IL_HDRSIZE){ netlog(il->f, Logil, "il: hlenerr\n"); - ipriv->hlenerr++; + ipriv->stats[HlenErrs]++; goto raise; } illen = nhgets(ih->illen); if(illen+IL_IPSIZE > plen){ netlog(il->f, Logil, "il: lenerr\n"); - ipriv->lenerr++; + ipriv->stats[LenErrs]++; goto raise; } @@ -512,7 +542,7 @@ iliput(Proto *il, uchar*, Block *bp) st = "?"; else st = iltype[ih->iltype]; - ipriv->csumerr++; + ipriv->stats[CsumErrs]++; netlog(il->f, Logil, "il: cksum %ux %ux, pkt(%s id %lud ack %lud %I/%d->%d)\n", csum, st, nhgetl(ih->ilid), nhgetl(ih->ilack), raddr, sp, dp); goto raise; @@ -616,6 +646,7 @@ _ilprocess(Conv *s, Ilhdr *h, Block *bp) { Ilcb *ic; ulong id, ack; + Ilpriv *priv; id = nhgetl(h->ilid); ack = nhgetl(h->ilack); @@ -624,6 +655,8 @@ _ilprocess(Conv *s, Ilhdr *h, Block *bp) ic->lastrecv = msec; ic->querytime = msec + QueryTime; + priv = s->p->priv; + priv->stats[InMsgs]++; switch(ic->state) { default: @@ -865,7 +898,7 @@ ilpullup(Conv *s) } if(oid != ic->recvd+1){ ipriv = s->p->priv; - ipriv->order++; + ipriv->stats[OutOfOrder]++; break; } @@ -923,8 +956,8 @@ iloutoforder(Conv *s, Ilhdr *h, Block *bp) newid = nhgetl(lid); if(id <= newid) { if(id == newid) { - ipriv->dup++; - ipriv->dupb += blocklen(bp); + ipriv->stats[DupMsg]++; + ipriv->stats[DupBytes] += blocklen(bp); qunlock(&ic->outo); freeblist(bp); return; diff --git a/ip/ip.c b/ip/ip.c index 08cc122b543d5a676c62107be95b13bee219b940..097c8b04576107f1518314fe7f2a55e72afb1ebe 100644 --- a/ip/ip.c +++ b/ip/ip.c @@ -52,34 +52,58 @@ struct Ipfrag }; /* MIB II counters */ -typedef struct Ipstats Ipstats; -struct Ipstats +enum { - ulong ipForwarding; - ulong ipDefaultTTL; - ulong ipInReceives; - ulong ipInHdrErrors; - ulong ipInAddrErrors; - ulong ipForwDatagrams; - ulong ipInUnknownProtos; - ulong ipInDiscards; - ulong ipInDelivers; - ulong ipOutRequests; - ulong ipOutDiscards; - ulong ipOutNoRoutes; - ulong ipReasmTimeout; - ulong ipReasmReqds; - ulong ipReasmOKs; - ulong ipReasmFails; - ulong ipFragOKs; - ulong ipFragFails; - ulong ipFragCreates; + Forwarding, + DefaultTTL, + InReceives, + InHdrErrors, + InAddrErrors, + ForwDatagrams, + InUnknownProtos, + InDiscards, + InDelivers, + OutRequests, + OutDiscards, + OutNoRoutes, + ReasmTimeout, + ReasmReqds, + ReasmOKs, + ReasmFails, + FragOKs, + FragFails, + FragCreates, + + Nstats, +}; + +static char *statnames[] = +{ +[Forwarding] "Forwarding", +[DefaultTTL] "DefaultTTL", +[InReceives] "InReceives", +[InHdrErrors] "InHdrErrors", +[InAddrErrors] "InAddrErrors", +[ForwDatagrams] "ForwDatagrams", +[InUnknownProtos] "InUnknownProtos", +[InDiscards] "InDiscards", +[InDelivers] "InDelivers", +[OutRequests] "OutRequests", +[OutDiscards] "OutDiscards", +[OutNoRoutes] "OutNoRoutes", +[ReasmTimeout] "ReasmTimeout", +[ReasmReqds] "ReasmReqds", +[ReasmOKs] "ReasmOKs", +[ReasmFails] "ReasmFails", +[FragOKs] "FragOKs", +[FragFails] "FragFails", +[FragCreates] "FragCreates", }; /* an instance of IP */ struct IP { - Ipstats istats; + ulong stats[Nstats]; QLock fraglock; Fragment* flisthead; @@ -116,9 +140,9 @@ iprouting(Fs *f, int on) { f->ip->iprouting = on; if(f->ip->iprouting==0) - f->ip->istats.ipForwarding = 2; + f->ip->stats[Forwarding] = 2; else - f->ip->istats.ipForwarding = 1; + f->ip->stats[Forwarding] = 1; } void @@ -138,7 +162,7 @@ ipoput(Fs *f, Block *bp, int gating, int ttl, int tos) /* Fill out the ip header */ eh = (Iphdr*)(bp->rp); - ip->istats.ipOutRequests++; + ip->stats[OutRequests]++; /* Number of uchars in data and ip header to write */ len = blocklen(bp); @@ -146,7 +170,7 @@ ipoput(Fs *f, Block *bp, int gating, int ttl, int tos) if(gating){ chunk = nhgets(eh->length); if(chunk > len){ - ip->istats.ipOutDiscards++; + ip->stats[OutDiscards]++; netlog(f, Logip, "short gated packet\n"); goto free; } @@ -154,14 +178,14 @@ ipoput(Fs *f, Block *bp, int gating, int ttl, int tos) len = chunk; } if(len >= IP_MAX){ - ip->istats.ipOutDiscards++; + ip->stats[OutDiscards]++; netlog(f, Logip, "exceeded ip max size %V\n", eh->dst); goto free; } r = v4lookup(f, eh->dst); if(r == nil){ - ip->istats.ipOutNoRoutes++; + ip->stats[OutNoRoutes]++; netlog(f, Logip, "no interface %V\n", eh->dst); goto free; } @@ -213,16 +237,16 @@ ipoput(Fs *f, Block *bp, int gating, int ttl, int tos) } if(eh->frag[0] & (IP_DF>>8)){ - ip->istats.ipFragFails++; - ip->istats.ipOutDiscards++; + ip->stats[FragFails]++; + ip->stats[OutDiscards]++; netlog(f, Logip, "%V: eh->frag[0] & (IP_DF>>8)\n", eh->dst); goto raise; } seglen = (medialen - IPHDR) & ~7; if(seglen < 8){ - ip->istats.ipFragFails++; - ip->istats.ipOutDiscards++; + ip->stats[FragFails]++; + ip->stats[OutDiscards]++; netlog(f, Logip, "%V seglen < 8\n", eh->dst); goto raise; } @@ -262,8 +286,8 @@ ipoput(Fs *f, Block *bp, int gating, int ttl, int tos) chunk = seglen; while(chunk) { if(!xp) { - ip->istats.ipOutDiscards++; - ip->istats.ipFragFails++; + ip->stats[OutDiscards]++; + ip->stats[FragFails]++; freeblist(nb); netlog(f, Logip, "!xp: chunk %d\n", chunk); goto raise; @@ -283,9 +307,9 @@ ipoput(Fs *f, Block *bp, int gating, int ttl, int tos) feh->cksum[1] = 0; hnputs(feh->cksum, ipcsum(&feh->vihl)); ifc->m->bwrite(ifc, nb, V4, gate); - ip->istats.ipFragCreates++; + ip->stats[FragCreates]++; } - ip->istats.ipFragOKs++; + ip->stats[FragOKs]++; raise: runlock(ifc); poperror(); @@ -324,7 +348,7 @@ ipiput(Fs *f, uchar *ia, Block *bp) Route *r, *sr; ip = f->ip; - ip->istats.ipInReceives++; + ip->stats[InReceives]++; // h = (Iphdr *)(bp->rp); // DBG(nhgetl(h->src))(Logipmsg, "ipiput %V %V len %d proto %d\n", @@ -349,7 +373,7 @@ ipiput(Fs *f, uchar *ia, Block *bp) /* dump anything that whose header doesn't checksum */ if(ipcsum(&h->vihl)) { - ip->istats.ipInHdrErrors++; + ip->stats[InHdrErrors]++; netlog(f, Logip, "ip: checksum error %V\n", h->src); freeblist(bp); return; @@ -362,7 +386,7 @@ ipiput(Fs *f, uchar *ia, Block *bp) if(h->vihl != (IP_VER|IP_HLEN)) { hl = (h->vihl&0xF)<<2; if((h->vihl&0xF0) != IP_VER || hl < (IP_HLEN<<2)) { - ip->istats.ipInHdrErrors++; + ip->stats[InHdrErrors]++; netlog(f, Logip, "ip: %V bad hivl %ux\n", h->src, h->vihl); freeblist(bp); return; @@ -388,20 +412,20 @@ ipiput(Fs *f, uchar *ia, Block *bp) sr = v4lookup(f, h->src); r = v4lookup(f, h->dst); if(r == nil || sr == r){ - ip->istats.ipOutDiscards++; + ip->stats[OutDiscards]++; freeblist(bp); return; } /* don't forward if packet has timed out */ if(h->ttl <= 1){ - ip->istats.ipInHdrErrors++; + ip->stats[InHdrErrors]++; icmpttlexceeded(f, ia, bp); freeblist(bp); return; } - ip->istats.ipForwDatagrams++; + ip->stats[ForwDatagrams]++; ipoput(f, bp, 1, h->ttl - 1, h->tos); return; @@ -422,12 +446,12 @@ ipiput(Fs *f, uchar *ia, Block *bp) p = Fsrcvpcol(f, h->proto); if(p != nil && p->rcv != nil) { - ip->istats.ipInDelivers++; + ip->stats[InDelivers]++; (*p->rcv)(p, ia, bp); return; } - ip->istats.ipInDiscards++; - ip->istats.ipInUnknownProtos++; + ip->stats[InDiscards]++; + ip->stats[InUnknownProtos]++; freeblist(bp); } @@ -435,21 +459,17 @@ int ipstats(Fs *f, char *buf, int len) { IP *ip; + char *p, *e; + int i; ip = f->ip; - ip->istats.ipDefaultTTL = MAXTTL; - return snprint(buf, len, "%lud %lud %lud %lud %lud %lud %lud %lud %lud %lud " - "%lud %lud %lud %lud %lud %lud %lud %lud %lud", - ip->istats.ipForwarding, ip->istats.ipDefaultTTL, - ip->istats.ipInReceives, ip->istats.ipInHdrErrors, - ip->istats.ipInAddrErrors, ip->istats.ipForwDatagrams, - ip->istats.ipInUnknownProtos, ip->istats.ipInDiscards, - ip->istats.ipInDelivers, ip->istats.ipOutRequests, - ip->istats.ipOutDiscards, ip->istats.ipOutNoRoutes, - ip->istats.ipReasmTimeout, ip->istats.ipReasmReqds, - ip->istats.ipReasmOKs, ip->istats.ipReasmFails, - ip->istats.ipFragOKs, ip->istats.ipFragFails, - ip->istats.ipFragCreates); + ip->stats[DefaultTTL] = MAXTTL; + + p = buf; + e = p+len; + for(i = 0; i < Nstats; i++) + p = seprint(p, e, "%s: %lud\n", statnames[i], ip->stats[i]); + return p - buf; } Block* @@ -484,7 +504,7 @@ ipreassemble(IP *ip, int offset, Block *bp, Iphdr *ih) if(f->src == src && f->dst == dst && f->id == id) break; if(f->age < msec){ - ip->istats.ipReasmTimeout++; + ip->stats[ReasmTimeout]++; ipfragfree(ip, f); } } @@ -497,7 +517,7 @@ ipreassemble(IP *ip, int offset, Block *bp, Iphdr *ih) if(!ih->tos && (offset & ~(IP_MF|IP_DF)) == 0) { if(f != nil) { ipfragfree(ip, f); - ip->istats.ipReasmFails++; + ip->stats[ReasmFails]++; } qunlock(&ip->fraglock); return bp; @@ -521,7 +541,7 @@ ipreassemble(IP *ip, int offset, Block *bp, Iphdr *ih) f->blist = bp; qunlock(&ip->fraglock); - ip->istats.ipReasmReqds++; + ip->stats[ReasmReqds]++; return nil; } @@ -607,7 +627,7 @@ ipreassemble(IP *ip, int offset, Block *bp, Iphdr *ih) ih = BLKIP(bl); hnputs(ih->length, len); qunlock(&ip->fraglock); - ip->istats.ipReasmOKs++; + ip->stats[ReasmOKs]++; return bl; } pktposn += BKFG(bl)->flen; diff --git a/ip/netdevmedium.c b/ip/netdevmedium.c index e54c9c4b4e25aae208a7e02547cd1bfd6c63d711..e80007f4c08cb20cde04bf189b8c4f6d7c91566f 100644 --- a/ip/netdevmedium.c +++ b/ip/netdevmedium.c @@ -24,10 +24,10 @@ struct Netdevrock Medium netdevmedium = { .name= "netdev", -.hsize= 14, //ZZZ what should these be? -.minmtu= 60, -.maxmtu= 1514, -.maclen= 6, +.hsize= 0, +.minmtu= 0, +.maxmtu= 64000, +.maclen= 0, .bind= netdevbind, .unbind= netdevunbind, .bwrite= netdevbwrite, diff --git a/ip/tcp.c b/ip/tcp.c index 33051c536dc30355b346690c3a7789a5a34f9c40..62c2f4bcdb96dac806d8db5ea7f32d917151d6e0 100644 --- a/ip/tcp.c +++ b/ip/tcp.c @@ -196,25 +196,46 @@ struct Tcpctl int tcp_irtt = DEF_RTT; /* Initial guess at round trip time */ ushort tcp_mss = DEF_MSS; /* Maximum segment size to be sent */ -/* MIB II counters */ -typedef struct Tcpstats Tcpstats; -struct Tcpstats +enum { + /* MIB stats */ + MaxConn, + ActiveOpens, + PassiveOpens, + EstabResets, + CurrEstab, + InSegs, + OutSegs, + RetransSegs, + RetransTimeouts, + InErrs, + OutRsts, + + /* non-MIB stats */ + CsumErrs, + HlenErrs, + LenErrs, + OutOfOrder, + + Nstats +}; + +static char *statnames[] = { - ulong tcpRtoAlgorithm; - ulong tcpRtoMin; - ulong tcpRtoMax; - ulong tcpMaxConn; - ulong tcpActiveOpens; - ulong tcpPassiveOpens; - ulong tcpAttemptFails; - ulong tcpEstabResets; - ulong tcpCurrEstab; - ulong tcpInSegs; - ulong tcpOutSegs; - ulong tcpRetransSegs; - ulong tcpRetransTimeouts; - ulong InErrs; - ulong OutRsts; +[MaxConn] "MaxConn", +[ActiveOpens] "ActiveOpens", +[PassiveOpens] "PassiveOpens", +[EstabResets] "EstabResets", +[CurrEstab] "CurrEstab", +[InSegs] "InSegs", +[OutSegs] "OutSegs", +[RetransSegs] "RetransSegs", +[RetransTimeouts] "RetransTimeouts", +[InErrs] "InErrs", +[OutRsts] "OutRsts", +[CsumErrs] "CsumErrs", +[HlenErrs] "HlenErrs", +[LenErrs] "LenErrs", +[OutOfOrder] "OutOfOrder", }; typedef struct Tcppriv Tcppriv; @@ -224,14 +245,7 @@ struct Tcppriv QLock tl; /* Protect timer list */ Rendez tcpr; /* used by tcpackproc */ - /* MIB stats */ - Tcpstats tstats; - - /* non-MIB stats */ - ulong csumerr; /* checksum errors */ - ulong hlenerr; /* header length error */ - ulong lenerr; /* short packet */ - ulong order; /* out of order */ + ulong stats[Nstats]; /* for keeping track of tcpackproc */ int ackprocstarted; @@ -270,9 +284,9 @@ tcpsetstate(Conv *s, uchar newstate) return; if(oldstate == Established) - tpriv->tstats.tcpCurrEstab--; + tpriv->stats[CurrEstab]--; if(newstate == Established) - tpriv->tstats.tcpCurrEstab++; + tpriv->stats[CurrEstab]++; /** print( "%d/%d %s->%s CurrEstab=%d\n", s->lport, s->rport, @@ -691,13 +705,13 @@ tcpstart(Conv *s, int mode, ushort window) switch(mode) { case TCP_LISTEN: - tpriv->tstats.tcpPassiveOpens++; + tpriv->stats[PassiveOpens]++; tcb->flags |= CLONE; tcpsetstate(s, Listen); break; case TCP_CONNECT: - tpriv->tstats.tcpActiveOpens++; + tpriv->stats[ActiveOpens]++; /* Send SYN, go into SYN_SENT state */ qlock(s); if(waserror()){ @@ -895,7 +909,7 @@ sndrst(Proto *tcp, uchar *source, uchar *dest, ushort length, Tcp *seg) hnputs(ph.tcpsport, seg->dest); hnputs(ph.tcpdport, seg->source); - tpriv->tstats.OutRsts++; + tpriv->stats[OutRsts]++; rflags = RST; /* convince the other end that this reset is in band */ @@ -1207,7 +1221,7 @@ tcpiput(Proto *tcp, uchar*, Block *bp) f = tcp->f; tpriv = tcp->priv; - tpriv->tstats.tcpInSegs++; + tpriv->stats[InSegs]++; h = (Tcphdr*)(bp->rp); @@ -1218,7 +1232,8 @@ tcpiput(Proto *tcp, uchar*, Block *bp) h->Unused = 0; hnputs(h->tcplen, length-TCP_PKT); if(ptclcsum(bp, TCP_IPLEN, length-TCP_IPLEN)) { - tpriv->csumerr++; + tpriv->stats[CsumErrs]++; + tpriv->stats[InErrs]++; netlog(f, Logtcp, "bad tcp proto cksum\n"); freeblist(bp); return; @@ -1226,7 +1241,8 @@ tcpiput(Proto *tcp, uchar*, Block *bp) hdrlen = ntohtcp(&seg, &bp); if(hdrlen < 0){ - tpriv->hlenerr++; + tpriv->stats[HlenErrs]++; + tpriv->stats[InErrs]++; netlog(f, Logtcp, "bad tcp hdr len\n"); return; } @@ -1235,7 +1251,8 @@ tcpiput(Proto *tcp, uchar*, Block *bp) length -= hdrlen+TCP_PKT; bp = trimblock(bp, hdrlen+TCP_PKT, length); if(bp == nil){ - tpriv->lenerr++; + tpriv->stats[LenErrs]++; + tpriv->stats[InErrs]++; netlog(f, Logtcp, "tcp len < 0 after trim\n"); return; } @@ -1424,7 +1441,7 @@ tcpiput(Proto *tcp, uchar*, Block *bp) if(seg.seq != tcb->rcv.nxt) if(length != 0 || (seg.flags & (SYN|FIN))) { update(s, &seg); - tpriv->order++; + tpriv->stats[OutOfOrder]++; if(addreseq(tcb, &seg, bp, length) < 0) print("reseq %I.%d -> %I.%d\n", s->raddr, s->rport, s->laddr, s->lport); tcb->flags |= FORCE; @@ -1438,7 +1455,7 @@ tcpiput(Proto *tcp, uchar*, Block *bp) for(;;) { if(seg.flags & RST) { if(tcb->state == Established) - tpriv->tstats.tcpEstabResets++; + tpriv->stats[EstabResets]++; localclose(s, Econrefused); goto raise; } @@ -1771,7 +1788,7 @@ tcpoutput(Conv *s) if(ssize < n) n = ssize; tcb->resent += n; - tpriv->tstats.tcpRetransSegs++; + tpriv->stats[RetransSegs]++; } tcb->snd.ptr += ssize; @@ -1820,7 +1837,7 @@ tcpoutput(Conv *s) } } - tpriv->tstats.tcpOutSegs++; + tpriv->stats[OutSegs]++; if(tcb->kacounter > 0) tcpgo(tpriv, &tcb->katimer); ipoput(f, hbp, 0, s->ttl, s->tos); @@ -1982,7 +1999,7 @@ tcptimeout(void *arg) break; } tcprxmit(s); - tpriv->tstats.tcpRetransTimeouts++; + tpriv->stats[RetransTimeouts]++; tcb->snd.dupacks = 0; break; case Time_wait: @@ -2219,28 +2236,16 @@ tcpctl(Conv* c, char** f, int n) int tcpstats(Proto *tcp, char *buf, int len) { - Tcppriv *tpriv; - - tpriv = tcp->priv; - - + Tcppriv *priv; + char *p, *e; + int i; - return snprint(buf, len, "%lud %lud %lud %lud %lud %lud %lud %lud %lud %lud %lud %lud %lud %lud %lud", - tpriv->tstats.tcpRtoAlgorithm, - tpriv->tstats.tcpRtoMin, - tpriv->tstats.tcpRtoMax, - tpriv->tstats.tcpMaxConn, - tpriv->tstats.tcpActiveOpens, - tpriv->tstats.tcpPassiveOpens, - tpriv->tstats.tcpAttemptFails, - tpriv->tstats.tcpEstabResets, - tpriv->tstats.tcpCurrEstab, - tpriv->tstats.tcpInSegs, - tpriv->tstats.tcpOutSegs, - tpriv->tstats.tcpRetransSegs, - tpriv->tstats.tcpRetransTimeouts, - tpriv->tstats.InErrs, - tpriv->tstats.OutRsts); + priv = tcp->priv; + p = buf; + e = p+len; + for(i = 0; i < Nstats; i++) + p = seprint(p, e, "%s: %lud\n", statnames[i], priv->stats[i]); + return p - buf; } /* @@ -2312,7 +2317,7 @@ tcpinit(Fs *fs) tcp->ipproto = IP_TCPPROTO; tcp->nc = Nchans; tcp->ptclsize = sizeof(Tcpctl); - tpriv->tstats.tcpMaxConn = Nchans; + tpriv->stats[MaxConn] = Nchans; Fsproto(fs, tcp); } diff --git a/ip/udp.c b/ip/udp.c index 4b6a22b2b10bec13ea3cc651a650b7e23835fc31..209f4fbaaf0621da4f1885523bd87bf8f80960fd 100644 --- a/ip/udp.c +++ b/ip/udp.c @@ -45,25 +45,35 @@ struct Udphdr uchar udpcksum[2]; /* Checksum */ }; -/* MIB II counters */ -typedef struct Udpstats Udpstats; -struct Udpstats +enum { - ulong udpInDatagrams; - ulong udpNoPorts; - ulong udpInErrors; - ulong udpOutDatagrams; + /* MIB II counters */ + InDatagrams, + NoPorts, + InErrors, + OutDatagrams, + + /* non-MIB counters */ + CsumErrs, + LenErrs, + + Nstats, +}; + +static char *statnames[] = { +[InDatagrams] "InDatagrams", +[NoPorts] "NoPorts", +[InErrors] "InErrors", +[OutDatagrams] "OutDatagrams", +[CsumErrs] "CsumErrs", +[LenErrs] "LenErrs", }; + typedef struct Udppriv Udppriv; struct Udppriv { - /* MIB counters */ - Udpstats ustats; - - /* non-MIB stats */ - ulong csumerr; /* checksum errors */ - ulong lenerr; /* short packet */ + ulong stats[Nstats]; }; /* @@ -226,7 +236,7 @@ udpkick(Conv *c, int) hnputs(uh->udpcksum, ptclcsum(bp, UDP_IPHDR, dlen+UDP_HDRSIZE)); - upriv->ustats.udpOutDatagrams++; + upriv->stats[OutDatagrams]++; ipoput(f, bp, 0, c->ttl, c->tos); } @@ -245,7 +255,7 @@ udpiput(Proto *udp, uchar *ia, Block *bp) upriv = udp->priv; f = udp->f; - upriv->ustats.udpInDatagrams++; + upriv->stats[InDatagrams]++; uh = (Udphdr*)(bp->rp); @@ -263,7 +273,8 @@ udpiput(Proto *udp, uchar *ia, Block *bp) if(nhgets(uh->udpcksum)) { if(ptclcsum(bp, UDP_IPHDR, len+UDP_PHDRSIZE)) { - upriv->ustats.udpInErrors++; + upriv->stats[InErrors]++; + upriv->stats[CsumErrs]++; netlog(f, Logudp, "udp: checksum error %I\n", raddr); DPRINT("udp: checksum error %I\n", raddr); freeblist(bp); @@ -319,7 +330,7 @@ found: } c->state = Connected; } else { - upriv->ustats.udpNoPorts++; + upriv->stats[NoPorts]++; qunlock(udp); netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport, laddr, lport); @@ -344,7 +355,8 @@ found: qunlock(c); netlog(f, Logudp, "udp: len err %I.%d -> %I.%d\n", raddr, rport, laddr, lport); - upriv->lenerr++; + upriv->stats[LenErrs]++; + upriv->stats[InErrors]++; return; } @@ -469,14 +481,16 @@ udpadvise(Proto *udp, Block *bp, char *msg) int udpstats(Proto *udp, char *buf, int len) { - Udppriv *upriv; - - upriv = udp->priv; - return snprint(buf, len, "%lud %lud %lud %lud", - upriv->ustats.udpInDatagrams, - upriv->ustats.udpNoPorts, - upriv->ustats.udpInErrors, - upriv->ustats.udpOutDatagrams); + Udppriv *priv; + char *p, *e; + int i; + + priv = udp->priv; + p = buf; + e = p+len; + for(i = 0; i < Nstats; i++) + p = seprint(p, e, "%s: %lud\n", statnames[i], priv->stats[i]); + return p - buf; } void diff --git a/pc/i8253.c b/pc/i8253.c index 9b6d479782fc1dd21d8d00f67d8743e8dfa342a3..63d94b95b93619ed9ad556820a44acc271dae6c2 100644 --- a/pc/i8253.c +++ b/pc/i8253.c @@ -47,6 +47,8 @@ enum Freq= 1193182, /* Real clock frequency */ + Minusec=20, /* minimum cycles for a clock interrupt */ + FreqMul=16, /* extra accuracy in fastticks/Freq calculation; ok up to ~8ghz */ }; @@ -187,8 +189,8 @@ clockintrsched0(vlong next) i8253.mode = Trigger; set--; } - if(set < 3) - set = 5; + if(set < Minusec) + set = Minusec; outb(T0cntr, set); /* low byte */ outb(T0cntr, set>>8); /* high byte */ }else if(i8253.mode != Square){ diff --git a/port/devcons.c b/port/devcons.c index a2dc10be607d888fdab2ebcba5dac43afb4df2f5..3bcfc28627106020fc2e6daf74d447cb4960848d 100644 --- a/port/devcons.c +++ b/port/devcons.c @@ -139,6 +139,18 @@ sprint(char *s, char *fmt, ...) return n; } +char* +seprint(char *buf, char *e, char *fmt, ...) +{ + char *out; + va_list arg; + + va_start(arg, fmt); + out = doprint(buf, e, fmt, arg); + va_end(arg); + return out; +} + int noprint; int diff --git a/port/devsd.c b/port/devsd.c index 33c8cf4e58543fad042892c8fe6567d62b222b5f..66e3b544206cee309bf2102d8761a1f7b49da7d4 100644 --- a/port/devsd.c +++ b/port/devsd.c @@ -211,6 +211,8 @@ sdgetunit(SDev* sdev, int subno) sdev->enabled = 1; snprint(unit->name, NAMELEN, "%s%d", sdev->name, subno); + strncpy(unit->user, eve, NAMELEN); + unit->perm = 0555; unit->subno = subno; unit->dev = sdev; @@ -314,17 +316,28 @@ sd2gen(Chan* c, int i, Dir* dp) Qid q; vlong l; SDpart *pp; + SDperm *perm; SDunit *unit; unit = sdunit[UNIT(c->qid)]; switch(i){ case Qctl: q = (Qid){QID(UNIT(c->qid), PART(c->qid), Qctl), unit->vers}; - devdir(c, q, "ctl", 0, eve, 0640, dp); + perm = &unit->ctlperm; + if(perm->user[0] == '\0'){ + strncpy(perm->user, eve, NAMELEN); + perm->perm = 0640; + } + devdir(c, q, "ctl", 0, perm->user, perm->perm, dp); return 1; case Qraw: q = (Qid){QID(UNIT(c->qid), PART(c->qid), Qraw), unit->vers}; - devdir(c, q, "raw", 0, eve, CHEXCL|0600, dp); + perm = &unit->rawperm; + if(perm->user[0] == '\0'){ + strncpy(perm->user, eve, NAMELEN); + perm->perm = CHEXCL|0600; + } + devdir(c, q, "raw", 0, perm->user, perm->perm, dp); return 1; case Qpart: pp = &unit->part[PART(c->qid)]; @@ -367,10 +380,14 @@ sdgen(Chan* c, Dirtab*, int, int s, Dir* dp) return 1; } if(s < sdnunit){ - if(sdunit[s] == nil && sdindex2unit(s) == nil) - return 0; + if((unit = sdunit[s]) == nil){ + if((unit = sdindex2unit(s)) == nil) + return 0; + } q = (Qid){QID(s, 0, Qunitdir)|CHDIR, 0}; - devdir(c, q, sdunit[s]->name, 0, eve, 0555, dp); + if(unit->user[0] == '\0') + strncpy(unit->user, eve, NAMELEN); + devdir(c, q, unit->name, 0, unit->user, unit->perm, dp); return 1; } s -= sdnunit; @@ -388,10 +405,12 @@ sdgen(Chan* c, Dirtab*, int, int s, Dir* dp) /* * Check for media change. * If one has already been detected, sectors will be zero. - * If there is one waiting to be detected, online will return > 1. + * If there is one waiting to be detected, online + * will return > 1. * Online is a bit of a large hammer but does the job. */ - if(unit->sectors == 0 || (unit->dev->ifc->online && unit->dev->ifc->online(unit) > 1)) + if(unit->sectors == 0 + || (unit->dev->ifc->online && unit->dev->ifc->online(unit) > 1)) sdinitpart(unit); i = s+Qunitbase; @@ -858,9 +877,10 @@ sdwstat(Chan* c, char* dp) { Dir d; SDpart *pp; + SDperm *perm; SDunit *unit; - if((c->qid.path & CHDIR) || TYPE(c->qid) != Qpart) + if(c->qid.path & CHDIR) error(Eperm); unit = sdunit[UNIT(c->qid)]; @@ -870,15 +890,28 @@ sdwstat(Chan* c, char* dp) nexterror(); } - pp = &unit->part[PART(c->qid)]; - if(unit->vers+pp->vers != c->qid.vers) - error(Enonexist); - if(strncmp(up->user, pp->user, NAMELEN) && !iseve()) + switch(TYPE(c->qid)){ + default: error(Eperm); + case Qctl: + perm = &unit->ctlperm; + break; + case Qraw: + perm = &unit->rawperm; + break; + case Qpart: + pp = &unit->part[PART(c->qid)]; + if(unit->vers+pp->vers != c->qid.vers) + error(Enonexist); + perm = &pp->SDperm; + break; + } + if(strncmp(up->user, perm->user, NAMELEN) && !iseve()) + error(Eperm); convM2D(dp, &d); - strncpy(pp->user, d.uid, NAMELEN); - pp->perm = d.mode&0777; + strncpy(perm->user, d.uid, NAMELEN); + perm->perm = (perm->perm & ~0777) | (d.mode & 0777); qunlock(&unit->ctl); poperror(); diff --git a/port/lib.h b/port/lib.h index c28f0ee2f3915344adce22a2f1ecad6decf3d529..a5ac58e6c3450e958e62c5931c3724cfccf9a6e1 100644 --- a/port/lib.h +++ b/port/lib.h @@ -62,6 +62,7 @@ extern int numbconv(va_list*, Fconv*); extern char *doprint(char*, char*, char*, va_list); extern int fmtinstall(int, int (*)(va_list*, Fconv*)); extern int sprint(char*, char*, ...); +extern char* seprint(char*, char*, char*, ...); extern int snprint(char*, int, char*, ...); extern int print(char*, ...); diff --git a/port/sd.h b/port/sd.h index 9093a20cbfcf3d7ec945ebedfa14bd3ad6f310f1..e0eb1675b358b3204ef6c860031d560b9ef1c96c 100644 --- a/port/sd.h +++ b/port/sd.h @@ -4,15 +4,20 @@ typedef struct SDev SDev; typedef struct SDifc SDifc; typedef struct SDpart SDpart; +typedef struct SDperm SDperm; typedef struct SDreq SDreq; typedef struct SDunit SDunit; -typedef struct SDpart { - ulong start; - ulong end; +typedef struct SDperm { char name[NAMELEN]; char user[NAMELEN]; ulong perm; +} SDperm; + +typedef struct SDpart { + ulong start; + ulong end; + SDperm; int valid; ulong vers; } SDpart; @@ -21,18 +26,20 @@ typedef struct SDunit { SDev* dev; int subno; uchar inquiry[256]; /* format follows SCSI spec */ - char name[NAMELEN]; + SDperm; Rendez rendez; QLock ctl; ulong sectors; ulong secsize; - SDpart* part; /* either nil or points at array of size SDnpart */ + SDpart* part; /* nil or array of size SDnpart */ ulong vers; + SDperm ctlperm; Lock rawinuse; /* really just a test-and-set */ int state; SDreq* req; + SDperm rawperm; } SDunit; typedef struct SDev {