📄 devsd.c
字号:
/* * 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 "sd.h"extern Dev sddevtab;extern SDifc* sdifc[];static QLock sdqlock;static SDev* sdlist;static SDunit** sdunit;static int* sdunitflg;static int sdnunit;enum { Rawcmd, Rawdata, Rawstatus,};enum { Qtopdir = 1, /* top level directory */ Qtopbase, Qunitdir, /* directory per unit */ Qunitbase, Qctl = Qunitbase, Qraw, Qpart,};#define TYPE(q) ((q).path & 0x0F)#define PART(q) (((q).path>>4) & 0x0F)#define UNIT(q) (((q).path>>8) & 0xFF)#define QID(u, p, t) (((u)<<8)|((p)<<4)|(t))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 < SDnpart; i++){ pp = &unit->part[i]; if(!pp->valid){ if(partno == -1) partno = i; break; } if(strncmp(name, pp->name, NAMELEN) == 0){ if(pp->start == start && pp->end == end) return; error(Ebadctl); } } } else{ if((unit->part = malloc(sizeof(SDpart)*SDnpart)) == nil) error(Enomem); partno = 0; } /* * Check there is a free slot and size and extent are valid. */ if(partno == -1 || start > end || end > unit->sectors) error(Eio); pp = &unit->part[partno]; pp->start = start; pp->end = end; strncpy(pp->name, name, NAMELEN); strncpy(pp->user, eve, NAMELEN); pp->perm = 0640; pp->valid = 1; unit->npart++;}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. * If it's the last valid partition zap the * whole table. */ pp = unit->part; for(i = 0; i < SDnpart; i++){ if(strncmp(name, pp->name, NAMELEN) == 0) break; pp++; } if(i >= SDnpart) error(Ebadctl); if(strncmp(up->user, pp->user, NAMELEN) && !iseve()) error(Eperm); if(pp->nopen) error(Einuse); pp->valid = 0; unit->npart--; if(unit->npart == 0){ free(unit->part); unit->part = nil; }}static intsdinitpart(SDunit* unit){ int nf; ulong start, end; char *f[4], *p, *q, buf[10]; unit->sectors = unit->secsize = 0; unit->npart = 0; if(unit->part){ free(unit->part); unit->part = nil; } 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 = getfields(p, f, nelem(f), 1, " \t\r"); 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 SDunit*sdgetunit(SDev* sdev, int subno){ int index; SDunit *unit; /* * 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(&sdqlock); index = sdev->index+subno; unit = sdunit[index]; if(unit == nil){ /* * Probe the unit only once. This decision * may be a little severe and reviewed later. */ if(sdunitflg[index]){ qunlock(&sdqlock); return nil; } if((unit = malloc(sizeof(SDunit))) == nil){ qunlock(&sdqlock); return nil; } sdunitflg[index] = 1; if(sdev->enabled == 0 && sdev->ifc->enable) sdev->ifc->enable(sdev); sdev->enabled = 1; snprint(unit->name, NAMELEN, "%s%d", sdev->name, subno); unit->subno = subno; unit->dev = sdev; /* * 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(&sdqlock); free(unit); return nil; } sdunit[index] = unit; } qunlock(&sdqlock); return unit;}static SDunit*sdindex2unit(int index){ SDev *sdev; /* * Associate a unit with a given index into the top-level * device directory. * The device will be probed if it has not already been * successfully accessed. */ for(sdev = sdlist; sdev != nil; sdev = sdev->next){ if(index >= sdev->index && index < sdev->index+sdev->nunit) return sdgetunit(sdev, index-sdev->index); } return nil;}static voidsdreset(void){ int i; SDev *sdev, *tail; /* * 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 = 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){ sdev->index = sdnunit; sdnunit += tail->nunit; } tail->index = sdnunit; sdnunit += tail->nunit; } /* * 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(sdnunit == 0) return; if((sdunit = malloc(sdnunit*sizeof(SDunit*))) == nil) return; if((sdunitflg = malloc(sdnunit*sizeof(int))) == nil){ free(sdunit); sdunit = nil; 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); }}static intsd2gen(Chan* c, int i, Dir* dp){ Qid q; vlong l; SDpart *pp; SDunit *unit; switch(i){ case Qctl: q = (Qid){QID(UNIT(c->qid), PART(c->qid), Qctl), c->qid.vers}; devdir(c, q, "ctl", 0, eve, 0640, dp); return 1; case Qraw: q = (Qid){QID(UNIT(c->qid), PART(c->qid), Qraw), c->qid.vers}; devdir(c, q, "raw", 0, eve, CHEXCL|0600, dp); return 1; case Qpart: unit = sdunit[UNIT(c->qid)]; if(unit->changed) break; pp = &unit->part[PART(c->qid)]; l = (pp->end - pp->start) * (vlong)unit->secsize; q = (Qid){QID(UNIT(c->qid), PART(c->qid), Qpart), c->qid.vers}; if(pp->user[0] == '\0') strncpy(pp->user, eve, NAMELEN); devdir(c, q, pp->name, l, pp->user, pp->perm, dp); return 1; } return -1;}static intsd1gen(Chan*, int i, Dir*){ switch(i){ default: return -1; } return -1;}static intsdgen(Chan* c, Dirtab*, int, int s, Dir* dp){ Qid q; vlong l; int i, r; SDpart *pp; SDunit *unit; char name[NAMELEN]; switch(TYPE(c->qid)){ case Qtopdir: if(s == DEVDOTDOT){ q = (Qid){QID(0, 0, Qtopdir)|CHDIR, 0}; snprint(name, NAMELEN, "#%C", sddevtab.dc); devdir(c, q, name, 0, eve, 0555, dp); return 1; } if(s < sdnunit){ if(sdunit[s] == nil && sdindex2unit(s) == nil) return 0; q = (Qid){QID(s, 0, Qunitdir)|CHDIR, 0}; devdir(c, q, sdunit[s]->name, 0, eve, 0555, dp); return 1; } s -= sdnunit; return sd1gen(c, s+Qtopbase, dp); case Qunitdir: if(s == DEVDOTDOT){ q = (Qid){QID(0, 0, Qtopdir)|CHDIR, 0}; snprint(name, NAMELEN, "#%C", sddevtab.dc); devdir(c, q, name, 0, eve, 0555, dp); return 1; } unit = sdunit[UNIT(c->qid)]; qlock(&unit->ctl); if(!unit->changed && unit->sectors == 0) sdinitpart(unit); i = s+Qunitbase; if(i < Qpart){ r = sd2gen(c, i, dp); qunlock(&unit->ctl); return r; } i -= Qpart; if(unit->npart == 0 || i >= SDnpart){ qunlock(&unit->ctl); break; } pp = &unit->part[i]; if(unit->changed || !pp->valid){ qunlock(&unit->ctl); return 0; } l = (pp->end - pp->start) * (vlong)unit->secsize; q = (Qid){QID(UNIT(c->qid), i, Qpart), c->qid.vers}; if(pp->user[0] == '\0') strncpy(pp->user, eve, NAMELEN); devdir(c, q, pp->name, l, pp->user, pp->perm, dp); qunlock(&unit->ctl); return 1; case Qraw: case Qctl: case Qpart: unit = sdunit[UNIT(c->qid)]; qlock(&unit->ctl); r = sd2gen(c, TYPE(c->qid), dp); qunlock(&unit->ctl); return r; default: break; } return -1;}static Chan*sdattach(char* spec){ Chan *c; char *p; SDev *sdev; int idno, subno; if(sdnunit == 0 || *spec == '\0'){ c = devattach(sddevtab.dc, spec); c->qid = (Qid){QID(0, 0, Qtopdir)|CHDIR, 0}; return c; } if(spec[0] != 's' || spec[1] != 'd') error(Ebadspec); idno = spec[2]; subno = strtol(&spec[3], &p, 0); if(p == &spec[3]) error(Ebadspec); for(sdev = sdlist; sdev != nil; sdev = sdev->next){ if(sdev->idno == idno && subno < sdev->nunit) break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -