]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/sdloop.c
merge
[plan9front.git] / sys / src / 9 / port / sdloop.c
1 /*
2  * sd loopback driver,
3  * copyright © 2009-10 erik quanstrom
4  */
5
6 #include "u.h"
7 #include "../port/lib.h"
8 #include "mem.h"
9 #include "dat.h"
10 #include "fns.h"
11 #include "io.h"
12 #include "../port/error.h"
13 #include "../port/sd.h"
14 #include "../port/netif.h"
15
16 extern  char    Echange[];
17
18 enum {
19         Maxpath         = 256,
20         Devsectsize     = 512,
21 };
22
23 typedef struct Ctlr Ctlr;
24 struct Ctlr {
25         QLock;
26
27         Ctlr    *next;
28         SDunit  *unit;
29
30         char    path[Maxpath];
31         Chan    *c;
32
33         uint    vers;
34         uchar   drivechange;
35
36         uvlong  sectors;
37         uint    sectsize;
38 };
39
40 static  Lock    ctlrlock;
41 static  Ctlr    *head;
42 static  Ctlr    *tail;
43
44 SDifc sdloopifc;
45
46 /* must call with c qlocked */
47 static void
48 identify(Ctlr *c, SDunit *u)
49 {
50         int n;
51         uvlong s, osectors;
52         uchar buf[sizeof(Dir) + 100];
53         Dir dir;
54
55         if(waserror()){
56                 iprint("sdloop: identify: %s\n", up->errstr);
57                 nexterror();
58         }
59         osectors = c->sectors;
60         n = devtab[c->c->type]->stat(c->c, buf, sizeof buf);
61         if(convM2D(buf, n, &dir, nil) == 0)
62                 error("internal error: stat error in seek");
63         s = dir.length / c->sectsize;
64         poperror();
65
66         memset(u->inquiry, 0, sizeof u->inquiry);
67         u->inquiry[2] = 2;
68         u->inquiry[3] = 2;
69         u->inquiry[4] = sizeof u->inquiry - 4;
70         memmove(u->inquiry+8, c->path, 40);
71
72         if(osectors == 0 || osectors != s){
73                 c->sectors = s;
74                 c->drivechange = 1;
75                 c->vers++;
76         }
77 }
78
79 static Ctlr*
80 ctlrlookup(char *path)
81 {
82         Ctlr *c;
83
84         lock(&ctlrlock);
85         for(c = head; c; c = c->next)
86                 if(strcmp(c->path, path) == 0)
87                         break;
88         unlock(&ctlrlock);
89         return c;
90 }
91
92 static Ctlr*
93 newctlr(char *path)
94 {
95         Ctlr *c;
96
97         if(ctlrlookup(path))
98                 error(Eexist);
99         if((c = malloc(sizeof *c)) == nil)
100                 error(Enomem);
101         if(waserror()){
102                 free(c);
103                 nexterror();
104         }
105         c->c = namec(path, Aopen, ORDWR, 0);
106         poperror();
107         kstrcpy(c->path, path, sizeof c->path);
108         lock(&ctlrlock);
109         if(head != nil)
110                 tail->next = c;
111         else
112                 head = c;
113         tail = c;
114         unlock(&ctlrlock);
115         return c;
116 }
117
118 static void
119 delctlr(Ctlr *c)
120 {
121         Ctlr *x, *prev;
122
123         lock(&ctlrlock);
124
125         for(prev = 0, x = head; x; prev = x, x = c->next)
126                 if(strcmp(c->path, x->path) == 0)
127                         break;
128         if(x == 0){
129                 unlock(&ctlrlock);
130                 error(Enonexist);
131         }
132
133         if(prev)
134                 prev->next = x->next;
135         else
136                 head = x->next;
137         if(x->next == nil)
138                 tail = prev;
139         unlock(&ctlrlock);
140
141         if(x->c)
142                 cclose(x->c);
143         free(x);
144 }
145
146 static SDev*
147 probe(char *path, SDev *s)
148 {
149         char *p;
150         uint sectsize;
151         Ctlr *c;
152
153         sectsize = 0;
154         if(p = strchr(path, '!')){
155                 *p = 0;
156                 sectsize = strtoul(p + 1, 0, 0);
157         }
158         c = newctlr(path);
159         c->sectsize = sectsize? sectsize: Devsectsize;
160         if(s == nil && (s = malloc(sizeof *s)) == nil)
161                 return nil;
162         s->ctlr = c;
163         s->ifc = &sdloopifc;
164         s->nunit = 1;
165         return s;
166 }
167
168 static char     *probef[32];
169 static int      nprobe;
170
171 static int
172 pnpprobeid(char *s)
173 {
174         int id;
175
176         if(strlen(s) < 2)
177                 return 0;
178         id = 'l';
179         if(s[1] == '!')
180                 id = s[0];
181         return id;
182 }
183
184 static SDev*
185 pnp(void)
186 {
187         int i, id;
188         char *p;
189         SDev *h, *t, *s;
190
191         if((p = getconf("loopdev")) == 0)
192                 return 0;
193         nprobe = tokenize(p, probef, nelem(probef));
194         h = t = 0;
195         for(i = 0; i < nprobe; i++){
196                 id = pnpprobeid(probef[i]);
197                 if(id == 0)
198                         continue;
199                 s = malloc(sizeof *s);
200                 if(s == nil)
201                         break;
202                 s->ctlr = 0;
203                 s->idno = id;
204                 s->ifc = &sdloopifc;
205                 s->nunit = 1;
206
207                 if(h)
208                         t->next = s;
209                 else
210                         h = s;
211                 t = s;
212         }
213         return h;
214 }
215
216 static Ctlr*
217 pnpprobe(SDev *s)
218 {
219         char *p;
220         static int i;
221
222         if(i > nprobe)
223                 return 0;
224         p = probef[i++];
225         if(strlen(p) < 2)
226                 return 0;
227         if(p[1] == '!')
228                 p += 2;
229         s = probe(p, s);
230         return s->ctlr;
231 }
232
233
234 static int
235 loopverify(SDunit *u)
236 {
237         SDev *s;
238         Ctlr *c;
239
240         s = u->dev;
241         c = s->ctlr;
242         if(c == nil){
243                 if(waserror())
244                         return 0;
245                 s->ctlr = c = pnpprobe(s);
246                 poperror();
247         }
248         c->drivechange = 1;
249         return 1;
250 }
251
252 static int
253 connect(SDunit *u, Ctlr *c)
254 {
255         qlock(c);
256         if(waserror()){
257                 qunlock(c);
258                 return -1;
259         }
260         identify(u->dev->ctlr, u);
261         qunlock(c);
262         poperror();
263         return 0;
264 }
265
266 static int
267 looponline(SDunit *u)
268 {
269         Ctlr *c;
270         int r;
271
272         c = u->dev->ctlr;
273         if(c->drivechange){
274                 if(connect(u, c) == -1)
275                         return 0;
276                 r = 2;
277                 c->drivechange = 0;
278                 u->sectors = c->sectors;
279                 u->secsize = c->sectsize;
280         } else
281                 r = 1;
282         return r;
283 }
284
285 static long
286 loopbio(SDunit *u, int, int write, void *a, long count, uvlong lba)
287 {
288         uchar *data;
289         int n;
290         long (*rio)(Chan*, void*, long, vlong);
291         Ctlr *c;
292
293         c = u->dev->ctlr;
294         data = a;
295         if(write)
296                 rio = devtab[c->c->type]->write;
297         else
298                 rio = devtab[c->c->type]->read;
299
300         if(waserror()){
301                 if(strcmp(up->errstr, Echange) == 0 ||
302                     strstr(up->errstr, "device is down") != nil)
303                         u->sectors = 0;
304                 nexterror();
305         }
306         n = rio(c->c, data, c->sectsize * count, c->sectsize * lba);
307         poperror();
308         return n;
309 }
310
311 static int
312 looprio(SDreq *r)
313 {
314         int i, count, rw;
315         uvlong lba;
316         SDunit *u;
317
318         u = r->unit;
319
320         if(r->cmd[0] == 0x35 || r->cmd[0] == 0x91)
321                 return sdsetsense(r, SDok, 0, 0, 0);
322
323         if((i = sdfakescsi(r)) != SDnostatus)
324                 return r->status = i;
325         if((i = sdfakescsirw(r, &lba, &count, &rw)) != SDnostatus)
326                 return i;
327         r->rlen = loopbio(u, r->lun, rw == SDwrite, r->data, count, lba);
328         return r->status = SDok;
329 }
330
331 static int
332 looprctl(SDunit *u, char *p, int l)
333 {
334         Ctlr *c;
335         char *e, *op;
336
337         if((c = u->dev->ctlr) == nil)
338                 return 0;
339         e = p+l;
340         op = p;
341
342         p = seprint(p, e, "path\t%s\n", c->path);
343         p = seprint(p, e, "geometry %llud %d\n", c->sectors, c->sectsize);
344         return p - op;
345 }
346
347 static int
348 loopwctl(SDunit *, Cmdbuf *cmd)
349 {
350         cmderror(cmd, Ebadarg);
351         return 0;
352 }
353
354 static SDev*
355 loopprobew(DevConf *c)
356 {
357         char *p;
358
359         p = strchr(c->type, '/');
360         if(p == nil || strlen(p) > Maxpath - 1)
361                 error(Ebadarg);
362         p++;
363         if(ctlrlookup(p))
364                 error(Einuse);
365         return probe(p, 0);
366 }
367
368 static void
369 loopclear(SDev *s)
370 {
371         delctlr((Ctlr *)s->ctlr);
372 }
373
374 static char*
375 looprtopctl(SDev *s, char *p, char *e)
376 {
377         Ctlr *c;
378
379         c = s->ctlr;
380         return seprint(p, e, "%s loop %s\n", s->name, c? c->path: "");
381 }
382
383 static int
384 loopwtopctl(SDev *, Cmdbuf *cmd)
385 {
386         switch(cmd->nf){
387         default:
388                 cmderror(cmd, Ebadarg);
389         }
390         return 0;
391 }
392
393 SDifc sdloopifc = {
394         "loop",
395
396         pnp,
397         nil,            /* legacy */
398         nil,            /* enable */
399         nil,            /* disable */
400
401         loopverify,
402         looponline,
403         looprio,
404         looprctl,
405         loopwctl,
406
407         loopbio,
408         loopprobew,     /* probe */
409         loopclear,      /* clear */
410         looprtopctl,
411         loopwtopctl,
412 };