#include "u.h"#include "lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "ureg.h"#include "error.h" #include "sd.h"#include <fis.h> #pragma varargck argpos atadebug 3 extern 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) */};#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<27-24> */ 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 */ Crs = 0x20, /* Read Sectors */ Crs48 = 0x24, /* Read Sectors Ext */ Crd48 = 0x25, /* Read w/ DMA Ext */ Crsm48 = 0x29, /* Read Multiple Ext */ Cws = 0x30, /* Write Sectors */ Cws48 = 0x34, /* Write Sectors Ext */ Cwd48 = 0x35, /* Write w/ DMA 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 */ Crd = 0xC8, /* Read DMA */ Cwd = 0xCA, /* Write DMA */ Cid = 0xEC, /* Identify Device */}; 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, /* 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, /* End of Transfer */}; 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 */}; typedef struct Ctlr Ctlr;typedef struct Drive Drive; typedef struct Prd { /* Physical Region Descriptor */ 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 */ Pcidev* pcidev; void (*ienable)(Ctlr*); void (*idisable)(Ctlr*); SDev* sdev; Drive* drive[2]; // Prd* prdt; /* physical region descriptor table */ void (*irqack)(Ctlr*); // QLock; /* current command */ Drive* curdrive; int command; /* last command issued (debugging) */// Rendez; int done; uint nrq; uint nildrive; uint bsy; Lock; /* register access */} Ctlr; typedef struct Drive { Ctlr* ctlr; int dev; ushort info[256]; int c; /* cylinder */ int h; /* head */ int s; /* sector */ vlong 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; int flags; /* internal flags */ uint missirq; uint spurloop; uint irq; uint bsy;} Drive; enum { /* internal flags */ Lba48 = 0x1, /* LBA48 mode */ Lba48always = 0x2, /* ... */}; static 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 voidatadebug(int cmdport, int ctlport, char* fmt, ...){ char *p, *e, buf[PRINTSIZE]; int i; va_list arg; if(!(DEBUG & DbgPROBE)) return; p = buf; e = buf + sizeof buf; va_start(arg, fmt); p = vseprint(p, e, fmt, arg); va_end(arg); if(cmdport){ if(p > buf && p[-1] == '\n') p--; p = seprint(p, e, " ataregs 0x%uX:", cmdport); for(i = Features; i < Command; i++) p = seprint(p, e, " 0x%2.2uX", inb(cmdport+i)); if(ctlport) p = seprint(p, e, " 0x%2.2uX", inb(ctlport+As)); p = seprint(p, e, "\n"); } putstrn(buf, p - buf);} 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 */ } 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 intatacsfenabled(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[Icsfe+i]; if(cmdset == 0 || cmdset == 0xFFFF) return 0; return cmdset & x; } return 0;} static intataidentify(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, 400*1000); if(as < 0) return -1; if(as & Err) return as; memset(info, 0, 512); inss(cmdport+Data, info, 256); inb(cmdport+Status); return 0;} static Drive*atadrive(int cmdport, int ctlport, int dev){ Drive *drive; int as, i, pkt; uchar buf[512], *p; ushort iconfig, *sp; 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; /* * Beware the CompactFlash Association feature set. * Now, why this value in Iconfig just walks all over the bit * definitions used in the other parts of the ATA/ATAPI standards * is a mystery and a sign of true stupidity on someone's part. * Anyway, the standard says if this value is 0x848A then it's * CompactFlash and it's NOT a packet device. */ iconfig = drive->info[Iconfig]; if(iconfig != 0x848A && (iconfig & 0xC000) == 0x8000){ if(iconfig & 0x01) drive->pkt = 16; else drive->pkt = 12; } else{ if(drive->info[Ivalid] & 0x0001){ drive->c = drive->info[Iccyl]; drive->h = drive->info[Ichead]; drive->s = drive->info[Icsec]; } else{ drive->c = drive->info[Ilcyl]; drive->h = drive->info[Ilhead]; drive->s = drive->info[Ilsec]; } if(drive->info[Icapabilities] & 0x0200){ if(drive->info[Icsfs+1] & 0x0400){ drive->sectors = drive->info[Ilba48] |(drive->info[Ilba48+1]<<16) |((vlong)drive->info[Ilba48+2]<<32); drive->flags |= Lba48; } else{ drive->sectors = (drive->info[Ilba+1]<<16) |drive->info[Ilba]; } drive->dev |= Lba; } else drive->sectors = drive->c*drive->h*drive->s; // atarwmmode(drive, cmdport, ctlport, dev); }Lines 1–500 of 1801. Load more
#include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "ureg.h" #include "error.h" #include "sd.h" #include <fis.h> #pragma varargck argpos atadebug 3 extern 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) */ }; #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<27-24> */ 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 */ Crs = 0x20, /* Read Sectors */ Crs48 = 0x24, /* Read Sectors Ext */ Crd48 = 0x25, /* Read w/ DMA Ext */ Crsm48 = 0x29, /* Read Multiple Ext */ Cws = 0x30, /* Write Sectors */ Cws48 = 0x34, /* Write Sectors Ext */ Cwd48 = 0x35, /* Write w/ DMA 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 */ Crd = 0xC8, /* Read DMA */ Cwd = 0xCA, /* Write DMA */ Cid = 0xEC, /* Identify Device */ }; 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, /* 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, /* End of Transfer */ }; 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 */ }; typedef struct Ctlr Ctlr; typedef struct Drive Drive; typedef struct Prd { /* Physical Region Descriptor */ 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 */ Pcidev* pcidev; void (*ienable)(Ctlr*); void (*idisable)(Ctlr*); SDev* sdev; Drive* drive[2]; // Prd* prdt; /* physical region descriptor table */ void (*irqack)(Ctlr*); // QLock; /* current command */ Drive* curdrive; int command; /* last command issued (debugging) */ // Rendez; int done; uint nrq; uint nildrive; uint bsy; Lock; /* register access */ } Ctlr; typedef struct Drive { Ctlr* ctlr; int dev; ushort info[256]; int c; /* cylinder */ int h; /* head */ int s; /* sector */ vlong 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; int flags; /* internal flags */ uint missirq; uint spurloop; uint irq; uint bsy; } Drive; enum { /* internal flags */ Lba48 = 0x1, /* LBA48 mode */ Lba48always = 0x2, /* ... */ }; 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 atadebug(int cmdport, int ctlport, char* fmt, ...) { char *p, *e, buf[PRINTSIZE]; int i; va_list arg; if(!(DEBUG & DbgPROBE)) return; p = buf; e = buf + sizeof buf; va_start(arg, fmt); p = vseprint(p, e, fmt, arg); va_end(arg); if(cmdport){ if(p > buf && p[-1] == '\n') p--; p = seprint(p, e, " ataregs 0x%uX:", cmdport); for(i = Features; i < Command; i++) p = seprint(p, e, " 0x%2.2uX", inb(cmdport+i)); if(ctlport) p = seprint(p, e, " 0x%2.2uX", inb(ctlport+As)); p = seprint(p, e, "\n"); } putstrn(buf, p - buf); } 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){ /* nothing to do */ } 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[Icsfe+i]; if(cmdset == 0 || cmdset == 0xFFFF) return 0; return cmdset & x; } return 0; } 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, 400*1000); if(as < 0) return -1; if(as & Err) return as; memset(info, 0, 512); inss(cmdport+Data, info, 256); inb(cmdport+Status); return 0; } static Drive* atadrive(int cmdport, int ctlport, int dev) { Drive *drive; int as, i, pkt; uchar buf[512], *p; ushort iconfig, *sp; 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; /* * Beware the CompactFlash Association feature set. * Now, why this value in Iconfig just walks all over the bit * definitions used in the other parts of the ATA/ATAPI standards * is a mystery and a sign of true stupidity on someone's part. * Anyway, the standard says if this value is 0x848A then it's * CompactFlash and it's NOT a packet device. */ iconfig = drive->info[Iconfig]; if(iconfig != 0x848A && (iconfig & 0xC000) == 0x8000){ if(iconfig & 0x01) drive->pkt = 16; else drive->pkt = 12; } else{ if(drive->info[Ivalid] & 0x0001){ drive->c = drive->info[Iccyl]; drive->h = drive->info[Ichead]; drive->s = drive->info[Icsec]; } else{ drive->c = drive->info[Ilcyl]; drive->h = drive->info[Ilhead]; drive->s = drive->info[Ilsec]; } if(drive->info[Icapabilities] & 0x0200){ if(drive->info[Icsfs+1] & 0x0400){ drive->sectors = drive->info[Ilba48] |(drive->info[Ilba48+1]<<16) |((vlong)drive->info[Ilba48+2]<<32); drive->flags |= Lba48; } else{ drive->sectors = (drive->info[Ilba+1]<<16) |drive->info[Ilba]; } drive->dev |= Lba; } else drive->sectors = drive->c*drive->h*drive->s; // atarwmmode(drive, cmdport, ctlport, dev); }