xref: /plan9-contrib/sys/src/9k/port/sdaoe.c (revision 05ffe48f6a7c47e3c5823db8baa092dde4ecb671)
1 /*
2  * aoe sd driver, copyright © 2007 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 "../port/error.h"
11 
12 #include "../port/netif.h"
13 #include "../port/sd.h"
14 
15 #include "etherif.h"
16 #include "../port/aoe.h"
17 
18 #define uprint(...)	snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__);
19 
20 enum {
21 	Nctlr	= 32,
22 	Maxpath	= 128,
23 
24 	Probeintvl	= 100,		/* ms. between probes */
25 	Probemax	= 20,		/* max probes */
26 };
27 
28 enum {
29 	/* sync with ahci.h */
30 	Dllba 	= 1<<0,
31 	Dsmart	= 1<<1,
32 	Dpower	= 1<<2,
33 	Dnop	= 1<<3,
34 	Datapi	= 1<<4,
35 	Datapi16= 1<<5,
36 };
37 
38 static char *flagname[] = {
39 	"llba",
40 	"smart",
41 	"power",
42 	"nop",
43 	"atapi",
44 	"atapi16",
45 };
46 
47 typedef struct Ctlr Ctlr;
48 struct Ctlr{
49 	QLock;
50 
51 	Ctlr	*next;
52 	SDunit	*unit;
53 
54 	char	path[Maxpath];
55 	Chan	*c;
56 
57 	ulong	vers;
58 	uchar	mediachange;
59 	uchar	flag;
60 	uchar	smart;
61 	uchar	smartrs;
62 	uchar	feat;
63 
64 	uvlong	sectors;
65 	char	serial[20+1];
66 	char	firmware[8+1];
67 	char	model[40+1];
68 	char	ident[0x100];
69 };
70 
71 void	aoeidmove(char *p, ushort *a, unsigned n);
72 
73 static	Lock	ctlrlock;
74 static	Ctlr	*head;
75 static	Ctlr	*tail;
76 
77 SDifc sdaoeifc;
78 
79 static ushort
gbit16(void * a)80 gbit16(void *a)
81 {
82 	uchar *i;
83 
84 	i = a;
85 	return i[1] << 8 | i[0];
86 }
87 
88 static ulong
gbit32(void * a)89 gbit32(void *a)
90 {
91 	ulong j;
92 	uchar *i;
93 
94 	i = a;
95 	j  = i[3] << 24;
96 	j |= i[2] << 16;
97 	j |= i[1] << 8;
98 	j |= i[0];
99 	return j;
100 }
101 
102 static uvlong
gbit64(void * a)103 gbit64(void *a)
104 {
105 	uchar *i;
106 
107 	i = a;
108 	return (uvlong)gbit32(i+4)<<32 | gbit32(i);
109 }
110 
111 static int
identify(Ctlr * c,ushort * id)112 identify(Ctlr *c, ushort *id)
113 {
114 	int i;
115 	uchar oserial[21];
116 	uvlong osectors, s;
117 
118 	osectors = c->sectors;
119 	memmove(oserial, c->serial, sizeof c->serial);
120 
121 	c->feat &= ~(Dllba|Dpower|Dsmart|Dnop);
122 	i = gbit16(id+83) | gbit16(id+86);
123 	if(i & (1<<10)){
124 		c->feat |= Dllba;
125 		s = gbit64(id+100);
126 	}else
127 		s = gbit32(id+60);
128 
129 	i = gbit16(id+83);
130 	if((i>>14) == 1) {
131 		if(i & (1<<3))
132 			c->feat |= Dpower;
133 		i = gbit16(id+82);
134 		if(i & 1)
135 			c->feat |= Dsmart;
136 		if(i & (1<<14))
137 			c->feat |= Dnop;
138 	}
139 
140 	aoeidmove(c->serial, id+10, 20);
141 	aoeidmove(c->firmware, id+23, 8);
142 	aoeidmove(c->model, id+27, 40);
143 
144 	if((osectors == 0 || osectors != s) &&
145 	    memcmp(oserial, c->serial, sizeof oserial) != 0){
146 		c->sectors = s;
147 		c->mediachange = 1;
148 		c->vers++;
149 	}
150 	return 0;
151 }
152 
153 /* must call with d qlocked */
154 static int
aoeidentify(Ctlr * d,SDunit * u)155 aoeidentify(Ctlr *d, SDunit *u)
156 {
157 	Chan *c;
158 
159 	c = nil;
160 	if(waserror()){
161 		if(c)
162 			cclose(c);
163 		iprint("aoeidentify: %s\n", up->errstr);
164 		nexterror();
165 	}
166 
167 	uprint("%s/ident", d->path);
168 	c = namec(up->genbuf, Aopen, OREAD, 0);
169 	c->dev->read(c, d->ident, sizeof d->ident, 0);
170 
171 	poperror();
172 	cclose(c);
173 
174 	d->feat = 0;
175 	d->smart = 0;
176 	identify(d, (ushort*)d->ident);
177 
178 	memset(u->inquiry, 0, sizeof u->inquiry);
179 	u->inquiry[2] = 2;
180 	u->inquiry[3] = 2;
181 	u->inquiry[4] = sizeof u->inquiry - 4;
182 	memmove(u->inquiry+8, d->model, 40);
183 
184 	return 0;
185 }
186 
187 static Ctlr*
ctlrlookup(char * path)188 ctlrlookup(char *path)
189 {
190 	Ctlr *c;
191 
192 	lock(&ctlrlock);
193 	for(c = head; c; c = c->next)
194 		if(strcmp(c->path, path) == 0)
195 			break;
196 	unlock(&ctlrlock);
197 	return c;
198 }
199 
200 static Ctlr*
newctlr(char * path)201 newctlr(char *path)
202 {
203 	Ctlr *c;
204 
205 	/* race? */
206 	if(ctlrlookup(path))
207 		error(Eexist);
208 
209 	if((c = malloc(sizeof *c)) == nil)
210 		return 0;
211 	kstrcpy(c->path, path, sizeof c->path);
212 	lock(&ctlrlock);
213 	if(head != nil)
214 		tail->next = c;
215 	else
216 		head = c;
217 	tail = c;
218 	unlock(&ctlrlock);
219 	return c;
220 }
221 
222 static void
delctlr(Ctlr * c)223 delctlr(Ctlr *c)
224 {
225 	Ctlr *x, *prev;
226 
227 	lock(&ctlrlock);
228 
229 	for(prev = 0, x = head; x; prev = x, x = c->next)
230 		if(strcmp(c->path, x->path) == 0)
231 			break;
232 	if(x == 0){
233 		unlock(&ctlrlock);
234 		error(Enonexist);
235 	}
236 
237 	if(prev)
238 		prev->next = x->next;
239 	else
240 		head = x->next;
241 	if(x->next == nil)
242 		tail = prev;
243 	unlock(&ctlrlock);
244 
245 	if(x->c)
246 		cclose(x->c);
247 	free(x);
248 }
249 
250 /* don't call aoeprobe from within a loop; it loops internally retrying open. */
251 static SDev*
aoeprobe(char * path,SDev * s)252 aoeprobe(char *path, SDev *s)
253 {
254 	int n, i;
255 	char *p;
256 	Chan *c;
257 	Ctlr *ctlr;
258 
259 	if((p = strrchr(path, '/')) == 0)
260 		error(Ebadarg);
261 	*p = 0;
262 	uprint("%s/ctl", path);
263 	*p = '/';
264 
265 	c = namec(up->genbuf, Aopen, OWRITE, 0);
266 	if(waserror()) {
267 		cclose(c);
268 		nexterror();
269 	}
270 	n = uprint("discover %s", p+1);
271 	c->dev->write(c, up->genbuf, n, 0);
272 	poperror();
273 	cclose(c);
274 
275 	for(i = 0; i < Probemax; i++){
276 		tsleep(&up->sleep, return0, 0, Probeintvl);
277 		uprint("%s/ident", path);
278 		if(!waserror()) {
279 			c = namec(up->genbuf, Aopen, OREAD, 0);
280 			poperror();
281 			cclose(c);
282 			break;
283 		}
284 	}
285 	if(i >= Probemax)
286 		error(Etimedout);
287 	uprint("%s/ident", path);
288 	ctlr = newctlr(path);
289 	if(ctlr == nil || s == nil && (s = malloc(sizeof *s)) == nil)
290 		return nil;
291 	s->ctlr = ctlr;
292 	s->ifc = &sdaoeifc;
293 	s->nunit = 1;
294 	return s;
295 }
296 
297 static char 	*probef[32];
298 static int 	nprobe;
299 
300 static int
pnpprobeid(char * s)301 pnpprobeid(char *s)
302 {
303 	if(strlen(s) < 2)
304 		return 0;
305 	return s[1] == '!'? s[0]: 'e';
306 }
307 
308 static SDev*
aoepnp(void)309 aoepnp(void)
310 {
311 	int i, id;
312 	char *p;
313 	SDev *h, *t, *s;
314 
315 	if((p = getconf("aoedev")) == 0)
316 		return 0;
317 	nprobe = tokenize(p, probef, nelem(probef));
318 	h = t = 0;
319 	for(i = 0; i < nprobe; i++){
320 		id = pnpprobeid(probef[i]);
321 		if(id == 0)
322 			continue;
323 		s = malloc(sizeof *s);
324 		if(s == nil)
325 			break;
326 		s->ctlr = 0;
327 		s->idno = id;
328 		s->ifc = &sdaoeifc;
329 		s->nunit = 1;
330 
331 		if(h)
332 			t->next = s;
333 		else
334 			h = s;
335 		t = s;
336 	}
337 	return h;
338 }
339 
340 static Ctlr*
pnpprobe(SDev * sd)341 pnpprobe(SDev *sd)
342 {
343 	ulong start;
344 	char *p;
345 	static int i;
346 
347 	if(i > nprobe)
348 		return 0;
349 	p = probef[i++];
350 	if(strlen(p) < 2)
351 		return 0;
352 	if(p[1] == '!')
353 		p += 2;
354 
355 	start = TK2MS(sys->ticks);
356 	if(waserror()){
357 		print("#æ: pnpprobe failed in %lud ms: %s: %s\n",
358 			TK2MS(sys->ticks) - start, probef[i-1],
359 			up->errstr);
360 		return nil;
361 	}
362 	sd = aoeprobe(p, sd);			/* does a round of probing */
363 	poperror();
364 	print("#æ: pnpprobe established %s in %lud ms\n",
365 		probef[i-1], TK2MS(sys->ticks) - start);
366 	return sd->ctlr;
367 }
368 
369 
370 static int
aoeverify(SDunit * u)371 aoeverify(SDunit *u)
372 {
373 	SDev *s;
374 	Ctlr *c;
375 
376 	s = u->dev;
377 	c = s->ctlr;
378 	if(c == nil && (s->ctlr = c = pnpprobe(s)) == nil)
379 		return 0;
380 	c->mediachange = 1;
381 	return 1;
382 }
383 
384 static int
aoeconnect(SDunit * u,Ctlr * c)385 aoeconnect(SDunit *u, Ctlr *c)
386 {
387 	qlock(c);
388 	if(waserror()){
389 		qunlock(c);
390 		return -1;
391 	}
392 
393 	aoeidentify(u->dev->ctlr, u);
394 	if(c->c)
395 		cclose(c->c);
396 	c->c = 0;
397 	uprint("%s/data", c->path);
398 	c->c = namec(up->genbuf, Aopen, ORDWR, 0);
399 	qunlock(c);
400 	poperror();
401 
402 	return 0;
403 }
404 
405 static int
aoeonline(SDunit * u)406 aoeonline(SDunit *u)
407 {
408 	Ctlr *c;
409 	int r;
410 
411 	c = u->dev->ctlr;
412 	r = 0;
413 
414 	if((c->feat&Datapi) && c->mediachange){
415 		if(aoeconnect(u, c) == 0 && (r = scsionline(u)) > 0)
416 			c->mediachange = 0;
417 		return r;
418 	}
419 
420 	if(c->mediachange){
421 		if(aoeconnect(u, c) == -1)
422 			return 0;
423 		r = 2;
424 		c->mediachange = 0;
425 		u->sectors = c->sectors;
426 		u->secsize = Aoesectsz;
427 	} else
428 		r = 1;
429 
430 	return r;
431 }
432 
433 static int
aoerio(SDreq * r)434 aoerio(SDreq *r)
435 {
436 	int i;
437 	ulong count;
438 	uvlong lba;
439 	char *name;
440 	uchar *cmd;
441 	long (*rio)(Chan*, void*, long, vlong);
442 	Ctlr *c;
443 	SDunit *unit;
444 
445 	unit = r->unit;
446 	c = unit->dev->ctlr;
447 //	if(c->feat & Datapi)
448 //		return aoeriopkt(r, d);
449 
450 	cmd = r->cmd;
451 	name = unit->name;
452 
453 	if(*cmd == ScmdSynccache || *cmd == ScmdSynccache16)
454 //		qlock(c);
455 //		i = flushcache();
456 //		qunlock(c);
457 //		if(i == 0)
458 //			return sdsetsense(r, SDok, 0, 0, 0);
459 		return sdsetsense(r, SDcheck, 3, 0xc, 2);
460 
461 	if((i = sdfakescsi(r, c->ident, sizeof c->ident)) != SDnostatus){
462 		r->status = i;
463 		return i;
464 	}
465 
466 	switch(*cmd){
467 	case ScmdRead16:
468 	case ScmdExtread:
469 		rio = c->c->dev->read;
470 		break;
471 	case ScmdWrite16:
472 	case ScmdExtwrite:
473 		rio = c->c->dev->write;
474 		break;
475 	default:
476 		print("%s: bad cmd %#.2ux\n", name, cmd[0]);
477 		r->status = SDcheck;
478 		return SDcheck;
479 	}
480 
481 	if(r->data == nil)
482 		return SDok;
483 
484 	if(r->clen == 16){
485 		/* ata commands only go to 48-bit lba */
486 		if(cmd[2] || cmd[3])
487 			return sdsetsense(r, SDcheck, 3, 0xc, 2);
488 	}
489 	scsilbacount(cmd, r->clen, &lba, &count);
490 	count *= Aoesectsz;
491 
492 	if(r->dlen < count)
493 		count = r->dlen & ~0x1ff;
494 
495 	if(waserror()){
496 		if(strcmp(up->errstr, Echange) == 0 ||
497 		    strcmp(up->errstr, Eaoedown) == 0)
498 			unit->sectors = 0;
499 		nexterror();
500 	}
501 	r->rlen = rio(c->c, r->data, count, Aoesectsz * lba);
502 	poperror();
503 	r->status = SDok;
504 	return SDok;
505 }
506 
507 static char *smarttab[] = {
508 	"unset",
509 	"error",
510 	"threshold exceeded",
511 	"normal"
512 };
513 
514 static char *
pflag(char * s,char * e,uchar f)515 pflag(char *s, char *e, uchar f)
516 {
517 	uchar i;
518 
519 	for(i = 0; i < 8; i++)
520 		if(f & (1 << i))
521 			s = seprint(s, e, "%s ", flagname[i]);
522 	return seprint(s, e, "\n");
523 }
524 
525 static int
aoerctl(SDunit * u,char * p,int l)526 aoerctl(SDunit *u, char *p, int l)
527 {
528 	Ctlr *c;
529 	char *e, *op;
530 
531 	if((c = u->dev->ctlr) == nil)
532 		return 0;
533 	e = p+l;
534 	op = p;
535 
536 	p = seprint(p, e, "model\t%s\n", c->model);
537 	p = seprint(p, e, "serial\t%s\n", c->serial);
538 	p = seprint(p, e, "firm	%s\n", c->firmware);
539 	if(c->smartrs == 0xff)
540 		p = seprint(p, e, "smart\tenable error\n");
541 	else if(c->smartrs == 0)
542 		p = seprint(p, e, "smart\tdisabled\n");
543 	else
544 		p = seprint(p, e, "smart\t%s\n", smarttab[c->smart]);
545 	p = seprint(p, e, "flag	");
546 	p = pflag(p, e, c->feat);
547 	p = seprint(p, e, "geometry %llud %d\n", c->sectors, Aoesectsz);
548 	return p-op;
549 }
550 
551 static int
aoewctl(SDunit *,Cmdbuf * cmd)552 aoewctl(SDunit *, Cmdbuf *cmd)
553 {
554 	cmderror(cmd, Ebadarg);
555 	return 0;
556 }
557 
558 static SDev*
aoeprobew(DevConf * c)559 aoeprobew(DevConf *c)
560 {
561 	char *p;
562 
563 	p = strchr(c->type, '/');
564 	if(p == nil || strlen(p) > Maxpath - 11)
565 		error(Ebadarg);
566 	if(p[1] == '#')
567 		p++;			/* hack */
568 	if(ctlrlookup(p))
569 		error(Einuse);
570 	return aoeprobe(p, 0);
571 }
572 
573 static void
aoeclear(SDev * s)574 aoeclear(SDev *s)
575 {
576 	delctlr((Ctlr *)s->ctlr);
577 }
578 
579 static char*
aoertopctl(SDev * s,char * p,char * e)580 aoertopctl(SDev *s, char *p, char *e)
581 {
582 	Ctlr *c;
583 
584 	if(s == nil || (c = s->ctlr) == nil)
585 		return p;
586 
587 	return seprint(p, e, "%s aoe %s\n", s->name, c->path);
588 }
589 
590 static int
aoewtopctl(SDev *,Cmdbuf * cmd)591 aoewtopctl(SDev *, Cmdbuf *cmd)
592 {
593 	switch(cmd->nf){
594 	default:
595 		cmderror(cmd, Ebadarg);
596 	}
597 	return 0;
598 }
599 
600 SDifc sdaoeifc = {
601 	"aoe",
602 
603 	aoepnp,
604 	nil,		/* legacy */
605 	nil,		/* enable */
606 	nil,		/* disable */
607 
608 	aoeverify,
609 	aoeonline,
610 	aoerio,
611 	aoerctl,
612 	aoewctl,
613 
614 	scsibio,
615 	aoeprobew,	/* probe */
616 	aoeclear,	/* clear */
617 	aoertopctl,
618 	aoewtopctl,
619 };
620