diff options
author | cinap_lenrek <cinap_lenrek@localhost> | 2011-07-10 14:14:23 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@localhost> | 2011-07-10 14:14:23 +0200 |
commit | c2fc2fad133d51bc7dc86af015a20aed11a1817f (patch) | |
tree | 8366e17787c48975b1ce1401c731d80763c94629 /sys/src/9/port/sdloop.c | |
parent | ae00ac74659e69a1aee9dc3e3ab20d5ec70b8126 (diff) |
merge sd changes from 9atom
Diffstat (limited to 'sys/src/9/port/sdloop.c')
-rw-r--r-- | sys/src/9/port/sdloop.c | 415 |
1 files changed, 415 insertions, 0 deletions
diff --git a/sys/src/9/port/sdloop.c b/sys/src/9/port/sdloop.c new file mode 100644 index 000000000..80118369d --- /dev/null +++ b/sys/src/9/port/sdloop.c @@ -0,0 +1,415 @@ +/* + * sd loopback driver, + * copyright © 2009-10 erik quanstrom + */ + +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" +#include "../port/sd.h" +#include "../port/netif.h" + +extern char Echange[]; +extern char Enotup[]; + +#define uprint(...) snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__); + +enum { + Maxpath = 256, + Devsectsize = 512, +}; + +typedef struct Ctlr Ctlr; +struct Ctlr { + QLock; + + Ctlr *next; + SDunit *unit; + + char path[Maxpath]; + Chan *c; + + uint vers; + uchar drivechange; + + uvlong sectors; + uint sectsize; +}; + +static Lock ctlrlock; +static Ctlr *head; +static Ctlr *tail; + +SDifc sdloopifc; + +/* must call with c qlocked */ +static void +identify(Ctlr *c, SDunit *u) +{ + int n; + uvlong s, osectors; + uchar buf[sizeof(Dir) + 100]; + Dir dir; + + if(waserror()){ + iprint("sdloop: identify: %s\n", up->errstr); + nexterror(); + } + osectors = c->sectors; + n = devtab[c->c->type]->stat(c->c, buf, sizeof buf); + if(convM2D(buf, n, &dir, nil) == 0) + error("internal error: stat error in seek"); + s = dir.length / c->sectsize; + poperror(); + + memset(u->inquiry, 0, sizeof u->inquiry); + u->inquiry[2] = 2; + u->inquiry[3] = 2; + u->inquiry[4] = sizeof u->inquiry - 4; + memmove(u->inquiry+8, c->path, 40); + + if(osectors == 0 || osectors != s){ + c->sectors = s; + c->drivechange = 1; + c->vers++; + } +} + +static Ctlr* +ctlrlookup(char *path) +{ + Ctlr *c; + + lock(&ctlrlock); + for(c = head; c; c = c->next) + if(strcmp(c->path, path) == 0) + break; + unlock(&ctlrlock); + return c; +} + +static Ctlr* +newctlr(char *path) +{ + Ctlr *c; + + if(ctlrlookup(path)) + error(Eexist); + if((c = malloc(sizeof *c)) == nil) + error(Enomem); + if(waserror()){ + free(c); + nexterror(); + } + c->c = namec(path, Aopen, ORDWR, 0); + poperror(); + kstrcpy(c->path, path, sizeof c->path); + lock(&ctlrlock); + if(head != nil) + tail->next = c; + else + head = c; + tail = c; + unlock(&ctlrlock); + return c; +} + +static void +delctlr(Ctlr *c) +{ + Ctlr *x, *prev; + + lock(&ctlrlock); + + for(prev = 0, x = head; x; prev = x, x = c->next) + if(strcmp(c->path, x->path) == 0) + break; + if(x == 0){ + unlock(&ctlrlock); + error(Enonexist); + } + + if(prev) + prev->next = x->next; + else + head = x->next; + if(x->next == nil) + tail = prev; + unlock(&ctlrlock); + + if(x->c) + cclose(x->c); + free(x); +} + +static SDev* +probe(char *path, SDev *s) +{ + char *p; + uint sectsize; + Ctlr *c; + + sectsize = 0; + if(p = strchr(path, '!')){ + *p = 0; + sectsize = strtoul(p + 1, 0, 0); + } + c = newctlr(path); + c->sectsize = sectsize? sectsize: Devsectsize; + if(s == nil && (s = malloc(sizeof *s)) == nil) + return nil; + s->ctlr = c; + s->ifc = &sdloopifc; + s->nunit = 1; + return s; +} + +static char *probef[32]; +static int nprobe; + +static int +pnpprobeid(char *s) +{ + int id; + + if(strlen(s) < 2) + return 0; + id = 'l'; + if(s[1] == '!') + id = s[0]; + return id; +} + +static SDev* +pnp(void) +{ + int i, id; + char *p; + SDev *h, *t, *s; + + if((p = getconf("loopdev")) == 0) + return 0; + nprobe = tokenize(p, probef, nelem(probef)); + h = t = 0; + for(i = 0; i < nprobe; i++){ + id = pnpprobeid(probef[i]); + if(id == 0) + continue; + s = malloc(sizeof *s); + if(s == nil) + break; + s->ctlr = 0; + s->idno = id; + s->ifc = &sdloopifc; + s->nunit = 1; + + if(h) + t->next = s; + else + h = s; + t = s; + } + return h; +} + +static Ctlr* +pnpprobe(SDev *s) +{ + char *p; + static int i; + + if(i > nprobe) + return 0; + p = probef[i++]; + if(strlen(p) < 2) + return 0; + if(p[1] == '!') + p += 2; + s = probe(p, s); + return s->ctlr; +} + + +static int +loopverify(SDunit *u) +{ + SDev *s; + Ctlr *c; + + s = u->dev; + c = s->ctlr; + if(c == nil){ + if(waserror()) + return 0; + s->ctlr = c = pnpprobe(s); + poperror(); + } + c->drivechange = 1; + return 1; +} + +static int +connect(SDunit *u, Ctlr *c) +{ + qlock(c); + if(waserror()){ + qunlock(c); + return -1; + } + identify(u->dev->ctlr, u); + qunlock(c); + poperror(); + return 0; +} + +static int +looponline(SDunit *u) +{ + Ctlr *c; + int r; + + c = u->dev->ctlr; + if(c->drivechange){ + if(connect(u, c) == -1) + return 0; + r = 2; + c->drivechange = 0; + u->sectors = c->sectors; + u->secsize = c->sectsize; + } else + r = 1; + return r; +} + +static long +loopbio(SDunit *u, int, int write, void *a, long count, uvlong lba) +{ + uchar *data; + int n; + long (*rio)(Chan*, void*, long, vlong); + Ctlr *c; + + c = u->dev->ctlr; + data = a; + if(write) + rio = devtab[c->c->type]->write; + else + rio = devtab[c->c->type]->read; + + if(waserror()){ + if(strcmp(up->errstr, Echange) == 0 || + strcmp(up->errstr, Enotup) == 0) + u->sectors = 0; + nexterror(); + } + n = rio(c->c, data, c->sectsize * count, c->sectsize * lba); + poperror(); + return n; +} + +static int +looprio(SDreq *r) +{ + int i, count, rw; + uvlong lba; + SDunit *u; + + u = r->unit; + + if(r->cmd[0] == 0x35 || r->cmd[0] == 0x91) + return sdsetsense(r, SDok, 0, 0, 0); + + if((i = sdfakescsi(r)) != SDnostatus) + return r->status = i; + if((i = sdfakescsirw(r, &lba, &count, &rw)) != SDnostatus) + return i; + r->rlen = loopbio(u, r->lun, rw == SDwrite, r->data, count, lba); + return r->status = SDok; +} + +static int +looprctl(SDunit *u, char *p, int l) +{ + Ctlr *c; + char *e, *op; + + if((c = u->dev->ctlr) == nil) + return 0; + e = p+l; + op = p; + + p = seprint(p, e, "path\t%s\n", c->path); + p = seprint(p, e, "geometry %llud %d\n", c->sectors, c->sectsize); + return p - op; +} + +static int +loopwctl(SDunit *, Cmdbuf *cmd) +{ + cmderror(cmd, Ebadarg); + return 0; +} + +static SDev* +loopprobew(DevConf *c) +{ + char *p; + + p = strchr(c->type, '/'); + if(p == nil || strlen(p) > Maxpath - 1) + error(Ebadarg); + p++; + if(ctlrlookup(p)) + error(Einuse); + return probe(p, 0); +} + +static void +loopclear(SDev *s) +{ + delctlr((Ctlr *)s->ctlr); +} + +static char* +looprtopctl(SDev *s, char *p, char *e) +{ + Ctlr *c; + + c = s->ctlr; + return seprint(p, e, "%s loop %s\n", s->name, c? c->path: ""); +} + +static int +loopwtopctl(SDev *, Cmdbuf *cmd) +{ + switch(cmd->nf){ + default: + cmderror(cmd, Ebadarg); + } + return 0; +} + +SDifc sdloopifc = { + "loop", + + pnp, + nil, /* legacy */ + nil, /* enable */ + nil, /* disable */ + + loopverify, + looponline, + looprio, + looprctl, + loopwctl, + + loopbio, + loopprobew, /* probe */ + loopclear, /* clear */ + looprtopctl, + loopwtopctl, +}; |