vx32

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

devsd.c (30944B)


      1 /*
      2  * Storage Device.
      3  */
      4 #include "u.h"
      5 #include "lib.h"
      6 #include "mem.h"
      7 #include "dat.h"
      8 #include "fns.h"
      9 #include "io.h"
     10 #include "ureg.h"
     11 #include "error.h"
     12 
     13 #include "sd.h"
     14 
     15 extern Dev sddevtab;
     16 extern SDifc* sdifc[];
     17 
     18 static char Echange[] = "media or partition has changed";
     19 
     20 static char devletters[] = "0123456789"
     21 	"abcdefghijklmnopqrstuvwxyz"
     22 	"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
     23 
     24 static SDev *devs[sizeof devletters-1];
     25 static QLock devslock;
     26 
     27 enum {
     28 	Rawcmd,
     29 	Rawdata,
     30 	Rawstatus,
     31 };
     32 
     33 enum {
     34 	Qtopdir		= 1,		/* top level directory */
     35 	Qtopbase,
     36 	Qtopctl		 = Qtopbase,
     37 
     38 	Qunitdir,			/* directory per unit */
     39 	Qunitbase,
     40 	Qctl		= Qunitbase,
     41 	Qraw,
     42 	Qpart,
     43 
     44 	TypeLOG		= 4,
     45 	NType		= (1<<TypeLOG),
     46 	TypeMASK	= (NType-1),
     47 	TypeSHIFT	= 0,
     48 
     49 	PartLOG		= 8,
     50 	NPart		= (1<<PartLOG),
     51 	PartMASK	= (NPart-1),
     52 	PartSHIFT	= TypeLOG,
     53 
     54 	UnitLOG		= 8,
     55 	NUnit		= (1<<UnitLOG),
     56 	UnitMASK	= (NUnit-1),
     57 	UnitSHIFT	= (PartLOG+TypeLOG),
     58 
     59 	DevLOG		= 8,
     60 	NDev		= (1 << DevLOG),
     61 	DevMASK		= (NDev-1),
     62 	DevSHIFT	 = (UnitLOG+PartLOG+TypeLOG),
     63 
     64 	Ncmd = 20,
     65 };
     66 
     67 #define TYPE(q)		((((ulong)(q).path)>>TypeSHIFT) & TypeMASK)
     68 #define PART(q)		((((ulong)(q).path)>>PartSHIFT) & PartMASK)
     69 #define UNIT(q)		((((ulong)(q).path)>>UnitSHIFT) & UnitMASK)
     70 #define DEV(q)		((((ulong)(q).path)>>DevSHIFT) & DevMASK)
     71 #define QID(d,u, p, t)	(((d)<<DevSHIFT)|((u)<<UnitSHIFT)|\
     72 					 ((p)<<PartSHIFT)|((t)<<TypeSHIFT))
     73 
     74 
     75 void
     76 sdaddpart(SDunit* unit, char* name, uvlong start, uvlong end)
     77 {
     78 	SDpart *pp;
     79 	int i, partno;
     80 
     81 	/*
     82 	 * Check name not already used
     83 	 * and look for a free slot.
     84 	 */
     85 	if(unit->part != nil){
     86 		partno = -1;
     87 		for(i = 0; i < unit->npart; i++){
     88 			pp = &unit->part[i];
     89 			if(!pp->valid){
     90 				if(partno == -1)
     91 					partno = i;
     92 				break;
     93 			}
     94 			if(strcmp(name, pp->perm.name) == 0){
     95 				if(pp->start == start && pp->end == end)
     96 					return;
     97 				error(Ebadctl);
     98 			}
     99 		}
    100 	}
    101 	else{
    102 		if((unit->part = malloc(sizeof(SDpart)*SDnpart)) == nil)
    103 			error(Enomem);
    104 		unit->npart = SDnpart;
    105 		partno = 0;
    106 	}
    107 
    108 	/*
    109 	 * If no free slot found then increase the
    110 	 * array size (can't get here with unit->part == nil).
    111 	 */
    112 	if(partno == -1){
    113 		if(unit->npart >= NPart)
    114 			error(Enomem);
    115 		if((pp = malloc(sizeof(SDpart)*(unit->npart+SDnpart))) == nil)
    116 			error(Enomem);
    117 		memmove(pp, unit->part, sizeof(SDpart)*unit->npart);
    118 		free(unit->part);
    119 		unit->part = pp;
    120 		partno = unit->npart;
    121 		unit->npart += SDnpart;
    122 	}
    123 
    124 	/*
    125 	 * Check size and extent are valid.
    126 	 */
    127 	if(start > end || end > unit->sectors)
    128 		error(Eio);
    129 	pp = &unit->part[partno];
    130 	pp->start = start;
    131 	pp->end = end;
    132 	kstrdup(&pp->perm.name, name);
    133 	kstrdup(&pp->perm.user, eve);
    134 	pp->perm.perm = 0640;
    135 	pp->valid = 1;
    136 }
    137 
    138 static void
    139 sddelpart(SDunit* unit, char* name)
    140 {
    141 	int i;
    142 	SDpart *pp;
    143 
    144 	/*
    145 	 * Look for the partition to delete.
    146 	 * Can't delete if someone still has it open.
    147 	 */
    148 	pp = unit->part;
    149 	for(i = 0; i < unit->npart; i++){
    150 		if(strcmp(name, pp->perm.name) == 0)
    151 			break;
    152 		pp++;
    153 	}
    154 	if(i >= unit->npart)
    155 		error(Ebadctl);
    156 	if(strcmp(up->user, pp->perm.user) && !iseve())
    157 		error(Eperm);
    158 	pp->valid = 0;
    159 	pp->vers++;
    160 }
    161 
    162 static void
    163 sdincvers(SDunit *unit)
    164 {
    165 	int i;
    166 
    167 	unit->vers++;
    168 	if(unit->part){
    169 		for(i = 0; i < unit->npart; i++){
    170 			unit->part[i].valid = 0;
    171 			unit->part[i].vers++;
    172 		}
    173 	}
    174 }
    175 
    176 static int
    177 sdinitpart(SDunit* unit)
    178 {
    179 	if(unit->sectors > 0){
    180 		unit->sectors = unit->secsize = 0;
    181 		sdincvers(unit);
    182 	}
    183 
    184 	if(unit->inquiry[0] & 0xC0)
    185 		return 0;
    186 	switch(unit->inquiry[0] & 0x1F){
    187 	case 0x00:			/* DA */
    188 	case 0x04:			/* WORM */
    189 	case 0x05:			/* CD-ROM */
    190 	case 0x07:			/* MO */
    191 		break;
    192 	default:
    193 		return 0;
    194 	}
    195 
    196 	if(unit->dev->ifc->online)
    197 		unit->dev->ifc->online(unit);
    198 	if(unit->sectors){
    199 		sdincvers(unit);
    200 		sdaddpart(unit, "data", 0, unit->sectors);
    201 		partition(unit);
    202 	}
    203 
    204 	return 1;
    205 }
    206 
    207 static int
    208 sdindex(int idno)
    209 {
    210 	char *p;
    211 
    212 	p = strchr(devletters, idno);
    213 	if(p == nil)
    214 		return -1;
    215 	return p-devletters;
    216 }
    217 
    218 static SDev*
    219 sdgetdev(int idno)
    220 {
    221 	SDev *sdev;
    222 	int i;
    223 
    224 	if((i = sdindex(idno)) < 0)
    225 		return nil;
    226 
    227 	qlock(&devslock);
    228 	if(sdev = devs[i])
    229 		incref(&sdev->r);
    230 	qunlock(&devslock);
    231 	return sdev;
    232 }
    233 
    234 static SDunit*
    235 sdgetunit(SDev* sdev, int subno)
    236 {
    237 	SDunit *unit;
    238 	char buf[32];
    239 
    240 	/*
    241 	 * Associate a unit with a given device and sub-unit
    242 	 * number on that device.
    243 	 * The device will be probed if it has not already been
    244 	 * successfully accessed.
    245 	 */
    246 	qlock(&sdev->unitlock);
    247 	if(subno > sdev->nunit){
    248 		qunlock(&sdev->unitlock);
    249 		return nil;
    250 	}
    251 
    252 	unit = sdev->unit[subno];
    253 	if(unit == nil){
    254 		/*
    255 		 * Probe the unit only once. This decision
    256 		 * may be a little severe and reviewed later.
    257 		 */
    258 		if(sdev->unitflg[subno]){
    259 			qunlock(&sdev->unitlock);
    260 			return nil;
    261 		}
    262 		if((unit = malloc(sizeof(SDunit))) == nil){
    263 			qunlock(&sdev->unitlock);
    264 			return nil;
    265 		}
    266 		sdev->unitflg[subno] = 1;
    267 
    268 		snprint(buf, sizeof(buf), "%s%d", sdev->name, subno);
    269 		kstrdup(&unit->perm.name, buf);
    270 		kstrdup(&unit->perm.user, eve);
    271 		unit->perm.perm = 0555;
    272 		unit->subno = subno;
    273 		unit->dev = sdev;
    274 
    275 		if(sdev->enabled == 0 && sdev->ifc->enable)
    276 			sdev->ifc->enable(sdev);
    277 		sdev->enabled = 1;
    278 
    279 		/*
    280 		 * No need to lock anything here as this is only
    281 		 * called before the unit is made available in the
    282 		 * sdunit[] array.
    283 		 */
    284 		if(unit->dev->ifc->verify(unit) == 0){
    285 			qunlock(&sdev->unitlock);
    286 			free(unit);
    287 			return nil;
    288 		}
    289 		sdev->unit[subno] = unit;
    290 	}
    291 	qunlock(&sdev->unitlock);
    292 	return unit;
    293 }
    294 
    295 static void
    296 sdreset(void)
    297 {
    298 	int i;
    299 	SDev *sdev;
    300 
    301 	/*
    302 	 * Probe all known controller types and register any devices found.
    303 	 */
    304 	for(i = 0; sdifc[i] != nil; i++){
    305 		if(sdifc[i]->pnp == nil || (sdev = sdifc[i]->pnp()) == nil)
    306 			continue;
    307 		sdadddevs(sdev);
    308 	}
    309 }
    310 
    311 void
    312 sdadddevs(SDev *sdev)
    313 {
    314 	int i, j, id;
    315 	SDev *next;
    316 
    317 	for(; sdev; sdev=next){
    318 		next = sdev->next;
    319 
    320 		sdev->unit = (SDunit**)malloc(sdev->nunit * sizeof(SDunit*));
    321 		sdev->unitflg = (int*)malloc(sdev->nunit * sizeof(int));
    322 		if(sdev->unit == nil || sdev->unitflg == nil){
    323 			print("sdadddevs: out of memory\n");
    324 		giveup:
    325 			free(sdev->unit);
    326 			free(sdev->unitflg);
    327 			if(sdev->ifc->clear)
    328 				sdev->ifc->clear(sdev);
    329 			free(sdev);
    330 			continue;
    331 		}
    332 		id = sdindex(sdev->idno);
    333 		if(id == -1){
    334 			print("sdadddevs: bad id number %d (%C)\n", id, id);
    335 			goto giveup;
    336 		}
    337 		qlock(&devslock);
    338 		for(i=0; i<nelem(devs); i++){
    339 			if(devs[j = (id+i)%nelem(devs)] == nil){
    340 				sdev->idno = devletters[j];
    341 				devs[j] = sdev;
    342 				snprint(sdev->name, sizeof sdev->name, "sd%c", devletters[j]);
    343 				break;
    344 			}
    345 		}
    346 		qunlock(&devslock);
    347 		if(i == nelem(devs)){
    348 			print("sdadddevs: out of device letters\n");
    349 			goto giveup;
    350 		}
    351 	}
    352 }
    353 
    354 // void
    355 // sdrmdevs(SDev *sdev)
    356 // {
    357 // 	char buf[2];
    358 //
    359 // 	snprint(buf, sizeof buf, "%c", sdev->idno);
    360 // 	unconfigure(buf);
    361 // }
    362 
    363 static int
    364 sd2gen(Chan* c, int i, Dir* dp)
    365 {
    366 	Qid q;
    367 	uvlong l;
    368 	SDpart *pp;
    369 	SDperm *perm;
    370 	SDunit *unit;
    371 	SDev *sdev;
    372 	int rv;
    373 
    374 	sdev = sdgetdev(DEV(c->qid));
    375 	assert(sdev);
    376 	unit = sdev->unit[UNIT(c->qid)];
    377 
    378 	rv = -1;
    379 	switch(i){
    380 	case Qctl:
    381 		mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qctl),
    382 			unit->vers, QTFILE);
    383 		perm = &unit->ctlperm;
    384 		if(emptystr(perm->user)){
    385 			kstrdup(&perm->user, eve);
    386 			perm->perm = 0640;
    387 		}
    388 		devdir(c, q, "ctl", 0, perm->user, perm->perm, dp);
    389 		rv = 1;
    390 		break;
    391 
    392 	case Qraw:
    393 		mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qraw),
    394 			unit->vers, QTFILE);
    395 		perm = &unit->rawperm;
    396 		if(emptystr(perm->user)){
    397 			kstrdup(&perm->user, eve);
    398 			perm->perm = DMEXCL|0600;
    399 		}
    400 		devdir(c, q, "raw", 0, perm->user, perm->perm, dp);
    401 		rv = 1;
    402 		break;
    403 
    404 	case Qpart:
    405 		pp = &unit->part[PART(c->qid)];
    406 		l = (pp->end - pp->start) * unit->secsize;
    407 		mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qpart),
    408 			unit->vers+pp->vers, QTFILE);
    409 		if(emptystr(pp->perm.user))
    410 			kstrdup(&pp->perm.user, eve);
    411 		devdir(c, q, pp->perm.name, l, pp->perm.user, pp->perm.perm, dp);
    412 		rv = 1;
    413 		break;
    414 	}
    415 
    416 	decref(&sdev->r);
    417 	return rv;
    418 }
    419 
    420 static int
    421 sd1gen(Chan* c, int i, Dir* dp)
    422 {
    423 	Qid q;
    424 
    425 	switch(i){
    426 	case Qtopctl:
    427 		mkqid(&q, QID(0, 0, 0, Qtopctl), 0, QTFILE);
    428 		devdir(c, q, "sdctl", 0, eve, 0640, dp);
    429 		return 1;
    430 	}
    431 	return -1;
    432 }
    433 
    434 static int
    435 sdgen(Chan* c, char *name, Dirtab *dt, int j, int s, Dir* dp)
    436 {
    437 	Qid q;
    438 	uvlong l;
    439 	int i, r;
    440 	SDpart *pp;
    441 	SDunit *unit;
    442 	SDev *sdev;
    443 
    444 	switch(TYPE(c->qid)){
    445 	case Qtopdir:
    446 		if(s == DEVDOTDOT){
    447 			mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);
    448 			sprint(up->genbuf, "#%C", sddevtab.dc);
    449 			devdir(c, q, up->genbuf, 0, eve, 0555, dp);
    450 			return 1;
    451 		}
    452 
    453 		if(s+Qtopbase < Qunitdir)
    454 			return sd1gen(c, s+Qtopbase, dp);
    455 		s -= (Qunitdir-Qtopbase);
    456 
    457 		qlock(&devslock);
    458 		for(i=0; i<nelem(devs); i++){
    459 			if(devs[i]){
    460 				if(s < devs[i]->nunit)
    461 					break;
    462 				s -= devs[i]->nunit;
    463 			}
    464 		}
    465 
    466 		if(i == nelem(devs)){
    467 			/* Run off the end of the list */
    468 			qunlock(&devslock);
    469 			return -1;
    470 		}
    471 
    472 		if((sdev = devs[i]) == nil){
    473 			qunlock(&devslock);
    474 			return 0;
    475 		}
    476 
    477 		incref(&sdev->r);
    478 		qunlock(&devslock);
    479 
    480 		if((unit = sdev->unit[s]) == nil)
    481 			if((unit = sdgetunit(sdev, s)) == nil){
    482 				decref(&sdev->r);
    483 				return 0;
    484 			}
    485 
    486 		mkqid(&q, QID(sdev->idno, s, 0, Qunitdir), 0, QTDIR);
    487 		if(emptystr(unit->perm.user))
    488 			kstrdup(&unit->perm.user, eve);
    489 		devdir(c, q, unit->perm.name, 0, unit->perm.user, unit->perm.perm, dp);
    490 		decref(&sdev->r);
    491 		return 1;
    492 
    493 	case Qunitdir:
    494 		if(s == DEVDOTDOT){
    495 			mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);
    496 			sprint(up->genbuf, "#%C", sddevtab.dc);
    497 			devdir(c, q, up->genbuf, 0, eve, 0555, dp);
    498 			return 1;
    499 		}
    500 
    501 		if((sdev = sdgetdev(DEV(c->qid))) == nil){
    502 			devdir(c, c->qid, "unavailable", 0, eve, 0, dp);
    503 			return 1;
    504 		}
    505 
    506 		unit = sdev->unit[UNIT(c->qid)];
    507 		qlock(&unit->ctl);
    508 
    509 		/*
    510 		 * Check for media change.
    511 		 * If one has already been detected, sectors will be zero.
    512 		 * If there is one waiting to be detected, online
    513 		 * will return > 1.
    514 		 * Online is a bit of a large hammer but does the job.
    515 		 */
    516 		if(unit->sectors == 0
    517 		|| (unit->dev->ifc->online && unit->dev->ifc->online(unit) > 1))
    518 			sdinitpart(unit);
    519 
    520 		i = s+Qunitbase;
    521 		if(i < Qpart){
    522 			r = sd2gen(c, i, dp);
    523 			qunlock(&unit->ctl);
    524 			decref(&sdev->r);
    525 			return r;
    526 		}
    527 		i -= Qpart;
    528 		if(unit->part == nil || i >= unit->npart){
    529 			qunlock(&unit->ctl);
    530 			decref(&sdev->r);
    531 			break;
    532 		}
    533 		pp = &unit->part[i];
    534 		if(!pp->valid){
    535 			qunlock(&unit->ctl);
    536 			decref(&sdev->r);
    537 			return 0;
    538 		}
    539 		l = (pp->end - pp->start) * unit->secsize;
    540 		mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), i, Qpart),
    541 			unit->vers+pp->vers, QTFILE);
    542 		if(emptystr(pp->perm.user))
    543 			kstrdup(&pp->perm.user, eve);
    544 		devdir(c, q, pp->perm.name, l, pp->perm.user, pp->perm.perm, dp);
    545 		qunlock(&unit->ctl);
    546 		decref(&sdev->r);
    547 		return 1;
    548 	case Qraw:
    549 	case Qctl:
    550 	case Qpart:
    551 		if((sdev = sdgetdev(DEV(c->qid))) == nil){
    552 			devdir(c, q, "unavailable", 0, eve, 0, dp);
    553 			return 1;
    554 		}
    555 		unit = sdev->unit[UNIT(c->qid)];
    556 		qlock(&unit->ctl);
    557 		r = sd2gen(c, TYPE(c->qid), dp);
    558 		qunlock(&unit->ctl);
    559 		decref(&sdev->r);
    560 		return r;
    561 	case Qtopctl:
    562 		return sd1gen(c, TYPE(c->qid), dp);
    563 	default:
    564 		break;
    565 	}
    566 
    567 	return -1;
    568 }
    569 
    570 static Chan*
    571 sdattach(char* spec)
    572 {
    573 	Chan *c;
    574 	char *p;
    575 	SDev *sdev;
    576 	int idno, subno;
    577 
    578 	if(*spec == '\0'){
    579 		c = devattach(sddevtab.dc, spec);
    580 		mkqid(&c->qid, QID(0, 0, 0, Qtopdir), 0, QTDIR);
    581 		return c;
    582 	}
    583 
    584 	if(spec[0] != 's' || spec[1] != 'd')
    585 		error(Ebadspec);
    586 	idno = spec[2];
    587 	subno = strtol(&spec[3], &p, 0);
    588 	if(p == &spec[3])
    589 		error(Ebadspec);
    590 
    591 	if((sdev=sdgetdev(idno)) == nil)
    592 		error(Enonexist);
    593 	if(sdgetunit(sdev, subno) == nil){
    594 		decref(&sdev->r);
    595 		error(Enonexist);
    596 	}
    597 
    598 	c = devattach(sddevtab.dc, spec);
    599 	mkqid(&c->qid, QID(sdev->idno, subno, 0, Qunitdir), 0, QTDIR);
    600 	c->dev = (sdev->idno << UnitLOG) + subno;
    601 	decref(&sdev->r);
    602 	return c;
    603 }
    604 
    605 static Walkqid*
    606 sdwalk(Chan* c, Chan* nc, char** name, int nname)
    607 {
    608 	return devwalk(c, nc, name, nname, nil, 0, sdgen);
    609 }
    610 
    611 static int
    612 sdstat(Chan* c, uchar* db, int n)
    613 {
    614 	return devstat(c, db, n, nil, 0, sdgen);
    615 }
    616 
    617 static Chan*
    618 sdopen(Chan* c, int omode)
    619 {
    620 	SDpart *pp;
    621 	SDunit *unit;
    622 	SDev *sdev;
    623 	uchar tp;
    624 
    625 	c = devopen(c, omode, 0, 0, sdgen);
    626 	if((tp = TYPE(c->qid)) != Qctl && tp != Qraw && tp != Qpart)
    627 		return c;
    628 
    629 	sdev = sdgetdev(DEV(c->qid));
    630 	if(sdev == nil)
    631 		error(Enonexist);
    632 
    633 	unit = sdev->unit[UNIT(c->qid)];
    634 
    635 	switch(TYPE(c->qid)){
    636 	case Qctl:
    637 		c->qid.vers = unit->vers;
    638 		break;
    639 	case Qraw:
    640 		c->qid.vers = unit->vers;
    641 		if(tas(&unit->rawinuse) != 0){
    642 			c->flag &= ~COPEN;
    643 			decref(&sdev->r);
    644 			error(Einuse);
    645 		}
    646 		unit->state = Rawcmd;
    647 		break;
    648 	case Qpart:
    649 		qlock(&unit->ctl);
    650 		if(waserror()){
    651 			qunlock(&unit->ctl);
    652 			c->flag &= ~COPEN;
    653 			decref(&sdev->r);
    654 			nexterror();
    655 		}
    656 		pp = &unit->part[PART(c->qid)];
    657 		c->qid.vers = unit->vers+pp->vers;
    658 		qunlock(&unit->ctl);
    659 		poperror();
    660 		break;
    661 	}
    662 	decref(&sdev->r);
    663 	return c;
    664 }
    665 
    666 static void
    667 sdclose(Chan* c)
    668 {
    669 	SDunit *unit;
    670 	SDev *sdev;
    671 
    672 	if(c->qid.type & QTDIR)
    673 		return;
    674 	if(!(c->flag & COPEN))
    675 		return;
    676 
    677 	switch(TYPE(c->qid)){
    678 	default:
    679 		break;
    680 	case Qraw:
    681 		sdev = sdgetdev(DEV(c->qid));
    682 		if(sdev){
    683 			unit = sdev->unit[UNIT(c->qid)];
    684 			unit->rawinuse = 0;
    685 			decref(&sdev->r);
    686 		}
    687 		break;
    688 	}
    689 }
    690 
    691 static long
    692 sdbio(Chan* c, int write, char* a, long len, uvlong off)
    693 {
    694 	int nchange;
    695 	long l;
    696 	uchar *b;
    697 	SDpart *pp;
    698 	SDunit *unit;
    699 	SDev *sdev;
    700 	ulong max, nb, offset;
    701 	uvlong bno;
    702 
    703 	sdev = sdgetdev(DEV(c->qid));
    704 	if(sdev == nil){
    705 		decref(&sdev->r);
    706 		error(Enonexist);
    707 	}
    708 	unit = sdev->unit[UNIT(c->qid)];
    709 	if(unit == nil)
    710 		error(Enonexist);
    711 
    712 	nchange = 0;
    713 	qlock(&unit->ctl);
    714 	while(waserror()){
    715 		/* notification of media change; go around again */
    716 		if(strcmp(up->errstr, Eio) == 0 && unit->sectors == 0 && nchange++ == 0){
    717 			sdinitpart(unit);
    718 			continue;
    719 		}
    720 
    721 		/* other errors; give up */
    722 		qunlock(&unit->ctl);
    723 		decref(&sdev->r);
    724 		nexterror();
    725 	}
    726 	pp = &unit->part[PART(c->qid)];
    727 	if(unit->vers+pp->vers != c->qid.vers)
    728 		error(Echange);
    729 
    730 	/*
    731 	 * Check the request is within bounds.
    732 	 * Removeable drives are locked throughout the I/O
    733 	 * in case the media changes unexpectedly.
    734 	 * Non-removeable drives are not locked during the I/O
    735 	 * to allow the hardware to optimise if it can; this is
    736 	 * a little fast and loose.
    737 	 * It's assumed that non-removeable media parameters
    738 	 * (sectors, secsize) can't change once the drive has
    739 	 * been brought online.
    740 	 */
    741 	bno = (off/unit->secsize) + pp->start;
    742 	nb = ((off+len+unit->secsize-1)/unit->secsize) + pp->start - bno;
    743 	max = SDmaxio/unit->secsize;
    744 	if(nb > max)
    745 		nb = max;
    746 	if(bno+nb > pp->end)
    747 		nb = pp->end - bno;
    748 	if(bno >= pp->end || nb == 0){
    749 		if(write)
    750 			error(Eio);
    751 		qunlock(&unit->ctl);
    752 		decref(&sdev->r);
    753 		poperror();
    754 		return 0;
    755 	}
    756 	if(!(unit->inquiry[1] & 0x80)){
    757 		qunlock(&unit->ctl);
    758 		poperror();
    759 	}
    760 
    761 	b = sdmalloc(nb*unit->secsize);
    762 	if(b == nil)
    763 		error(Enomem);
    764 	if(waserror()){
    765 		sdfree(b);
    766 		if(!(unit->inquiry[1] & 0x80))
    767 			decref(&sdev->r);		/* gadverdamme! */
    768 		nexterror();
    769 	}
    770 
    771 	offset = off%unit->secsize;
    772 	if(offset+len > nb*unit->secsize)
    773 		len = nb*unit->secsize - offset;
    774 	if(write){
    775 		if(offset || (len%unit->secsize)){
    776 			l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
    777 			if(l < 0)
    778 				error(Eio);
    779 			if(l < (nb*unit->secsize)){
    780 				nb = l/unit->secsize;
    781 				l = nb*unit->secsize - offset;
    782 				if(len > l)
    783 					len = l;
    784 			}
    785 		}
    786 		memmove(b+offset, a, len);
    787 		l = unit->dev->ifc->bio(unit, 0, 1, b, nb, bno);
    788 		if(l < 0)
    789 			error(Eio);
    790 		if(l < offset)
    791 			len = 0;
    792 		else if(len > l - offset)
    793 			len = l - offset;
    794 	}
    795 	else{
    796 		l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
    797 		if(l < 0)
    798 			error(Eio);
    799 		if(l < offset)
    800 			len = 0;
    801 		else if(len > l - offset)
    802 			len = l - offset;
    803 		memmove(a, b+offset, len);
    804 	}
    805 	sdfree(b);
    806 	poperror();
    807 
    808 	if(unit->inquiry[1] & 0x80){
    809 		qunlock(&unit->ctl);
    810 		poperror();
    811 	}
    812 
    813 	decref(&sdev->r);
    814 	return len;
    815 }
    816 
    817 static long
    818 sdrio(SDreq* r, void* a, long n)
    819 {
    820 	void *data;
    821 
    822 	if(n >= SDmaxio || n < 0)
    823 		error(Etoobig);
    824 
    825 	data = nil;
    826 	if(n){
    827 		if((data = sdmalloc(n)) == nil)
    828 			error(Enomem);
    829 		if(r->write)
    830 			memmove(data, a, n);
    831 	}
    832 	r->data = data;
    833 	r->dlen = n;
    834 
    835 	if(waserror()){
    836 		sdfree(data);
    837 		r->data = nil;
    838 		nexterror();
    839 	}
    840 
    841 	if(r->unit->dev->ifc->rio(r) != SDok)
    842 		error(Eio);
    843 
    844 	if(!r->write && r->rlen > 0)
    845 		memmove(a, data, r->rlen);
    846 	sdfree(data);
    847 	r->data = nil;
    848 	poperror();
    849 
    850 	return r->rlen;
    851 }
    852 
    853 /*
    854  * SCSI simulation for non-SCSI devices
    855  */
    856 int
    857 sdsetsense(SDreq *r, int status, int key, int asc, int ascq)
    858 {
    859 	int len;
    860 	SDunit *unit;
    861 
    862 	unit = r->unit;
    863 	unit->sense[2] = key;
    864 	unit->sense[12] = asc;
    865 	unit->sense[13] = ascq;
    866 
    867 	r->status = status;
    868 	if(status == SDcheck && !(r->flags & SDnosense)){
    869 		/* request sense case from sdfakescsi */
    870 		len = sizeof unit->sense;
    871 		if(len > sizeof r->sense-1)
    872 			len = sizeof r->sense-1;
    873 		memmove(r->sense, unit->sense, len);
    874 		unit->sense[2] = 0;
    875 		unit->sense[12] = 0;
    876 		unit->sense[13] = 0;
    877 		r->flags |= SDvalidsense;
    878 		return SDok;
    879 	}
    880 	return status;
    881 }
    882 
    883 int
    884 sdmodesense(SDreq *r, uchar *cmd, void *info, int ilen)
    885 {
    886 	int len;
    887 	uchar *data;
    888 
    889 	/*
    890 	 * Fake a vendor-specific request with page code 0,
    891 	 * return the drive info.
    892 	 */
    893 	if((cmd[2] & 0x3F) != 0 && (cmd[2] & 0x3F) != 0x3F)
    894 		return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
    895 	len = (cmd[7]<<8)|cmd[8];
    896 	if(len == 0)
    897 		return SDok;
    898 	if(len < 8+ilen)
    899 		return sdsetsense(r, SDcheck, 0x05, 0x1A, 0);
    900 	if(r->data == nil || r->dlen < len)
    901 		return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
    902 	data = r->data;
    903 	memset(data, 0, 8);
    904 	data[0] = ilen>>8;
    905 	data[1] = ilen;
    906 	if(ilen)
    907 		memmove(data+8, info, ilen);
    908 	r->rlen = 8+ilen;
    909 	return sdsetsense(r, SDok, 0, 0, 0);
    910 }
    911 
    912 int
    913 sdfakescsi(SDreq *r, void *info, int ilen)
    914 {
    915 	uchar *cmd, *p;
    916 	uvlong len;
    917 	SDunit *unit;
    918 
    919 	cmd = r->cmd;
    920 	r->rlen = 0;
    921 	unit = r->unit;
    922 
    923 	/*
    924 	 * Rewrite read(6)/write(6) into read(10)/write(10).
    925 	 */
    926 	switch(cmd[0]){
    927 	case 0x08:	/* read */
    928 	case 0x0A:	/* write */
    929 		cmd[9] = 0;
    930 		cmd[8] = cmd[4];
    931 		cmd[7] = 0;
    932 		cmd[6] = 0;
    933 		cmd[5] = cmd[3];
    934 		cmd[4] = cmd[2];
    935 		cmd[3] = cmd[1] & 0x0F;
    936 		cmd[2] = 0;
    937 		cmd[1] &= 0xE0;
    938 		cmd[0] |= 0x20;
    939 		break;
    940 	}
    941 
    942 	/*
    943 	 * Map SCSI commands into ATA commands for discs.
    944 	 * Fail any command with a LUN except INQUIRY which
    945 	 * will return 'logical unit not supported'.
    946 	 */
    947 	if((cmd[1]>>5) && cmd[0] != 0x12)
    948 		return sdsetsense(r, SDcheck, 0x05, 0x25, 0);
    949 
    950 	switch(cmd[0]){
    951 	default:
    952 		return sdsetsense(r, SDcheck, 0x05, 0x20, 0);
    953 
    954 	case 0x00:	/* test unit ready */
    955 		return sdsetsense(r, SDok, 0, 0, 0);
    956 
    957 	case 0x03:	/* request sense */
    958 		if(cmd[4] < sizeof unit->sense)
    959 			len = cmd[4];
    960 		else
    961 			len = sizeof unit->sense;
    962 		if(r->data && r->dlen >= len){
    963 			memmove(r->data, unit->sense, len);
    964 			r->rlen = len;
    965 		}
    966 		return sdsetsense(r, SDok, 0, 0, 0);
    967 
    968 	case 0x12:	/* inquiry */
    969 		if(cmd[4] < sizeof unit->inquiry)
    970 			len = cmd[4];
    971 		else
    972 			len = sizeof unit->inquiry;
    973 		if(r->data && r->dlen >= len){
    974 			memmove(r->data, unit->inquiry, len);
    975 			r->rlen = len;
    976 		}
    977 		return sdsetsense(r, SDok, 0, 0, 0);
    978 
    979 	case 0x1B:	/* start/stop unit */
    980 		/*
    981 		 * nop for now, can use power management later.
    982 		 */
    983 		return sdsetsense(r, SDok, 0, 0, 0);
    984 
    985 	case 0x25:	/* read capacity */
    986 		if((cmd[1] & 0x01) || cmd[2] || cmd[3])
    987 			return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
    988 		if(r->data == nil || r->dlen < 8)
    989 			return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
    990 
    991 		/*
    992 		 * Read capacity returns the LBA of the last sector.
    993 		 */
    994 		len = unit->sectors - 1;
    995 		p = r->data;
    996 		*p++ = len>>24;
    997 		*p++ = len>>16;
    998 		*p++ = len>>8;
    999 		*p++ = len;
   1000 		len = 512;
   1001 		*p++ = len>>24;
   1002 		*p++ = len>>16;
   1003 		*p++ = len>>8;
   1004 		*p++ = len;
   1005 		r->rlen = p - (uchar*)r->data;
   1006 		return sdsetsense(r, SDok, 0, 0, 0);
   1007 
   1008 	case 0x9E:	/* long read capacity */
   1009 		if((cmd[1] & 0x01) || cmd[2] || cmd[3])
   1010 			return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
   1011 		if(r->data == nil || r->dlen < 8)
   1012 			return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
   1013 		/*
   1014 		 * Read capcity returns the LBA of the last sector.
   1015 		 */
   1016 		len = unit->sectors - 1;
   1017 		p = r->data;
   1018 		*p++ = len>>56;
   1019 		*p++ = len>>48;
   1020 		*p++ = len>>40;
   1021 		*p++ = len>>32;
   1022 		*p++ = len>>24;
   1023 		*p++ = len>>16;
   1024 		*p++ = len>>8;
   1025 		*p++ = len;
   1026 		len = 512;
   1027 		*p++ = len>>24;
   1028 		*p++ = len>>16;
   1029 		*p++ = len>>8;
   1030 		*p++ = len;
   1031 		r->rlen = p - (uchar*)r->data;
   1032 		return sdsetsense(r, SDok, 0, 0, 0);
   1033 
   1034 	case 0x5A:	/* mode sense */
   1035 		return sdmodesense(r, cmd, info, ilen);
   1036 
   1037 	case 0x28:	/* read */
   1038 	case 0x2A:	/* write */
   1039 	case 0x88:	/* read16 */
   1040 	case 0x8a:	/* write16 */
   1041 		return SDnostatus;
   1042 	}
   1043 }
   1044 
   1045 static long
   1046 sdread(Chan *c, void *a, long n, vlong off)
   1047 {
   1048 	char *p, *e, *buf;
   1049 	SDpart *pp;
   1050 	SDunit *unit;
   1051 	SDev *sdev;
   1052 	ulong offset;
   1053 	int i, l, m, status;
   1054 
   1055 	offset = off;
   1056 	switch(TYPE(c->qid)){
   1057 	default:
   1058 		error(Eperm);
   1059 	case Qtopctl:
   1060 		m = 64*1024;	/* room for register dumps */
   1061 		p = buf = malloc(m);
   1062 		assert(p);
   1063 		e = p + m;
   1064 		qlock(&devslock);
   1065 		for(i = 0; i < nelem(devs); i++){
   1066 			sdev = devs[i];
   1067 			if(sdev && sdev->ifc->rtopctl)
   1068 				p = sdev->ifc->rtopctl(sdev, p, e);
   1069 		}
   1070 		qunlock(&devslock);
   1071 		n = readstr(off, a, n, buf);
   1072 		free(buf);
   1073 		return n;
   1074 
   1075 	case Qtopdir:
   1076 	case Qunitdir:
   1077 		return devdirread(c, a, n, 0, 0, sdgen);
   1078 
   1079 	case Qctl:
   1080 		sdev = sdgetdev(DEV(c->qid));
   1081 		if(sdev == nil)
   1082 			error(Enonexist);
   1083 
   1084 		unit = sdev->unit[UNIT(c->qid)];
   1085 		m = 16*1024;	/* room for register dumps */
   1086 		p = malloc(m);
   1087 		l = snprint(p, m, "inquiry %.48s\n",
   1088 			(char*)unit->inquiry+8);
   1089 		qlock(&unit->ctl);
   1090 		/*
   1091 		 * If there's a device specific routine it must
   1092 		 * provide all information pertaining to night geometry
   1093 		 * and the garscadden trains.
   1094 		 */
   1095 		if(unit->dev->ifc->rctl)
   1096 			l += unit->dev->ifc->rctl(unit, p+l, m-l);
   1097 		if(unit->sectors == 0)
   1098 			sdinitpart(unit);
   1099 		if(unit->sectors){
   1100 			if(unit->dev->ifc->rctl == nil)
   1101 				l += snprint(p+l, m-l,
   1102 					"geometry %llud %lud\n",
   1103 					unit->sectors, unit->secsize);
   1104 			pp = unit->part;
   1105 			for(i = 0; i < unit->npart; i++){
   1106 				if(pp->valid)
   1107 					l += snprint(p+l, m-l,
   1108 						"part %s %llud %llud\n",
   1109 						pp->perm.name, pp->start, pp->end);
   1110 				pp++;
   1111 			}
   1112 		}
   1113 		qunlock(&unit->ctl);
   1114 		decref(&sdev->r);
   1115 		l = readstr(offset, a, n, p);
   1116 		free(p);
   1117 		return l;
   1118 
   1119 	case Qraw:
   1120 		sdev = sdgetdev(DEV(c->qid));
   1121 		if(sdev == nil)
   1122 			error(Enonexist);
   1123 
   1124 		unit = sdev->unit[UNIT(c->qid)];
   1125 		qlock(&unit->raw);
   1126 		if(waserror()){
   1127 			qunlock(&unit->raw);
   1128 			decref(&sdev->r);
   1129 			nexterror();
   1130 		}
   1131 		if(unit->state == Rawdata){
   1132 			unit->state = Rawstatus;
   1133 			i = sdrio(unit->req, a, n);
   1134 		}
   1135 		else if(unit->state == Rawstatus){
   1136 			status = unit->req->status;
   1137 			unit->state = Rawcmd;
   1138 			free(unit->req);
   1139 			unit->req = nil;
   1140 			i = readnum(0, a, n, status, NUMSIZE);
   1141 		} else
   1142 			i = 0;
   1143 		qunlock(&unit->raw);
   1144 		decref(&sdev->r);
   1145 		poperror();
   1146 		return i;
   1147 
   1148 	case Qpart:
   1149 		return sdbio(c, 0, a, n, off);
   1150 	}
   1151 }
   1152 
   1153 static void legacytopctl(Cmdbuf*);
   1154 
   1155 static long
   1156 sdwrite(Chan* c, void* a, long n, vlong off)
   1157 {
   1158 	char *f0;
   1159 	int i;
   1160 	uvlong end, start;
   1161 	Cmdbuf *cb;
   1162 	SDifc *ifc;
   1163 	SDreq *req;
   1164 	SDunit *unit;
   1165 	SDev *sdev;
   1166 
   1167 	switch(TYPE(c->qid)){
   1168 	default:
   1169 		error(Eperm);
   1170 	case Qtopctl:
   1171 		cb = parsecmd(a, n);
   1172 		if(waserror()){
   1173 			free(cb);
   1174 			nexterror();
   1175 		}
   1176 		if(cb->nf == 0)
   1177 			error("empty control message");
   1178 		f0 = cb->f[0];
   1179 		cb->f++;
   1180 		cb->nf--;
   1181 		if(strcmp(f0, "config") == 0){
   1182 			/* wormhole into ugly legacy interface */
   1183 			legacytopctl(cb);
   1184 			poperror();
   1185 			free(cb);
   1186 			break;
   1187 		}
   1188 		/*
   1189 		 * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb),
   1190 		 * where sdifc[i]->name=="ata" and cb contains the args.
   1191 		 */
   1192 		ifc = nil;
   1193 		sdev = nil;
   1194 		for(i=0; sdifc[i]; i++){
   1195 			if(strcmp(sdifc[i]->name, f0) == 0){
   1196 				ifc = sdifc[i];
   1197 				sdev = nil;
   1198 				goto subtopctl;
   1199 			}
   1200 		}
   1201 		/*
   1202 		 * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb),
   1203 		 * where sdifc[i] and sdev match controller letter "1",
   1204 		 * and cb contains the args.
   1205 		 */
   1206 		if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){
   1207 			if((sdev = sdgetdev(f0[2])) != nil){
   1208 				ifc = sdev->ifc;
   1209 				goto subtopctl;
   1210 			}
   1211 		}
   1212 		error("unknown interface");
   1213 
   1214 	subtopctl:
   1215 		if(waserror()){
   1216 			if(sdev)
   1217 				decref(&sdev->r);
   1218 			nexterror();
   1219 		}
   1220 		if(ifc->wtopctl)
   1221 			ifc->wtopctl(sdev, cb);
   1222 		else
   1223 			error(Ebadctl);
   1224 		poperror();
   1225 		poperror();
   1226 		if (sdev)
   1227 			decref(&sdev->r);
   1228 		free(cb);
   1229 		break;
   1230 
   1231 	case Qctl:
   1232 		cb = parsecmd(a, n);
   1233 		sdev = sdgetdev(DEV(c->qid));
   1234 		if(sdev == nil)
   1235 			error(Enonexist);
   1236 		unit = sdev->unit[UNIT(c->qid)];
   1237 
   1238 		qlock(&unit->ctl);
   1239 		if(waserror()){
   1240 			qunlock(&unit->ctl);
   1241 			decref(&sdev->r);
   1242 			free(cb);
   1243 			nexterror();
   1244 		}
   1245 		if(unit->vers != c->qid.vers)
   1246 			error(Echange);
   1247 
   1248 		if(cb->nf < 1)
   1249 			error(Ebadctl);
   1250 		if(strcmp(cb->f[0], "part") == 0){
   1251 			if(cb->nf != 4)
   1252 				error(Ebadctl);
   1253 			if(unit->sectors == 0 && !sdinitpart(unit))
   1254 				error(Eio);
   1255 			start = strtoull(cb->f[2], 0, 0);
   1256 			end = strtoull(cb->f[3], 0, 0);
   1257 			sdaddpart(unit, cb->f[1], start, end);
   1258 		}
   1259 		else if(strcmp(cb->f[0], "delpart") == 0){
   1260 			if(cb->nf != 2 || unit->part == nil)
   1261 				error(Ebadctl);
   1262 			sddelpart(unit, cb->f[1]);
   1263 		}
   1264 		else if(unit->dev->ifc->wctl)
   1265 			unit->dev->ifc->wctl(unit, cb);
   1266 		else
   1267 			error(Ebadctl);
   1268 		qunlock(&unit->ctl);
   1269 		decref(&sdev->r);
   1270 		poperror();
   1271 		free(cb);
   1272 		break;
   1273 
   1274 	case Qraw:
   1275 		sdev = sdgetdev(DEV(c->qid));
   1276 		if(sdev == nil)
   1277 			error(Enonexist);
   1278 		unit = sdev->unit[UNIT(c->qid)];
   1279 		qlock(&unit->raw);
   1280 		if(waserror()){
   1281 			qunlock(&unit->raw);
   1282 			decref(&sdev->r);
   1283 			nexterror();
   1284 		}
   1285 		switch(unit->state){
   1286 		case Rawcmd:
   1287 			if(n < 6 || n > sizeof(req->cmd))
   1288 				error(Ebadarg);
   1289 			if((req = malloc(sizeof(SDreq))) == nil)
   1290 				error(Enomem);
   1291 			req->unit = unit;
   1292 			memmove(req->cmd, a, n);
   1293 			req->clen = n;
   1294 			req->flags = SDnosense;
   1295 			req->status = ~0;
   1296 
   1297 			unit->req = req;
   1298 			unit->state = Rawdata;
   1299 			break;
   1300 
   1301 		case Rawstatus:
   1302 			unit->state = Rawcmd;
   1303 			free(unit->req);
   1304 			unit->req = nil;
   1305 			error(Ebadusefd);
   1306 
   1307 		case Rawdata:
   1308 			unit->state = Rawstatus;
   1309 			unit->req->write = 1;
   1310 			n = sdrio(unit->req, a, n);
   1311 		}
   1312 		qunlock(&unit->raw);
   1313 		decref(&sdev->r);
   1314 		poperror();
   1315 		break;
   1316 	case Qpart:
   1317 		return sdbio(c, 1, a, n, off);
   1318 	}
   1319 
   1320 	return n;
   1321 }
   1322 
   1323 static int
   1324 sdwstat(Chan* c, uchar* dp, int n)
   1325 {
   1326 	Dir *d;
   1327 	SDpart *pp;
   1328 	SDperm *perm;
   1329 	SDunit *unit;
   1330 	SDev *sdev;
   1331 
   1332 	if(c->qid.type & QTDIR)
   1333 		error(Eperm);
   1334 
   1335 	sdev = sdgetdev(DEV(c->qid));
   1336 	if(sdev == nil)
   1337 		error(Enonexist);
   1338 	unit = sdev->unit[UNIT(c->qid)];
   1339 	qlock(&unit->ctl);
   1340 	d = nil;
   1341 	if(waserror()){
   1342 		free(d);
   1343 		qunlock(&unit->ctl);
   1344 		decref(&sdev->r);
   1345 		nexterror();
   1346 	}
   1347 
   1348 	switch(TYPE(c->qid)){
   1349 	default:
   1350 		error(Eperm);
   1351 	case Qctl:
   1352 		perm = &unit->ctlperm;
   1353 		break;
   1354 	case Qraw:
   1355 		perm = &unit->rawperm;
   1356 		break;
   1357 	case Qpart:
   1358 		pp = &unit->part[PART(c->qid)];
   1359 		if(unit->vers+pp->vers != c->qid.vers)
   1360 			error(Enonexist);
   1361 		perm = &pp->perm;
   1362 		break;
   1363 	}
   1364 
   1365 	if(strcmp(up->user, perm->user) && !iseve())
   1366 		error(Eperm);
   1367 
   1368 	d = smalloc(sizeof(Dir)+n);
   1369 	n = convM2D(dp, n, &d[0], (char*)&d[1]);
   1370 	if(n == 0)
   1371 		error(Eshortstat);
   1372 	if(!emptystr(d[0].uid))
   1373 		kstrdup(&perm->user, d[0].uid);
   1374 	if(d[0].mode != ~0UL)
   1375 		perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
   1376 
   1377 	free(d);
   1378 	qunlock(&unit->ctl);
   1379 	decref(&sdev->r);
   1380 	poperror();
   1381 	return n;
   1382 }
   1383 
   1384 static int
   1385 configure(char* spec, DevConf* cf)
   1386 {
   1387 	SDev *s, *sdev;
   1388 	char *p;
   1389 	int i;
   1390 
   1391 	if(sdindex(*spec) < 0)
   1392 		error("bad sd spec");
   1393 
   1394 	if((p = strchr(cf->type, '/')) != nil)
   1395 		*p++ = '\0';
   1396 
   1397 	for(i = 0; sdifc[i] != nil; i++)
   1398 		if(strcmp(sdifc[i]->name, cf->type) == 0)
   1399 			break;
   1400 	if(sdifc[i] == nil)
   1401 		error("sd type not found");
   1402 	if(p)
   1403 		*(p-1) = '/';
   1404 
   1405 	if(sdifc[i]->probe == nil)
   1406 		error("sd type cannot probe");
   1407 
   1408 	sdev = sdifc[i]->probe(cf);
   1409 	for(s=sdev; s; s=s->next)
   1410 		s->idno = *spec;
   1411 	sdadddevs(sdev);
   1412 	return 0;
   1413 }
   1414 
   1415 static int
   1416 unconfigure(char* spec)
   1417 {
   1418 	int i;
   1419 	SDev *sdev;
   1420 	SDunit *unit;
   1421 
   1422 	if((i = sdindex(*spec)) < 0)
   1423 		error(Enonexist);
   1424 
   1425 	qlock(&devslock);
   1426 	if((sdev = devs[i]) == nil){
   1427 		qunlock(&devslock);
   1428 		error(Enonexist);
   1429 	}
   1430 	if(sdev->r.ref){
   1431 		qunlock(&devslock);
   1432 		error(Einuse);
   1433 	}
   1434 	devs[i] = nil;
   1435 	qunlock(&devslock);
   1436 
   1437 	/* make sure no interrupts arrive anymore before removing resources */
   1438 	if(sdev->enabled && sdev->ifc->disable)
   1439 		sdev->ifc->disable(sdev);
   1440 
   1441 	for(i = 0; i != sdev->nunit; i++){
   1442 		if(unit = sdev->unit[i]){
   1443 			free(unit->perm.name);
   1444 			free(unit->perm.user);
   1445 			free(unit);
   1446 		}
   1447 	}
   1448 
   1449 	if(sdev->ifc->clear)
   1450 		sdev->ifc->clear(sdev);
   1451 	free(sdev);
   1452 	return 0;
   1453 }
   1454 
   1455 static int
   1456 sdconfig(int on, char* spec, DevConf* cf)
   1457 {
   1458 	if(on)
   1459 		return configure(spec, cf);
   1460 	return unconfigure(spec);
   1461 }
   1462 
   1463 Dev sddevtab = {
   1464 	'S',
   1465 	"sd",
   1466 
   1467 	sdreset,
   1468 	devinit,
   1469 	devshutdown,
   1470 	sdattach,
   1471 	sdwalk,
   1472 	sdstat,
   1473 	sdopen,
   1474 	devcreate,
   1475 	sdclose,
   1476 	sdread,
   1477 	devbread,
   1478 	sdwrite,
   1479 	devbwrite,
   1480 	devremove,
   1481 	sdwstat,
   1482 	devpower,
   1483 	sdconfig,
   1484 };
   1485 
   1486 /*
   1487  * This is wrong for so many reasons.  This code must go.
   1488  */
   1489 typedef struct Confdata Confdata;
   1490 struct Confdata {
   1491 	int	on;
   1492 	char*	spec;
   1493 	DevConf	cf;
   1494 };
   1495 
   1496 static void
   1497 parseswitch(Confdata* cd, char* option)
   1498 {
   1499 	if(!strcmp("on", option))
   1500 		cd->on = 1;
   1501 	else if(!strcmp("off", option))
   1502 		cd->on = 0;
   1503 	else
   1504 		error(Ebadarg);
   1505 }
   1506 
   1507 static void
   1508 parsespec(Confdata* cd, char* option)
   1509 {
   1510 	if(strlen(option) > 1)
   1511 		error(Ebadarg);
   1512 	cd->spec = option;
   1513 }
   1514 
   1515 static Devport*
   1516 getnewport(DevConf* dc)
   1517 {
   1518 	Devport *p;
   1519 
   1520 	p = (Devport *)malloc((dc->nports + 1) * sizeof(Devport));
   1521 	if(dc->nports > 0){
   1522 		memmove(p, dc->ports, dc->nports * sizeof(Devport));
   1523 		free(dc->ports);
   1524 	}
   1525 	dc->ports = p;
   1526 	p = &dc->ports[dc->nports++];
   1527 	p->size = -1;
   1528 	p->port = (ulong)-1;
   1529 	return p;
   1530 }
   1531 
   1532 static void
   1533 parseport(Confdata* cd, char* option)
   1534 {
   1535 	char *e;
   1536 	Devport *p;
   1537 
   1538 	if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].port != (ulong)-1)
   1539 		p = getnewport(&cd->cf);
   1540 	else
   1541 		p = &cd->cf.ports[cd->cf.nports-1];
   1542 	p->port = strtol(option, &e, 0);
   1543 	if(e == nil || *e != '\0')
   1544 		error(Ebadarg);
   1545 }
   1546 
   1547 static void
   1548 parsesize(Confdata* cd, char* option)
   1549 {
   1550 	char *e;
   1551 	Devport *p;
   1552 
   1553 	if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].size != -1)
   1554 		p = getnewport(&cd->cf);
   1555 	else
   1556 		p = &cd->cf.ports[cd->cf.nports-1];
   1557 	p->size = (int)strtol(option, &e, 0);
   1558 	if(e == nil || *e != '\0')
   1559 		error(Ebadarg);
   1560 }
   1561 
   1562 static void
   1563 parseirq(Confdata* cd, char* option)
   1564 {
   1565 	char *e;
   1566 
   1567 	cd->cf.intnum = strtoul(option, &e, 0);
   1568 	if(e == nil || *e != '\0')
   1569 		error(Ebadarg);
   1570 }
   1571 
   1572 static void
   1573 parsetype(Confdata* cd, char* option)
   1574 {
   1575 	cd->cf.type = option;
   1576 }
   1577 
   1578 static struct {
   1579 	char	*name;
   1580 	void	(*parse)(Confdata*, char*);
   1581 } options[] = {
   1582 	"switch",	parseswitch,
   1583 	"spec",		parsespec,
   1584 	"port",		parseport,
   1585 	"size",		parsesize,
   1586 	"irq",		parseirq,
   1587 	"type",		parsetype,
   1588 };
   1589 
   1590 static void
   1591 legacytopctl(Cmdbuf *cb)
   1592 {
   1593 	char *opt;
   1594 	int i, j;
   1595 	Confdata cd;
   1596 
   1597 	memset(&cd, 0, sizeof cd);
   1598 	cd.on = -1;
   1599 	for(i=0; i<cb->nf; i+=2){
   1600 		if(i+2 > cb->nf)
   1601 			error(Ebadarg);
   1602 		opt = cb->f[i];
   1603 		for(j=0; j<nelem(options); j++)
   1604 			if(strcmp(opt, options[j].name) == 0){
   1605 				options[j].parse(&cd, cb->f[i+1]);
   1606 				break;
   1607 			}
   1608 		if(j == nelem(options))
   1609 			error(Ebadarg);
   1610 	}
   1611 	/* this has been rewritten to accomodate sdaoe */
   1612 	if(cd.on < 0 || cd.spec == 0)
   1613 		error(Ebadarg);
   1614 	if(cd.on && cd.cf.type == nil)
   1615 		error(Ebadarg);
   1616 	sdconfig(cd.on, cd.spec, &cd.cf);
   1617 }
   1618 
   1619 SDpart*
   1620 sdfindpart(SDunit *unit, char *name)
   1621 {
   1622 	int i;
   1623 
   1624 	for(i=0; i<unit->npart; i++) {
   1625 		if(strcmp(unit->part[i].perm.name, name) == 0){
   1626 			return &unit->part[i];
   1627 		}
   1628 	}
   1629 	return nil;
   1630 }