📄 sdata.c
字号:
/* * (S)ATA(PI)/(E)IDE disk driver for file server. * derived from /sys/src/boot/pc/sdata.c and /sys/src/9/pc/sdata.c * * we can't write message into a ctl file on the file server, so * enable dma and rwm as advertised by the drive & controller. * if that doesn't work, fix the hardware or turn it off in the source * (set conf.idedma = 0). * * entry points:../fs64/9fsfs64.c:38: { "hd", ataread, ataseek, atawrite, setatapart, },../fs64/9fsfs64.c:58: nhd = atainit();../port/sub.c:1065: return ideread(d, b, c);../port/sub.c:1129: return idewrite(d, b, c);../port/sub.c:1182: return idesize(d);../port/sub.c:1362: ideinit(d); */#include "all.h"#include "io.h"#include "mem.h"#include "sd.h"#include "compat.h"#undef error#define HOWMANY(x, y) (((x)+((y)-1))/(y))#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y))enum { IDEBUG = 0, /* old stuff carried forward */ NCtlr= 8, NCtlrdrv= 2, /* fixed by hardware */ NDrive= NCtlr*NCtlrdrv, Maxxfer= 16*1024, /* maximum transfer size/cmd */ Read = 0, Write, /* I/O ports */ Ctlr0cmd = 0x1f0, Ctlr0ctl = 0x3f4, Ctlr1cmd = 0x170, Ctlr1ctl = 0x374, Ctl2cmd = Ctlr0ctl - Ctlr0cmd,};#define IDPRINT if(IDEBUG)printextern SDifc sdataifc;enum { DbgCONFIG = 0x0001, /* detected drive config info */ DbgIDENTIFY = 0x0002, /* detected drive identify info */ DbgSTATE = 0x0004, /* dump state on panic */ DbgPROBE = 0x0008, /* trace device probing */ DbgDEBUG = 0x0080, /* the current problem... */ DbgINL = 0x0100, /* That Inil20+ message we hate */ Dbg48BIT = 0x0200, /* 48-bit LBA */ DbgBsy = 0x0400, /* interrupt but Bsy (shared IRQ) */};/* adjust to taste */#define DEBUG (DbgDEBUG|DbgCONFIG)enum { /* I/O ports */ Data = 0, Error = 1, /* (read) */ Features = 1, /* (write) */ Count = 2, /* sector count<7-0>, sector count<15-8> */ Ir = 2, /* interrupt reason (PACKET) */ Sector = 3, /* sector number */ Lbalo = 3, /* LBA<7-0>, LBA<31-24> */ Cyllo = 4, /* cylinder low */ Bytelo = 4, /* byte count low (PACKET) */ Lbamid = 4, /* LBA<15-8>, LBA<39-32> */ Cylhi = 5, /* cylinder high */ Bytehi = 5, /* byte count hi (PACKET) */ Lbahi = 5, /* LBA<23-16>, LBA<47-40> */ Dh = 6, /* Device/Head, LBA<32-14> */ Status = 7, /* (read) */ Cmd = 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, /* Cmd/Data */ Io = 0x02, /* I/O direction */ Rel = 0x04, /* Bus Release */};enum { /* Device/Head */ Dev0 = 0xA0, /* Master */ Dev1 = 0xB0, /* Slave */ Lba = 0x40, /* LBA mode */};enum { /* internal flags */ Lba48 = 0x1, /* LBA48 mode */ Lba48always = 0x2, /* ... */};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 { /* Cmd */ Cnop = 0x00, /* NOP */ Cdr = 0x08, /* Device Reset */ Crs = 0x20, /* Read Sectors */ Crs48 = 0x24, /* Read Sectors Ext */ Crd48 = 0x25, /* Read w/ DMA Ext */ Crdq48 = 0x26, /* Read w/ DMA Queued Ext */ Crsm48 = 0x29, /* Read Multiple Ext */ Cws = 0x30, /* Write Sectors */ Cws48 = 0x34, /* Write Sectors Ext */ Cwd48 = 0x35, /* Write w/ DMA Ext */ Cwdq48 = 0x36, /* Write w/ DMA Queued Ext */ Cwsm48 = 0x39, /* Write Multiple Ext */ 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 */ Cstandby = 0xE2, /* Standby */ Cid = 0xEC, /* Identify Device */ Csf = 0xEF, /* Set Features */};enum { /* Device Control */ Nien = 0x02, /* (not) Interrupt Enable */ Srst = 0x04, /* Software Reset */ Hob = 0x80, /* High Order Bit [sic] */};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, /* Cmd */ 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 */ Ilba = 60, /* 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 */ Icsfs = 82, /* command set/feature supported */ Icsfe = 85, /* command set/feature enabled */ Iudma = 88, /* ultra DMA mode */ Ierase = 89, /* time for security erase */ Ieerase = 90, /* time for enhanced security erase */ Ipower = 91, /* current advanced power management */ Ilba48 = 100, /* 48-bit LBA size (64 bits in 100-103) */ Irmsn = 127, /* removable status notification */ Isecstat = 128, /* security status */ Icfapwr = 160, /* CFA power mode */ Imediaserial = 176, /* current media serial number */ Icksum = 255, /* checksum */};enum { /* bit masks for config identify info */ Mpktsz = 0x0003, /* packet command size */ Mincomplete = 0x0004, /* incomplete information */ Mdrq = 0x0060, /* DRQ type */ Mrmdev = 0x0080, /* device is removable */ Mtype = 0x1F00, /* device type */ Mproto = 0x8000, /* command protocol */};enum { /* bit masks for capabilities identify info */ Mdma = 0x0100, /* DMA supported */ Mlba = 0x0200, /* LBA supported */ Mnoiordy = 0x0400, /* IORDY may be disabled */ Miordy = 0x0800, /* IORDY supported */ Msoftrst = 0x1000, /* needs soft reset when Bsy */ Mstdby = 0x2000, /* standby supported */ Mqueueing = 0x4000, /* queueing overlap supported */ Midma = 0x8000, /* interleaved DMA supported */};enum { /* bit masks for supported/enabled features */ Msmart = 0x0001, Msecurity = 0x0002, Mrmmedia = 0x0004, Mpwrmgmt = 0x0008, Mpkt = 0x0010, Mwcache = 0x0020, Mlookahead = 0x0040, Mrelirq = 0x0080, Msvcirq = 0x0100, Mreset = 0x0200, Mprotected = 0x0400, Mwbuf = 0x1000, Mrbuf = 0x2000, Mnop = 0x4000, Mmicrocode = 0x0001, Mqueued = 0x0002, Mcfa = 0x0004, Mapm = 0x0008, Mnotify = 0x0010, Mstandby = 0x0020, Mspinup = 0x0040, Mmaxsec = 0x0100, Mautoacoustic = 0x0200, Maddr48 = 0x0400, Mdevconfov = 0x0800, Mflush = 0x1000, Mflush48 = 0x2000, Msmarterror = 0x0001, Msmartselftest = 0x0002, Mmserial = 0x0004, Mmpassthru = 0x0008, Mlogging = 0x0020,};typedef struct Ctlr Ctlr;typedef struct Drive Drive;typedef struct Prd { ulong pa; /* Physical Base Address */ int count;} Prd;enum { BMspan = 64*1024, /* must be power of 2 <= 64*1024 */ Nprd = SDmaxio/BMspan+2,};typedef struct Ctlr { int cmdport; int ctlport; int irq; int tbdf; int bmiba; /* bus master interface base address */ int maxio; /* sector count transfer maximum */ int span; /* don't span this boundary with dma */ Pcidev* pcidev; void (*ienable)(Ctlr*); void (*idisable)(Ctlr*); SDev* sdev; Drive* drive[NCtlrdrv]; Target target[NTarget]; /* contains filters for stats */ Prd* prdt; /* physical region descriptor table */ void* prdtbase; QLock; /* current command */ Drive* curdrive; int command; /* last command issued (debugging) */ Rendez; int done; Lock; /* register access */ /* old stuff carried forward */ QLock idelock; /* make seek & i/o atomic in ide* routines */} Ctlr;typedef struct Drive { Ctlr* ctlr; int dev; ushort info[256]; int c; /* cylinder */ int h; /* head */ int s; /* sector */ Devsize sectors; /* total sectors */ 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; int flags; /* internal flags */ /* for ata* routines */ int online; Devsize offset; int driveno; /* ctlr*NCtlrdrv + unit */ char lba; /* true if drive has logical block addressing */ char multi; /* non-0 if drive does multiple block xfers */ /* * old stuff carried forward. it's in Drive not Ctlr to maximise * possible concurrency. */ uchar buf[RBUFSIZE];} Drive;/* file-server-specific data */static Ctlr *atactlr[NCtlr];static SDev *sdevs[NCtlr];static Drive *atadrive[NDrive];// static SDunit *sdunits[NDrive];SDunit* sdgetunit(SDev* sdev, int subno);static Drive *atadriveprobe(int driveno);voidpresleep(Rendez *r, int (*fn)(void*), void *v){ int x; if (u != nil) { sleep(r, fn, v); return; } /* else we're in predawn with no u */ x = spllo(); while (!fn(v)) continue; splx(x);}voidpretsleep(Rendez *r, int (*fn)(void*), void *v, int msec){ int x; ulong start; if (u != nil) { tsleep(r, fn, v, msec); return; } /* else we're in predawn with no u */ x = spllo(); for (start = m->ticks; TK2MS(m->ticks - start) < msec && !fn(v); ) continue; splx(x);}#define sleep presleep#define tsleep pretsleepstatic voidpc87415ienable(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 voidatadumpstate(Drive* drive, uchar* cmd, Devsize 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 -> %lld, count %d -> %d (%d)\n", (cmd[2]<<24)|(cmd[3]<<16)|(cmd[4]<<8)|cmd[5], (Wideoff)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 intatadebug(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 = vseprint(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 < Cmd; 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 intataready(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){ /* nothing to do */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -