Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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