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