📄 sdmv50xx.c
字号:
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 intmv50wctl(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); updatedrive(drive, eDevDis); 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;}#endifstatic intmv50rio(SDreq *r){ int count, max, n, status; 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: print("sdmv50xx: bad cmd 0x%.2ux\n", 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; /* * 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; srb = srbrw(cmd[0]==0x28 ? SRBread : SRBwrite, drive, data, n, lba); ilock(drive); startsrb(drive, srb); iunlock(drive); /* * 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"); } iunlock(drive); } if(srb->flag & SFerror){ freesrb(srb); error("i/o error"); } freesrb(srb); count -= n; lba += n; data += n*unit->secsize; } r->rlen = data - (uchar*)r->data; return SDok;err: return SDeio;}SDifc sdmv50xxifc = { "mv50xx", /* name */ mv50pnp, /* pnp */ nil, /* legacy */#ifdef FS nil, /* id */#endif mv50enable, /* enable */ mv50disable, /* disable */ mv50verify, /* verify */ mv50online, /* online */ mv50rio, /* rio */#ifdef FS nil, nil,#else mv50rctl, /* rctl */ mv50wctl, /* wctl */#endif scsibio, /* bio */#ifndef FS nil, /* probe */ mv50clear, /* clear */ mv50rtopctl, /* rtopctl */#endif};/* * file-server-specific routines * * mvide* routines implement the `m' device and call the mvsata* routines. */static Drive*mvsatapart(Drive *dp){ return dp;}static Drive*mvsatadriveprobe(int driveno){ Drive *drive; drive = mvsatadrive[driveno]; if (drive == nil) return nil; if (drive->magic != Drvmagic) print("mv50xx: mvsatadriveprobe(m%d): bad drive magic 0x%lux\n", driveno, drive->magic); drive->driveno = driveno; if(drive->online == 0){ /* LBA assumed */ print("m%d: LBA %,llud sectors\n", drive->driveno, (Wideoff)drive->sectors); drive->online = 1; } return mvsatapart(drive);}/* find all the controllers, enable interrupts, set up SDevs & SDunits */intmvsatainit(void){ unsigned i; SDev *sdp; SDev **sdpp; SDunit *sup; SDunit **supp; static int first = 1; if (first) first = 0; else return 0xFF; mv50pnp(); for (sdpp = sdevs; sdpp < sdevs + nelem(sdevs); sdpp++) { sdp = *sdpp; if (sdp == nil) continue; i = sdpp - sdevs; sdp->ifc = &sdmv50xxifc; sdp->nunit = NCtlrdrv; sdp->index = i; sdp->idno = 'E' + i; sdp->ctlr = mvsatactlr[i]; if (sdp->ctlr != nil) mv50enable(sdp); } for (supp = sdunits; supp < sdunits + nelem(sdunits); supp++) { sup = *supp; if (sup == nil) continue; i = supp - sdunits; sup->dev = sdevs[i/NCtlrdrv]; /* controller */ sup->subno = i%NCtlrdrv; /* drive within controller */ snprint(sup->name, sizeof sup->name, "m%d", i); } statsinit(); return 0xFF;}Devsizemvsataseek(int driveno, Devsize offset){ Drive *drive = mvsatadrive[driveno]; if (drive == nil || !drive->online) return -1; drive->offset = offset; return offset;}/* zero indicates failure; only otherinit() cares */intsetmv50part(int driveno, char *){ /* mvsatadriveprobe() sets drive->online */ if(mvsatadriveprobe(driveno) == nil) return 0; return 1;}static voidkeepstats(SDunit *unit, int dbytes){ Ctlr *ctlr = unit->dev->ctlr; Target *tp = &ctlr->target[unit->subno]; qlock(tp); if(tp->fflag == 0) { dofilter(tp->work+0, C0a, C0b, 1); /* was , 1000); */ dofilter(tp->work+1, C1a, C1b, 1); /* was , 1000); */ dofilter(tp->work+2, C2a, C2b, 1); /* was , 1000); */ dofilter(tp->rate+0, C0a, C0b, 1); dofilter(tp->rate+1, C1a, C1b, 1); dofilter(tp->rate+2, C2a, C2b, 1); tp->fflag = 1; } tp->work[0].count++; tp->work[1].count++; tp->work[2].count++; tp->rate[0].count += dbytes; tp->rate[1].count += dbytes; tp->rate[2].count += dbytes; qunlock(tp);}static longmvsataxfer(Drive *dp, void *, int inout, Devsize start, long bytes){ unsigned driveno = dp->driveno; ulong secsize = dp->unit->secsize, sects; SDunit *unit; SDunit **unitp = sdunits + driveno; static int beenhere; DPRINT("%s: mvsataxfer\n", dp->unit->name); unit = *unitp; if (unit == nil) { print("mvsataxfer: nil unit\n"); return -1; } if (!beenhere && dp->unit != unit) { beenhere = 1; print("mvsataxfer: units differ: dp->unit %p unit %p\n", dp->unit, unit); } if (dp->driveno == -1) panic("mvsataxfer: dp->driveno unset"); if (unit->dev != sdevs[driveno/NCtlrdrv]) panic("mvsataxfer: SDunit[%d].dev is wrong controller", driveno); if (unit->subno != driveno%NCtlrdrv) panic("mvsataxfer: SDunit[%d].subno is %d, not %d", driveno, unit->subno, driveno%NCtlrdrv); if (unit->sectors == 0) { unit->sectors = dp->sectors; unit->secsize = secsize; } keepstats(unit, bytes); sects = (bytes + secsize - 1) / secsize; /* round up */ if (start%secsize != 0) print("mvsataxfer: start offset not on sector boundary\n"); return scsibio(unit, 0, inout, dp->buf, sects, start/secsize);}/* * mvsataread & mvsatawrite do the real work; * mvideread & mvidewrite just call them. * mvsataread & mvsatawrite are called by the nvram routines. * mvideread & mvidewrite are called for normal file server I/O. */Offmvsataread(int driveno, void *a, long n){ int skip; Off rv, i; uchar *aa = a;// Ctlr *cp; Drive *dp; DPRINT("m%d: mvsataread\n", driveno); dp = mvsatadrive[driveno]; if(dp == nil || !dp->online) return 0; DPRINT("%s: mvsataread drive=%p\n", dp->unit->name, dp);// cp = dp->ctlr; if (dp->unit->secsize == 0) panic("mvsataread: %s: sector size of zero", dp->unit->name); skip = dp->offset % dp->unit->secsize; for(rv = 0; rv < n; rv += i){ i = mvsataxfer(dp, nil, Read, dp->offset+rv-skip, n-rv+skip); if(i == 0) break; if(i < 0) { return -1; } i -= skip; if(i > n - rv) i = n - rv; memmove(aa+rv, dp->buf + skip, i); skip = 0; } dp->offset += rv; return rv;}Offmvsatawrite(int driveno, void *a, long n){ Off rv, i, partial; uchar *aa = a;// Ctlr *cp; Drive *dp; DPRINT("m%d: mvsatawrite\n", driveno); dp = mvsatadrive[driveno]; if(dp == nil || !dp->online) return 0; DPRINT("%s: mvsatawrite drive=%p\n", dp->unit->name, dp);// cp = dp->ctlr; /* * if not starting on a sector boundary, * read in the first sector before writing it out. */ if (dp->unit->secsize == 0) panic("mvsatawrite: %s: sector size of zero", dp->unit->name); partial = dp->offset % dp->unit->secsize; if(partial){ if (mvsataxfer(dp, nil, Read, dp->offset-partial, dp->unit->secsize) < 0) return -1; if(partial+n > dp->unit->secsize) rv = dp->unit->secsize - partial; else rv = n; memmove(dp->buf+partial, aa, rv); if (mvsataxfer(dp, nil, Write, dp->offset-partial, dp->unit->secsize) < 0) return -1; } else rv = 0; /* * write out the full sectors (common case) */ partial = (n - rv) % dp->unit->secsize; n -= partial; for(; rv < n; rv += i){ i = n - rv; if(i > Maxxfer) i = Maxxfer; memmove(dp->buf, aa+rv, i); i = mvsataxfer(dp, nil, Write, dp->offset+rv, i); if(i == 0) break; if(i < 0) return -1; } /* * if not ending on a sector boundary, * read in the last sector before writing it out. */ if(partial){ if (mvsataxfer(dp, nil, Read, dp->offset+rv, dp->unit->secsize) < 0) return -1; memmove(dp->buf, aa+rv, partial); if (mvsataxfer(dp, nil, Write, dp->offset+rv, dp->unit->secsize) < 0) return -1; rv += partial; } dp->offset += rv; return rv;}/* * normal file server I/O interface *//* result is size of d in blocks of RBUFSIZE bytes */Devsizemvidesize(Device *d){ Drive *dp = d->private; if (dp == nil) return 0; /* * dividing first is sloppy but reduces the range of intermediate * values, avoiding possible overflow. */ return (dp->sectors / RBUFSIZE) * dp->unit->secsize;}voidmvideinit(Device *d){ int driveno; Drive *dp; DPRINT("mvideinit\n"); mvsatainit(); if (d->private) return; /* call setmv50part() first in case we didn't boot off this drive */ driveno = d->wren.ctrl*NCtlrdrv + d->wren.targ; DPRINT("%Z: mvideinit\n", d); setmv50part(driveno, "disk"); dp = mvsatadriveprobe(driveno); if (dp) { print("mvideinit(ctrl %d targ %d) driveno %d\n", d->wren.ctrl, d->wren.targ, dp->driveno); if (dp->driveno != driveno) panic("mvideinit: dp->dev != driveno"); if (dp->magic != Drvmagic) panic("mvideinit: %Z: bad drive magic", d); d->private = dp; if (dp->unit == nil) panic("mvideinit: %Z: nil dp->unit", d); /* print the sizes now, not later */ print( " mvidesize(driveno %d): %llud %lud-byte sectors -> %llud blocks\n", dp->driveno, (Wideoff)dp->sectors, dp->unit->secsize, (Wideoff)mvidesize(d)); if (dp->unit->secsize == 0) panic("%Z: zero sector size", d); if (dp->sectors == 0) panic("%Z: zero sectors", d); }}intmvideread(Device *d, Devsize b, void *c){ int x, driveno; Drive *dp; Ctlr *cp; if (d == nil || d->private == nil) { print("mvideread: %Z: nil d or d->private == nil\n", d); return 1; } dp = d->private; cp = dp->ctlr; if (cp == nil) panic("mvideread: no controller for drive"); qlock(&cp->idelock); cp->idelock.name = "mvideio"; driveno = dp->driveno; if (driveno == -1) panic("mvideread: dp->driveno unset"); IDPRINT("mvideread(dev %lux, %lld, %lux, %d): %lux\n", (ulong)d, (Wideoff)b, (ulong)c, driveno, (ulong)dp); mvsataseek(driveno, b * RBUFSIZE); x = mvsataread(driveno, c, RBUFSIZE) != RBUFSIZE; qunlock(&cp->idelock); return x;}intmvidewrite(Device *d, Devsize b, void *c){ int x, driveno; Drive *dp; Ctlr *cp; if (d == nil || d->private == nil) { print("mvidewrite: %Z: nil d or d->private == nil\n", d); return 1; } dp = d->private; cp = dp->ctlr; if (cp == nil) panic("mvidewrite: no controller for drive"); qlock(&cp->idelock); cp->idelock.name = "mvideio"; driveno = dp->driveno; if (driveno == -1) panic("mvidewrite: dp->driveno unset"); IDPRINT("mvidewrite(%ux, %lld, %ux): driveno %d\n", (int)d, (Wideoff)b, (int)c, driveno); mvsataseek(driveno, b * RBUFSIZE); x = mvsatawrite(driveno, c, RBUFSIZE) != RBUFSIZE; qunlock(&cp->idelock); return x;}static voidcmd_stat(int, char*[]){ Ctlr *ctlr; int ctlrno, targetno; Target *tp; for(ctlrno = 0; ctlrno < nelem(mvsatactlr); ctlrno++){ ctlr = mvsatactlr[ctlrno]; if(ctlr == nil || ctlr->sdev == nil) continue; for(targetno = 0; targetno < NTarget; targetno++){ tp = &ctlr->target[targetno]; if(tp->fflag == 0) continue; print("\t%d.%d work =%7W%7W%7W xfrs\n", ctlrno, targetno, tp->work+0, tp->work+1, tp->work+2); print("\t rate =%7W%7W%7W tBps\n", tp->rate+0, tp->rate+1, tp->rate+2); } }}static voidstatsinit(void){ cmd_install("statm", "-- marvell sata stats", cmd_stat);}/* Tab 4 Font* 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.*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -