123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755 |
- /*
- * 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.
- * The original copyright notice appears at the end of this file.
- */
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "io.h"
- #include "../port/error.h"
- #include "../port/sd.h"
- #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,
- };
- enum {
- SrbRing = 32,
- /* Addresses of ATA register */
- ARcmd = 027,
- ARdev = 026,
- ARerr = 021,
- ARfea = 021,
- ARlba2 = 025,
- ARlba1 = 024,
- ARlba0 = 023,
- ARseccnt = 022,
- ARstat = 027,
- ATAerr = (1<<0),
- ATAdrq = (1<<3),
- ATAdf = (1<<5),
- ATAdrdy = (1<<6),
- ATAbusy = (1<<7),
- ATAabort = (1<<2),
- ATAobs = (1<<1 | 1<<2 | 1<<4),
- ATAeIEN = (1<<1),
- ATAsrst = (1<<2),
- ATAhob = (1<<7),
- ATAbad = (ATAbusy|ATAdf|ATAdrq|ATAerr),
- SFdone = (1<<0),
- SFerror = (1<<1),
- SRBident = 0,
- SRBread,
- SRBwrite,
- SRBsmart,
- SRBnodata = 0,
- SRBdatain,
- SRBdataout,
- RQread = 1, /* data coming IN from device */
- PRDeot = (1<<15),
- /* EDMA interrupt error cause register */
- ePrtDataErr = (1<<0),
- ePrtPRDErr = (1<<1),
- eDevErr = (1<<2),
- eDevDis = (1<<3),
- eDevCon = (1<<4),
- eOverrun = (1<<5),
- eUnderrun = (1<<6),
- eSelfDis = (1<<8),
- ePrtCRQBErr = (1<<9),
- ePrtCRPBErr = (1<<10),
- ePrtIntErr = (1<<11),
- eIORdyErr = (1<<12),
- /* flags for sata 2 version */
- eSelfDis2 = (1<<7),
- SerrInt = (1<<5),
- /* EDMA Command Register */
- eEnEDMA = (1<<0),
- eDsEDMA = (1<<1),
- eAtaRst = (1<<2),
- /* Interrupt mask for errors we care about */
- IEM = (eDevDis | eDevCon | eSelfDis),
- IEM2 = (eDevDis | eDevCon | eSelfDis2),
- /* drive states */
- Dnull = 0,
- Dnew,
- Dready,
- Derror,
- Dmissing,
- 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,
- };
- static char* diskstates[Dlast] = {
- "null",
- "new",
- "ready",
- "error",
- "missing",
- "reset",
- };
- 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;
- /*
- * there are 4 drives per chip. thus an 8-port
- * card has two chips.
- */
- struct Chip
- {
- Arb *arb;
- Edma *edma;
- };
- enum{
- DMautoneg,
- DMsatai,
- DMsataii,
- };
- struct Drive
- {
- Lock;
- Ctlr *ctlr;
- SDunit *unit;
- char name[10];
- ulong magic;
- Bridge *bridge;
- Edma *edma;
- Chip *chip;
- int chipx;
- int mediachange;
- int state;
- int flag;
- uvlong sectors;
- ulong pm2; /* phymode 2 init state */
- ulong intick; /* check for hung western digital drives. */
- int wait;
- int mode; /* DMautoneg, satai or sataii. */
- char serial[20+1];
- char firmware[8+1];
- char model[40+1];
- ushort info[256];
- Srb *srb[SrbRing-1];
- int nsrb;
- Prd *prd;
- Tx *tx;
- Rx *rx;
- Srb *srbhead;
- Srb *srbtail;
- int driveno; /* ctlr*NCtlrdrv + unit */
- };
- struct Ctlr
- {
- Lock;
- int irq;
- int tbdf;
- int rid;
- ulong magic;
- int enabled;
- int type;
- SDev *sdev;
- Pcidev *pcidev;
- uchar *mmio;
- ulong *lmmio;
- Chip chip[2];
- int nchip;
- Drive drive[NCtlrdrv];
- int ndrive;
- };
- struct Srb /* request buffer */
- {
- Lock;
- Rendez;
- Srb *next;
- Drive *drive;
- uvlong blockno;
- int count;
- int req;
- int flag;
- uchar *data;
- uchar cmd;
- uchar lba[6];
- uchar sectors;
- int sta;
- int err;
- };
- /*
- * Memory-mapped I/O registers in many forms.
- */
- struct Bridge /* memory-mapped per-Drive registers */
- {
- ulong status;
- ulong serror;
- ulong sctrl;
- ulong phyctrl;
- ulong phymode3;
- ulong phymode4;
- uchar fill0[0x14];
- ulong phymode1;
- ulong phymode2;
- char fill1[8];
- ulong ctrl;
- char fill2[0x34];
- ulong phymode;
- char fill3[0x88];
- }; /* length must be 0x100 */
- struct Arb /* memory-mapped per-Chip registers */
- {
- ulong config; /* satahc configuration register (sata2 only) */
- ulong rqop; /* request queue out-pointer */
- 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 */
- char fill1[0xdc];
- Bridge bridge[4];
- };
- struct Edma /* memory-mapped per-Drive DMA-related registers */
- {
- 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 */
- };
- /*
- * Memory structures shared with card.
- */
- struct Prd /* physical region descriptor */
- {
- ulong pa; /* byte address of physical memory */
- ushort count; /* byte count (bit0 must be 0) */
- ushort flag;
- ulong zero; /* high long of 64 bit address */
- ulong reserved;
- };
- struct Tx /* command request block */
- {
- ulong prdpa; /* physical region descriptor table structures */
- ulong zero; /* must be zero (high long of prd address) */
- ushort flag; /* control flags */
- ushort regs[11];
- };
- struct Rx /* command response block */
- {
- ushort cid; /* cID of response */
- uchar cEdmaSts; /* EDMA status */
- uchar cDevSts; /* status from disk */
- ulong ts; /* time stamp */
- };
- static Drive *mvsatadrive[NDrive];
- static int nmvsatadrive;
- /*
- * 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<n/2; i++){
- *p++ = a[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;
- for(i=0; i<ms && (*p & mask) != v; i++)
- microdelay(1000);
- return (*p & mask) == v;
- }
- /*
- * Drive initialization
- */
- /* 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)
- {
- int i;
- Srb *srb;
- for(i=0; i<nelem(d->srb); 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);
- }
- }
- 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;
- }
- static int
- enabledrive(Drive *d)
- {
- Edma *edma;
- dprint("%s: enabledrive..", d->unit->name);
- if((d->bridge->status & 0xf) != 3){
- dprint("%s: not present\n", d->unit->name);
- d->state = Dmissing;
- return -1;
- }
- edma = d->edma;
- if(satawait(&edma->cmdstat, ATAbusy, 0, 5*1000) == 0){
- dprint("%s: busy timeout\n", d->unit->name);
- d->state = Dmissing;
- return -1;
- }
- edma->iec = 0;
- d->chip->arb->ic &= ~(0x101 << d->chipx);
- edma->config = 0x51f;
- if (d->ctlr->type == 2)
- edma->config |= 7<<11;
- edma->txi = PADDR(d->tx);
- edma->txo = (ulong)d->tx & 0x3e0;
- edma->rxi = (ulong)d->rx & 0xf8;
- edma->rxo = PADDR(d->rx);
- edma->ctl |= 1; /* enable dma */
- if(d->bridge->status = 0x113){
- dprint("%s: new\n", d->unit->name);
- d->state = Dnew;
- }else
- print("%s: status not forced (should be okay)\n", d->unit->name);
- return 0;
- }
- static void
- disabledrive(Drive *d)
- {
- int i;
- ulong *r;
- dprint("%s: disabledrive\n", d->unit->name);
- if(d->tx == nil) /* never enabled */
- return;
- d->edma->ctl = 0;
- d->edma->iem = 0;
- r = (ulong*)(d->ctlr->mmio + 0x1d64);
- 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;
- dprint("%s: setudmamode %d\n", d->unit->name, mode);
- edma = d->edma;
- 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);
- return 0;
- }
- edma->altstat = ATAeIEN;
- edma->err = 3;
- edma->seccnt = 0x40 | mode;
- edma->cmdstat = 0xef;
- microdelay(1);
- if(satawait(&edma->cmdstat, ATAbusy, 0, 5*1000) == 0){
- iprint("%s: cmdstat 0x%.2ux busy timeout\n", d->unit->name, edma->cmdstat);
- return 0;
- }
- return 1;
- }
- static int
- identifydrive(Drive *d)
- {
- int i;
- ushort *id;
- Edma *edma;
- SDunit *unit;
- dprint("%s: identifydrive\n", d->unit->name);
- 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;
- if(satawait(&edma->cmdstat, ~ATAobs, ATAdrdy, 5*1000) == 0)
- goto Error;
- edma->altstat = ATAeIEN; /* no interrupts */
- edma->cmdstat = 0xec;
- microdelay(1);
- if(satawait(&edma->cmdstat, ATAbusy, 0, 5*1000) == 0)
- goto Error;
- for(i = 0; i < 256; i++)
- id[i] = edma->pio;
- if(edma->cmdstat & ATAbad)
- 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);
- 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);
- if(enabledrive(d) == 0) {
- d->state = Dready;
- d->mediachange = 1;
- idprint("%s: LLBA %lld sectors\n", d->unit->name, d->sectors);
- } else
- d->state = Derror;
- if(d->state == Dready)
- return 0;
- return -1;
- Error:
- dprint("error...");
- d->state = Derror;
- 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<<i)) && stab[i]){
- *s++ = stab[i];
- if(sbad&(1<<i))
- *s++ = '*';
- }
- }
- *s = 0;
- }
- 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<<i))
- return iectab[i];
- return "";
- }
- enum{
- Cerror = ePrtDataErr|ePrtPRDErr|eDevErr|eSelfDis2|ePrtCRPBErr|ePrtIntErr,
- };
- static void
- updatedrive(Drive *d)
- {
- int x;
- ulong cause;
- Edma *edma;
- char buf[32+4+1];
- edma = d->edma;
- if((edma->ctl&eEnEDMA) == 0){
- /* FEr SATA#4 40xx */
- x = d->edma->cmdstat;
- USED(x);
- }
- cause = edma->iec;
- if(cause == 0)
- return;
- dprint("%s: cause %08ulx [%s]\n", d->unit->name, cause, iecdecode(cause));
- if(cause & eDevCon)
- d->state = Dnew;
- 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;
- }
- }
- edma->iec = ~cause;
- }
- /*
- * 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 };
- 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;
- mask = 0x1F<<shift;
- n = (pa & mask) + (1<<shift);
- return (pa & ~mask) | (n & mask);
- }
- #define CMD(r, v) (((r)<<8) | ((v)&0xFF))
- static void
- mvsatarequest(ushort *cmd, Srb *srb, int ext)
- {
- *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]);
- *cmd++ = CMD(ARdev, 0xe0);
- }else{
- *cmd++ = CMD(ARlba0, srb->lba[0]);
- *cmd++ = CMD(ARlba1, srb->lba[1]);
- *cmd++ = CMD(ARlba2, srb->lba[2]);
- *cmd++ = CMD(ARdev, srb->lba[3] | 0xe0);
- }
- *cmd = CMD(ARcmd, srb->cmd) | (1<<15);
- }
- static void
- startsrb(Drive *d, Srb *srb)
- {
- int i;
- Edma *edma;
- Prd *prd;
- Tx *tx;
- if(d->nsrb >= nelem(d->srb)){
- srb->next = nil;
- if(d->srbhead)
- d->srbtail->next = srb;
- else
- d->srbhead = srb;
- d->srbtail = srb;
- return;
- }
- d->nsrb++;
- for(i=0; i<nelem(d->srb); i++)
- if(d->srb[i] == nil)
- break;
- if(i == nelem(d->srb))
- panic("sdmv50xx: no free srbs");
- d->intick = MACHP(0)->ticks;
- 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;
- mvsatarequest(tx->regs, srb, d->flag&Dext);
- coherence();
- edma->txi = advance(edma->txi, 5);
- d->intick = MACHP(0)->ticks;
- }
- enum{
- Rpidx = 0x1f<<3,
- };
- static void
- completesrb(Drive *d)
- {
- Edma *edma;
- Rx *rx;
- Srb *srb;
- edma = d->edma;
- if((edma->ctl & eEnEDMA) == 0)
- return;
- while((edma->rxo&Rpidx) != (edma->rxi&Rpidx)){
- rx = (Rx*)KADDR(edma->rxo);
- if(srb = d->srb[rx->cid]){
- d->srb[rx->cid] = nil;
- d->nsrb--;
- if(rx->cDevSts & ATAbad)
- srb->flag |= SFerror;
- if (rx->cEdmaSts)
- iprint("cEdmaSts: %02ux\n", rx->cEdmaSts);
- srb->sta = rx->cDevSts;
- srb->flag |= SFdone;
- wakeup(srb);
- }else
- iprint("srb missing\n");
- edma->rxo = advance(edma->rxo, 3);
- if(srb = d->srbhead){
- d->srbhead = srb->next;
- startsrb(d, srb);
- }
- }
- }
- static int
- srbdone(void *v)
- {
- Srb *srb;
- srb = v;
- return srb->flag & SFdone;
- }
- /*
- * Interrupts
- */
- static void
- mv50interrupt(Ureg*, void *a)
- {
- int i;
- ulong cause;
- Ctlr *ctlr;
- Drive *drive;
- ctlr = a;
- ilock(ctlr);
- cause = ctlr->lmmio[0x1d60/4];
- // dprint("sd%c: mv50interrupt: 0x%lux\n", ctlr->sdev->idno, cause);
- for(i=0; i<ctlr->ndrive; i++)
- if(cause & (3<<(i*2+i/4))){
- drive = &ctlr->drive[i];
- if(drive->edma == 0)
- continue; /* not ready yet. */
- ilock(drive);
- updatedrive(drive);
- while(ctlr->chip[i/4].arb->ic & (0x0101 << (i%4))){
- ctlr->chip[i/4].arb->ic = ~(0x101 << (i%4));
- completesrb(drive);
- }
- iunlock(drive);
- }
- iunlock(ctlr);
- }
- 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);
- }
- }
- /*
- * Device discovery
- */
- static SDev*
- mv50pnp(void)
- {
- int i, nunit;
- uchar *base;
- ulong io, n, *mem;
- Ctlr *ctlr;
- Pcidev *p;
- SDev *head, *tail, *sdev;
- Drive *d;
- static int ctlrno, done;
- dprint("mv50pnp\n");
- if(done++)
- return nil;
- p = nil;
- head = nil;
- tail = nil;
- while((p = pcimatch(p, 0x11ab, 0)) != nil){
- switch(p->did){
- case 0x5040:
- case 0x5041:
- case 0x5080:
- case 0x5081:
- case 0x6041:
- case 0x6081:
- break;
- default:
- print("mv50pnp: unknown did %ux ignored\n", (ushort)p->did);
- continue;
- }
- 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"));
- if((sdev = malloc(sizeof(SDev))) == nil)
- continue;
- if((ctlr = malloc(sizeof(Ctlr))) == nil){
- free(sdev);
- continue;
- }
- memset(sdev, 0, sizeof *sdev);
- memset(ctlr, 0, sizeof *ctlr);
- io = p->mem[0].bar & ~0x0F;
- mem = (ulong*)vmap(io, p->mem[0].size);
- if(mem == 0){
- print("sdmv50xx: address 0x%luX in use\n", io);
- free(sdev);
- free(ctlr);
- continue;
- }
- 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;
- }
- sdev->ifc = &sdmv50xxifc;
- sdev->ctlr = ctlr;
- sdev->nunit = nunit;
- sdev->idno = 'E';
- ctlr->sdev = sdev;
- ctlr->irq = p->intl;
- ctlr->tbdf = p->tbdf;
- ctlr->pcidev = p;
- ctlr->lmmio = mem;
- ctlr->mmio = (uchar*)mem;
- ctlr->nchip = (nunit+3)/4;
- ctlr->ndrive = nunit;
- ctlr->enabled = 0;
- for(i = 0; i < ctlr->nchip; i++){
- base = ctlr->mmio+0x20000+0x10000*i;
- ctlr->chip[i].arb = (Arb*)base;
- ctlr->chip[i].edma = (Edma*)(base + 0x2000);
- }
- 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++;
- 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;
- dprint("sd%c: enable\n", sdev->idno);
- ctlr = sdev->ctlr;
- if (ctlr->enabled)
- return 1;
- snprint(name, sizeof name, "%s (%s)", sdev->name, sdev->ifc->name);
- intrenable(ctlr->irq, mv50interrupt, ctlr, ctlr->tbdf, name);
- ctlr->enabled = 1;
- return 1;
- }
- /*
- * Disable the controller.
- */
- static int
- mv50disable(SDev *sdev)
- {
- char name[32];
- int i;
- Ctlr *ctlr;
- Drive *drive;
- dprint("sd%c: disable\n", sdev->idno);
- ctlr = sdev->ctlr;
- ilock(ctlr);
- for(i=0; i<ctlr->sdev->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;
- dprint("sd%c: clear\n", sdev->idno);
- ctlr = sdev->ctlr;
- for(i=0; i<ctlr->ndrive; 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;
- dprint("%s: verify\n", unit->name);
- ctlr = unit->dev->ctlr;
- drive = &ctlr->drive[unit->subno];
- ilock(ctlr);
- ilock(drive);
- i = configdrive(ctlr, drive, unit);
- iunlock(drive);
- iunlock(ctlr);
- /*
- * 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();
- }
- }
- return 1;
- }
- /*
- * Check whether the disk is online.
- */
- static int
- mv50online(SDunit *unit)
- {
- Ctlr *ctlr;
- Drive *d;
- int r, s0;
- static int once;
- if(once++ == 0)
- kproc("mvsata", satakproc, 0);
- ctlr = unit->dev->ctlr;
- 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;
- unit->secsize = 512;
- d->mediachange = 0;
- } else if(d->state == Dready)
- r = 1;
- iunlock(d);
- return r;
- }
- /*
- * 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<n; i++)
- p = seprint(p, e, "%s%s%-19s %.8ux\n",
- prefix ? prefix : "", prefix ? ": " : "",
- r[i].name, *(ulong *)((uchar*)base+r[i].offset));
- return p;
- }
- static char*
- rdinfo(char *p, char *e, ushort *info)
- {
- int i;
- p = seprint(p, e, "info");
- for(i=0; i<256; i++){
- p = seprint(p, e, "%s%.4ux%s",
- i%8==0 ? "\t" : "",
- info[i],
- 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);
- drive->state = Dreset;
- 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
- 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
- mv50rio(SDreq *r)
- {
- int count, max, n, status, try, flag;
- uchar *cmd, *data;
- uvlong lba;
- Ctlr *ctlr;
- Drive *drive;
- SDunit *unit;
- Srb *srb;
- unit = r->unit;
- ctlr = unit->dev->ctlr;
- drive = &ctlr->drive[unit->subno];
- cmd = r->cmd;
- 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:
- iprint("%s: bad cmd 0x%.2ux\n", drive->unit->name, cmd[0]);
- r->status = SDcheck;
- return SDcheck;
- }
- 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;
- try = 0;
- retry:
- if(waitready(drive) != SDok)
- return SDeio;
- /*
- * 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;
- if((drive->edma->ctl&eEnEDMA) == 0)
- goto tryagain;
- srb = srbrw(cmd[0]==0x28 ? SRBread : SRBwrite, drive, data, n, lba);
- ilock(drive);
- startsrb(drive, srb);
- iunlock(drive);
- /* 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;
- }
- dprint("%s: retry\n", drive->unit->name);
- if(!waserror()){
- tsleep(&up->sleep, return0, 0, 1000);
- poperror();
- }
- goto retry;
- }
- if(flag & SFerror){
- print("%s: i/o error\n", drive->unit->name);
- return SDeio;
- }
- count -= n;
- lba += n;
- data += n*unit->secsize;
- }
- r->rlen = data - (uchar*)r->data;
- return SDok;
- }
- SDifc sdmv50xxifc = {
- "mv50xx", /* name */
- mv50pnp, /* pnp */
- nil, /* legacy */
- mv50enable, /* enable */
- mv50disable, /* disable */
- mv50verify, /* verify */
- mv50online, /* online */
- mv50rio, /* rio */
- mv50rctl, /* rctl */
- mv50wctl, /* wctl */
- scsibio, /* bio */
- nil, /* probe */
- mv50clear, /* clear */
- mv50rtopctl, /* rtopctl */
- };
- /*
- * 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.
- */
|