/* <<<<<<< sdmv50xx.c.orig * Marvell 88SX5040, 5041, 5080, 5081 driver * This is a heavily-modified version of a driver written by Coraid, Inc. ======= * Marvell 88SX[56]0[48][01] fileserver Serial ATA (SATA) driver * * See MV-S101357-00 Rev B Marvell PCI/PCI-X to 8-Port/4-Port * SATA Host Controller, ATA-5 ANSI NCITS 340-2000. * * This is a heavily-modified version (by Coraid) of a heavily-modified * version (from The Labs) of a driver written by Coraid, Inc. >>>>>>> sdmv50xx.c * The original copyright notice appears at the end of this file. */ <<<<<<< sdmv50xx.c.orig #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" ======= #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" >>>>>>> sdmv50xx.c #include "../port/sd.h" <<<<<<< /sys/src/9/pc/sdmv50xx.c #define dprint if(!0){}else iprint #define idprint if(!0){}else iprint #define ioprint if(!0){}else iprint enum{ NCtlr = 4, NCtlrdrv = 8, NDrive = NCtlr*NCtlrdrv, Read = 0, Write, }; ||||||| sdmv50xx.c.orig #define DPRINT if(0)iprint ======= #define dprint(...) // print(__VA_ARGS__) #define idprint(...) #define ioprint(...) enum{ NCtlr = 4, NCtlrdrv = 8, NDrive = NCtlr*NCtlrdrv, Read = 0, Write, }; >>>>>>> sdmv50xx.c enum { SrbRing = 32, <<<<<<< sdmv50xx.c.orig ======= >>>>>>> sdmv50xx.c /* Addresses of ATA register */ ARcmd = 027, ARdev = 026, ARerr = 021, ARfea = 021, ARlba2 = 025, ARlba1 = 024, ARlba0 = 023, <<<<<<< sdmv50xx.c.orig ARseccnt = 022, ======= ARseccnt = 022, >>>>>>> sdmv50xx.c ARstat = 027, <<<<<<< sdmv50xx.c.orig ATAerr = (1<<0), ATAdrq = (1<<3), ATAdf = (1<<5), ======= ATAerr = (1<<0), ATAdrq = (1<<3), ATAdf = (1<<5), >>>>>>> sdmv50xx.c ATAdrdy = (1<<6), ATAbusy = (1<<7), ATAabort = (1<<2), <<<<<<< sdmv50xx.c.orig ======= ATAobs = (1<<1 | 1<<2 | 1<<4), >>>>>>> sdmv50xx.c ATAeIEN = (1<<1), <<<<<<< sdmv50xx.c.orig ATAsrst = (1<<2), ATAhob = (1<<7), ======= ATAsrst = (1<<2), ATAhob = (1<<7), ATAbad = (ATAbusy|ATAdf|ATAdrq|ATAerr), >>>>>>> sdmv50xx.c <<<<<<< sdmv50xx.c.orig SFdone = (1<<0), SFerror = (1<<1), ======= SFdone = (1<<0), SFerror = (1<<1), >>>>>>> sdmv50xx.c <<<<<<< sdmv50xx.c.orig SRBident = 0, ======= SRBident = 0, >>>>>>> sdmv50xx.c SRBread, SRBwrite, SRBsmart, SRBnodata = 0, SRBdatain, SRBdataout, <<<<<<< sdmv50xx.c.orig RQread = 1, /* data coming IN from device */ PRDeot = (1<<15), ======= RQread = 1, /* data coming IN from device */ PRDeot = (1<<15), >>>>>>> sdmv50xx.c /* EDMA interrupt error cause register */ ePrtDataErr = (1<<0), ePrtPRDErr = (1<<1), eDevErr = (1<<2), <<<<<<< sdmv50xx.c.orig eDevDis = (1<<3), eDevCon = (1<<4), eOverrun = (1<<5), ======= eDevDis = (1<<3), eDevCon = (1<<4), eOverrun = (1<<5), >>>>>>> sdmv50xx.c eUnderrun = (1<<6), eSelfDis = (1<<8), ePrtCRQBErr = (1<<9), ePrtCRPBErr = (1<<10), <<<<<<< sdmv50xx.c.orig ePrtIntErr = (1<<11), eIORdyErr = (1<<12), ======= ePrtIntErr = (1<<11), eIORdyErr = (1<<12), // flags for sata 2 version eSelfDis2 = (1<<7), SerrInt = (1<<5), >>>>>>> sdmv50xx.c /* EDMA Command Register */ <<<<<<< sdmv50xx.c.orig eEnEDMA = (1<<0), ======= eEnEDMA = (1<<0), >>>>>>> sdmv50xx.c eDsEDMA = (1<<1), eAtaRst = (1<<2), /* Interrupt mask for errors we care about */ <<<<<<< sdmv50xx.c.orig IEM = (eDevDis | eDevCon | eSelfDis), Dnull = 0, ======= IEM = (eDevDis | eDevCon | eSelfDis), IEM2 = (eDevDis | eDevCon | eSelfDis2), /* drive states */ Dnull = 0, >>>>>>> sdmv50xx.c Dnew, <<<<<<< sdmv50xx.c.orig Dident, ======= >>>>>>> sdmv50xx.c Dready, Derror, Dmissing, <<<<<<< sdmv50xx.c.orig Dunconfig, ======= Dreset, Dlast, /* drive flags */ Dext = (1<<0), /* use ext commands */ Dpio = (1<<1), /* doing pio */ Dwanted = (1<<2), /* someone wants an srb entry */ Dedma = (1<<3), /* device in edma mode */ Dpiowant = (1<<4), /* some wants to use the pio mode */ // phyerrata magic crap Mpreamp = 0x7e0, Dpreamp = 0x720, REV60X1B2 = 0x7, REV60X1C0 = 0x9, >>>>>>> sdmv50xx.c <<<<<<< sdmv50xx.c.orig Dext = (1<<0), /* use ext commands */ Dpio = (1<<1), /* doing pio */ Dwanted = (1<<2), /* someone wants an srb entry */ Dedma = (1<<3), /* device in edma mode */ Dpiowant = (1<<4), /* some wants to use the pio mode */ ======= >>>>>>> sdmv50xx.c }; <<<<<<< sdmv50xx.c.orig static char* diskstates[] = { ======= static char* diskstates[Dlast] = { >>>>>>> sdmv50xx.c "null", "new", <<<<<<< sdmv50xx.c.orig "ident", ======= >>>>>>> sdmv50xx.c "ready", "error", "missing", <<<<<<< sdmv50xx.c.orig "unconfigured", ======= "reset", >>>>>>> sdmv50xx.c }; extern SDifc sdmv50xxifc; typedef struct Arb Arb; typedef struct Bridge Bridge; typedef struct Chip Chip; typedef struct Ctlr Ctlr; typedef struct Drive Drive; typedef struct Edma Edma; typedef struct Prd Prd; typedef struct Rx Rx; typedef struct Srb Srb; typedef struct Tx Tx; <<<<<<< sdmv50xx.c.orig struct Chip /* pointers to per-Chip mmio */ ======= // there are 4 drives per chip. thus an 8-port // card has two chips. struct Chip >>>>>>> sdmv50xx.c { <<<<<<< sdmv50xx.c.orig Arb *arb; Edma *edma; /* array of 4 */ ======= Arb *arb; Edma *edma; }; enum{ DMautoneg, DMsatai, DMsataii, >>>>>>> sdmv50xx.c }; <<<<<<< sdmv50xx.c.orig struct Drive /* a single disk */ ======= struct Drive >>>>>>> sdmv50xx.c { Lock; <<<<<<< sdmv50xx.c.orig Ctlr *ctlr; ======= Ctlr *ctlr; >>>>>>> sdmv50xx.c SDunit *unit; <<<<<<< sdmv50xx.c.orig int subno; char name[10]; ======= char name[10]; ulong magic; >>>>>>> sdmv50xx.c Bridge *bridge; Edma *edma; <<<<<<< sdmv50xx.c.orig Chip *chip; int chipx; int state; int flag; uvlong sectors; ======= Chip *chip; int chipx; >>>>>>> sdmv50xx.c <<<<<<< sdmv50xx.c.orig char serial[20+1]; char firmware[8+1]; char model[40+1]; ======= int mediachange; int state; int flag; uvlong sectors; ulong pm2; // phymode 2 init state ulong intick; // check for hung westerdigital drives. int wait; int mode; // DMautoneg, satai or sataii. char serial[20+1]; char firmware[8+1]; char model[40+1]; >>>>>>> sdmv50xx.c ushort info[256]; <<<<<<< sdmv50xx.c.orig Srb *srb[SrbRing-1]; int nsrb; Prd *prd; Tx *tx; Rx *rx; Srb *srbhead; Srb *srbtail; ======= Srb *srb[SrbRing-1]; int nsrb; Prd *prd; Tx *tx; Rx *rx; Srb *srbhead; Srb *srbtail; int driveno; // ctlr*NCtlrdrv + unit >>>>>>> sdmv50xx.c }; <<<<<<< sdmv50xx.c.orig struct Ctlr /* a single PCI card */ ======= struct Ctlr >>>>>>> sdmv50xx.c { Lock; <<<<<<< sdmv50xx.c.orig int irq; int tbdf; SDev *sdev; ======= int irq; int tbdf; int rid; ulong magic; int enabled; int type; SDev *sdev; >>>>>>> sdmv50xx.c Pcidev *pcidev; uchar *mmio; <<<<<<< sdmv50xx.c.orig Chip chip[2]; int nchip; Drive drive[8]; int ndrive; ======= ulong *lmmio; Chip chip[2]; int nchip; Drive drive[NCtlrdrv]; int ndrive; >>>>>>> sdmv50xx.c }; <<<<<<< sdmv50xx.c.orig struct Srb /* request buffer */ ======= struct Srb /* request buffer */ >>>>>>> sdmv50xx.c { Lock; Rendez; <<<<<<< sdmv50xx.c.orig Srb *next; ======= Srb *next; >>>>>>> sdmv50xx.c Drive *drive; uvlong blockno; <<<<<<< sdmv50xx.c.orig int count; int req; int flag; ======= int count; int req; int flag; >>>>>>> sdmv50xx.c uchar *data; <<<<<<< sdmv50xx.c.orig ======= >>>>>>> sdmv50xx.c uchar cmd; uchar lba[6]; uchar sectors; <<<<<<< sdmv50xx.c.orig int sta; int err; ======= int sta; int err; >>>>>>> sdmv50xx.c }; /* * Memory-mapped I/O registers in many forms. */ <<<<<<< sdmv50xx.c.orig struct Bridge /* memory-mapped per-Drive registers */ ======= struct Bridge /* memory-mapped per-Drive registers */ >>>>>>> sdmv50xx.c { ulong status; ulong serror; ulong sctrl; ulong phyctrl; <<<<<<< sdmv50xx.c.orig char fill1[0x2c]; ======= ulong phymode3; ulong phymode4; uchar fill0[0x14]; ulong phymode1; ulong phymode2; char fill1[8]; >>>>>>> sdmv50xx.c ulong ctrl; <<<<<<< sdmv50xx.c.orig char fill2[0x34]; ======= char fill2[0x34]; >>>>>>> sdmv50xx.c ulong phymode; <<<<<<< sdmv50xx.c.orig char fill3[0x88]; /* pad to 0x100 in length */ }; ======= char fill3[0x88]; }; // most be 0x100 hex in length >>>>>>> sdmv50xx.c <<<<<<< sdmv50xx.c.orig struct Arb /* memory-mapped per-Chip registers */ ======= struct Arb /* memory-mapped per-Chip registers */ >>>>>>> sdmv50xx.c { <<<<<<< sdmv50xx.c.orig ulong fill0; ulong rqop; /* request queue out-pointer */ ======= ulong config; /* satahc configuration register (sata2 only) */ ulong rqop; /* request queue out-pointer */ >>>>>>> sdmv50xx.c ulong rqip; /* response queue in pointer */ ulong ict; /* inerrupt caolescing threshold */ ulong itt; /* interrupt timer threshold */ ulong ic; /* interrupt cause */ ulong btc; /* bridges test control */ ulong bts; /* bridges test status */ ulong bpc; /* bridges pin configuration */ <<<<<<< sdmv50xx.c.orig char fill1[0xdc]; ======= char fill1[0xdc]; >>>>>>> sdmv50xx.c Bridge bridge[4]; }; <<<<<<< sdmv50xx.c.orig struct Edma /* memory-mapped per-Drive DMA-related registers */ ======= struct Edma /* memory-mapped per-Drive DMA-related registers */ >>>>>>> sdmv50xx.c { <<<<<<< sdmv50xx.c.orig ulong config; /* configuration register */ ulong timer; ulong iec; /* interrupt error cause */ ulong iem; /* interrupt error mask */ ulong txbasehi; /* request queue base address high */ ulong txi; /* request queue in pointer */ ulong txo; /* request queue out pointer */ ulong rxbasehi; /* response queue base address high */ ulong rxi; /* response queue in pointer */ ulong rxo; /* response queue out pointer */ ulong ctl; /* command register */ ulong testctl; /* test control */ ulong status; ulong iordyto; /* IORDY timeout */ char fill[0xc8]; ushort pio; /* data register */ char pad0[2]; uchar err; /* features and error */ char pad1[3]; uchar seccnt; /* sector count */ char pad2[3]; uchar lba0; char pad3[3]; uchar lba1; char pad4[3]; uchar lba2; char pad5[3]; uchar lba3; char pad6[3]; uchar cmdstat; /* cmd/status */ char pad7[3]; uchar altstat; /* alternate status */ char fill2[0x1edc]; /* pad to 0x2000 bytes */ ======= ulong config; /* configuration register */ ulong timer; ulong iec; /* interrupt error cause */ ulong iem; /* interrupt error mask */ ulong txbasehi; /* request queue base address high */ ulong txi; /* request queue in pointer */ ulong txo; /* request queue out pointer */ ulong rxbasehi; /* response queue base address high */ ulong rxi; /* response queue in pointer */ ulong rxo; /* response queue out pointer */ ulong ctl; /* command register */ ulong testctl; /* test control */ ulong status; ulong iordyto; /* IORDY timeout */ char fill[0x18]; ulong sataconfig; /* sata 2 */ char fill[0xac]; ushort pio; /* data register */ char pad0[2]; uchar err; /* features and error */ char pad1[3]; uchar seccnt; /* sector count */ char pad2[3]; uchar lba0; char pad3[3]; uchar lba1; char pad4[3]; uchar lba2; char pad5[3]; uchar lba3; char pad6[3]; uchar cmdstat; /* cmd/status */ char pad7[3]; uchar altstat; /* alternate status */ uchar fill2[0x1df]; Bridge port; char fill3[0x1c00]; /* pad to 0x2000 bytes */ >>>>>>> sdmv50xx.c }; /* * Memory structures shared with card. */ <<<<<<< sdmv50xx.c.orig struct Prd /* physical region descriptor */ ======= struct Prd /* physical region descriptor */ >>>>>>> sdmv50xx.c { ulong pa; /* byte address of physical memory */ ushort count; /* byte count (bit0 must be 0) */ ushort flag; <<<<<<< sdmv50xx.c.orig ulong zero; /* high long of 64 bit address */ ======= ulong zero; /* high long of 64 bit address */ >>>>>>> sdmv50xx.c ulong reserved; }; <<<<<<< sdmv50xx.c.orig struct Tx /* command request block */ ======= struct Tx /* command request block */ >>>>>>> sdmv50xx.c { ulong prdpa; /* physical region descriptor table structures */ <<<<<<< sdmv50xx.c.orig ulong zero; /* must be zero (high long of prd address) */ ushort flag; /* control flags */ ======= ulong zero; /* must be zero (high long of prd address) */ ushort flag; /* control flags */ >>>>>>> sdmv50xx.c ushort regs[11]; }; <<<<<<< sdmv50xx.c.orig struct Rx /* command response block */ ======= struct Rx /* command response block */ >>>>>>> sdmv50xx.c { <<<<<<< sdmv50xx.c.orig ushort cid; /* cID of response */ uchar cEdmaSts; /* EDMA status */ ======= ushort cid; /* cID of response */ uchar cEdmaSts; /* EDMA status */ >>>>>>> sdmv50xx.c uchar cDevSts; /* status from disk */ <<<<<<< sdmv50xx.c.orig ulong ts; /* time stamp */ ======= ulong ts; /* time stamp */ >>>>>>> sdmv50xx.c }; <<<<<<< /sys/src/9/pc/sdmv50xx.c static Drive *mvsatadrive[NDrive]; static int nmvsatadrive; ||||||| sdmv50xx.c.orig ======= static Ctlr *mvsatactlr[NCtlr]; static Drive *mvsatadrive[NDrive]; static int nmvsatadrive; >>>>>>> sdmv50xx.c /* * Little-endian parsing for drive data. */ static ushort lhgets(void *p) { uchar *a = p; return ((ushort) a[1] << 8) | a[0]; } static ulong lhgetl(void *p) { uchar *a = p; return ((ulong) lhgets(a+2) << 16) | lhgets(a); } static uvlong lhgetv(void *p) { uchar *a = p; return ((uvlong) lhgetl(a+4) << 32) | lhgetl(a); } static void idmove(char *p, ushort *a, int n) { char *op; int i; op = p; for(i=0; i>8; *p++ = a[i]; } while(p>op && *--p == ' ') *p = 0; } /* * Request buffers. */ struct { Lock; Srb *freechain; int nalloc; } srblist; static Srb* allocsrb(void) { Srb *p; ilock(&srblist); if((p = srblist.freechain) == nil){ srblist.nalloc++; iunlock(&srblist); p = smalloc(sizeof *p); }else{ srblist.freechain = p->next; iunlock(&srblist); } return p; } static void freesrb(Srb *p) { ilock(&srblist); p->next = srblist.freechain; srblist.freechain = p; iunlock(&srblist); } /* * Wait for a byte to be a particular value. */ static int satawait(uchar *p, uchar mask, uchar v, int ms) { int i; <<<<<<< sdmv50xx.c.orig // DPRINT("satawait %p %#x %#x %d...", p, mask, v, ms); // DPRINT("!%#x...", *p); for(i=0; i>>>>>> sdmv50xx.c microdelay(1000); <<<<<<< sdmv50xx.c.orig } ======= >>>>>>> sdmv50xx.c return (*p & mask) == v; } /* * Drive initialization */ <<<<<<< sdmv50xx.c.orig static int configdrive(Ctlr *ctlr, Drive *d, SDunit *unit) ======= // unmask in the pci registers err done static void unmask(ulong *mmio, int port, int coal) { port &= 7; if(coal) coal = 1; if (port < 4) mmio[0x1d64/4] |= (3 << (((port&3)*2)) | (coal<<8)); else mmio[0x1d64/4] |= (3 << (((port&3)*2+9)) | (coal<<17)); } static void mask(ulong *mmio, int port, int coal) { port &= 7; if(coal) coal = 1; if (port < 4) mmio[0x1d64/4] &= ~(3 << (((port&3)*2)) | (coal<<8)); else mmio[0x1d64/4] &= ~(3 << (((port&3)*2+9)) | (coal<<17)); } /* I give up, marvell. You win. */ static void phyerrata(Drive *d) { ulong n, m; enum { BadAutoCal = 0xf << 26, }; if (d->ctlr->type == 1) return; microdelay(200); n = d->bridge->phymode2; while ((n & BadAutoCal) == BadAutoCal) { dprint("%s: badautocal\n", d->unit->name); n &= ~(1<<16); n |= (1<<31); d->bridge->phymode2 = n; microdelay(200); d->bridge->phymode2 &= ~((1<<16) | (1<<31)); microdelay(200); n = d->bridge->phymode2; } n &= ~(1<<31); d->bridge->phymode2 = n; microdelay(200); /* abra cadabra! (random magic) */ m = d->bridge->phymode3; m &= ~0x7f800000; m |= 0x2a800000; d->bridge->phymode3 = m; /* fix phy mode 4 */ m = d->bridge->phymode3; n = d->bridge->phymode4; n &= ~(1<<1); n |= 1; switch(d->ctlr->rid){ case REV60X1B2: default: d->bridge->phymode4 = n; d->bridge->phymode3 = m; break; case REV60X1C0: d->bridge->phymode4 = n; break; } /* revert values of pre-emphasis and signal amps to the saved ones */ n = d->bridge->phymode2; n &= ~Mpreamp; n |= d->pm2; n &= ~(1<<16); d->bridge->phymode2 = n; } static void edmacleanout(Drive *d) >>>>>>> sdmv50xx.c { int i; <<<<<<< sdmv50xx.c.orig ulong *r; DPRINT("%s: configdrive\n", unit->name); d->unit = unit; d->ctlr = ctlr; d->chipx = unit->subno%4; d->chip = &ctlr->chip[unit->subno/4]; d->bridge = &d->chip->arb->bridge[d->chipx]; d->edma = &d->chip->edma[d->chipx]; if(d->tx == nil){ d->tx = mallocalign(32*sizeof(Tx), 1024, 0, 0); d->rx = mallocalign(32*sizeof(Rx), 256, 0, 0); d->prd = mallocalign(32*sizeof(Prd), 32, 0, 0); if(d->tx == nil || d->rx == nil || d->prd == nil){ iprint("%s: out of memory allocating ring buffers\n", unit->name); free(d->tx); d->tx = nil; free(d->rx); d->rx = nil; free(d->prd); d->prd = nil; d->state = Dunconfig; return 0; ======= Srb *srb; for(i=0; isrb); i++){ if(srb = d->srb[i]){ d->srb[i] = nil; d->nsrb--; srb->flag |= SFerror|SFdone; wakeup(srb); >>>>>>> sdmv50xx.c } <<<<<<< sdmv50xx.c.orig for(i=0; i<32; i++) d->tx[i].prdpa = PADDR(&d->prd[i]); coherence(); ======= >>>>>>> sdmv50xx.c } <<<<<<< sdmv50xx.c.orig /* leave disk interrupts turned off until we use it ... */ d->edma->iem = 0; /* ... but enable them on the controller */ r = (ulong*)(d->ctlr->mmio + 0x1D64); if(d->unit->subno < 4) *r |= 3 << (d->chipx*2); else *r |= 3 << (d->chipx*2+9); ======= while(srb = d->srbhead){ d->srbhead = srb->next; srb->flag |= SFerror|SFdone; wakeup(srb); } } >>>>>>> sdmv50xx.c <<<<<<< /sys/src/9/pc/sdmv50xx.c static void resetdisk(Drive *d) { ulong n; d->sectors = 0; d->unit->sectors = 0; if (d->ctlr->type == 2) { // without bit 8 we can boot without disks, but // inserted disks will never appear. :-X n = d->edma->sataconfig; n &= 0xff; n |= 0x9b1100; d->edma->sataconfig = n; n = d->edma->sataconfig; //flush USED(n); } d->edma->ctl = eDsEDMA; microdelay(1); d->edma->ctl = eAtaRst; microdelay(25); d->edma->ctl = 0; if (satawait((uchar *)&d->edma->ctl, eEnEDMA, 0, 3*1000) == 0) print("%s: eEnEDMA never cleared on reset\n", d->unit->name); edmacleanout(d); phyerrata(d); d->bridge->sctrl = 0x301 | (d->mode << 4); d->state = Dmissing; } static void edmainit(Drive *d) { int i; if(d->tx != nil) return; d->tx = xspanalloc(32*sizeof(Tx), 1024, 0); d->rx = xspanalloc(32*sizeof(Rx), 256, 0); d->prd = xspanalloc(32*sizeof(Prd), 32, 0); for(i = 0; i < 32; i++) d->tx[i].prdpa = PADDR(&d->prd[i]); coherence(); } static int configdrive(Ctlr *ctlr, Drive *d, SDunit *unit) { dprint("%s: configdrive\n", unit->name); if(d->driveno < 0) panic("mv50xx: configdrive: unset driveno\n"); d->unit = unit; edmainit(d); d->mode = DMsatai; if(d->ctlr->type == 1){ d->edma->iem = IEM; d->bridge = &d->chip->arb->bridge[d->chipx]; }else{ d->edma->iem = IEM2; d->bridge = &d->chip->edma[d->chipx].port; d->edma->iem = ~(1<<6); d->pm2 = Dpreamp; if(d->ctlr->lmmio[0x180d8/4] & 1) d->pm2 = d->bridge->phymode2 & Mpreamp; } resetdisk(d); unmask(ctlr->lmmio, d->driveno, 0); delay(100); if(d->bridge->status){ dprint("%s: configdrive: found drive %lx\n", unit->name, d->bridge->status); return 0; } return -1; ||||||| sdmv50xx.c.orig return 1; ======= static void resetdisk(Drive *d) { ulong n; d->sectors = 0; d->unit->sectors = 0; if (d->ctlr->type == 2) { // without bit 8 we can boot without disks, but // inserted disks will never appear. :-X n = d->edma->sataconfig; n &= 0xff; n |= 0x9b1100; d->edma->sataconfig = n; n = d->edma->sataconfig; //flush USED(n); } d->edma->ctl = eDsEDMA; microdelay(1); d->edma->ctl = eAtaRst; microdelay(25); d->edma->ctl = 0; if (satawait((uchar *)&d->edma->ctl, eEnEDMA, 0, 3*1000) == 0) print("%s: eEnEDMA never cleared on reset\n", d->unit->name); edmacleanout(d); phyerrata(d); d->bridge->sctrl = 0x301 | (d->mode << 4); d->state = Dmissing; } static void edmainit(Drive *d) { int i; if(d->tx != nil) return; d->tx = xspanalloc(32*sizeof(Tx), 1024, 0); d->rx = xspanalloc(32*sizeof(Rx), 256, 0); d->prd = xspanalloc(32*sizeof(Prd), 32, 0); for(i = 0; i < 32; i++) d->tx[i].prdpa = PADDR(&d->prd[i]); coherence(); } static int configdrive(Ctlr *ctlr, Drive *d, SDunit *unit) { Rendez r; dprint("%s: configdrive\n", unit->name); if (d->driveno < 0) panic("mv50xx: configdrive: unset driveno\n"); d->unit = unit; edmainit(d); d->mode = DMsatai; if(d->ctlr->type == 1){ d->edma->iem = IEM; d->bridge = &d->chip->arb->bridge[d->chipx]; }else{ d->edma->iem = IEM2; d->bridge = &d->chip->edma[d->chipx].port; d->edma->iem = ~(1<<6); d->pm2 = Dpreamp; if(d->ctlr->lmmio[0x180d8/4] & 1) d->pm2 = d->bridge->phymode2 & Mpreamp; } resetdisk(d); unmask(ctlr->lmmio, d->driveno, 0); delay(100); if(d->bridge->status){ dprint("%s: configdrive: found drive %lx\n", unit->name, d->bridge->status); memset(&r, 0, sizeof r); tsleep(&r, return0, 0, 1400); // don't burn out the power supply. } return 0; >>>>>>> sdmv50xx.c } static int enabledrive(Drive *d) { Edma *edma; <<<<<<< sdmv50xx.c.orig DPRINT("%s: enabledrive\n", d->unit->name); ======= >>>>>>> sdmv50xx.c <<<<<<< sdmv50xx.c.orig if((d->bridge->status & 0xF) != 0x3){ /* Det */ DPRINT("%s: not present\n", d->unit->name); ======= dprint("%s: enabledrive..", d->unit->name); if((d->bridge->status & 0xf) != 3){ dprint("%s: not present\n", d->unit->name); >>>>>>> sdmv50xx.c d->state = Dmissing; <<<<<<< sdmv50xx.c.orig return 0; ======= return -1; >>>>>>> sdmv50xx.c } edma = d->edma; <<<<<<< sdmv50xx.c.orig if(satawait(&edma->cmdstat, ATAbusy, 0, 10*1000) == 0){ print("%s: busy timeout\n", d->unit->name); ======= if(satawait(&edma->cmdstat, ATAbusy, 0, 5*1000) == 0){ dprint("%s: busy timeout\n", d->unit->name); >>>>>>> sdmv50xx.c d->state = Dmissing; <<<<<<< sdmv50xx.c.orig return 0; ======= return -1; >>>>>>> sdmv50xx.c } <<<<<<< sdmv50xx.c.orig ======= >>>>>>> sdmv50xx.c edma->iec = 0; d->chip->arb->ic &= ~(0x101 << d->chipx); <<<<<<< sdmv50xx.c.orig edma->config = 0x11F; ======= edma->config = 0x51f; if (d->ctlr->type == 2) edma->config |= 7<<11; >>>>>>> sdmv50xx.c edma->txi = PADDR(d->tx); <<<<<<< sdmv50xx.c.orig edma->txo = (ulong)d->tx & 0x3E0; edma->rxi = (ulong)d->rx & 0xF8; ======= edma->txo = (ulong)d->tx & 0x3e0; edma->rxi = (ulong)d->rx & 0xf8; >>>>>>> sdmv50xx.c edma->rxo = PADDR(d->rx); edma->ctl |= 1; /* enable dma */ <<<<<<< sdmv50xx.c.orig DPRINT("%s: enable interrupts\n", d->unit->name); if(d->bridge->status = 0x113) ======= if(d->bridge->status = 0x113){ dprint("%s: new\n", d->unit->name); >>>>>>> sdmv50xx.c d->state = Dnew; <<<<<<< sdmv50xx.c.orig d->edma->iem = IEM; return 1; ======= }else print("%s: status not forced (should be okay)\n", d->unit->name); return 0; >>>>>>> sdmv50xx.c } static void disabledrive(Drive *d) { int i; ulong *r; <<<<<<< sdmv50xx.c.orig DPRINT("%s: disabledrive\n", d->unit->name); ======= dprint("%s: disabledrive\n", d->unit->name); >>>>>>> sdmv50xx.c if(d->tx == nil) /* never enabled */ return; d->edma->ctl = 0; d->edma->iem = 0; <<<<<<< sdmv50xx.c.orig r = (ulong*)(d->ctlr->mmio + 0x1D64); ======= r = (ulong*)(d->ctlr->mmio + 0x1d64); >>>>>>> sdmv50xx.c i = d->chipx; if(d->chipx < 4) *r &= ~(3 << (i*2)); else *r |= ~(3 << (i*2+9)); } static int setudmamode(Drive *d, uchar mode) { Edma *edma; <<<<<<< sdmv50xx.c.orig DPRINT("%s: setudmamode %d\n", d->unit->name, mode); ======= dprint("%s: setudmamode %d\n", d->unit->name, mode); >>>>>>> sdmv50xx.c edma = d->edma; <<<<<<< sdmv50xx.c.orig if(satawait(&edma->cmdstat, ATAerr|ATAdrq|ATAdf|ATAdrdy|ATAbusy, ATAdrdy, 15*1000) == 0){ iprint("%s: cmdstat 0x%.2ux ready timeout\n", d->unit->name, edma->cmdstat); ======= if (edma == nil) { iprint("setudamode(m%d): zero d->edma\m", d->driveno); return 0; } if(satawait(&edma->cmdstat, ~ATAobs, ATAdrdy, 9*1000) == 0){ iprint("%s: cmdstat 0x%.2ux ready timeout\n", d->unit->name, edma->cmdstat); >>>>>>> sdmv50xx.c return 0; } edma->altstat = ATAeIEN; edma->err = 3; edma->seccnt = 0x40 | mode; <<<<<<< sdmv50xx.c.orig edma->cmdstat = 0xEF; ======= edma->cmdstat = 0xef; >>>>>>> sdmv50xx.c microdelay(1); <<<<<<< sdmv50xx.c.orig if(satawait(&edma->cmdstat, ATAbusy, 0, 15*1000) == 0){ iprint("%s: cmdstat 0x%.2ux busy timeout\n", d->unit->name, edma->cmdstat); ======= if(satawait(&edma->cmdstat, ATAbusy, 0, 5*1000) == 0){ iprint("%s: cmdstat 0x%.2ux busy timeout\n", d->unit->name, edma->cmdstat); >>>>>>> sdmv50xx.c return 0; } return 1; } <<<<<<< sdmv50xx.c.orig static void ======= static int >>>>>>> sdmv50xx.c identifydrive(Drive *d) { int i; ushort *id; Edma *edma; SDunit *unit; <<<<<<< sdmv50xx.c.orig DPRINT("%s: identifydrive\n", d->unit->name); ======= dprint("%s: identifydrive\n", d->unit->name); >>>>>>> sdmv50xx.c if(setudmamode(d, 5) == 0) /* do all SATA support 5? */ goto Error; id = d->info; memset(d->info, 0, sizeof d->info); edma = d->edma; <<<<<<< sdmv50xx.c.orig if(satawait(&edma->cmdstat, 0xE9, 0x40, 15*1000) == 0) ======= if(satawait(&edma->cmdstat, ~ATAobs, ATAdrdy, 5*1000) == 0) >>>>>>> sdmv50xx.c goto Error; edma->altstat = ATAeIEN; /* no interrupts */ <<<<<<< sdmv50xx.c.orig edma->cmdstat = 0xEC; ======= edma->cmdstat = 0xec; >>>>>>> sdmv50xx.c microdelay(1); <<<<<<< sdmv50xx.c.orig if(satawait(&edma->cmdstat, ATAbusy, 0, 15*1000) == 0) ======= if(satawait(&edma->cmdstat, ATAbusy, 0, 5*1000) == 0) >>>>>>> sdmv50xx.c goto Error; <<<<<<< sdmv50xx.c.orig for(i=0; i<256; i++) ======= for(i = 0; i < 256; i++) >>>>>>> sdmv50xx.c id[i] = edma->pio; <<<<<<< sdmv50xx.c.orig if(edma->cmdstat & (ATAerr|ATAdf)) ======= if(edma->cmdstat & ATAbad) >>>>>>> sdmv50xx.c goto Error; i = lhgets(id+83) | lhgets(id+86); if(i & (1<<10)){ d->flag |= Dext; d->sectors = lhgetv(id+100); }else{ d->flag &= ~Dext; d->sectors = lhgetl(id+60); } idmove(d->serial, id+10, 20); idmove(d->firmware, id+23, 8); idmove(d->model, id+27, 40); <<<<<<< sdmv50xx.c.orig ======= >>>>>>> sdmv50xx.c unit = d->unit; memset(unit->inquiry, 0, sizeof unit->inquiry); unit->inquiry[2] = 2; unit->inquiry[3] = 2; unit->inquiry[4] = sizeof(unit->inquiry)-4; idmove((char*)unit->inquiry+8, id+27, 40); <<<<<<< sdmv50xx.c.orig if(enabledrive(d)) ======= if(enabledrive(d) == 0) { >>>>>>> sdmv50xx.c d->state = Dready; <<<<<<< /sys/src/9/pc/sdmv50xx.c d->mediachange = 1; idprint("%s: LLBA %lld sectors\n", d->unit->name, d->sectors); } else ||||||| sdmv50xx.c.orig else ======= d->mediachange = 1; iprint("%s: LLBA %lld sectors\n", d->unit->name, d->sectors); } else >>>>>>> sdmv50xx.c d->state = Derror; <<<<<<< sdmv50xx.c.orig return; ======= if(d->state == Dready) return 0; return -1; >>>>>>> sdmv50xx.c Error: <<<<<<< sdmv50xx.c.orig DPRINT("error..."); ======= dprint("error..."); >>>>>>> sdmv50xx.c d->state = Derror; <<<<<<< sdmv50xx.c.orig ======= return -1; } /* p. 163: M recovered error P protocol error N PhyRdy change W CommWake B 8-to-10 encoding error D disparity error C crc error H handshake error S link sequence error T transport state transition error F unrecognized fis type X device changed */ static char stab[] = { [1] 'M', [10] 'P', [16] 'N', [18] 'W', 'B', 'D', 'C', 'H', 'S', 'T', 'F', 'X' }; static ulong sbad = (7<<20)|(3<<23); static void serrdecode(ulong r, char *s, char *e) { int i; e -= 3; for(i = 0; i < nelem(stab) && s < e; i++){ if((r&(1<>>>>>> sdmv50xx.c } <<<<<<< sdmv50xx.c.orig static void abortallsrb(Drive*); ======= char *iectab[] = { "ePrtDataErr", "ePrtPRDErr", "eDevErr", "eDevDis", "eDevCon", "SerrInt", "eUnderrun", "eSelfDis2", "eSelfDis", "ePrtCRQBErr", "ePrtCRPBErr", "ePrtIntErr", "eIORdyErr", }; static char* iecdecode(ulong cause) { int i; for(i = 0; i < nelem(iectab); i++) if(cause&(1<>>>>>> sdmv50xx.c static void <<<<<<< sdmv50xx.c.orig updatedrive(Drive *d, ulong cause) ======= updatedrive(Drive *d) >>>>>>> sdmv50xx.c { int x; <<<<<<< sdmv50xx.c.orig ======= ulong cause; >>>>>>> sdmv50xx.c Edma *edma; <<<<<<< sdmv50xx.c.orig if(cause == 0) return; DPRINT("%s: updatedrive %#lux\n", d->unit->name, cause); ======= char buf[32+4+1]; >>>>>>> sdmv50xx.c edma = d->edma; <<<<<<< sdmv50xx.c.orig if(cause & eDevDis){ d->state = Dmissing; edma->ctl |= eAtaRst; microdelay(25); edma->ctl &= ~eAtaRst; microdelay(25); ======= if((edma->ctl&eEnEDMA) == 0){ // FEr SATA#4 40xx x = d->edma->cmdstat; USED(x); >>>>>>> sdmv50xx.c } <<<<<<< sdmv50xx.c.orig if(cause & eDevCon){ d->bridge->sctrl = (d->bridge->sctrl & ~0xF) | 1; ======= cause = edma->iec; if(cause == 0) return; dprint("%s: cause %08ulx [%s]\n", d->unit->name, cause, iecdecode(cause)); if(cause & eDevCon) >>>>>>> sdmv50xx.c d->state = Dnew; <<<<<<< sdmv50xx.c.orig ======= if(cause&eDevDis && d->state == Dready) iprint("%s: pulled: st=%08ulx\n", d->unit->name, cause); switch(d->ctlr->type){ case 1: if(cause&eSelfDis) d->state = Derror; break; case 2: if(cause&Cerror) d->state = Derror; if(cause&SerrInt){ serrdecode(d->bridge->serror, buf, buf+sizeof buf); dprint("%s: serror %08ulx [%s]\n", d->unit->name, (ulong)d->bridge->serror, buf); d->bridge->serror = d->bridge->serror; } >>>>>>> sdmv50xx.c } <<<<<<< sdmv50xx.c.orig if(cause & eSelfDis) d->state = Derror; edma->iec = 0; d->sectors = 0; d->unit->sectors = 0; abortallsrb(d); x = edma->cmdstat; USED(x); ======= edma->iec = ~cause; >>>>>>> sdmv50xx.c } /* * Requests */ static Srb* srbrw(int req, Drive *d, uchar *data, uint sectors, uvlong lba) { int i; Srb *srb; static uchar cmd[2][2] = { 0xC8, 0x25, 0xCA, 0x35 }; <<<<<<< sdmv50xx.c.orig switch(req){ case SRBread: case SRBwrite: break; default: return nil; } ======= >>>>>>> sdmv50xx.c srb = allocsrb(); srb->req = req; srb->drive = d; srb->blockno = lba; srb->sectors = sectors; srb->count = sectors*512; srb->flag = 0; srb->data = data; for(i=0; i<6; i++) srb->lba[i] = lba >> (8*i); srb->cmd = cmd[srb->req!=SRBread][(d->flag&Dext)!=0]; return srb; } static uintptr advance(uintptr pa, int shift) { int n, mask; <<<<<<< sdmv50xx.c.orig ======= >>>>>>> sdmv50xx.c mask = 0x1F<>>>>>> sdmv50xx.c { *cmd++ = CMD(ARseccnt, 0); *cmd++ = CMD(ARseccnt, srb->sectors); *cmd++ = CMD(ARfea, 0); if(ext){ *cmd++ = CMD(ARlba0, srb->lba[3]); *cmd++ = CMD(ARlba0, srb->lba[0]); *cmd++ = CMD(ARlba1, srb->lba[4]); *cmd++ = CMD(ARlba1, srb->lba[1]); *cmd++ = CMD(ARlba2, srb->lba[5]); *cmd++ = CMD(ARlba2, srb->lba[2]); <<<<<<< sdmv50xx.c.orig *cmd++ = CMD(ARdev, 0xE0); ======= *cmd++ = CMD(ARdev, 0xe0); >>>>>>> sdmv50xx.c }else{ *cmd++ = CMD(ARlba0, srb->lba[0]); *cmd++ = CMD(ARlba1, srb->lba[1]); *cmd++ = CMD(ARlba2, srb->lba[2]); <<<<<<< sdmv50xx.c.orig *cmd++ = CMD(ARdev, srb->lba[3] | 0xE0); ======= *cmd++ = CMD(ARdev, srb->lba[3] | 0xe0); >>>>>>> sdmv50xx.c } <<<<<<< sdmv50xx.c.orig *cmd++ = CMD(ARcmd, srb->cmd) | (1<<15); USED(cmd); ======= *cmd = CMD(ARcmd, srb->cmd) | (1<<15); >>>>>>> sdmv50xx.c } static void startsrb(Drive *d, Srb *srb) { int i; Edma *edma; Prd *prd; Tx *tx; <<<<<<< sdmv50xx.c.orig ======= >>>>>>> sdmv50xx.c if(d->nsrb >= nelem(d->srb)){ srb->next = nil; if(d->srbhead) d->srbtail->next = srb; else d->srbhead = srb; d->srbtail = srb; return; } <<<<<<< sdmv50xx.c.orig ======= >>>>>>> sdmv50xx.c d->nsrb++; for(i=0; isrb); i++) if(d->srb[i] == nil) break; if(i == nelem(d->srb)) panic("sdmv50xx: no free srbs"); <<<<<<< sdmv50xx.c.orig ======= d->intick = MACHP(0)->ticks; >>>>>>> sdmv50xx.c d->srb[i] = srb; edma = d->edma; tx = (Tx*)KADDR(edma->txi); tx->flag = (i<<1) | (srb->req == SRBread); prd = KADDR(tx->prdpa); prd->pa = PADDR(srb->data); prd->count = srb->count; prd->flag = PRDeot; <<<<<<< sdmv50xx.c.orig atarequest(tx->regs, srb, d->flag&Dext); ======= mvsatarequest(tx->regs, srb, d->flag&Dext); >>>>>>> sdmv50xx.c coherence(); edma->txi = advance(edma->txi, 5); <<<<<<< sdmv50xx.c.orig ======= d->intick = MACHP(0)->ticks; >>>>>>> sdmv50xx.c } <<<<<<< sdmv50xx.c.orig ======= enum{ Rpidx = 0x1f<<3, }; >>>>>>> sdmv50xx.c static void completesrb(Drive *d) { Edma *edma; Rx *rx; Srb *srb; <<<<<<< sdmv50xx.c.orig ======= >>>>>>> sdmv50xx.c edma = d->edma; if((edma->ctl & eEnEDMA) == 0) return; <<<<<<< sdmv50xx.c.orig while((edma->rxo & (0x1F<<3)) != (edma->rxi & (0x1F<<3))){ ======= while((edma->rxo&Rpidx) != (edma->rxi&Rpidx)){ >>>>>>> sdmv50xx.c rx = (Rx*)KADDR(edma->rxo); if(srb = d->srb[rx->cid]){ d->srb[rx->cid] = nil; d->nsrb--; <<<<<<< sdmv50xx.c.orig if(rx->cDevSts & (ATAerr|ATAdf)) ======= if(rx->cDevSts & ATAbad) >>>>>>> sdmv50xx.c srb->flag |= SFerror; <<<<<<< sdmv50xx.c.orig srb->flag |= SFdone; ======= if (rx->cEdmaSts) iprint("cEdmaSts: %02ux\n", rx->cEdmaSts); >>>>>>> sdmv50xx.c srb->sta = rx->cDevSts; <<<<<<< sdmv50xx.c.orig ======= srb->flag |= SFdone; >>>>>>> sdmv50xx.c wakeup(srb); }else iprint("srb missing\n"); edma->rxo = advance(edma->rxo, 3); if(srb = d->srbhead){ d->srbhead = srb->next; startsrb(d, srb); } } } <<<<<<< sdmv50xx.c.orig static void abortallsrb(Drive *d) { int i; Srb *srb; for(i=0; isrb); i++){ if(srb = d->srb[i]){ d->srb[i] = nil; d->nsrb--; srb->flag |= SFerror|SFdone; wakeup(srb); } } while(srb = d->srbhead){ d->srbhead = srb->next; srb->flag |= SFerror|SFdone; wakeup(srb); } } ======= >>>>>>> sdmv50xx.c static int srbdone(void *v) { Srb *srb; <<<<<<< sdmv50xx.c.orig ======= >>>>>>> sdmv50xx.c srb = v; return srb->flag & SFdone; } /* * Interrupts */ static void mv50interrupt(Ureg*, void *a) { int i; ulong cause; Ctlr *ctlr; Drive *drive; <<<<<<< sdmv50xx.c.orig ======= >>>>>>> sdmv50xx.c ctlr = a; ilock(ctlr); <<<<<<< sdmv50xx.c.orig cause = *(ulong*)(ctlr->mmio + 0x1D60); DPRINT("sd%c: mv50interrupt: 0x%lux\n", ctlr->sdev->idno, cause); for(i=0; indrive; i++){ ======= cause = ctlr->lmmio[0x1d60/4]; // dprint("sd%c: mv50interrupt: 0x%lux\n", ctlr->sdev->idno, cause); for(i=0; indrive; i++) >>>>>>> sdmv50xx.c if(cause & (3<<(i*2+i/4))){ drive = &ctlr->drive[i]; <<<<<<< sdmv50xx.c.orig if(drive->edma == nil) continue; /* not ready yet */ ======= if(drive->edma == 0) continue; // not ready yet. >>>>>>> sdmv50xx.c ilock(drive); <<<<<<< sdmv50xx.c.orig updatedrive(drive, drive->edma->iec); ======= updatedrive(drive); >>>>>>> sdmv50xx.c while(ctlr->chip[i/4].arb->ic & (0x0101 << (i%4))){ ctlr->chip[i/4].arb->ic = ~(0x101 << (i%4)); completesrb(drive); } iunlock(drive); } <<<<<<< sdmv50xx.c.orig } ======= >>>>>>> sdmv50xx.c iunlock(ctlr); } <<<<<<< /sys/src/9/pc/sdmv50xx.c enum{ Nms = 256, Midwait = 16*1024/Nms-1, Mphywait = 512/Nms-1, }; static void westerndigitalhung(Drive *d) { Edma *e; e = d->edma; if(d->srb && TK2MS(MACHP(0)->ticks-d->intick) > 5*1000 && (e->rxo&Rpidx) == (e->rxi&Rpidx)){ dprint("westerndigital drive hung; resetting\n"); d->state = Dreset; } } static void checkdrive(Drive *d, int i) { static ulong s, olds[NCtlr*NCtlrdrv]; char *name; ilock(d); name = d->unit->name; s = d->bridge->status; if(s != olds[i]){ dprint("%s: status: %08lx -> %08lx: %s\n", name, olds[i], s, diskstates[d->state]); olds[i] = s; } // westerndigitalhung(d); switch(d->state){ case Dnew: case Dmissing: switch(s){ case 0x000: break; default: dprint("%s: unknown state %8lx\n", name, s); case 0x100: if(++d->wait&Mphywait) break; reset: d->mode ^= 1; dprint("%s: reset; new mode %d\n", name, d->mode); resetdisk(d); break; case 0x123: case 0x113: s = d->edma->cmdstat; if(s == 0x7f || (s&~ATAobs) != ATAdrdy){ if((++d->wait&Midwait) == 0) goto reset; }else if(identifydrive(d) == -1) goto reset; } break; case Dready: if(s != 0) break; iprint("%s: pulled: st=%08ulx\n", name, s); // never happens case Dreset: case Derror: dprint("%s reset: mode %d\n", name, d->mode); resetdisk(d); break; } iunlock(d); } static void satakproc(void*) { int i; while(waserror()) ; for(;;){ tsleep(&up->sleep, return0, 0, Nms); for(i = 0; i < nmvsatadrive; i++) checkdrive(mvsatadrive[i], i); } } ||||||| sdmv50xx.c.orig ======= enum{ Nms = 256, Midwait = 16*1024/Nms-1, Mphywait = 512/Nms-1, }; static void westerndigitalhung(Drive *d) { Edma *e; e = d->edma; if(d->srb && TK2MS(MACHP(0)->ticks-d->intick) > 5*1000 && (e->rxo&Rpidx) == (e->rxi&Rpidx)){ dprint("westerndigital drive hung; resetting\n"); d->state = Dreset; } } static void checkdrive(Drive *d, int i) { static ulong s, olds[NCtlr*NCtlrdrv]; char *name; ilock(d); name = d->unit->name; s = d->bridge->status; if(s != olds[i]){ dprint("%s: status: %08lx -> %08lx: %s\n", name, olds[i], s, diskstates[d->state]); olds[i] = s; } // westerndigitalhung(d); switch(d->state){ case Dnew: case Dmissing: switch(s){ case 0x000: break; default: dprint("%s: unknown state %8lx\n", name, s); case 0x100: if(++d->wait&Mphywait) break; reset: d->mode ^= 1; dprint("%s: reset; new mode %d\n", name, d->mode); resetdisk(d); break; case 0x123: case 0x113: s = d->edma->cmdstat; if(s == 0x7f || (s&~ATAobs) != ATAdrdy){ if((++d->wait&Midwait) == 0) goto reset; }else if(identifydrive(d) == -1) goto reset; } break; case Dready: if(s != 0) break; iprint("%s: pulled: st=%08ulx\n", name, s); // never happens case Dreset: case Derror: dprint("%s reset: mode %d\n", name, d->mode); resetdisk(d); break; } iunlock(d); } static void satakproc(void*) { int i; static Rendez r; memset(&r, 0, sizeof r); for(;;){ tsleep(&r, return0, 0, Nms); for(i = 0; i < nmvsatadrive; i++) checkdrive(mvsatadrive[i], i); } } >>>>>>> sdmv50xx.c /* * Device discovery */ static SDev* mv50pnp(void) { int i, dno, nunit; uchar *base; <<<<<<< sdmv50xx.c.orig ulong io; void *mem; ======= ulong io, n, *mem; >>>>>>> sdmv50xx.c Ctlr *ctlr; Pcidev *p; SDev *head, *tail, *sdev; <<<<<<< sdmv50xx.c.orig ======= Drive *d; static int ctlrno, done; >>>>>>> sdmv50xx.c <<<<<<< sdmv50xx.c.orig DPRINT("mv50pnp\n"); ======= dprint("mv50pnp\n"); if(done++) return nil; >>>>>>> sdmv50xx.c p = nil; head = nil; tail = nil; <<<<<<< sdmv50xx.c.orig while((p = pcimatch(p, 0x11AB, 0)) != nil){ ======= while((p = pcimatch(p, 0x11ab, 0)) != nil){ >>>>>>> sdmv50xx.c switch(p->did){ <<<<<<< sdmv50xx.c.orig ======= case 0x5040: >>>>>>> sdmv50xx.c case 0x5041: <<<<<<< sdmv50xx.c.orig nunit = 4; break; ======= case 0x5080: >>>>>>> sdmv50xx.c case 0x5081: <<<<<<< sdmv50xx.c.orig nunit = 8; ======= case 0x6041: case 0x6081: >>>>>>> sdmv50xx.c break; default: <<<<<<< sdmv50xx.c.orig ======= print("mv50pnp: unknown did %ux ignored\n", (ushort)p->did); >>>>>>> sdmv50xx.c continue; } <<<<<<< sdmv50xx.c.orig ======= if (ctlrno >= NCtlr) { print("mv50pnp: too many controllers\n"); break; } nunit = (p->did&0xf0) >> 4; print("Marvell 88SX%ux: %d SATA-%s ports with%s flash\n", (ushort)p->did, nunit, ((p->did&0xf000)==0x6000? "II": "I"), (p->did&1? "": "out")); >>>>>>> sdmv50xx.c if((sdev = malloc(sizeof(SDev))) == nil) continue; if((ctlr = malloc(sizeof(Ctlr))) == nil){ free(sdev); continue; } <<<<<<< sdmv50xx.c.orig ======= memset(sdev, 0, sizeof *sdev); memset(ctlr, 0, sizeof *ctlr); >>>>>>> sdmv50xx.c io = p->mem[0].bar & ~0x0F; <<<<<<< sdmv50xx.c.orig mem = vmap(io, p->mem[0].size); ======= mem = (ulong*)vmap(io, p->mem[0].size); >>>>>>> sdmv50xx.c if(mem == 0){ print("sdmv50xx: address 0x%luX in use\n", io); free(sdev); free(ctlr); continue; } <<<<<<< sdmv50xx.c.orig ======= ctlr->rid = p->rid; // avert thine eyes! (what does this do?) mem[0x104f0/4] = 0; ctlr->type = (p->did >> 12) & 3; if(ctlr->type == 1){ n = mem[0xc00/4]; n &= ~(3<<4); mem[0xc00/4] = n; } >>>>>>> sdmv50xx.c sdev->ifc = &sdmv50xxifc; sdev->ctlr = ctlr; sdev->nunit = nunit; sdev->idno = 'E' + ctlrno; ctlr->sdev = sdev; ctlr->irq = p->intl; ctlr->tbdf = p->tbdf; ctlr->pcidev = p; <<<<<<< sdmv50xx.c.orig ctlr->mmio = mem; ======= ctlr->lmmio = mem; ctlr->mmio = (uchar*)mem; >>>>>>> sdmv50xx.c ctlr->nchip = (nunit+3)/4; ctlr->ndrive = nunit; <<<<<<< sdmv50xx.c.orig for(i=0; inchip; i++){ ======= ctlr->enabled = 0; for(i = 0; i < ctlr->nchip; i++){ >>>>>>> sdmv50xx.c base = ctlr->mmio+0x20000+0x10000*i; ctlr->chip[i].arb = (Arb*)base; ctlr->chip[i].edma = (Edma*)(base + 0x2000); } <<<<<<< /sys/src/9/pc/sdmv50xx.c for (i = 0; i < nunit; i++) { d = &ctlr->drive[i]; d->sectors = 0; d->ctlr = ctlr; d->driveno = ctlrno*NCtlrdrv + i; d->chipx = i%4; d->chip = &ctlr->chip[i/4]; d->edma = &d->chip->edma[d->chipx]; mvsatadrive[d->driveno] = d; } nmvsatadrive += nunit; ctlrno++; ||||||| sdmv50xx.c.orig ======= for (i = 0; i < nunit; i++) { d = &ctlr->drive[i]; d->sectors = 0; d->ctlr = ctlr; d->driveno = dno = ctlrno*NCtlrdrv + i; d->chipx = dno%4; d->chip =&ctlr->chip[dno/4]; d->edma = &d->chip->edma[d->chipx]; mvsatadrive[d->driveno] = d; } mvsatactlr[ctlrno] = ctlr; nmvsatadrive += i; ctlrno++; >>>>>>> sdmv50xx.c if(head) tail->next = sdev; else head = sdev; tail = sdev; } return head; } /* * Enable the controller. Each disk has its own interrupt mask, * and those get enabled as the disks are brought online. */ static int mv50enable(SDev *sdev) { char name[32]; Ctlr *ctlr; <<<<<<< sdmv50xx.c.orig DPRINT("sd%c: enable\n", sdev->idno); ======= dprint("sd%c: enable\n", sdev->idno); >>>>>>> sdmv50xx.c ctlr = sdev->ctlr; <<<<<<< sdmv50xx.c.orig ======= if (ctlr->enabled) return 1; >>>>>>> sdmv50xx.c snprint(name, sizeof name, "%s (%s)", sdev->name, sdev->ifc->name); intrenable(ctlr->irq, mv50interrupt, ctlr, ctlr->tbdf, name); <<<<<<< sdmv50xx.c.orig ======= ctlr->enabled = 1; >>>>>>> sdmv50xx.c return 1; } /* * Disable the controller. */ static int mv50disable(SDev *sdev) { char name[32]; int i; Ctlr *ctlr; Drive *drive; <<<<<<< sdmv50xx.c.orig DPRINT("sd%c: disable\n", sdev->idno); ======= dprint("sd%c: disable\n", sdev->idno); >>>>>>> sdmv50xx.c ctlr = sdev->ctlr; ilock(ctlr); for(i=0; isdev->nunit; i++){ drive = &ctlr->drive[i]; ilock(drive); disabledrive(drive); iunlock(drive); } iunlock(ctlr); snprint(name, sizeof name, "%s (%s)", sdev->name, sdev->ifc->name); intrdisable(ctlr->irq, mv50interrupt, ctlr, ctlr->tbdf, name); return 0; } /* * Clean up all disk structures. Already disabled. * Could keep count of number of allocated controllers * and free the srblist when it drops to zero. */ static void mv50clear(SDev *sdev) { int i; Ctlr *ctlr; Drive *d; <<<<<<< sdmv50xx.c.orig DPRINT("sd%c: clear\n", sdev->idno); ======= dprint("sd%c: clear\n", sdev->idno); >>>>>>> sdmv50xx.c ctlr = sdev->ctlr; for(i=0; indrive; i++){ d = &ctlr->drive[i]; free(d->tx); free(d->rx); free(d->prd); } free(ctlr); } /* * Check that there is a disk or at least a hot swap bay in the drive. */ static int mv50verify(SDunit *unit) { Ctlr *ctlr; Drive *drive; int i; <<<<<<< sdmv50xx.c.orig DPRINT("%s: verify\n", unit->name); /* * First access of unit. */ ======= dprint("%s: verify\n", unit->name); >>>>>>> sdmv50xx.c ctlr = unit->dev->ctlr; drive = &ctlr->drive[unit->subno]; ilock(ctlr); ilock(drive); <<<<<<< /sys/src/9/pc/sdmv50xx.c i = configdrive(ctlr, drive, unit); ||||||| sdmv50xx.c.orig if(!configdrive(ctlr, drive, unit) || !enabledrive(drive)){ iunlock(drive); iunlock(ctlr); return 0; } /* * Need to reset the drive before the first call to * identifydrive, or else the satawait in setudma will * freeze the machine when accessing edma->cmdstat. * I do not understand this. -rsc */ updatedrive(drive, eDevDis); ======= configdrive(ctlr, drive, unit); >>>>>>> sdmv50xx.c iunlock(drive); iunlock(ctlr); <<<<<<< /sys/src/9/pc/sdmv50xx.c /* * If ctlr->type == 1, then the drives spin up whenever * the controller feels like it; if ctlr->type != 1, then * they spin up as a result of configdrive. * * If there is a drive in the slot, give it 1.5s to spin up * before returning. There is a noticeable drag on the * power supply when spinning up fifteen drives * all at once (like in the Coraid enclosures). */ if(ctlr->type != 1 && i == 0){ if(!waserror()){ tsleep(&up->sleep, return0, 0, 1500); poperror(); } } ||||||| sdmv50xx.c.orig ======= >>>>>>> sdmv50xx.c return 1; } /* * Check whether the disk is online. */ static int mv50online(SDunit *unit) { Ctlr *ctlr; <<<<<<< sdmv50xx.c.orig Drive *drive; ======= Drive *d; int r, s0; static int once; if(once++ == 0) kproc("mvsata", satakproc, 0); >>>>>>> sdmv50xx.c ctlr = unit->dev->ctlr; <<<<<<< /sys/src/9/pc/sdmv50xx.c d = &ctlr->drive[unit->subno]; r = 0; ilock(d); s0 = d->state; USED(s0); if(d->state == Dnew) identifydrive(d); if(d->mediachange){ idprint("%s: online: %s -> %s\n", unit->name, diskstates[s0], diskstates[d->state]); r = 2; unit->sectors = d->sectors; ||||||| sdmv50xx.c.orig drive = &ctlr->drive[unit->subno]; ilock(drive); if(drive->state == Dready){ unit->sectors = drive->sectors; ======= d = &ctlr->drive[unit->subno]; r = 0; ilock(d); s0 = d->state; if(d->state == Dnew) identifydrive(d); if(d->mediachange){ iprint("%s: online: %s -> %s\n", unit->name, diskstates[s0], diskstates[d->state]); r = 2; unit->sectors = d->sectors; >>>>>>> sdmv50xx.c unit->secsize = 512; <<<<<<< sdmv50xx.c.orig iunlock(drive); return 1; } DPRINT("%s: online %s\n", unit->name, diskstates[drive->state]); if(drive->state == Dnew){ identifydrive(drive); if(drive->state == Dready){ unit->sectors = drive->sectors; unit->secsize = 512; iunlock(drive); return 2; /* media changed */ } } iunlock(drive); return 0; ======= d->mediachange = 0; } else if(d->state == Dready) r = 1; iunlock(d); return r; >>>>>>> sdmv50xx.c } /* * Register dumps */ typedef struct Regs Regs; struct Regs { ulong offset; char *name; }; static Regs regsctlr[] = { 0x0C28, "pci serr# mask", 0x1D40, "pci err addr low", 0x1D44, "pci err addr hi", 0x1D48, "pci err attr", 0x1D50, "pci err cmd", 0x1D58, "pci intr cause", 0x1D5C, "pci mask cause", 0x1D60, "device micr", 0x1D64, "device mimr", }; static Regs regsarb[] = { 0x0004, "arb rqop", 0x0008, "arb rqip", 0x000C, "arb ict", 0x0010, "arb itt", 0x0014, "arb ic", 0x0018, "arb btc", 0x001C, "arb bts", 0x0020, "arb bpc", }; static Regs regsbridge[] = { 0x0000, "bridge status", 0x0004, "bridge serror", 0x0008, "bridge sctrl", 0x000C, "bridge phyctrl", 0x003C, "bridge ctrl", 0x0074, "bridge phymode", }; static Regs regsedma[] = { 0x0000, "edma config", 0x0004, "edma timer", 0x0008, "edma iec", 0x000C, "edma iem", 0x0010, "edma txbasehi", 0x0014, "edma txi", 0x0018, "edma txo", 0x001C, "edma rxbasehi", 0x0020, "edma rxi", 0x0024, "edma rxo", 0x0028, "edma c", 0x002C, "edma tc", 0x0030, "edma status", 0x0034, "edma iordyto", /* 0x0100, "edma pio", 0x0104, "edma err", 0x0108, "edma sectors", 0x010C, "edma lba0", 0x0110, "edma lba1", 0x0114, "edma lba2", 0x0118, "edma lba3", 0x011C, "edma cmdstat", 0x0120, "edma altstat", */ }; static char* rdregs(char *p, char *e, void *base, Regs *r, int n, char *prefix) { int i; for(i=0; i>>>>>> sdmv50xx.c p = seprint(p, e, "info"); for(i=0; i<256; i++){ <<<<<<< sdmv50xx.c.orig p = seprint(p, e, "%s%.4ux%s", ======= p = seprint(p, e, "%s%.4ux%s", >>>>>>> sdmv50xx.c i%8==0 ? "\t" : "", <<<<<<< sdmv50xx.c.orig info[i], ======= info[i], >>>>>>> sdmv50xx.c i%8==7 ? "\n" : ""); } return p; } static int mv50rctl(SDunit *unit, char *p, int l) { char *e, *op; Ctlr *ctlr; Drive *drive; if((ctlr = unit->dev->ctlr) == nil) return 0; drive = &ctlr->drive[unit->subno]; e = p+l; op = p; if(drive->state == Dready){ p = seprint(p, e, "model %s\n", drive->model); p = seprint(p, e, "serial %s\n", drive->serial); p = seprint(p, e, "firmware %s\n", drive->firmware); }else p = seprint(p, e, "no disk present\n"); p = seprint(p, e, "geometry %llud 512\n", drive->sectors); p = rdinfo(p, e, drive->info); p = rdregs(p, e, drive->chip->arb, regsarb, nelem(regsarb), nil); p = rdregs(p, e, drive->bridge, regsbridge, nelem(regsbridge), nil); p = rdregs(p, e, drive->edma, regsedma, nelem(regsedma), nil); return p-op; } static int mv50wctl(SDunit *unit, Cmdbuf *cb) { Ctlr *ctlr; Drive *drive; USED(unit); if(strcmp(cb->f[0], "reset") == 0){ ctlr = unit->dev->ctlr; drive = &ctlr->drive[unit->subno]; ilock(drive); <<<<<<< sdmv50xx.c.orig updatedrive(drive, eDevDis); ======= drive->state = Dreset; >>>>>>> sdmv50xx.c iunlock(drive); return 0; } cmderror(cb, Ebadctl); return -1; } static char* mv50rtopctl(SDev *sdev, char *p, char *e) { char name[10]; Ctlr *ctlr; ctlr = sdev->ctlr; if(ctlr == nil) return p; snprint(name, sizeof name, "sd%c", sdev->idno); p = rdregs(p, e, ctlr->mmio, regsctlr, nelem(regsctlr), name); /* info for first disk */ p = rdregs(p, e, ctlr->chip[0].arb, regsarb, nelem(regsarb), name); p = rdregs(p, e, &ctlr->chip[0].arb->bridge[0], regsbridge, nelem(regsbridge), name); p = rdregs(p, e, &ctlr->chip[0].edma[0], regsedma, nelem(regsedma), name); return p; } static int <<<<<<< /sys/src/9/pc/sdmv50xx.c waitready(Drive *d) { ulong s, i; for(i = 0; i < 120; i++){ ilock(d); s = d->bridge->status; iunlock(d); if(s == 0) return SDeio; if (d->state == Dready) return SDok; if ((i+1)%60 == 0){ ilock(d); resetdisk(d); iunlock(d); } if(!waserror()){ tsleep(&up->sleep, return0, 0, 1000); poperror(); } } print("%s: not responding after 2 minutes\n", d->unit->name); return SDeio; } static int ||||||| sdmv50xx.c.orig ======= waitready(Drive *d) { ulong s, i; Rendez r; for(i = 0; i < 120; i++){ ilock(d); s = d->bridge->status; iunlock(d); if(s == 0) return SDeio; if (d->state == Dready) return SDok; if ((i+1)%60 == 0){ ilock(d); resetdisk(d); iunlock(d); } memset(&r, 0, sizeof r); tsleep(&r, return0, 0, 1000); } print("%s: not responding after 2 minutes\n", d->unit->name); return SDeio; } static int >>>>>>> sdmv50xx.c mv50rio(SDreq *r) { <<<<<<< sdmv50xx.c.orig int count, max, n, status; ======= int count, max, n, status, try, flag; >>>>>>> sdmv50xx.c uchar *cmd, *data; uvlong lba; Ctlr *ctlr; Drive *drive; SDunit *unit; Srb *srb; <<<<<<< /sys/src/9/pc/sdmv50xx.c ||||||| sdmv50xx.c.orig ======= Rendez rz; >>>>>>> sdmv50xx.c unit = r->unit; ctlr = unit->dev->ctlr; drive = &ctlr->drive[unit->subno]; cmd = r->cmd; <<<<<<< sdmv50xx.c.orig ======= >>>>>>> sdmv50xx.c if((status = sdfakescsi(r, drive->info, sizeof drive->info)) != SDnostatus){ /* XXX check for SDcheck here */ r->status = status; return status; } switch(cmd[0]){ case 0x28: /* read */ case 0x2A: /* write */ break; default: <<<<<<< sdmv50xx.c.orig print("sdmv50xx: bad cmd 0x%.2ux\n", cmd[0]); ======= iprint("%s: bad cmd 0x%.2ux\n", drive->unit->name, cmd[0]); >>>>>>> sdmv50xx.c r->status = SDcheck; return SDcheck; } <<<<<<< sdmv50xx.c.orig ======= >>>>>>> sdmv50xx.c lba = (cmd[2]<<24)|(cmd[3]<<16)|(cmd[4]<<8)|cmd[5]; count = (cmd[7]<<8)|cmd[8]; if(r->data == nil) return SDok; if(r->dlen < count*unit->secsize) count = r->dlen/unit->secsize; <<<<<<< sdmv50xx.c.orig /* ======= try = 0; retry: if(waitready(drive) != SDok) return SDeio; /* >>>>>>> sdmv50xx.c * Could arrange here to have an Srb always outstanding: * * lsrb = nil; * while(count > 0 || lsrb != nil){ * srb = nil; * if(count > 0){ * srb = issue next srb; * } * if(lsrb){ * sleep on lsrb and handle it * } * } * * On the disks I tried, this didn't help. If anything, * it's a little slower. -rsc */ data = r->data; while(count > 0){ /* * Max is 128 sectors (64kB) because prd->count is 16 bits. */ max = 128; n = count; if(n > max) n = max; <<<<<<< sdmv50xx.c.orig ======= if((drive->edma->ctl&eEnEDMA) == 0) goto tryagain; >>>>>>> sdmv50xx.c srb = srbrw(cmd[0]==0x28 ? SRBread : SRBwrite, drive, data, n, lba); ilock(drive); startsrb(drive, srb); iunlock(drive); <<<<<<< /sys/src/9/pc/sdmv50xx.c /* Don't let user interrupt DMA. */ while(waserror()) ; sleep(srb, srbdone, srb); poperror(); flag = srb->flag; freesrb(srb); if(flag == 0){ tryagain: if(++try == 10){ print("%s: bad disk\n", drive->unit->name); return SDeio; ||||||| sdmv50xx.c.orig /* * Cannot let user interrupt the DMA. */ while(waserror()) ; tsleep(srb, srbdone, srb, 60*1000); poperror(); if(!(srb->flag & SFdone)){ ilock(drive); if(!(srb->flag & SFdone)){ /* * DMA didn't finish but we have to let go of * the data buffer. Reset the drive to (try to) keep it * from using the buffer after we're gone. */ iprint("%s: i/o timeout\n", unit->name); updatedrive(drive, eDevDis); enabledrive(drive); freesrb(srb); iunlock(drive); error("i/o timeout"); ======= sleep(&srb->Rendez, srbdone, srb); flag = srb->flag; freesrb(srb); if(flag == 0){ tryagain: if(++try == 10){ print("%s: bad disk\n", drive->unit->name); return SDeio; >>>>>>> sdmv50xx.c } <<<<<<< /sys/src/9/pc/sdmv50xx.c dprint("%s: retry\n", drive->unit->name); if(!waserror()){ tsleep(&up->sleep, return0, 0, 1000); poperror(); } goto retry; ||||||| sdmv50xx.c.orig iunlock(drive); ======= dprint("%s: retry\n", drive->unit->name); memset(&rz, 0, sizeof rz); tsleep(&rz, return0, 0, 1000); goto retry; >>>>>>> sdmv50xx.c } <<<<<<< /sys/src/9/pc/sdmv50xx.c if(flag & SFerror){ print("%s: i/o error\n", drive->unit->name); return SDeio; ||||||| sdmv50xx.c.orig if(srb->flag & SFerror){ freesrb(srb); error("i/o error"); ======= if(srb->flag & SFerror){ print("%s: i/o error\n", drive->unit->name); return SDeio; >>>>>>> sdmv50xx.c } <<<<<<< sdmv50xx.c.orig freesrb(srb); ======= >>>>>>> sdmv50xx.c count -= n; lba += n; data += n*unit->secsize; } r->rlen = data - (uchar*)r->data; <<<<<<< sdmv50xx.c.orig return SDok; ======= return SDok; >>>>>>> sdmv50xx.c } SDifc sdmv50xxifc = { <<<<<<< sdmv50xx.c.orig "mv50xx", /* name */ ======= "mv50xx", /* name */ >>>>>>> sdmv50xx.c mv50pnp, /* pnp */ nil, /* legacy */ <<<<<<< sdmv50xx.c.orig mv50enable, /* enable */ mv50disable, /* disable */ ======= mv50enable, /* enable */ mv50disable, /* disable */ >>>>>>> sdmv50xx.c mv50verify, /* verify */ mv50online, /* online */ mv50rio, /* rio */ mv50rctl, /* rctl */ mv50wctl, /* wctl */ scsibio, /* bio */ nil, /* probe */ mv50clear, /* clear */ mv50rtopctl, /* rtopctl */ <<<<<<< sdmv50xx.c.orig nil, /* wtopctl */ ======= >>>>>>> sdmv50xx.c }; /* * The original driver on which this one is based came with the * following notice: * * Copyright 2005 * Coraid, Inc. * * This software is provided `as-is,' without any express or implied * warranty. In no event will the author be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must * not claim that you wrote the original software. If you use this * software in a product, an acknowledgment in the product documentation * would be appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and must * not be misrepresented as being the original software. * * 3. This notice may not be removed or altered from any source * distribution. */