vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

sdaoe.c (9903B)


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