📄 sdata.c
字号:
ataenable(SDev* sdev){ Ctlr *ctlr; char name[32]; ctlr = sdev->ctlr; if(ctlr->bmiba){#define ALIGN (4 * 1024) if(ctlr->pcidev != nil) pcisetbme(ctlr->pcidev); // ctlr->prdt = xspanalloc(Nprd*sizeof(Prd), 4, 4*1024); ctlr->prdtbase = xalloc(Nprd * sizeof(Prd) + ALIGN); ctlr->prdt = (Prd *)(((ulong)ctlr->prdtbase + ALIGN) & ~(ALIGN - 1)); } snprint(name, sizeof(name), "%s (%s)", sdev->name, sdev->ifc->name); intrenable(ctlr->irq, atainterrupt, ctlr, ctlr->tbdf, name); outb(ctlr->ctlport+Dc, 0); if(ctlr->ienable) ctlr->ienable(ctlr); return 1;}static intatadisable(SDev *sdev){ Ctlr *ctlr; char name[32]; ctlr = sdev->ctlr; outb(ctlr->ctlport+Dc, Nien); /* disable interrupts */ if (ctlr->idisable) ctlr->idisable(ctlr); snprint(name, sizeof(name), "%s (%s)", sdev->name, sdev->ifc->name); intrdisable(ctlr->irq, atainterrupt, ctlr, ctlr->tbdf, name); if (ctlr->bmiba) { if (ctlr->pcidev) pciclrbme(ctlr->pcidev); xfree(ctlr->prdtbase); } return 0;}#ifndef FSstatic intatarctl(SDunit* unit, char* p, int l){ int n; Ctlr *ctlr; Drive *drive; if((ctlr = unit->dev->ctlr) == nil || ctlr->drive[unit->subno] == nil) return 0; drive = ctlr->drive[unit->subno]; qlock(drive); n = snprint(p, l, "config %4.4uX capabilities %4.4uX", drive->info[Iconfig], drive->info[Icapabilities]); if(drive->dma) n += snprint(p+n, l-n, " dma %8.8uX dmactl %8.8uX", drive->dma, drive->dmactl); if(drive->rwm) n += snprint(p+n, l-n, " rwm %ud rwmctl %ud", drive->rwm, drive->rwmctl); if(drive->flags&Lba48) n += snprint(p+n, l-n, " lba48always %s", (drive->flags&Lba48always) ? "on" : "off"); n += snprint(p+n, l-n, "\n"); if(drive->sectors){ n += snprint(p+n, l-n, "geometry %lld %d", (Wideoff)drive->sectors, drive->secsize); if(drive->pkt == 0) n += snprint(p+n, l-n, " %d %d %d", drive->c, drive->h, drive->s); n += snprint(p+n, l-n, "\n"); } qunlock(drive); return n;}static intatawctl(SDunit* unit, Cmdbuf* cb){ int period; Ctlr *ctlr; Drive *drive; if((ctlr = unit->dev->ctlr) == nil || ctlr->drive[unit->subno] == nil) return 0; drive = ctlr->drive[unit->subno]; qlock(drive); if(waserror()){ qunlock(drive); nexterror(); } /* * Dma and rwm control is passive at the moment, * i.e. it is assumed that the hardware is set up * correctly already either by the BIOS or when * the drive was initially identified. */ if(strcmp(cb->f[0], "dma") == 0){ if(cb->nf != 2 || drive->dma == 0) error(Ebadctl); if(strcmp(cb->f[1], "on") == 0) drive->dmactl = drive->dma; else if(strcmp(cb->f[1], "off") == 0) drive->dmactl = 0; else error(Ebadctl); } else if(strcmp(cb->f[0], "rwm") == 0){ if(cb->nf != 2 || drive->rwm == 0) error(Ebadctl); if(strcmp(cb->f[1], "on") == 0) drive->rwmctl = drive->rwm; else if(strcmp(cb->f[1], "off") == 0) drive->rwmctl = 0; else error(Ebadctl); } else if(strcmp(cb->f[0], "standby") == 0){ switch(cb->nf){ default: error(Ebadctl); case 2: period = strtol(cb->f[1], 0, 0); if(period && (period < 30 || period > 240*5)) error(Ebadctl); period /= 5; break; } if(atastandby(drive, period) != SDok) error(Ebadctl); } else if(strcmp(cb->f[0], "lba48always") == 0){ if(cb->nf != 2 || !(drive->flags&Lba48)) error(Ebadctl); if(strcmp(cb->f[1], "on") == 0) drive->flags |= Lba48always; else if(strcmp(cb->f[1], "off") == 0) drive->flags &= ~Lba48always; else error(Ebadctl); } else error(Ebadctl); qunlock(drive); poperror(); return 0;}#endifSDifc sdataifc = { "ata", /* name */ atapnp, /* pnp */ atalegacy, /* legacy */ ataid, /* id */ ataenable, /* enable */ atadisable, /* disable */ scsiverify, /* verify */ scsionline, /* online */ atario, /* rio */ nil, //atarctl, /* rctl */ nil, //atawctl, /* wctl */ scsibio, /* bio */#ifndef FS nil, //ataprobew, /* probe */ ataclear, /* clear */ atastat, /* stat */#endif};/* * file-server-specific routines * * ata* routines below this point are used to access nvram file, * ide* routines implement the `h' device and call the ata* routines. */static Drive*atapart(Drive *dp){ return dp;}static Drive*atadriveprobe(int driveno){ Drive *drive; drive = atadrive[driveno]; if (drive == nil) return nil; drive->driveno = driveno; if(drive->online == 0){ if(drive->lba) print("h%d: LBA %llud sectors\n", drive->driveno, (Wideoff)drive->sectors); else print("h%d: CHS %d/%d/%d %llud sectors\n", drive->driveno, drive->c, drive->h, drive->s, (Wideoff)drive->sectors); drive->online = 1; } return atapart(drive);}static voidcmd_stat(int, char*[]){ Ctlr *ctlr; int ctlrno, targetno; Target *tp; for(ctlrno = 0; ctlrno < nelem(atactlr); ctlrno++){ ctlr = atactlr[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); } }}/* find all the controllers, enable interrupts, set up SDevs & SDunits */intatainit(void){ unsigned i; SDev *sdp; SDev **sdpp; static int first = 1; if (first) first = 0; else return 0xFF; atapnp(); for (sdpp = sdevs; sdpp < sdevs + nelem(sdevs); sdpp++) { sdp = *sdpp; if (sdp == nil) continue; i = sdpp - sdevs; sdp->ifc = &sdataifc; sdp->nunit = NCtlrdrv; sdp->index = i; sdp->idno = 'C' + i; sdp->ctlr = atactlr[i]; if (sdp->ctlr != nil) ataenable(sdp); } cmd_install("stati", "-- ide/ata stats", cmd_stat); return 0xFF;}Devsizeataseek(int driveno, Devsize offset){ Drive *drive = atadrive[driveno]; if (drive == nil || !drive->online) return -1; drive->offset = offset; return offset;}/* zero indicates failure; only otherinit() cares */intsetatapart(int driveno, char *){ /* atadriveprobe() sets drive->online */ if(atadriveprobe(driveno) == nil) return 0; return 1;}static voidkeepstats(Drive *dp, int dbytes){ Target *tp = &dp->ctlr->target[dp->driveno%NCtlrdrv]; qlock(tp);// if(tp->ok == 0)// scsiprobe(d); 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 longataxfer(Drive *dp, int inout, Devsize start, long bytes){ unsigned driveno = dp->driveno; ulong secsize = dp->secsize, sects; SDunit *unit = sdgetunit(sdevs[driveno/NCtlrdrv], driveno%NCtlrdrv); if (unit == nil) { print("mvsataxfer: nil unit\n"); return -1; } if (dp->driveno == -1) panic("ataxfer: dp->driveno unset"); /* * unit->dev will be nil if the controller is missing (e.g., h0 on a * machine with only sdD, not sdC), so make this a non-fatal error. */ if (unit->dev == nil) { print("ataxfer: missing controller for h%d\n", driveno); return -1; } if (unit->dev != sdevs[driveno/NCtlrdrv]) panic("ataxfer: sdunits[%d].dev=%p is wrong controller (want %p)", driveno, unit->dev, sdevs + driveno/NCtlrdrv); if (unit->subno != driveno%NCtlrdrv) panic("ataxfer: sdunits[%d].subno is %d, not %d", driveno, unit->subno, driveno%NCtlrdrv); keepstats(dp, bytes); if (unit->sectors == 0) { unit->sectors = dp->sectors; unit->secsize = secsize; } sects = (bytes + secsize - 1) / secsize; /* round up */ if (start%secsize != 0) print("ataxfer: start offset not on sector boundary\n"); return scsibio(unit, 0, inout, dp->buf, sects, start/secsize);}/* * ataread & atawrite do the real work; ideread & idewrite just call them. * ataread & atawrite are called by the nvram routines. * ideread & idewrite are called for normal file server I/O. */Offataread(int driveno, void *a, long n){ int skip; Off rv, i; uchar *aa = a;// Ctlr *cp; Drive *dp; dp = atadrive[driveno]; if(dp == nil || !dp->online) return 0;// cp = dp->ctlr; if (dp->secsize == 0) panic("ataread: sector size of zero"); skip = dp->offset % dp->secsize; for(rv = 0; rv < n; rv += i){ i = ataxfer(dp, 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;}Offatawrite(int driveno, void *a, long n){ Off rv, i, partial; uchar *aa = a;// Ctlr *cp; Drive *dp; dp = atadrive[driveno]; if(dp == nil || !dp->online) return 0;// cp = dp->ctlr; /* * if not starting on a sector boundary, * read in the first sector before writing it out. */ if (dp->secsize == 0) panic("atawrite: sector size of zero"); partial = dp->offset % dp->secsize; if(partial){ if (ataxfer(dp, Read, dp->offset-partial, dp->secsize) < 0) return -1; if(partial+n > dp->secsize) rv = dp->secsize - partial; else rv = n; memmove(dp->buf+partial, aa, rv); if(ataxfer(dp, Write, dp->offset-partial, dp->secsize) < 0) return -1; } else rv = 0; /* * write out the full sectors (common case) */ partial = (n - rv) % dp->secsize; n -= partial; for(; rv < n; rv += i){ i = n - rv; if(i > Maxxfer) i = Maxxfer; memmove(dp->buf, aa+rv, i); i = ataxfer(dp, 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(ataxfer(dp, Read, dp->offset+rv, dp->secsize) < 0) return -1; memmove(dp->buf, aa+rv, partial); if(ataxfer(dp, Write, dp->offset+rv, dp->secsize) < 0) return -1; rv += partial; } dp->offset += rv; return rv;}/* * normal I/O interface *//* result is size of d in blocks of RBUFSIZE bytes */Devsizeidesize(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->secsize;}voidideinit(Device *d){ int driveno; Drive *dp; atainit(); if (d->private) return; /* call setatapart() first in case we didn't boot off this drive */ driveno = d->wren.ctrl*NCtlrdrv + d->wren.targ; setatapart(driveno, "disk"); dp = atadriveprobe(driveno); if (dp) { print("ideinit(ctrl %d targ %d) driveno %d\n", d->wren.ctrl, d->wren.targ, dp->driveno); if (dp->driveno != driveno) panic("ideinit: dp->dev != driveno"); d->private = dp; /* print the sizes now, not later */ print( " idesize(driveno %d): %llud %d-byte sectors -> %llud blocks\n", dp->driveno, (Wideoff)dp->sectors, dp->secsize, (Wideoff)idesize(d)); }}intideread(Device *d, Devsize b, void *c){ int x, driveno; Drive *dp; Ctlr *cp; if (d == nil || d->private == nil) return 1; dp = d->private; cp = dp->ctlr; if (cp == nil) panic("ideread: no controller for drive"); qlock(&cp->idelock); cp->idelock.name = "ideio"; driveno = dp->driveno; if (driveno == -1) panic("ideread: dp->driveno unset"); IDPRINT("ideread(dev %p, %lld, %p, %d): %p\n", d, (Wideoff)b, c, driveno, dp); ataseek(driveno, b * RBUFSIZE); x = ataread(driveno, c, RBUFSIZE) != RBUFSIZE; qunlock(&cp->idelock); return x;}intidewrite(Device *d, Devsize b, void *c){ int x, driveno; Drive *dp; Ctlr *cp; if (d == nil || d->private == nil) return 1; dp = d->private; cp = dp->ctlr; if (cp == nil) panic("idewrite: no controller for drive"); qlock(&cp->idelock); cp->idelock.name = "ideio"; driveno = dp->driveno; if (driveno == -1) panic("idewrite: dp->driveno unset"); IDPRINT("idewrite(%p, %lld, %p): driveno %d\n", d, (Wideoff)b, c, driveno); ataseek(driveno, b * RBUFSIZE); x = atawrite(driveno, c, RBUFSIZE) != RBUFSIZE; qunlock(&cp->idelock); return x;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -