/* * Storage Device. */#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "ureg.h"#include "../port/error.h" #include "../port/sd.h" extern Dev sddevtab;extern SDifc* sdifc[]; typedef struct SDevgrp { SDev* dev; int nunits; /* num units in dev */} SDevgrp; static SDevgrp* devs; /* all devices */static QLock devslock; /* insertion and removal of devices */static int ndevs; /* total number of devices in the system */ enum { Rawcmd, Rawdata, Rawstatus,}; enum { Qtopdir = 1, /* top level directory */ Qtopbase, Qtopctl = Qtopbase, Qtopstat, Qunitdir, /* directory per unit */ Qunitbase, Qctl = Qunitbase, Qraw, Qpart, TypeLOG = 4, NType = (1<<TypeLOG), TypeMASK = (NType-1), TypeSHIFT = 0, PartLOG = 8, NPart = (1<<PartLOG), PartMASK = (NPart-1), PartSHIFT = TypeLOG, UnitLOG = 8, NUnit = (1<<UnitLOG), UnitMASK = (NUnit-1), UnitSHIFT = (PartLOG+TypeLOG), DevLOG = 8, NDev = (1 << DevLOG), DevMASK = (NDev-1), DevSHIFT = (UnitLOG+PartLOG+TypeLOG), Ncmd = 20,}; #define TYPE(q) ((((ulong)(q).path)>>TypeSHIFT) & TypeMASK)#define PART(q) ((((ulong)(q).path)>>PartSHIFT) & PartMASK)#define UNIT(q) ((((ulong)(q).path)>>UnitSHIFT) & UnitMASK)#define DEV(q) ((((ulong)(q).path)>>DevSHIFT) & DevMASK)#define QID(d,u, p, t) (((d)<<DevSHIFT)|((u)<<UnitSHIFT)|\ ((p)<<PartSHIFT)|((t)<<TypeSHIFT)) static voidsdaddpart(SDunit* unit, char* name, ulong start, ulong end){ SDpart *pp; int i, partno; /* * Check name not already used * and look for a free slot. */ if(unit->part != nil){ partno = -1; for(i = 0; i < unit->npart; i++){ pp = &unit->part[i]; if(!pp->valid){ if(partno == -1) partno = i; break; } if(strcmp(name, pp->name) == 0){ if(pp->start == start && pp->end == end) return; error(Ebadctl); } } } else{ if((unit->part = malloc(sizeof(SDpart)*SDnpart)) == nil) error(Enomem); unit->npart = SDnpart; partno = 0; } /* * If no free slot found then increase the * array size (can't get here with unit->part == nil). */ if(partno == -1){ if(unit->npart >= NPart) error(Enomem); if((pp = malloc(sizeof(SDpart)*(unit->npart+SDnpart))) == nil) error(Enomem); memmove(pp, unit->part, sizeof(SDpart)*unit->npart); free(unit->part); unit->part = pp; partno = unit->npart; unit->npart += SDnpart; } /* * Check size and extent are valid. */ if(start > end || end > unit->sectors) error(Eio); pp = &unit->part[partno]; pp->start = start; pp->end = end; kstrdup(&pp->name, name); kstrdup(&pp->user, eve); pp->perm = 0640; pp->valid = 1;} static voidsddelpart(SDunit* unit, char* name){ int i; SDpart *pp; /* * Look for the partition to delete. * Can't delete if someone still has it open. */ pp = unit->part; for(i = 0; i < unit->npart; i++){ if(strcmp(name, pp->name) == 0) break; pp++; } if(i >= unit->npart) error(Ebadctl); if(strcmp(up->env->user, pp->user) && !iseve()) error(Eperm); pp->valid = 0; pp->vers++;} static intsdinitpart(SDunit* unit){ int i, nf; ulong start, end; char *f[4], *p, *q, buf[10]; unit->vers++; unit->sectors = unit->secsize = 0; if(unit->part){ for(i = 0; i < unit->npart; i++){ unit->part[i].valid = 0; unit->part[i].vers++; } } if(unit->inquiry[0] & 0xC0) return 0; switch(unit->inquiry[0] & 0x1F){ case 0x00: /* DA */ case 0x04: /* WORM */ case 0x05: /* CD-ROM */ case 0x07: /* MO */ break; default: return 0; } if(unit->dev->ifc->online) unit->dev->ifc->online(unit); if(unit->sectors){ sdaddpart(unit, "data", 0, unit->sectors); /* * Use partitions passed from boot program, * e.g. * sdC0part=dos 63 123123/plan9 123123 456456 * This happens before /boot sets hostname so the * partitions will have the null-string for user. * The gen functions patch it up. */ snprint(buf, sizeof buf, "%spart", unit->name); for(p = getconf(buf); p != nil; p = q){ if(q = strchr(p, '/')) *q++ = '\0'; nf = tokenize(p, f, nelem(f)); if(nf < 3) continue; start = strtoul(f[1], 0, 0); end = strtoul(f[2], 0, 0); if(!waserror()){ sdaddpart(unit, f[0], start, end); poperror(); } } } return 1;} static SDev*sdgetdev(int idno){ SDev *sdev; int i; qlock(&devslock); for(i = 0; i != ndevs; i++) if(devs[i].dev->idno == idno) break; if(i == ndevs) sdev = nil; else{ sdev = devs[i].dev; incref(&sdev->r); } qunlock(&devslock); return sdev;} static SDunit*sdgetunit(SDev* sdev, int subno){ SDunit *unit; char buf[32]; /* * Associate a unit with a given device and sub-unit * number on that device. * The device will be probed if it has not already been * successfully accessed. */ qlock(&sdev->unitlock); if(subno > sdev->nunit){ qunlock(&sdev->unitlock); return nil; } unit = sdev->unit[subno]; if(unit == nil){ /* * Probe the unit only once. This decision * may be a little severe and reviewed later. */ if(sdev->unitflg[subno]){ qunlock(&sdev->unitlock); return nil; } if((unit = malloc(sizeof(SDunit))) == nil){ qunlock(&sdev->unitlock); return nil; } sdev->unitflg[subno] = 1; snprint(buf, sizeof(buf), "%s%d", sdev->name, subno); kstrdup(&unit->name, buf); kstrdup(&unit->user, eve); unit->perm = 0555; unit->subno = subno; unit->dev = sdev; if(sdev->enabled == 0 && sdev->ifc->enable) sdev->ifc->enable(sdev); sdev->enabled = 1; /* * No need to lock anything here as this is only * called before the unit is made available in the * sdunit[] array. */ if(unit->dev->ifc->verify(unit) == 0){ qunlock(&sdev->unitlock); free(unit); return nil; } sdev->unit[subno] = unit; } qunlock(&sdev->unitlock); return unit;} static voidsdreset(void){ int i; SDev *sdev, *tail, *sdlist; /* * Probe all configured controllers and make a list * of devices found, accumulating a possible maximum number * of units attached and marking each device with an index * into the linear top-level directory array of units. */ tail = sdlist = nil; for(i = 0; sdifc[i] != nil; i++){ if(sdifc[i]->pnp == nil || (sdev = sdifc[i]->pnp()) == nil) continue; if(sdlist != nil) tail->next = sdev; else sdlist = sdev; for(tail = sdev; tail->next != nil; tail = tail->next){ tail->unit = (SDunit**)malloc(tail->nunit * sizeof(SDunit*)); tail->unitflg = (int*)malloc(tail->nunit * sizeof(int)); assert(tail->unit && tail->unitflg); ndevs++; } tail->unit = (SDunit**)malloc(tail->nunit * sizeof(SDunit*)); tail->unitflg = (int*)malloc(tail->nunit * sizeof(int)); ndevs++; } /* * Legacy and option code goes here. This will be hard... */ /* * The maximum number of possible units is known, allocate * placeholders for their datastructures; the units will be * probed and structures allocated when attached. * Allocate controller names for the different types. */ if(ndevs == 0) return; for(i = 0; sdifc[i] != nil; i++){ /* * BUG: no check is made here or later when a * unit is attached that the id and name are set. */ if(sdifc[i]->id) sdifc[i]->id(sdlist); } /* * The IDs have been set, unlink the sdlist and copy the spec to * the devtab. */ devs = (SDevgrp*)malloc(ndevs * sizeof(SDevgrp)); memset(devs, 0, ndevs * sizeof(SDevgrp)); i = 0; while(sdlist != nil){ devs[i].dev = sdlist; devs[i].nunits = sdlist->nunit; sdlist = sdlist->next; devs[i].dev->next = nil; i++; }} static intsd2gen(Chan* c, int i, Dir* dp){ Qid q; vlong l; SDpart *pp; SDperm *perm; SDunit *unit; SDev *sdev; int rv; sdev = sdgetdev(DEV(c->qid)); assert(sdev); unit = sdev->unit[UNIT(c->qid)]; rv = -1; switch(i){ case Qctl: mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qctl), unit->vers, QTFILE); perm = &unit->ctlperm; if(emptystr(perm->user)){ kstrdup(&perm->user, eve); perm->perm = 0640; } devdir(c, q, "ctl", 0, perm->user, perm->perm, dp); rv = 1; break; case Qraw: mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qraw), unit->vers, QTFILE); perm = &unit->rawperm; if(emptystr(perm->user)){ kstrdup(&perm->user, eve); perm->perm = DMEXCL|0600; } devdir(c, q, "raw", 0, perm->user, perm->perm, dp); rv = 1; break; case Qpart: pp = &unit->part[PART(c->qid)]; l = (pp->end - pp->start) * (vlong)unit->secsize; mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qpart), unit->vers+pp->vers, QTFILE); if(emptystr(pp->user)) kstrdup(&pp->user, eve); devdir(c, q, pp->name, l, pp->user, pp->perm, dp); rv = 1; break; } decref(&sdev->r); return rv;} static intsd1gen(Chan* c, int i, Dir* dp){ Qid q; switch(i){ case Qtopctl: mkqid(&q, QID(0, 0, 0, Qtopctl), 0, QTFILE); devdir(c, q, "sdctl", 0, eve, 0640, dp); return 1; case Qtopstat: mkqid(&q, QID(0, 0, 0, Qtopstat), 0, QTFILE); devdir(c, q, "sdstat", 0, eve, 0640, dp); return 1; } return -1;} static intsdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp){ Qid q; vlong l; int i, r; SDpart *pp; SDunit *unit; SDev *sdev; switch(TYPE(c->qid)){ case Qtopdir: if(s == DEVDOTDOT){ mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR); sprint(up->genbuf, "#%C", sddevtab.dc); devdir(c, q, up->genbuf, 0, eve, 0555, dp); return 1; } if(s == 0 || s == 1) return sd1gen(c, s + Qtopbase, dp); s -= 2; qlock(&devslock); for(i = 0; i != ndevs; i++){ if(s < devs[i].nunits) break; s -= devs[i].nunits; } if(i == ndevs){ /* Run of the end of the list */ qunlock(&devslock); return -1; } if((sdev = devs[i].dev) == nil){ qunlock(&devslock); return 0; } incref(&sdev->r); qunlock(&devslock); if((unit = sdev->unit[s]) == nil) if((unit = sdgetunit(sdev, s)) == nil){ decref(&sdev->r); return 0; } mkqid(&q, QID(sdev->idno, s, 0, Qunitdir), 0, QTDIR); if(emptystr(unit->user))Lines 1–500 of 1474. Load more
/* * Storage Device. */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "ureg.h" #include "../port/error.h" #include "../port/sd.h" extern Dev sddevtab; extern SDifc* sdifc[]; typedef struct SDevgrp { SDev* dev; int nunits; /* num units in dev */ } SDevgrp; static SDevgrp* devs; /* all devices */ static QLock devslock; /* insertion and removal of devices */ static int ndevs; /* total number of devices in the system */ enum { Rawcmd, Rawdata, Rawstatus, }; enum { Qtopdir = 1, /* top level directory */ Qtopbase, Qtopctl = Qtopbase, Qtopstat, Qunitdir, /* directory per unit */ Qunitbase, Qctl = Qunitbase, Qraw, Qpart, TypeLOG = 4, NType = (1<<TypeLOG), TypeMASK = (NType-1), TypeSHIFT = 0, PartLOG = 8, NPart = (1<<PartLOG), PartMASK = (NPart-1), PartSHIFT = TypeLOG, UnitLOG = 8, NUnit = (1<<UnitLOG), UnitMASK = (NUnit-1), UnitSHIFT = (PartLOG+TypeLOG), DevLOG = 8, NDev = (1 << DevLOG), DevMASK = (NDev-1), DevSHIFT = (UnitLOG+PartLOG+TypeLOG), Ncmd = 20, }; #define TYPE(q) ((((ulong)(q).path)>>TypeSHIFT) & TypeMASK) #define PART(q) ((((ulong)(q).path)>>PartSHIFT) & PartMASK) #define UNIT(q) ((((ulong)(q).path)>>UnitSHIFT) & UnitMASK) #define DEV(q) ((((ulong)(q).path)>>DevSHIFT) & DevMASK) #define QID(d,u, p, t) (((d)<<DevSHIFT)|((u)<<UnitSHIFT)|\ ((p)<<PartSHIFT)|((t)<<TypeSHIFT)) static void sdaddpart(SDunit* unit, char* name, ulong start, ulong end) { SDpart *pp; int i, partno; /* * Check name not already used * and look for a free slot. */ if(unit->part != nil){ partno = -1; for(i = 0; i < unit->npart; i++){ pp = &unit->part[i]; if(!pp->valid){ if(partno == -1) partno = i; break; } if(strcmp(name, pp->name) == 0){ if(pp->start == start && pp->end == end) return; error(Ebadctl); } } } else{ if((unit->part = malloc(sizeof(SDpart)*SDnpart)) == nil) error(Enomem); unit->npart = SDnpart; partno = 0; } /* * If no free slot found then increase the * array size (can't get here with unit->part == nil). */ if(partno == -1){ if(unit->npart >= NPart) error(Enomem); if((pp = malloc(sizeof(SDpart)*(unit->npart+SDnpart))) == nil) error(Enomem); memmove(pp, unit->part, sizeof(SDpart)*unit->npart); free(unit->part); unit->part = pp; partno = unit->npart; unit->npart += SDnpart; } /* * Check size and extent are valid. */ if(start > end || end > unit->sectors) error(Eio); pp = &unit->part[partno]; pp->start = start; pp->end = end; kstrdup(&pp->name, name); kstrdup(&pp->user, eve); pp->perm = 0640; pp->valid = 1; } static void sddelpart(SDunit* unit, char* name) { int i; SDpart *pp; /* * Look for the partition to delete. * Can't delete if someone still has it open. */ pp = unit->part; for(i = 0; i < unit->npart; i++){ if(strcmp(name, pp->name) == 0) break; pp++; } if(i >= unit->npart) error(Ebadctl); if(strcmp(up->env->user, pp->user) && !iseve()) error(Eperm); pp->valid = 0; pp->vers++; } static int sdinitpart(SDunit* unit) { int i, nf; ulong start, end; char *f[4], *p, *q, buf[10]; unit->vers++; unit->sectors = unit->secsize = 0; if(unit->part){ for(i = 0; i < unit->npart; i++){ unit->part[i].valid = 0; unit->part[i].vers++; } } if(unit->inquiry[0] & 0xC0) return 0; switch(unit->inquiry[0] & 0x1F){ case 0x00: /* DA */ case 0x04: /* WORM */ case 0x05: /* CD-ROM */ case 0x07: /* MO */ break; default: return 0; } if(unit->dev->ifc->online) unit->dev->ifc->online(unit); if(unit->sectors){ sdaddpart(unit, "data", 0, unit->sectors); /* * Use partitions passed from boot program, * e.g. * sdC0part=dos 63 123123/plan9 123123 456456 * This happens before /boot sets hostname so the * partitions will have the null-string for user. * The gen functions patch it up. */ snprint(buf, sizeof buf, "%spart", unit->name); for(p = getconf(buf); p != nil; p = q){ if(q = strchr(p, '/')) *q++ = '\0'; nf = tokenize(p, f, nelem(f)); if(nf < 3) continue; start = strtoul(f[1], 0, 0); end = strtoul(f[2], 0, 0); if(!waserror()){ sdaddpart(unit, f[0], start, end); poperror(); } } } return 1; } static SDev* sdgetdev(int idno) { SDev *sdev; int i; qlock(&devslock); for(i = 0; i != ndevs; i++) if(devs[i].dev->idno == idno) break; if(i == ndevs) sdev = nil; else{ sdev = devs[i].dev; incref(&sdev->r); } qunlock(&devslock); return sdev; } static SDunit* sdgetunit(SDev* sdev, int subno) { SDunit *unit; char buf[32]; /* * Associate a unit with a given device and sub-unit * number on that device. * The device will be probed if it has not already been * successfully accessed. */ qlock(&sdev->unitlock); if(subno > sdev->nunit){ qunlock(&sdev->unitlock); return nil; } unit = sdev->unit[subno]; if(unit == nil){ /* * Probe the unit only once. This decision * may be a little severe and reviewed later. */ if(sdev->unitflg[subno]){ qunlock(&sdev->unitlock); return nil; } if((unit = malloc(sizeof(SDunit))) == nil){ qunlock(&sdev->unitlock); return nil; } sdev->unitflg[subno] = 1; snprint(buf, sizeof(buf), "%s%d", sdev->name, subno); kstrdup(&unit->name, buf); kstrdup(&unit->user, eve); unit->perm = 0555; unit->subno = subno; unit->dev = sdev; if(sdev->enabled == 0 && sdev->ifc->enable) sdev->ifc->enable(sdev); sdev->enabled = 1; /* * No need to lock anything here as this is only * called before the unit is made available in the * sdunit[] array. */ if(unit->dev->ifc->verify(unit) == 0){ qunlock(&sdev->unitlock); free(unit); return nil; } sdev->unit[subno] = unit; } qunlock(&sdev->unitlock); return unit; } static void sdreset(void) { int i; SDev *sdev, *tail, *sdlist; /* * Probe all configured controllers and make a list * of devices found, accumulating a possible maximum number * of units attached and marking each device with an index * into the linear top-level directory array of units. */ tail = sdlist = nil; for(i = 0; sdifc[i] != nil; i++){ if(sdifc[i]->pnp == nil || (sdev = sdifc[i]->pnp()) == nil) continue; if(sdlist != nil) tail->next = sdev; else sdlist = sdev; for(tail = sdev; tail->next != nil; tail = tail->next){ tail->unit = (SDunit**)malloc(tail->nunit * sizeof(SDunit*)); tail->unitflg = (int*)malloc(tail->nunit * sizeof(int)); assert(tail->unit && tail->unitflg); ndevs++; } tail->unit = (SDunit**)malloc(tail->nunit * sizeof(SDunit*)); tail->unitflg = (int*)malloc(tail->nunit * sizeof(int)); ndevs++; } /* * Legacy and option code goes here. This will be hard... */ /* * The maximum number of possible units is known, allocate * placeholders for their datastructures; the units will be * probed and structures allocated when attached. * Allocate controller names for the different types. */ if(ndevs == 0) return; for(i = 0; sdifc[i] != nil; i++){ /* * BUG: no check is made here or later when a * unit is attached that the id and name are set. */ if(sdifc[i]->id) sdifc[i]->id(sdlist); } /* * The IDs have been set, unlink the sdlist and copy the spec to * the devtab. */ devs = (SDevgrp*)malloc(ndevs * sizeof(SDevgrp)); memset(devs, 0, ndevs * sizeof(SDevgrp)); i = 0; while(sdlist != nil){ devs[i].dev = sdlist; devs[i].nunits = sdlist->nunit; sdlist = sdlist->next; devs[i].dev->next = nil; i++; } } static int sd2gen(Chan* c, int i, Dir* dp) { Qid q; vlong l; SDpart *pp; SDperm *perm; SDunit *unit; SDev *sdev; int rv; sdev = sdgetdev(DEV(c->qid)); assert(sdev); unit = sdev->unit[UNIT(c->qid)]; rv = -1; switch(i){ case Qctl: mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qctl), unit->vers, QTFILE); perm = &unit->ctlperm; if(emptystr(perm->user)){ kstrdup(&perm->user, eve); perm->perm = 0640; } devdir(c, q, "ctl", 0, perm->user, perm->perm, dp); rv = 1; break; case Qraw: mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qraw), unit->vers, QTFILE); perm = &unit->rawperm; if(emptystr(perm->user)){ kstrdup(&perm->user, eve); perm->perm = DMEXCL|0600; } devdir(c, q, "raw", 0, perm->user, perm->perm, dp); rv = 1; break; case Qpart: pp = &unit->part[PART(c->qid)]; l = (pp->end - pp->start) * (vlong)unit->secsize; mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qpart), unit->vers+pp->vers, QTFILE); if(emptystr(pp->user)) kstrdup(&pp->user, eve); devdir(c, q, pp->name, l, pp->user, pp->perm, dp); rv = 1; break; } decref(&sdev->r); return rv; } static int sd1gen(Chan* c, int i, Dir* dp) { Qid q; switch(i){ case Qtopctl: mkqid(&q, QID(0, 0, 0, Qtopctl), 0, QTFILE); devdir(c, q, "sdctl", 0, eve, 0640, dp); return 1; case Qtopstat: mkqid(&q, QID(0, 0, 0, Qtopstat), 0, QTFILE); devdir(c, q, "sdstat", 0, eve, 0640, dp); return 1; } return -1; } static int sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp) { Qid q; vlong l; int i, r; SDpart *pp; SDunit *unit; SDev *sdev; switch(TYPE(c->qid)){ case Qtopdir: if(s == DEVDOTDOT){ mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR); sprint(up->genbuf, "#%C", sddevtab.dc); devdir(c, q, up->genbuf, 0, eve, 0555, dp); return 1; } if(s == 0 || s == 1) return sd1gen(c, s + Qtopbase, dp); s -= 2; qlock(&devslock); for(i = 0; i != ndevs; i++){ if(s < devs[i].nunits) break; s -= devs[i].nunits; } if(i == ndevs){ /* Run of the end of the list */ qunlock(&devslock); return -1; } if((sdev = devs[i].dev) == nil){ qunlock(&devslock); return 0; } incref(&sdev->r); qunlock(&devslock); if((unit = sdev->unit[s]) == nil) if((unit = sdgetunit(sdev, s)) == nil){ decref(&sdev->r); return 0; } mkqid(&q, QID(sdev->idno, s, 0, Qunitdir), 0, QTDIR); if(emptystr(unit->user))