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