]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/sdaoe.c
devmnt: deal with partial response for Tversion request in mntversion()
[plan9front.git] / sys / src / 9 / port / sdaoe.c
1 /*
2  * aoe sd driver, copyright © 2007-9 coraid
3  */
4
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10 #include "io.h"
11 #include "../port/error.h"
12 #include "../port/sd.h"
13 #include "../port/netif.h"
14 #include "../port/aoe.h"
15 #include <fis.h>
16
17 extern  char    Echange[];
18 extern  char    Enotup[];
19
20 #define uprint(...)     snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__);
21
22 enum {
23         Maxpath         = 128,
24
25         Probeintvl      = 100,          /* ms. between probes */
26         Probemax        = 10*1000,      /* max ms. to wait */
27 };
28
29 typedef struct Ctlr Ctlr;
30 struct Ctlr {
31         QLock;
32
33         Ctlr    *next;
34         SDunit  *unit;
35
36         char    path[Maxpath];
37         Chan    *c;
38
39         ulong   vers;
40         uchar   drivechange;
41         Sfis;
42
43         uvlong  sectors;
44         char    serial[20+1];
45         char    firmware[8+1];
46         char    model[40+1];
47         char    ident[0x100];
48 };
49
50 static  Lock    ctlrlock;
51 static  Ctlr    *head;
52 static  Ctlr    *tail;
53
54 SDifc sdaoeifc;
55
56 static int
57 identify(Ctlr *c, ushort *id)
58 {
59         uchar oserial[21];
60         vlong osectors, s;
61
62         osectors = c->sectors;
63         memmove(oserial, c->serial, sizeof c->serial);
64         s = idfeat(c, id);
65         if(s == -1){
66                 uprint("%s: identify fails", c->unit->name);
67                 print("%s\n", up->genbuf);
68                 error(up->genbuf);
69         }
70         idmove(c->serial, id+10, 20);
71         idmove(c->firmware, id+23, 8);
72         idmove(c->model, id+27, 40);
73
74         if((osectors == 0 || osectors != s) &&
75             memcmp(oserial, c->serial, sizeof oserial) != 0){
76                 c->sectors = s;
77                 c->drivechange = 1;
78                 c->vers++;
79         }
80         return 0;
81 }
82
83 static void
84 aoectl(Ctlr *d, char *s)
85 {
86         Chan *c;
87
88         uprint("%s/ctl", d->path);
89         c = namec(up->genbuf, Aopen, OWRITE, 0);
90         if(waserror()){
91                 print("sdaoectl: %s\n", up->errstr);
92                 cclose(c);
93                 nexterror();
94         }
95         devtab[c->type]->write(c, s, strlen(s), 0);
96         cclose(c);
97         poperror();
98 }
99
100 /* must call with d qlocked */
101 static int
102 aoeidentify(Ctlr *d, SDunit *u)
103 {
104         Chan *c;
105
106         uprint("%s/ident", d->path);
107         c = namec(up->genbuf, Aopen, OREAD, 0);
108         if(waserror()){
109                 iprint("aoeidentify: %s\n", up->errstr);
110                 cclose(c);
111                 nexterror();
112         }
113         devtab[c->type]->read(c, d->ident, sizeof d->ident, 0);
114         cclose(c);
115         poperror();
116
117         d->feat = 0;
118         identify(d, (ushort*)d->ident);
119
120         memset(u->inquiry, 0, sizeof u->inquiry);
121         u->inquiry[2] = 2;
122         u->inquiry[3] = 2;
123         u->inquiry[4] = sizeof u->inquiry - 4;
124         memmove(u->inquiry+8, d->model, 40);
125
126         return 0;
127 }
128
129 static Ctlr*
130 ctlrlookup(char *path)
131 {
132         Ctlr *c;
133
134         lock(&ctlrlock);
135         for(c = head; c != nil; c = c->next)
136                 if(strcmp(c->path, path) == 0)
137                         break;
138         unlock(&ctlrlock);
139         return c;
140 }
141
142 static Ctlr*
143 newctlr(char *path)
144 {
145         Ctlr *c;
146
147         if(ctlrlookup(path))
148                 error(Eexist);
149
150         if((c = malloc(sizeof *c)) == nil)
151                 return 0;
152         kstrcpy(c->path, path, sizeof c->path);
153         lock(&ctlrlock);
154         if(head != nil)
155                 tail->next = c;
156         else
157                 head = c;
158         tail = c;
159         unlock(&ctlrlock);
160         return c;
161 }
162
163 static void
164 delctlr(Ctlr *c)
165 {
166         Ctlr *x, *prev;
167
168         lock(&ctlrlock);
169
170         for(prev = 0, x = head; x != nil; prev = x, x = c->next)
171                 if(strcmp(c->path, x->path) == 0)
172                         break;
173         if(x == nil){
174                 unlock(&ctlrlock);
175                 error(Enonexist);
176         }
177
178         if(prev != nil)
179                 prev->next = x->next;
180         else
181                 head = x->next;
182         if(x->next == nil)
183                 tail = prev;
184         unlock(&ctlrlock);
185
186         if(x->c != nil)
187                 cclose(x->c);
188         free(x);
189 }
190
191 static SDev*
192 aoeprobe(char *path, SDev *s)
193 {
194         int n, i;
195         char *p;
196         Chan *c;
197         Ctlr *ctlr;
198
199         if((p = strrchr(path, '/')) == nil)
200                 error(Ebadarg);
201         *p = 0;
202         uprint("%s/ctl", path);
203         *p = '/';
204         c = namec(up->genbuf, Aopen, OWRITE, 0);
205         if(waserror()) {
206                 cclose(c);
207                 nexterror();
208         }
209         n = uprint("discover %s", p+1);
210         devtab[c->type]->write(c, up->genbuf, n, 0);
211         cclose(c);
212         poperror();
213
214         for(i = 0;; i += Probeintvl){
215                 if(i > Probemax || waserror())
216                         error(Etimedout);
217                 tsleep(&up->sleep, return0, 0, Probeintvl);
218                 poperror();
219
220                 uprint("%s/ident", path);
221                 if(waserror())
222                         continue;
223                 c = namec(up->genbuf, Aopen, OREAD, 0);
224                 poperror();
225                 cclose(c);
226
227                 ctlr = newctlr(path);
228                 break;
229         }
230
231         if(s == nil && (s = malloc(sizeof *s)) == nil)
232                 return nil;
233         s->ctlr = ctlr;
234         s->ifc = &sdaoeifc;
235         s->nunit = 1;
236         return s;
237 }
238
239 static char     *probef[32];
240 static char     *probebuf;
241 static int      nprobe;
242
243 static SDev*
244 aoepnp(void)
245 {
246         int i, id;
247         char *p;
248         SDev *h, *t, *s;
249
250         if((p = getconf("aoedev")) == nil)
251                 return 0;
252         kstrdup(&probebuf, p);
253         nprobe = tokenize(probebuf, probef, nelem(probef));
254         h = t = 0;
255         for(i = 0; i < nprobe; i++){
256                 p = probef[i];
257                 if(strlen(p) < 2)
258                         continue;
259                 id = 'e';
260                 if(p[1] == '!'){
261                         id = p[0];
262                         p += 2;
263                 }
264                 /*
265                  * shorthand for: id!lun -> id!#æ/aoe/lun
266                  * because we cannot type æ in the bootloader console.
267                  */
268                 if(strchr(p, '/') == nil){
269                         char tmp[64];
270
271                         snprint(tmp, sizeof(tmp), "%c!#æ/aoe/%s", (char)id, p);
272
273                         probef[i] = nil;
274                         kstrdup(&probef[i], tmp);
275                 }
276                 s = malloc(sizeof *s);
277                 if(s == nil)
278                         break;
279                 s->ctlr = 0;
280                 s->idno = id;
281                 s->ifc = &sdaoeifc;
282                 s->nunit = 1;
283
284                 if(h)
285                         t->next = s;
286                 else
287                         h = s;
288                 t = s;
289         }
290         return h;
291 }
292
293 static Ctlr*
294 pnpprobe(SDev *sd)
295 {
296         int j;
297         char *p;
298         static int i;
299
300         if(i > nprobe)
301                 return 0;
302         p = probef[i++];
303         if(strlen(p) < 2)
304                 return 0;
305         if(p[1] == '!')
306                 p += 2;
307
308         for(j = 0;; j += Probeintvl){
309                 if(j > Probemax){
310                         print("#æ: pnpprobe: %s: %s\n", probef[i-1], up->errstr);
311                         return 0;
312                 }
313                 if(waserror()){
314                         tsleep(&up->sleep, return0, 0, Probeintvl);
315                         continue;
316                 }
317                 sd = aoeprobe(p, sd);
318                 poperror();
319                 break;
320         }
321         print("#æ: pnpprobe establishes %s in %dms\n", probef[i-1], j);
322         aoectl(sd->ctlr, "nofail on");
323         return sd->ctlr;
324 }
325
326
327 static int
328 aoeverify(SDunit *u)
329 {
330         SDev *s;
331         Ctlr *c;
332
333         s = u->dev;
334         c = s->ctlr;
335         if(c == nil && (s->ctlr = c = pnpprobe(s)) == nil)
336                 return 0;
337         c->drivechange = 1;
338         return 1;
339 }
340
341 static int
342 aoeconnect(SDunit *u, Ctlr *c)
343 {
344         qlock(c);
345         if(waserror()){
346                 qunlock(c);
347                 return -1;
348         }
349
350         aoeidentify(u->dev->ctlr, u);
351         if(c->c)
352                 cclose(c->c);
353         c->c = 0;
354         uprint("%s/data", c->path);
355         c->c = namec(up->genbuf, Aopen, ORDWR, 0);
356         qunlock(c);
357         poperror();
358
359         return 0;
360 }
361
362 static int
363 aoeonline(SDunit *u)
364 {
365         Ctlr *c;
366         int r;
367
368         c = u->dev->ctlr;
369         r = 0;
370
371         if((c->feat&Datapi) && c->drivechange){
372                 if(aoeconnect(u, c) == 0 && (r = scsionline(u)) > 0)
373                         c->drivechange = 0;
374                 return r;
375         }
376
377         if(c->drivechange){
378                 if(aoeconnect(u, c) == -1)
379                         return 0;
380                 r = 2;
381                 c->drivechange = 0;
382                 u->sectors = c->sectors;
383                 u->secsize = Aoesectsz;
384         } else
385                 r = 1;
386
387         return r;
388 }
389
390 static long
391 aoebio(SDunit *u, int, int write, void *a, long count, uvlong lba)
392 {
393         uchar *data;
394         int n;
395         long (*rio)(Chan*, void*, long, vlong);
396         Ctlr *c;
397
398         c = u->dev->ctlr;
399 //      if(c->feat & Datapi)
400 //              return scsibio(u, lun, write, a, count, lba);
401         data = a;
402         if(write)
403                 rio = devtab[c->c->type]->write;
404         else
405                 rio = devtab[c->c->type]->read;
406
407         if(waserror()){
408                 if(strcmp(up->errstr, Echange) == 0 ||
409                     strcmp(up->errstr, Enotup) == 0)
410                         u->sectors = 0;
411                 nexterror();
412         }
413         n = rio(c->c, data, Aoesectsz * count, Aoesectsz * lba);
414         poperror();
415         return n;
416 }
417
418 static int
419 flushcache(Ctlr *)
420 {
421         return -1;
422 }
423
424 static int
425 aoerio(SDreq *r)
426 {
427         int i, count, rw;
428         uvlong lba;
429         Ctlr *c;
430         SDunit *u;
431
432         u = r->unit;
433         c = u->dev->ctlr;
434 //      if(c->feat & Datapi)
435 //              return aoeriopkt(r, d);
436
437         if(r->cmd[0] == 0x35 || r->cmd[0] == 0x91){
438                 qlock(c);
439                 i = flushcache(c);
440                 qunlock(c);
441                 if(i == 0)
442                         return sdsetsense(r, SDok, 0, 0, 0);
443                 return sdsetsense(r, SDcheck, 3, 0xc, 2);
444         }
445
446         if((i = sdfakescsi(r)) != SDnostatus){
447                 r->status = i;
448                 return i;
449         }
450         if((i = sdfakescsirw(r, &lba, &count, &rw)) != SDnostatus)
451                 return i;
452         r->rlen = aoebio(u, r->lun, rw == SDwrite, r->data, count, lba);
453         return r->status = SDok;
454 }
455
456 static int
457 aoerctl(SDunit *u, char *p, int l)
458 {
459         Ctlr *c;
460         char *e, *op;
461
462         if((c = u->dev->ctlr) == nil)
463                 return 0;
464         e = p+l;
465         op = p;
466
467         p = seprint(p, e, "model\t%s\n", c->model);
468         p = seprint(p, e, "serial\t%s\n", c->serial);
469         p = seprint(p, e, "firm %s\n", c->firmware);
470         p = seprint(p, e, "flag ");
471         p = pflag(p, e, c);
472         p = seprint(p, e, "geometry %llud %d\n", c->sectors, Aoesectsz);
473         return p-op;
474 }
475
476 static int
477 aoewctl(SDunit *, Cmdbuf *cmd)
478 {
479         cmderror(cmd, Ebadarg);
480         return 0;
481 }
482
483 static SDev*
484 aoeprobew(DevConf *c)
485 {
486         char *p;
487
488         p = strchr(c->type, '/');
489         if(p == nil || strlen(p) > Maxpath - 11)
490                 error(Ebadarg);
491         if(p[1] == '#')
492                 p++;                    /* hack */
493         if(ctlrlookup(p))
494                 error(Einuse);
495         return aoeprobe(p, 0);
496 }
497
498 static void
499 aoeclear(SDev *s)
500 {
501         delctlr((Ctlr *)s->ctlr);
502 }
503
504 static char*
505 aoertopctl(SDev *s, char *p, char *e)
506 {
507         Ctlr *c;
508
509         c = s->ctlr;
510         return seprint(p, e, "%s aoe %s\n", s->name, c? c->path: "");
511 }
512
513 static int
514 aoewtopctl(SDev *, Cmdbuf *cmd)
515 {
516         switch(cmd->nf){
517         default:
518                 cmderror(cmd, Ebadarg);
519         }
520         return 0;
521 }
522
523 SDifc sdaoeifc = {
524         "aoe",
525
526         aoepnp,
527         nil,            /* legacy */
528         nil,            /* enable */
529         nil,            /* disable */
530
531         aoeverify,
532         aoeonline,
533         aoerio,
534         aoerctl,
535         aoewctl,
536
537         aoebio,
538         aoeprobew,      /* probe */
539         aoeclear,       /* clear */
540         aoertopctl,
541         aoewtopctl,
542 };