From b415f2a551fefafb2c0b01fd98da91753763b053 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Sat, 8 Sep 2001 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2001-09-08 --- bitsy/sd.h | 125 +++ bitsy/sdata.c | 2086 +++++++++++++++++++++++++++++++++++++++++++++ pc/screen.h | 1 + pc/vga.c | 15 +- pc/vga3dfx.c | 17 +- pc/vgaclgd546x.c | 16 +- pc/vgacyber938x.c | 19 +- pc/vgahiqvideo.c | 8 +- pc/vgamach64xx.c | 14 +- pc/vgamga2164w.c | 16 +- pc/vganeomagic.c | 16 +- pc/vganvidia.c | 16 +- pc/vgas3.c | 34 +- pc/vgat2r4.c | 16 +- pc/vgavmware.c | 11 +- 15 files changed, 2278 insertions(+), 132 deletions(-) create mode 100644 bitsy/sd.h create mode 100644 bitsy/sdata.c diff --git a/bitsy/sd.h b/bitsy/sd.h new file mode 100644 index 0000000000000000000000000000000000000000..c5d1cc81257fc644f5193410f30bf77a6b69bf32 --- /dev/null +++ b/bitsy/sd.h @@ -0,0 +1,125 @@ +/* + * Storage Device. + */ +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 SDperm { + char name[NAMELEN]; + char user[NAMELEN]; + ulong perm; +} SDperm; + +typedef struct SDpart { + ulong start; + ulong end; + SDperm; + int valid; + ulong vers; +} SDpart; + +typedef struct SDunit { + SDev* dev; + int subno; + uchar inquiry[256]; /* format follows SCSI spec */ + SDperm; + Rendez rendez; + + QLock ctl; + ulong sectors; + ulong secsize; + SDpart* part; /* nil or array of size npart */ + int npart; + ulong vers; + SDperm ctlperm; + + QLock raw; /* raw read or write in progress */ + Lock rawinuse; /* really just a test-and-set */ + int state; + SDreq* req; + SDperm rawperm; + + Log log; +} SDunit; + +typedef struct SDev { + SDifc* ifc; /* pnp/legacy */ + void *ctlr; + int idno; + char name[NAMELEN]; + int index; /* into unit space */ + int nunit; + SDev* next; + + QLock; /* enable/disable */ + int enabled; +} SDev; + +typedef struct SDifc { + char* name; + + SDev* (*pnp)(void); + SDev* (*legacy)(int, int); + SDev* (*id)(SDev*); + int (*enable)(SDev*); + int (*disable)(SDev*); + + int (*verify)(SDunit*); + int (*online)(SDunit*); + int (*rio)(SDreq*); + int (*rctl)(SDunit*, char*, int); + int (*wctl)(SDunit*, Cmdbuf*); + + long (*bio)(SDunit*, int, int, void*, long, long); + SDev* (*config)(int on, char *spec, void *cf); +} SDifc; + +typedef struct SDreq { + SDunit* unit; + int lun; + int write; + uchar cmd[16]; + int clen; + void* data; + int dlen; + + int flags; + + int status; + long rlen; + uchar sense[256]; +} SDreq; + +enum { + SDnosense = 0x00000001, + SDvalidsense = 0x00010000, +}; + +enum { + SDretry = -5, /* internal to controllers */ + SDmalloc = -4, + SDeio = -3, + SDtimeout = -2, + SDnostatus = -1, + + SDok = 0, + + SDcheck = 0x02, /* check condition */ + SDbusy = 0x08, /* busy */ + + SDmaxio = 2048*1024, + SDnpart = 16, +}; + +#define sdmalloc(n) malloc(n) +#define sdfree(p) free(p) + +/* sdscsi.c */ +extern int scsiverify(SDunit*); +extern int scsionline(SDunit*); +extern long scsibio(SDunit*, int, int, void*, long, long); +extern SDev* scsiid(SDev*, SDifc*); diff --git a/bitsy/sdata.c b/bitsy/sdata.c new file mode 100644 index 0000000000000000000000000000000000000000..13825d6347d18a64636c8b6055618c219a9c042d --- /dev/null +++ b/bitsy/sdata.c @@ -0,0 +1,2086 @@ +#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 "../port/sd.h" + + +extern SDifc sdataifc; + +//BUG? +#define PCIWADDR(x) ((ulong)(x)) + +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 */ + Cstandby = 0xE2, /* Standby */ + 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 */ + 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 */ + 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 */ + + 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; + + +char* +getconf(char*) +{ + return nil; +} + +static void +atadumpstate(Drive* drive, uchar* cmd, int lba, int count) +{ + Prd *prd; + 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++; + } + } +} + +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; + } + µdelay(4); + } + atadebug(cmdport, ctlport, "ataready: timeout"); + + return -1; +} + +static int +atacsf(Drive* drive, vlong csf, int supported) +{ + ushort *info; + int cmdset, i, x; + + if(supported) + info = &drive->info[Icsfs]; + else + info = &drive->info[Icsfe]; + + for(i = 0; i < 3; i++){ + x = (csf>>(16*i)) & 0xFFFF; + if(x == 0) + continue; + cmdset = info[i]; + if(cmdset == 0 || cmdset == 0xFFFF) + return 0; + return cmdset & x; + } + + return 0; +} + +static int +atadone(void* arg) +{ + return ((Ctlr*)arg)->done; +} + +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); + µdelay(4); + 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); + µdelay(4); + + 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); + + if(DEBUG & DbgIDENTIFY){ + int i; + ushort *sp; + + sp = (ushort*)info; + for(i = 0; i < 32; 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] != 0x848A && (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 port %uX config %4.4uX capabilities %4.4uX", + dev, cmdport, + drive->info[Iconfig], drive->info[Icapabilities]); + print(" mwdma %4.4uX", drive->info[Imwdma]); + if(drive->info[Ivalid] & 0x04) + print(" udma %4.4uX", drive->info[Iudma]); + print(" dma %8.8uX rwm %ud\n", drive->dma, 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. + */ + µdelay(20); + outb(ctlport+Dc, Srst); + µdelay(20); + outb(ctlport+Dc, 0); + µdelay(4*1000); +} + +static SDev* +ataprobe(int cmdport, int ctlport, int irq) +{ + Ctlr* ctlr; + SDev *sdev; + Drive *drive; + int dev, error, rhi, rlo; + + /* + * 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); + µdelay(5); +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: + 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(5); + 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; +#ifdef notdef + 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); + µdelay(1); + } + } +#endif + } + else + ctlr->drive[1] = drive; + + ctlr->cmdport = cmdport; + ctlr->ctlport = ctlport; + ctlr->irq = irq; + ctlr->tbdf = -1; + ctlr->command = Cedd; /* debugging */ + + sdev->ifc = &sdataifc; + sdev->ctlr = ctlr; + sdev->nunit = 1; + 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 +atastandby(Drive* drive, int period) +{ + Ctlr* ctlr; + int cmdport, done; + + ctlr = drive->ctlr; + drive->command = Cstandby; + qlock(ctlr); + + cmdport = ctlr->cmdport; + ilock(ctlr); + outb(cmdport+Count, period); + outb(cmdport+Dh, drive->dev); + ctlr->done = 0; + ctlr->curdrive = drive; + ctlr->command = Cstandby; /* debugging */ + outb(cmdport+Command, Cstandby); + iunlock(ctlr); + + while(waserror()) + ; + tsleep(ctlr, atadone, ctlr, 30*1000); + poperror(); + + done = ctlr->done; + qunlock(ctlr); + + if(!done || (drive->status & Err)) + return atasetsense(drive, SDcheck, 4, 8, drive->error); + return SDok; +} + +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); + + µdelay(1); + ctlport = ctlr->ctlport; + for(timeo = 0; timeo < 1000; timeo++){ + as = inb(ctlport+As); + if(!(as & Bsy)) + break; + µdelay(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(atacsf(drive, 0x0000000000004000LL, 0)) + atanop(drive, 0); + else{ + atasrst(drive->ctlr->ctlport); + drive->error |= Abrt; + } + if(dolock) + iunlock(drive->ctlr); +} + +static int +atadmasetup(Drive* drive, int ) +{ + drive->dmactl = 0; + return -1; + +#ifdef notdef + 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; +#endif +} + +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 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){ + µdelay(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, atadone, ctlr); + else for(timeo = 0; !ctlr->done; timeo++){ + tsleep(ctlr, atadone, 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 +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: + µdelay(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, atadone, ctlr, 30*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); + qunlock(ctlr); + 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/%2.2uX+", ctlr->command, status); + 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; + + case Cstandby: + ctlr->done = 1; + break; + } + iunlock(ctlr); + + if(drive->error){ + status |= Err; + ctlr->done = 1; + } + + if(ctlr->done){ + ctlr->curdrive = nil; + drive->status = status; + wakeup(ctlr); + } +} + +#ifdef notdef +static SDev* +atapnp(void) +{ + int cmdport; + int ctlport; + int irq; + + cmdport = 0x200; + ctlport = cmdport + 0x0C; + irq = 10; + return ataprobe(cmdport, ctlport, irq); +} +#endif + + +static SDev* +atalegacy(int port, int irq) +{ + return ataprobe(port, port+0x204, irq); +} + +static SDev* +ataid(SDev* sdev) +{ + int i; + Ctlr *ctlr; + + if(sdev == nil) + return nil; + ctlr = sdev->ctlr; + i = 0; + while(sdev){ + if(sdev->ifc == &sdataifc){ + ctlr = sdev->ctlr; + sdev->idno = 'C'+i; + i++; + snprint(sdev->name, NAMELEN, "sd%c", sdev->idno); + } + sdev = sdev->next; + } + + return nil; +} + +static int ataitype; +static int atairq; +static int +ataenable(SDev* sdev) +{ + Ctlr *ctlr; + char name[NAMELEN]; + + ctlr = sdev->ctlr; + + if(ctlr->bmiba){ + 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); + intrenable(ataitype, atairq, atainterrupt, ctlr, name); + 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->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) +{ + int period; + 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 if(strcmp(cb->f[0], "standby") == 0){ + switch(cb->nf){ + default: + error(Ebadctl); + case 2: + period = strtol(cb->f[1], 0, 0); + if(period && (period < 30 || period > 240*5)) + error(Ebadctl); + period /= 5; + break; + } + if(atastandby(drive, period) != SDok) + error(Ebadctl); + } + else + error(Ebadctl); + qunlock(drive); + poperror(); + + return 0; +} + +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); +} + +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; +} + + +static int +ataverify(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 +ataonline(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; +} + +static long +atabio(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; +} + + +struct Try { + int p; + int c; +} tries[] = { + { 0, 0x0c }, + { 0, 0 }, +}; + +static SDev* +ataconfig(int on, char *, void *pf) +{ + DevConf* cf = pf; + int cmdport; + int ctlport; + int irq; + SDev* rc; + struct Try *try; + + if(on == 0) + return nil; + rc = nil; + for (try = &tries[0]; try->p != 0 || try->c != 0; try++){ + ataitype = cf->itype; + atairq = cf->interrupt; + cmdport = cf->port + try->p; + ctlport = cmdport + try->c; + irq = cf->interrupt; + rc = ataprobe(cmdport, ctlport, irq); + if (rc) + break; + } + return rc; +} + +SDifc sdataifc = { + "ata", /* name */ + + nil, /* pnp */ + atalegacy, /* legacy */ + ataid, /* id */ + ataenable, /* enable */ + nil, /* disable */ + + ataverify, /* verify */ + ataonline, /* online */ + atario, /* rio */ + atarctl, /* rctl */ + atawctl, /* wctl */ + + atabio, /* bio */ + ataconfig, /* config */ +}; + diff --git a/pc/screen.h b/pc/screen.h index 809fae2fcc4712ae6d1d9ee5fcbb4cd5acef5fbf..fa61836334e1d7ee70a8667e341f88b63d397e78 100644 --- a/pc/screen.h +++ b/pc/screen.h @@ -125,6 +125,7 @@ extern void mousectl(char*[], int); /* screen.c */ extern int hwaccel; /* use hw acceleration; default on */ extern int hwblank; /* use hw blanking; default on */ +extern void addvgaseg(char*, ulong, ulong); extern uchar* attachscreen(Rectangle*, ulong*, int*, int*, int*); extern void flushmemscreen(Rectangle); extern int cursoron(int); diff --git a/pc/vga.c b/pc/vga.c index e740c139461a822565276d22fa009a7f6244e9d9..f40b3ffa6f56c6b9b5f53cd5630436811f02d99f 100644 --- a/pc/vga.c +++ b/pc/vga.c @@ -189,7 +189,6 @@ vgascreenwin(VGAscr* scr) curpos = window.min; screenputs = vgascreenputs; - } /* @@ -219,3 +218,17 @@ vgablank(VGAscr*, int blank) vgaxo(Crtx, 0x17, crtc17); outs(Crtx, 0x0300); /* end synchronous reset */ } + +void +addvgaseg(char *name, ulong pa, ulong size) +{ + Physseg seg; + + memset(&seg, 0, sizeof seg); + seg.attr = SG_PHYSICAL; + seg.name = name; + seg.pa = pa; + seg.size = size; + addphysseg(&seg); +} + diff --git a/pc/vga3dfx.c b/pc/vga3dfx.c index 7508e9ddb3545617211e6022116b06d90fff58ec..d35159dfb8c47aa234d560762cb1c1ea7d13378a 100644 --- a/pc/vga3dfx.c +++ b/pc/vga3dfx.c @@ -77,7 +77,6 @@ static void tdfxenable(VGAscr* scr) { Pcidev *p; - Physseg seg; ulong aperture; int align, i, *mmio, size; @@ -103,25 +102,15 @@ tdfxenable(VGAscr* scr) if(scr->io == 0) return; - memset(&seg, 0, sizeof(seg)); - seg.attr = SG_PHYSICAL; - kstrdup(&seg.name, "3dfxmmio"); - seg.pa = scr->io; - seg.size = p->mem[0].size; - addphysseg(&seg); + addvgaseg("3dfxmmio", (ulong)scr->io, p->mem[0].size); size = p->mem[1].size; align = 0; aperture = tdfxlinear(scr, &size, &align); - if(aperture) { + if(aperture){ scr->aperture = aperture; scr->apsize = size; - memset(&seg, 0, sizeof(seg)); - seg.attr = SG_PHYSICAL; - kstrdup(&seg.name, "3dfxscreen"); - seg.pa = aperture; - seg.size = size; - addphysseg(&seg); + addvgaseg("3dfxscreen", aperture, size); } /* diff --git a/pc/vgaclgd546x.c b/pc/vgaclgd546x.c index 6f5eafb0a273698690baa15e92519bd95941dd20..8b86b349be360a41108c615d530f935ad7c0df69 100644 --- a/pc/vgaclgd546x.c +++ b/pc/vgaclgd546x.c @@ -75,7 +75,6 @@ static void clgd546xenable(VGAscr* scr) { Pcidev *p; - Physseg seg; int size, align; ulong aperture; @@ -101,13 +100,7 @@ clgd546xenable(VGAscr* scr) scr->io = upamalloc(p->mem[1].bar & ~0x0F, p->mem[1].size, 0); if(scr->io == 0) return; - - memset(&seg, 0, sizeof(seg)); - seg.attr = SG_PHYSICAL; - kstrdup(&seg.name, "clgd546xmmio"); - seg.pa = scr->io; - seg.size = p->mem[1].size; - addphysseg(&seg); + addvgaseg("clgd546xmmio", scr->io, p->mem[1].size); scr->io = (ulong)KADDR(scr->io); @@ -117,12 +110,7 @@ clgd546xenable(VGAscr* scr) if(aperture) { scr->aperture = aperture; scr->apsize = size; - memset(&seg, 0, sizeof(seg)); - seg.attr = SG_PHYSICAL; - kstrdup(&seg.name, "clgd546xscreen"); - seg.pa = aperture; - seg.size = size; - addphysseg(&seg); + addvgaseg("clgd546xscreen", aperture, size); } } diff --git a/pc/vgacyber938x.c b/pc/vgacyber938x.c index 00cd74faf7e06de9386a8cfb97124a3ea1fd01f8..7c86679c5acbc20c25e9afbe2608efbdfb6b08cf 100644 --- a/pc/vgacyber938x.c +++ b/pc/vgacyber938x.c @@ -43,18 +43,27 @@ cyber938xlinear(VGAscr* scr, int* size, int* align) { ulong aperture, oaperture; int oapsize, wasupamem; + int osize; Pcidev *p; + osize = *size; oaperture = scr->aperture; oapsize = scr->apsize; wasupamem = scr->isupamem; if(wasupamem) upafree(oaperture, oapsize); scr->isupamem = 0; + scr->mmio = 0; if(p = pcimatch(nil, 0x1023, 0)){ aperture = p->mem[0].bar & ~0x0F; *size = p->mem[0].size; + /* + * Heuristic to detect the MMIO space. We're flying blind + * here, with only the XFree86 source to guide us. + */ + if(p->mem[1].size == 0x20000) + scr->mmio = (ulong*)(p->mem[1].bar & ~0x0F); } else aperture = 0; @@ -67,6 +76,11 @@ cyber938xlinear(VGAscr* scr, int* size, int* align) else scr->isupamem = 1; + if(aperture) + addvgaseg("cyber938xscreen", aperture, osize); + if(scr->mmio) + addvgaseg("cyber938xmmio", (ulong)scr->mmio, 0x20000); + return aperture; } @@ -194,10 +208,11 @@ cyber938xcurenable(VGAscr* scr) VGAdev vgacyber938xdev = { "cyber938x", - 0, /* enable */ - 0, /* disable */ + nil, /* enable */ + nil, /* disable */ cyber938xpage, /* page */ cyber938xlinear, /* linear */ + nil, /* drawinit */ }; VGAcur vgacyber938xcur = { diff --git a/pc/vgahiqvideo.c b/pc/vgahiqvideo.c index d0d905cddaadcfeffbf0905334c519b0eb5eba26..5488989ae44df56f111a80b108ba5fe1a326b01d 100644 --- a/pc/vgahiqvideo.c +++ b/pc/vgahiqvideo.c @@ -85,7 +85,6 @@ static void hiqvideoenable(VGAscr* scr) { Pcidev *p; - Physseg seg; int align, size, vmsize; ulong aperture; @@ -124,12 +123,7 @@ hiqvideoenable(VGAscr* scr) if(aperture) { scr->aperture = aperture; scr->apsize = size; - memset(&seg, 0, sizeof(seg)); - seg.attr = SG_PHYSICAL; - kstrdup(&seg.name, "hiqvideoscreen"); - seg.pa = aperture; - seg.size = size; - addphysseg(&seg); + addvgaseg("hiqvideoscreen", aperture, size); } /* diff --git a/pc/vgamach64xx.c b/pc/vgamach64xx.c index 7a1e1dd407467f635d10b94ea40bea1bec42842e..d2f3ddcd3fdf2bb5cc01ff767d0f601599c140d0 100644 --- a/pc/vgamach64xx.c +++ b/pc/vgamach64xx.c @@ -90,7 +90,6 @@ mach64xxlinear(VGAscr* scr, int* size, int* align) ulong aperture, osize, oaperture; int i, oapsize, wasupamem; Pcidev *p; - Physseg seg; osize = *size; oaperture = scr->aperture; @@ -128,17 +127,8 @@ mach64xxlinear(VGAscr* scr, int* size, int* align) scr->mmio = KADDR(aperture+osize-0x400); if(oaperture && oaperture != aperture) print("warning (BUG): redefinition of aperture does not change mach64mmio segment\n"); - memset(&seg, 0, sizeof(seg)); - seg.attr = SG_PHYSICAL; - kstrdup(&seg.name, "mach64mmio"); - seg.pa = aperture+osize - BY2PG; - seg.size = BY2PG; - addphysseg(&seg); - - kstrdup(&seg.name, "mach64screen"); - seg.pa = aperture; - seg.size = osize; - addphysseg(&seg); + addvgaseg("mach64mmio", aperture+osize-BY2PG, BY2PG); + addvgaseg("mach64screen", aperture, osize); return aperture; } diff --git a/pc/vgamga2164w.c b/pc/vgamga2164w.c index 3123801c454522657c05752be23b968ab90754c8..6332236ab3dd36d0516ab65625f4ff573d1e751e 100644 --- a/pc/vgamga2164w.c +++ b/pc/vgamga2164w.c @@ -86,7 +86,6 @@ static void mga2164wenable(VGAscr* scr) { Pcidev *p; - Physseg seg; int size, align, immio; ulong aperture; @@ -106,13 +105,7 @@ mga2164wenable(VGAscr* scr) scr->io = upamalloc(p->mem[immio].bar & ~0x0F, p->mem[immio].size, 0); if(scr->io == 0) return; - - memset(&seg, 0, sizeof(seg)); - seg.attr = SG_PHYSICAL; - kstrdup(&seg.name, "mga2164wmmio"); - seg.pa = scr->io; - seg.size = p->mem[immio].size; - addphysseg(&seg); + addvgaseg("mga2164wmmio", scr->io, p->mem[immio].size); scr->io = (ulong)KADDR(scr->io); @@ -123,12 +116,7 @@ mga2164wenable(VGAscr* scr) if(aperture) { scr->aperture = aperture; scr->apsize = size; - memset(&seg, 0, sizeof(seg)); - seg.attr = SG_PHYSICAL; - kstrdup(&seg.name, "mga2164wscreen"); - seg.pa = aperture; - seg.size = size; - addphysseg(&seg); + addvgaseg("mga2164wscreen", aperture, size); } } diff --git a/pc/vganeomagic.c b/pc/vganeomagic.c index c9b98010147ba917b82d14ebe5d46e9ee8549b4b..9a4c3f1a74931ccf03701f5776462d403b664e6a 100644 --- a/pc/vganeomagic.c +++ b/pc/vganeomagic.c @@ -72,7 +72,6 @@ static void neomagicenable(VGAscr* scr) { Pcidev *p; - Physseg seg; int align, curoff, size, vmsize; ulong aperture; @@ -107,13 +106,7 @@ neomagicenable(VGAscr* scr) scr->io = upamalloc(p->mem[1].bar & ~0x0F, p->mem[1].size, 0); if(scr->io == 0) return; - - memset(&seg, 0, sizeof(seg)); - seg.attr = SG_PHYSICAL; - kstrdup(&seg.name, "neomagicmmio"); - seg.pa = scr->io; - seg.size = p->mem[1].size; - addphysseg(&seg); + addvgaseg("neomagicmmio", scr->io, p->mem[1].size); /* * Find a place for the cursor data in display memory. @@ -129,12 +122,7 @@ neomagicenable(VGAscr* scr) if(aperture) { scr->aperture = aperture; scr->apsize = size; - memset(&seg, 0, sizeof(seg)); - seg.attr = SG_PHYSICAL; - kstrdup(&seg.name, "neomagicscreen"); - seg.pa = aperture; - seg.size = size; - addphysseg(&seg); + addvgaseg("neomagicscreen", aperture, size); } } diff --git a/pc/vganvidia.c b/pc/vganvidia.c index 29a34ff728cb5bbcd7401db20875c6d8fbf21203..0cb06aaea066a5f6025c27399ae35b5808b8e4d0 100644 --- a/pc/vganvidia.c +++ b/pc/vganvidia.c @@ -105,7 +105,6 @@ static void nvidiaenable(VGAscr* scr) { Pcidev *p; - Physseg seg; ulong aperture; int align, size; @@ -123,13 +122,7 @@ nvidiaenable(VGAscr* scr) scr->io = upamalloc(p->mem[0].bar & ~0x0F, p->mem[0].size, 0); if (scr->io == 0) return; - - memset(&seg, 0, sizeof(seg)); - seg.attr = SG_PHYSICAL; - seg.name = "nvidiammio"; - seg.pa = scr->io; - seg.size = p->mem[0].size; - addphysseg(&seg); + addvgaseg("nvidiammio", scr->io, p->mem[0].size); size = p->mem[1].size; align = 0; @@ -137,12 +130,7 @@ nvidiaenable(VGAscr* scr) if(aperture) { scr->aperture = aperture; scr->apsize = size; - memset(&seg, 0, sizeof(seg)); - seg.attr = SG_PHYSICAL; - seg.name = "nvidiascreen"; - seg.pa = aperture; - seg.size = size; - addphysseg(&seg); + addvgaseg("nvidiascreen", aperture, size); } } diff --git a/pc/vgas3.c b/pc/vgas3.c index a936d8f38dd1e0020b935b0ae34916e03c6a2bff..b39da040576d8b8348356063d55b47b177cc5f83 100644 --- a/pc/vgas3.c +++ b/pc/vgas3.c @@ -90,7 +90,6 @@ s3linear(VGAscr* scr, int* size, int* align) ulong aperture, oaperture, mmiobase, mmiosize; int i, id, j, osize, oapsize, wasupamem; Pcidev *p; - Physseg seg; osize = *size; oaperture = scr->aperture; @@ -100,7 +99,18 @@ s3linear(VGAscr* scr, int* size, int* align) mmiosize = 0; mmiobase = 0; mmioname = nil; - if(p = pcimatch(nil, PCIS3, 0)){ + + /* + * S3 makes cards other than display controllers, so + * look for the first S3 display controller (device class 3) + * and not one of their sound cards. + */ + p = nil; + while(p = pcimatch(p, PCIS3, 0)){ + if(p->ccrb == 0x03) + break; + } + if(p != nil){ for(i=0; imem); i++){ if(p->mem[i].size >= *size && ((p->mem[i].bar & ~0x0F) & (*align-1)) == 0) @@ -157,21 +167,11 @@ s3linear(VGAscr* scr, int* size, int* align) if(oaperture && oaperture != aperture) print("warning (BUG): redefinition of aperture does not change s3screen segment\n"); - memset(&seg, 0, sizeof(seg)); - seg.attr = SG_PHYSICAL; - kstrdup(&seg.name, "s3screen"); - seg.pa = aperture; - seg.size = osize; - addphysseg(&seg); - - if(mmiosize){ - memset(&seg, 0, sizeof(seg)); - seg.attr = SG_PHYSICAL; - kstrdup(&seg.name, mmioname); - seg.pa = mmiobase; - seg.size = mmiosize; - addphysseg(&seg); - } + addvgaseg("s3screen", aperture, osize); + + if(mmiosize) + addvgaseg(mmioname, mmiobase, mmiosize); + return aperture; } diff --git a/pc/vgat2r4.c b/pc/vgat2r4.c index 9f2153bf5090866417bb8ab26d860cd29e0b9aa9..a7f430ed0355571dab5af14b6228cbecf4cc4137 100644 --- a/pc/vgat2r4.c +++ b/pc/vgat2r4.c @@ -105,7 +105,6 @@ static void t2r4enable(VGAscr* scr) { Pcidev *p; - Physseg seg; int size, align; ulong aperture, mmio; @@ -129,13 +128,7 @@ t2r4enable(VGAscr* scr) mmio = upamalloc(p->mem[4].bar & ~0x0F, p->mem[4].size, 0); if(mmio == 0) return; - - memset(&seg, 0, sizeof(seg)); - seg.attr = SG_PHYSICAL; - kstrdup(&seg.name, "t2r4mmio"); - seg.pa = mmio; - seg.size = p->mem[4].size; - addphysseg(&seg); + addvgaseg("t2r4mmio", mmio, p->mem[4].size); scr->mmio = KADDR(mmio); @@ -145,12 +138,7 @@ t2r4enable(VGAscr* scr) if(aperture){ scr->aperture = aperture; scr->apsize = size; - memset(&seg, 0, sizeof(seg)); - seg.attr = SG_PHYSICAL; - kstrdup(&seg.name, "t2r4screen"); - seg.pa = aperture; - seg.size = size; - addphysseg(&seg); + addvgaseg("t2r4screen", aperture, size); } } diff --git a/pc/vgavmware.c b/pc/vgavmware.c index 323f9e209f4519593b91d8f2d5dfd9cd6bca12ad..c72daebe4d20141f18533cc0fbd5ca762de3bf8b 100644 --- a/pc/vgavmware.c +++ b/pc/vgavmware.c @@ -91,7 +91,6 @@ vmwarelinear(VGAscr* scr, int* size, int* align) ulong aperture, oaperture; int osize, oapsize, wasupamem; Pcidev *p; - Physseg seg; osize = *size; oaperture = scr->aperture; @@ -131,15 +130,9 @@ vmwarelinear(VGAscr* scr, int* size, int* align) }else scr->isupamem = 1; - if(oaperture) + if(oaperture && aperture != oaperture) print("warning (BUG): redefinition of aperture does not change vmwarescreen segment\n"); - memset(&seg, 0, sizeof(seg)); - seg.attr = SG_PHYSICAL; - seg.name = smalloc(32); - snprint(seg.name, 32, "vmwarescreen"); - seg.pa = aperture; - seg.size = osize; - addphysseg(&seg); + addvgaseg("vmwarescreen", aperture, osize); return aperture; }