| plan 9 kernel history: overview | file list | diff list |
1992/0808/port/devwren.c (diff list | history)
| port/devwren.c on 1991/0110 | ||
| 1991/0110 | #include "u.h" | |
| 1992/0321 | #include "../port/lib.h" | |
| 1991/0110 | #include "mem.h" #include "dat.h" #include "fns.h" | |
| 1992/0111 | #include "../port/error.h" | |
| 1991/0110 | #include "devtab.h" #include "io.h" | |
| 1991/0927 | #define DATASIZE (8*1024) | |
| 1991/0823 | typedef struct Partition Partition; typedef struct Drive Drive; | |
| 1991/0112 | ||
| 1991/0110 | enum { | |
| 1991/0823 | Npart= 8+2, /* 8 sub partitions, disk, and partition */ | |
| 1991/1019 | Ndisk= 64, /* maximum disks; if you change it, you must map from dev to disk */ | |
| 1991/0110 | ||
| 1991/0823 | /* file types */ | |
| 1991/0112 | Qdir= 0, | |
| 1991/0110 | }; | |
| 1991/0823 | #define PART(x) ((x)&0xF) | |
| 1991/0927 | #define DRIVE(x) (((x)>>4)&(Ndisk-1)) | |
| 1991/0823 | #define MKQID(d,p) (((d)<<4) | (p)) | |
| 1991/0110 | ||
| 1991/0823 | struct Partition | |
| 1991/0112 | { | |
| 1991/0823 | ulong start; ulong end; char name[NAMELEN+1]; | |
| 1991/0112 | }; | |
| 1991/0823 | struct Drive | |
| 1991/0112 | { | |
| 1992/0301 | QLock; | |
| 1991/0823 | ulong bytes; /* bytes per block */ int npart; /* actual number of partitions */ int drive; | |
| 1992/0808 | int readonly; | |
| 1991/0823 | Partition p[Npart]; | |
| 1991/0112 | }; | |
| 1991/0110 | ||
| 1991/0823 | static Drive wren[Ndisk]; | |
| 1991/0110 | ||
| 1991/0823 | static void wrenpart(int); | |
| 1991/1203 | static long wrenio(Chan*, int, char*, ulong, ulong); | |
| 1991/0115 | ||
| 1991/0110 | /* * accepts [0-7].[0-7], or abbreviation */ static int wrendev(char *p) { | |
| 1991/1019 | int drive, unit; | |
| 1991/0823 | ||
| 1991/1019 | if(p == 0 || p[0] == '\0') return 0; | |
| 1991/0823 | if(p[0] < '0' || p[0] > '7') | |
| 1992/0114 | error(Ebadarg); | |
| 1991/1019 | drive = p[0] - '0'; unit = 0; if(p[1]){ if(p[1] != '.' || p[2] < '0' || p[2] > '7' || p[3] != '\0') | |
| 1992/0114 | error(Ebadarg); | |
| 1991/1019 | unit = p[2] - '0'; } return (drive << 3) | unit; | |
| 1991/0110 | } static int | |
| 1991/0823 | wrengen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dirp) | |
| 1991/0110 | { | |
| 1991/0823 | Qid qid; int drive; char name[NAMELEN+4]; Drive *dp; Partition *pp; ulong l; | |
| 1991/0112 | ||
| 1992/0711 | USED(tab, ntab); | |
| 1991/0823 | qid.vers = 0; | |
| 1991/0927 | drive = c->dev; | |
| 1991/0823 | if(drive >= Ndisk) | |
| 1991/0110 | return -1; | |
| 1991/0823 | dp = &wren[drive]; | |
| 1991/0112 | ||
| 1991/0823 | if(s >= dp->npart) | |
| 1991/0927 | return -1; | |
| 1991/0823 | pp = &dp->p[s]; | |
| 1991/0927 | if(drive & 7) sprint(name, "hd%d.%d%s", drive>>3, drive&7, pp->name); else sprint(name, "hd%d%s", drive>>3, pp->name); | |
| 1991/0823 | name[NAMELEN] = 0; qid.path = MKQID(drive, s); l = (pp->end - pp->start) * dp->bytes; | |
| 1992/0808 | devdir(c, qid, name, l, eve, dp->readonly ? 0444 : 0666, dirp); | |
| 1991/0110 | return 1; } void wrenreset(void) | |
| 1991/0112 | { } | |
| 1991/0110 | void wreninit(void) | |
| 1991/0823 | { } | |
| 1991/0110 | /* | |
| 1992/0808 | * param is #w<target>.<lun> | |
| 1991/0110 | */ Chan * wrenattach(char *param) { Chan *c; | |
| 1991/0823 | int drive; | |
| 1991/0112 | ||
| 1991/0823 | drive = wrendev(param); wrenpart(drive); | |
| 1991/0921 | c = devattach('w', param); | |
| 1991/0823 | c->dev = drive; | |
| 1991/0110 | return c; } | |
| 1991/0823 | Chan* | |
| 1991/0110 | wrenclone(Chan *c, Chan *nc) { return devclone(c, nc); } int wrenwalk(Chan *c, char *name) { | |
| 1991/0823 | return devwalk(c, name, 0, 0, wrengen); | |
| 1991/0110 | } void | |
| 1991/0823 | wrenstat(Chan *c, char *dp) | |
| 1991/0110 | { | |
| 1991/0823 | devstat(c, dp, 0, 0, wrengen); | |
| 1991/0110 | } | |
| 1991/0823 | Chan* | |
| 1991/0110 | wrenopen(Chan *c, int omode) { | |
| 1991/0823 | return devopen(c, omode, 0, 0, wrengen); | |
| 1991/0110 | } void wrencreate(Chan *c, char *name, int omode, ulong perm) { | |
| 1991/1210 | USED(c, name, omode, perm); | |
| 1991/0110 | error(Eperm); } void wrenclose(Chan *c) | |
| 1991/0823 | { | |
| 1991/1210 | USED(c); | |
| 1991/0823 | } | |
| 1991/0110 | ||
| 1991/0823 | void wrenremove(Chan *c) { | |
| 1991/1210 | USED(c); | |
| 1991/0823 | error(Eperm); } void wrenwstat(Chan *c, char *dp) { | |
| 1991/1210 | USED(c, dp); | |
| 1991/0823 | error(Eperm); } | |
| 1991/0110 | long | |
| 1991/0411 | wrenread(Chan *c, char *a, long n, ulong offset) | |
| 1991/0110 | { | |
| 1991/0112 | if(c->qid.path == CHDIR) | |
| 1991/0823 | return devdirread(c, a, n, 0, 0, wrengen); | |
| 1991/1203 | return wrenio(c, 0, a, n, offset); | |
| 1991/0110 | } long | |
| 1991/0411 | wrenwrite(Chan *c, char *a, long n, ulong offset) | |
| 1991/0110 | { | |
| 1992/0129 | n = wrenio(c, 1, a, n, offset); if(n) return n; error("end of device"); | |
| 1992/0603 | return 0; /* not reached */ | |
| 1991/1203 | } static long wrenio(Chan *c, int write, char *a, ulong len, ulong offset) { | |
| 1991/0823 | Drive *d; Partition *p; | |
| 1991/1203 | Scsibuf *b; ulong block, n, max, x; | |
| 1991/0823 | d = &wren[DRIVE(c->qid.path)]; | |
| 1992/0114 | if(d->npart == 0) /* drive repartitioned */ error(Eio); | |
| 1991/0823 | p = &d->p[PART(c->qid.path)]; block = offset / d->bytes + p->start; | |
| 1991/1203 | n = (offset + len + d->bytes - 1) / d->bytes + p->start - block; max = DATASIZE / d->bytes; if(n > max) n = max; | |
| 1991/0823 | if(block + n > p->end) n = p->end - block; | |
| 1991/1203 | if(block >= p->end || n == 0) | |
| 1991/0823 | return 0; | |
| 1991/0927 | b = scsibuf(); | |
| 1991/0823 | if(waserror()){ | |
| 1991/0927 | scsifree(b); | |
| 1991/0823 | nexterror(); | |
| 1991/0110 | } | |
| 1991/1203 | offset %= d->bytes; | |
| 1991/0927 | if(write){ | |
| 1991/1203 | if(offset || len % d->bytes){ x = scsibread(d->drive, b, n, d->bytes, block); if(x < n * d->bytes){ n = x / d->bytes; x = n * d->bytes - offset; if(len > x) len = x; } } memmove((char*)b->virt + offset, a, len); x = scsibwrite(d->drive, b, n, d->bytes, block); if(x < offset) len = 0; else if(len > x - offset) len = x - offset; | |
| 1991/0927 | }else{ | |
| 1991/1203 | x = scsibread(d->drive, b, n, d->bytes, block); if(x < offset) len = 0; else if(len > x - offset) len = x - offset; memmove(a, (char*)b->virt + offset, len); | |
| 1991/0927 | } | |
| 1991/0823 | poperror(); | |
| 1991/0927 | scsifree(b); | |
| 1991/1203 | return len; | |
| 1991/0110 | } | |
| 1991/0823 | /* * read partition table. The partition table is just ascii strings. */ #define MAGIC "plan9 partitions" static void wrenpart(int dev) | |
| 1991/0110 | { | |
| 1991/0823 | Drive *dp; Partition *pp; uchar buf[32]; | |
| 1991/0927 | Scsibuf *b; char *rawpart, *line[Npart+1], *field[3]; | |
| 1991/0823 | ulong n; int i; | |
| 1991/0110 | ||
| 1992/0301 | dp = &wren[dev]; if(waserror()){ qunlock(dp); nexterror(); } qlock(dp); | |
| 1992/0808 | scsiready(dev); scsisense(dev, buf); if(scsicap(dev, buf)) error(Eio); dp->drive = dev; dp->readonly = scsiwp(dev); | |
| 1992/0301 | ||
| 1992/0808 | /* * we always have a partition for the whole disk * and one for the partition table */ dp->bytes = (buf[4]<<24)+(buf[5]<<16)+(buf[6]<<8)+(buf[7]); pp = &dp->p[0]; strcpy(pp->name, "disk"); pp->start = 0; pp->end = (buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+(buf[3]) + 1; pp++; strcpy(pp->name, "partition"); pp->start = dp->p[0].end - 1; pp->end = dp->p[0].end; | |
| 1991/0927 | ||
| 1991/0823 | /* * read partition table from disk, null terminate */ | |
| 1991/0927 | b = scsibuf(); | |
| 1991/0823 | if(waserror()){ | |
| 1991/0927 | scsifree(b); | |
| 1991/0823 | nexterror(); } | |
| 1991/0927 | scsibread(dev, b, 1, dp->bytes, dp->p[0].end-1); rawpart = b->virt; rawpart[dp->bytes-1] = 0; | |
| 1991/0823 | /* * parse partition table. */ | |
| 1992/0301 | pp = &dp->p[2]; | |
| 1991/0927 | n = getfields(rawpart, line, Npart+1, '\n'); | |
| 1992/0808 | if(n > 0 && strncmp(line[0], MAGIC, sizeof(MAGIC)-1) == 0){ | |
| 1991/0927 | for(i = 1; i < n; i++){ | |
| 1992/0219 | if(getfields(line[i], field, 3, ' ') != 3) | |
| 1991/0927 | break; strncpy(pp->name, field[0], NAMELEN); pp->start = strtoul(field[1], 0, 0); pp->end = strtoul(field[2], 0, 0); | |
| 1992/0219 | if(pp->start > pp->end || pp->start >= dp->p[0].end) | |
| 1991/0927 | break; | |
| 1992/0301 | pp++; | |
| 1991/0823 | } } | |
| 1992/0301 | dp->npart = pp - dp->p; | |
| 1991/0823 | poperror(); | |
| 1991/0927 | scsifree(b); | |
| 1992/0303 | poperror(); | |
| 1992/0301 | qunlock(dp); | |
| 1991/0110 | } | |