xref: /plan9-contrib/sys/src/9k/port/devsd.c (revision 465c1891ace366afe151a1d40ae292dba51c74ad)
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->devno = (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 long
sdstat(Chan * c,uchar * db,long n)652 sdstat(Chan* c, uchar* db, long 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,vlong off)732 sdbio(Chan* c, int write, char* a, long len, vlong off)
733 {
734 	int nchange;
735 	uchar *b;
736 	SDpart *pp;
737 	SDunit *unit;
738 	SDev *sdev;
739 	vlong bno;
740 	long l, max, nb, offset;
741 
742 	sdev = sdgetdev(DEV(c->qid));
743 	if(sdev == nil){
744 		decref(&sdev->r);
745 		error(Enonexist);
746 	}
747 	unit = sdev->unit[UNIT(c->qid)];
748 	if(unit == nil)
749 		error(Enonexist);
750 
751 	nchange = 0;
752 	qlock(&unit->ctl);
753 	while(waserror()){
754 		/* notification of media change; go around again */
755 		if(strcmp(up->errstr, Eio) == 0 && unit->sectors == 0 && nchange++ == 0){
756 			sdinitpart(unit);
757 			continue;
758 		}
759 
760 		/* other errors; give up */
761 		qunlock(&unit->ctl);
762 		decref(&sdev->r);
763 		nexterror();
764 	}
765 	pp = &unit->part[PART(c->qid)];
766 	if(unit->vers+pp->vers != c->qid.vers)
767 		error(Echange);
768 
769 	/*
770 	 * Check the request is within bounds.
771 	 * Removeable drives are locked throughout the I/O
772 	 * in case the media changes unexpectedly.
773 	 * Non-removeable drives are not locked during the I/O
774 	 * to allow the hardware to optimise if it can; this is
775 	 * a little fast and loose.
776 	 * It's assumed that non-removeable media parameters
777 	 * (sectors, secsize) can't change once the drive has
778 	 * been brought online.
779 	 */
780 	bno = (off/unit->secsize) + pp->start;
781 	nb = ((off+len+unit->secsize-1)/unit->secsize) + pp->start - bno;
782 	max = SDmaxio/unit->secsize;
783 	if(nb > max)
784 		nb = max;
785 	if(bno+nb > pp->end)
786 		nb = pp->end - bno;
787 	if(bno >= pp->end || nb == 0){
788 		if(write)
789 			error(Eio);
790 		qunlock(&unit->ctl);
791 		decref(&sdev->r);
792 		poperror();
793 		return 0;
794 	}
795 	if(!(unit->inquiry[1] & SDinq1removable)){
796 		qunlock(&unit->ctl);
797 		poperror();
798 	}
799 
800 	b = sdmalloc(nb*unit->secsize);
801 	if(b == nil)
802 		error(Enomem);
803 	if(waserror()){
804 		sdfree(b);
805 		if(!(unit->inquiry[1] & SDinq1removable))
806 			decref(&sdev->r);		/* gadverdamme! */
807 		nexterror();
808 	}
809 
810 	offset = off%unit->secsize;
811 	if(offset+len > nb*unit->secsize)
812 		len = nb*unit->secsize - offset;
813 	if(write){
814 		if(offset || (len%unit->secsize)){
815 			l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
816 			if(l < 0)
817 				error(Eio);
818 			if(l < (nb*unit->secsize)){
819 				nb = l/unit->secsize;
820 				l = nb*unit->secsize - offset;
821 				if(len > l)
822 					len = l;
823 			}
824 		}
825 		memmove(b+offset, a, len);
826 		l = unit->dev->ifc->bio(unit, 0, 1, b, nb, bno);
827 		if(l < 0)
828 			error(Eio);
829 		if(l < offset)
830 			len = 0;
831 		else if(len > l - offset)
832 			len = l - offset;
833 	}
834 	else{
835 		l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
836 		if(l < 0)
837 			error(Eio);
838 		if(l < offset)
839 			len = 0;
840 		else if(len > l - offset)
841 			len = l - offset;
842 		memmove(a, b+offset, len);
843 	}
844 	sdfree(b);
845 	poperror();
846 
847 	if(unit->inquiry[1] & SDinq1removable){
848 		qunlock(&unit->ctl);
849 		poperror();
850 	}
851 
852 	decref(&sdev->r);
853 	return len;
854 }
855 
856 static long
sdrio(SDreq * r,void * a,long n)857 sdrio(SDreq* r, void* a, long n)
858 {
859 	void *data;
860 
861 	if(n >= SDmaxio || n < 0)
862 		error(Etoobig);
863 
864 	data = nil;
865 	if(n){
866 		if((data = sdmalloc(n)) == nil)
867 			error(Enomem);
868 		if(r->write)
869 			memmove(data, a, n);
870 	}
871 	r->data = data;
872 	r->dlen = n;
873 
874 	if(waserror()){
875 		sdfree(data);
876 		r->data = nil;
877 		nexterror();
878 	}
879 
880 	if(r->unit->dev->ifc->rio(r) != SDok)
881 		error(Eio);
882 
883 	if(!r->write && r->rlen > 0)
884 		memmove(a, data, r->rlen);
885 	sdfree(data);
886 	r->data = nil;
887 	poperror();
888 
889 	return r->rlen;
890 }
891 
892 /*
893  * SCSI simulation for non-SCSI devices
894  */
895 int
sdsetsense(SDreq * r,int status,int key,int asc,int ascq)896 sdsetsense(SDreq *r, int status, int key, int asc, int ascq)
897 {
898 	int len;
899 	SDunit *unit;
900 
901 	unit = r->unit;
902 	unit->sense[2] = key;
903 	unit->sense[12] = asc;
904 	unit->sense[13] = ascq;
905 
906 	r->status = status;
907 	if(status == SDcheck && !(r->flags & SDnosense)){
908 		/* request sense case from sdfakescsi */
909 		len = sizeof unit->sense;
910 		if(len > sizeof r->sense-1)
911 			len = sizeof r->sense-1;
912 		memmove(r->sense, unit->sense, len);
913 		unit->sense[2] = 0;
914 		unit->sense[12] = 0;
915 		unit->sense[13] = 0;
916 		r->flags |= SDvalidsense;
917 		return SDok;
918 	}
919 	return status;
920 }
921 
922 int
sdmodesense(SDreq * r,uchar * cmd,void * info,int ilen)923 sdmodesense(SDreq *r, uchar *cmd, void *info, int ilen)
924 {
925 	int len;
926 	uchar *data;
927 
928 	/*
929 	 * Fake a vendor-specific request with page code 0,
930 	 * return the drive info.
931 	 */
932 	if((cmd[2] & 0x3F) != 0 && (cmd[2] & 0x3F) != 0x3F)
933 		return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
934 	len = (cmd[7]<<8)|cmd[8];
935 	if(len == 0)
936 		return SDok;
937 	if(len < 8+ilen)
938 		return sdsetsense(r, SDcheck, 0x05, 0x1A, 0);
939 	if(r->data == nil || r->dlen < len)
940 		return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
941 	data = r->data;
942 	memset(data, 0, 8);
943 	data[0] = ilen>>8;
944 	data[1] = ilen;
945 	if(ilen)
946 		memmove(data+8, info, ilen);
947 	r->rlen = 8+ilen;
948 	return sdsetsense(r, SDok, 0, 0, 0);
949 }
950 
951 int
sdfakescsi(SDreq * r,void * info,int ilen)952 sdfakescsi(SDreq *r, void *info, int ilen)
953 {
954 	uchar *cmd, *p;
955 	uvlong len;
956 	SDunit *unit;
957 
958 	cmd = r->cmd;
959 	r->rlen = 0;
960 	unit = r->unit;
961 
962 	/*
963 	 * Rewrite read(6)/write(6) into read(10)/write(10).
964 	 */
965 	switch(cmd[0]){
966 	case ScmdRead:
967 	case ScmdWrite:
968 		cmd[9] = 0;
969 		cmd[8] = cmd[4];
970 		cmd[7] = 0;
971 		cmd[6] = 0;
972 		cmd[5] = cmd[3];
973 		cmd[4] = cmd[2];
974 		cmd[3] = cmd[1] & 0x0F;
975 		cmd[2] = 0;
976 		cmd[1] &= 0xE0;
977 		cmd[0] |= 0x20;
978 		break;
979 	}
980 
981 	/*
982 	 * Map SCSI commands into ATA commands for discs.
983 	 * Fail any command with a LUN except INQUIRY which
984 	 * will return 'logical unit not supported'.
985 	 */
986 	if((cmd[1]>>5) && cmd[0] != ScmdInq)
987 		return sdsetsense(r, SDcheck, 0x05, 0x25, 0);
988 
989 	switch(cmd[0]){
990 	default:
991 		return sdsetsense(r, SDcheck, 0x05, 0x20, 0);
992 
993 	case ScmdTur:		/* test unit ready */
994 		return sdsetsense(r, SDok, 0, 0, 0);
995 
996 	case ScmdRsense:	/* request sense */
997 		if(cmd[4] < sizeof unit->sense)
998 			len = cmd[4];
999 		else
1000 			len = sizeof unit->sense;
1001 		if(r->data && r->dlen >= len){
1002 			memmove(r->data, unit->sense, len);
1003 			r->rlen = len;
1004 		}
1005 		return sdsetsense(r, SDok, 0, 0, 0);
1006 
1007 	case ScmdInq:		/* inquiry */
1008 		if(cmd[4] < sizeof unit->inquiry)
1009 			len = cmd[4];
1010 		else
1011 			len = sizeof unit->inquiry;
1012 		if(r->data && r->dlen >= len){
1013 			memmove(r->data, unit->inquiry, len);
1014 			r->rlen = len;
1015 		}
1016 		return sdsetsense(r, SDok, 0, 0, 0);
1017 
1018 	case ScmdStart:		/* start/stop unit */
1019 		/*
1020 		 * nop for now, can use power management later.
1021 		 */
1022 		return sdsetsense(r, SDok, 0, 0, 0);
1023 
1024 	case ScmdRcapacity:	/* read capacity */
1025 		if((cmd[1] & 0x01) || cmd[2] || cmd[3])
1026 			return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
1027 		if(r->data == nil || r->dlen < 8)
1028 			return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
1029 
1030 		/*
1031 		 * Read capacity returns the LBA of the last sector.
1032 		 */
1033 		len = unit->sectors - 1;
1034 		p = r->data;
1035 		*p++ = len>>24;
1036 		*p++ = len>>16;
1037 		*p++ = len>>8;
1038 		*p++ = len;
1039 		len = 512;
1040 		*p++ = len>>24;
1041 		*p++ = len>>16;
1042 		*p++ = len>>8;
1043 		*p++ = len;
1044 		r->rlen = p - (uchar*)r->data;
1045 		return sdsetsense(r, SDok, 0, 0, 0);
1046 
1047 	case ScmdRcapacity16:	/* long read capacity */
1048 		if((cmd[1] & 0x01) || cmd[2] || cmd[3])
1049 			return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
1050 		if(r->data == nil || r->dlen < 8)
1051 			return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
1052 		/*
1053 		 * Read capcity returns the LBA of the last sector.
1054 		 */
1055 		len = unit->sectors - 1;
1056 		p = r->data;
1057 		*p++ = len>>56;
1058 		*p++ = len>>48;
1059 		*p++ = len>>40;
1060 		*p++ = len>>32;
1061 		*p++ = len>>24;
1062 		*p++ = len>>16;
1063 		*p++ = len>>8;
1064 		*p++ = len;
1065 		len = 512;
1066 		*p++ = len>>24;
1067 		*p++ = len>>16;
1068 		*p++ = len>>8;
1069 		*p++ = len;
1070 		r->rlen = p - (uchar*)r->data;
1071 		return sdsetsense(r, SDok, 0, 0, 0);
1072 
1073 	case ScmdMsense10:	/* mode sense */
1074 		return sdmodesense(r, cmd, info, ilen);
1075 
1076 	case ScmdExtread:
1077 	case ScmdExtwrite:
1078 	case ScmdRead16:
1079 	case ScmdWrite16:
1080 		return SDnostatus;
1081 	}
1082 }
1083 
1084 int
sdfakescsirw(SDreq * r,uvlong * llba,int * nsec,int * rwp)1085 sdfakescsirw(SDreq *r, uvlong *llba, int *nsec, int *rwp)
1086 {
1087 	uchar *c;
1088 	int rw, count;
1089 	uvlong lba;
1090 
1091 	c = r->cmd;
1092 	rw = 0;
1093 	if((c[0] & 0xf) == 0xa)
1094 		rw = 1;
1095 	switch(c[0]){
1096 	case 0x08:	/* read6 */
1097 	case 0x0a:
1098 		lba = (c[1] & 0xf)<<16 | c[2]<<8 | c[3];
1099 		count = c[4];
1100 		break;
1101 	case 0x28:	/* read10 */
1102 	case 0x2a:
1103 		lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1104 		count = c[7]<<8 | c[8];
1105 		break;
1106 	case 0xa8:	/* read12 */
1107 	case 0xaa:
1108 		lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1109 		count = c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1110 		break;
1111 	case 0x88:	/* read16 */
1112 	case 0x8a:
1113 		/* ata commands only go to 48-bit lba */
1114 		if(c[2] || c[3])
1115 			return sdsetsense(r, SDcheck, 3, 0xc, 2);
1116 		lba = (uvlong)c[4]<<40 | (uvlong)c[5]<<32;
1117 		lba |= c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1118 		count = c[10]<<24 | c[11]<<16 | c[12]<<8 | c[13];
1119 		break;
1120 	default:
1121 		print("%s: bad cmd 0x%.2ux\n", r->unit->name, c[0]);
1122 		r->status  = sdsetsense(r, SDcheck, 0x05, 0x20, 0);
1123 		return SDcheck;
1124 	}
1125 	if(r->data == nil)
1126 		return SDok;
1127 	if(r->dlen < count * r->unit->secsize)
1128 		count = r->dlen/r->unit->secsize;
1129 	if(rwp)
1130 		*rwp = rw;
1131 	*llba = lba;
1132 	*nsec = count;
1133 	return SDnostatus;
1134 }
1135 
1136 static long
sdread(Chan * c,void * a,long n,vlong off)1137 sdread(Chan *c, void *a, long n, vlong off)
1138 {
1139 	char *p, *e, *buf;
1140 	SDpart *pp;
1141 	SDunit *unit;
1142 	SDev *sdev;
1143 	long offset;
1144 	int i, l, m, status;
1145 
1146 	offset = off;
1147 	switch(TYPE(c->qid)){
1148 	default:
1149 		error(Eperm);
1150 	case Qtopctl:
1151 		m = 64*1024;	/* room for register dumps */
1152 		p = buf = malloc(m);
1153 		if(p == nil)
1154 			error(Enomem);
1155 		e = p + m;
1156 		qlock(&devslock);
1157 		for(i = 0; i < nelem(devs); i++){
1158 			sdev = devs[i];
1159 			if(sdev && sdev->ifc->rtopctl)
1160 				p = sdev->ifc->rtopctl(sdev, p, e);
1161 		}
1162 		qunlock(&devslock);
1163 		n = readstr(offset, a, n, buf);
1164 		free(buf);
1165 		return n;
1166 
1167 	case Qtopdir:
1168 	case Qunitdir:
1169 		return devdirread(c, a, n, 0, 0, sdgen);
1170 
1171 	case Qctl:
1172 		sdev = sdgetdev(DEV(c->qid));
1173 		if(sdev == nil)
1174 			error(Enonexist);
1175 
1176 		unit = sdev->unit[UNIT(c->qid)];
1177 		m = 16*1024;	/* room for register dumps */
1178 		p = malloc(m);
1179 		if(p == nil)
1180 			error(Enomem);
1181 		l = snprint(p, m, "inquiry %.48s\n",
1182 			(char*)unit->inquiry+8);
1183 		qlock(&unit->ctl);
1184 		/*
1185 		 * If there's a device specific routine it must
1186 		 * provide all information pertaining to night geometry
1187 		 * and the garscadden trains.
1188 		 */
1189 		if(unit->dev->ifc->rctl)
1190 			l += unit->dev->ifc->rctl(unit, p+l, m-l);
1191 		if(unit->sectors == 0)
1192 			sdinitpart(unit);
1193 		if(unit->sectors){
1194 			if(unit->dev->ifc->rctl == nil)
1195 				l += snprint(p+l, m-l,
1196 					"geometry %llud %lud\n",
1197 					unit->sectors, unit->secsize);
1198 			pp = unit->part;
1199 			for(i = 0; i < unit->npart; i++){
1200 				if(pp->valid)
1201 					l += snprint(p+l, m-l,
1202 						"part %s %llud %llud\n",
1203 						pp->name, pp->start, pp->end);
1204 				pp++;
1205 			}
1206 		}
1207 		qunlock(&unit->ctl);
1208 		decref(&sdev->r);
1209 		l = readstr(offset, a, n, p);
1210 		free(p);
1211 		return l;
1212 
1213 	case Qraw:
1214 		sdev = sdgetdev(DEV(c->qid));
1215 		if(sdev == nil)
1216 			error(Enonexist);
1217 
1218 		unit = sdev->unit[UNIT(c->qid)];
1219 		qlock(&unit->raw);
1220 		if(waserror()){
1221 			qunlock(&unit->raw);
1222 			decref(&sdev->r);
1223 			nexterror();
1224 		}
1225 		if(unit->state == Rawdata){
1226 			unit->state = Rawstatus;
1227 			i = sdrio(unit->req, a, n);
1228 		}
1229 		else if(unit->state == Rawstatus){
1230 			status = unit->req->status;
1231 			unit->state = Rawcmd;
1232 			free(unit->req);
1233 			unit->req = nil;
1234 			i = readnum(0, a, n, status, NUMSIZE);
1235 		} else
1236 			i = 0;
1237 		qunlock(&unit->raw);
1238 		decref(&sdev->r);
1239 		poperror();
1240 		return i;
1241 
1242 	case Qpart:
1243 		return sdbio(c, 0, a, n, off);
1244 	}
1245 }
1246 
1247 static void legacytopctl(Cmdbuf*);
1248 
1249 static long
sdwrite(Chan * c,void * a,long n,vlong off)1250 sdwrite(Chan* c, void* a, long n, vlong off)
1251 {
1252 	char *f0;
1253 	int i;
1254 	uvlong end, start;
1255 	Cmdbuf *cb;
1256 	SDifc *ifc;
1257 	SDreq *req;
1258 	SDunit *unit;
1259 	SDev *sdev;
1260 
1261 	switch(TYPE(c->qid)){
1262 	default:
1263 		error(Eperm);
1264 	case Qtopctl:
1265 		cb = parsecmd(a, n);
1266 		if(waserror()){
1267 			free(cb);
1268 			nexterror();
1269 		}
1270 		if(cb->nf == 0)
1271 			error("empty control message");
1272 		f0 = cb->f[0];
1273 		cb->f++;
1274 		cb->nf--;
1275 		if(strcmp(f0, "config") == 0){
1276 			/* wormhole into ugly legacy interface */
1277 			legacytopctl(cb);
1278 			poperror();
1279 			free(cb);
1280 			break;
1281 		}
1282 		/*
1283 		 * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb),
1284 		 * where sdifc[i]->name=="ata" and cb contains the args.
1285 		 */
1286 		ifc = nil;
1287 		sdev = nil;
1288 		for(i=0; sdifc[i]; i++){
1289 			if(strcmp(sdifc[i]->name, f0) == 0){
1290 				ifc = sdifc[i];
1291 				sdev = nil;
1292 				goto subtopctl;
1293 			}
1294 		}
1295 		/*
1296 		 * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb),
1297 		 * where sdifc[i] and sdev match controller letter "1",
1298 		 * and cb contains the args.
1299 		 */
1300 		if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){
1301 			if((sdev = sdgetdev(f0[2])) != nil){
1302 				ifc = sdev->ifc;
1303 				goto subtopctl;
1304 			}
1305 		}
1306 		error("unknown interface");
1307 
1308 	subtopctl:
1309 		if(waserror()){
1310 			if(sdev)
1311 				decref(&sdev->r);
1312 			nexterror();
1313 		}
1314 		if(ifc->wtopctl)
1315 			ifc->wtopctl(sdev, cb);
1316 		else
1317 			error(Ebadctl);
1318 		poperror();
1319 		poperror();
1320 		if(sdev)
1321 			decref(&sdev->r);
1322 		free(cb);
1323 		break;
1324 
1325 	case Qctl:
1326 		cb = parsecmd(a, n);
1327 		sdev = sdgetdev(DEV(c->qid));
1328 		if(sdev == nil)
1329 			error(Enonexist);
1330 		unit = sdev->unit[UNIT(c->qid)];
1331 
1332 		qlock(&unit->ctl);
1333 		if(waserror()){
1334 			qunlock(&unit->ctl);
1335 			decref(&sdev->r);
1336 			free(cb);
1337 			nexterror();
1338 		}
1339 		if(unit->vers != c->qid.vers)
1340 			error(Echange);
1341 
1342 		if(cb->nf < 1)
1343 			error(Ebadctl);
1344 		if(strcmp(cb->f[0], "part") == 0){
1345 			if(cb->nf != 4)
1346 				error(Ebadctl);
1347 			if(unit->sectors == 0 && !sdinitpart(unit))
1348 				error(Eio);
1349 			start = strtoull(cb->f[2], 0, 0);
1350 			end = strtoull(cb->f[3], 0, 0);
1351 			sdaddpart(unit, cb->f[1], start, end);
1352 		}
1353 		else if(strcmp(cb->f[0], "delpart") == 0){
1354 			if(cb->nf != 2 || unit->part == nil)
1355 				error(Ebadctl);
1356 			sddelpart(unit, cb->f[1]);
1357 		}
1358 		else if(unit->dev->ifc->wctl)
1359 			unit->dev->ifc->wctl(unit, cb);
1360 		else
1361 			error(Ebadctl);
1362 		qunlock(&unit->ctl);
1363 		decref(&sdev->r);
1364 		poperror();
1365 		free(cb);
1366 		break;
1367 
1368 	case Qraw:
1369 		sdev = sdgetdev(DEV(c->qid));
1370 		if(sdev == nil)
1371 			error(Enonexist);
1372 		unit = sdev->unit[UNIT(c->qid)];
1373 		qlock(&unit->raw);
1374 		if(waserror()){
1375 			qunlock(&unit->raw);
1376 			decref(&sdev->r);
1377 			nexterror();
1378 		}
1379 		switch(unit->state){
1380 		case Rawcmd:
1381 			if(n < 6 || n > sizeof(req->cmd))
1382 				error(Ebadarg);
1383 			if((req = malloc(sizeof(SDreq))) == nil)
1384 				error(Enomem);
1385 			req->unit = unit;
1386 			memmove(req->cmd, a, n);
1387 			req->clen = n;
1388 			req->flags = SDnosense;
1389 			req->status = ~0;
1390 
1391 			unit->req = req;
1392 			unit->state = Rawdata;
1393 			break;
1394 
1395 		case Rawstatus:
1396 			unit->state = Rawcmd;
1397 			free(unit->req);
1398 			unit->req = nil;
1399 			error(Ebadusefd);
1400 
1401 		case Rawdata:
1402 			unit->state = Rawstatus;
1403 			unit->req->write = 1;
1404 			n = sdrio(unit->req, a, n);
1405 		}
1406 		qunlock(&unit->raw);
1407 		decref(&sdev->r);
1408 		poperror();
1409 		break;
1410 	case Qpart:
1411 		return sdbio(c, 1, a, n, off);
1412 	}
1413 
1414 	return n;
1415 }
1416 
1417 static long
sdwstat(Chan * c,uchar * dp,long n)1418 sdwstat(Chan* c, uchar* dp, long n)
1419 {
1420 	Dir *d;
1421 	SDpart *pp;
1422 	SDperm *perm;
1423 	SDunit *unit;
1424 	SDev *sdev;
1425 
1426 	if(c->qid.type & QTDIR)
1427 		error(Eperm);
1428 
1429 	sdev = sdgetdev(DEV(c->qid));
1430 	if(sdev == nil)
1431 		error(Enonexist);
1432 	unit = sdev->unit[UNIT(c->qid)];
1433 	qlock(&unit->ctl);
1434 	d = nil;
1435 	if(waserror()){
1436 		free(d);
1437 		qunlock(&unit->ctl);
1438 		decref(&sdev->r);
1439 		nexterror();
1440 	}
1441 
1442 	switch(TYPE(c->qid)){
1443 	default:
1444 		error(Eperm);
1445 	case Qctl:
1446 		perm = &unit->ctlperm;
1447 		break;
1448 	case Qraw:
1449 		perm = &unit->rawperm;
1450 		break;
1451 	case Qpart:
1452 		pp = &unit->part[PART(c->qid)];
1453 		if(unit->vers+pp->vers != c->qid.vers)
1454 			error(Enonexist);
1455 		perm = &pp->SDperm;
1456 		break;
1457 	}
1458 
1459 	if(strcmp(up->user, perm->user) && !iseve())
1460 		error(Eperm);
1461 
1462 	d = smalloc(sizeof(Dir)+n);
1463 	n = convM2D(dp, n, &d[0], (char*)&d[1]);
1464 	if(n == 0)
1465 		error(Eshortstat);
1466 	if(!emptystr(d[0].uid))
1467 		kstrdup(&perm->user, d[0].uid);
1468 	if(d[0].mode != ~0UL)
1469 		perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
1470 
1471 	free(d);
1472 	qunlock(&unit->ctl);
1473 	decref(&sdev->r);
1474 	poperror();
1475 	return n;
1476 }
1477 
1478 static int
configure(char * spec,DevConf * cf)1479 configure(char* spec, DevConf* cf)
1480 {
1481 	SDev *s, *sdev;
1482 	char *p;
1483 	int i;
1484 
1485 	if(sdindex(*spec) < 0)
1486 		error("bad sd spec");
1487 
1488 	if((p = strchr(cf->type, '/')) != nil)
1489 		*p++ = '\0';
1490 
1491 	for(i = 0; sdifc[i] != nil; i++)
1492 		if(strcmp(sdifc[i]->name, cf->type) == 0)
1493 			break;
1494 	if(sdifc[i] == nil)
1495 		error("sd type not found");
1496 	if(p)
1497 		*(p-1) = '/';
1498 
1499 	if(sdifc[i]->probe == nil)
1500 		error("sd type cannot probe");
1501 
1502 	sdev = sdifc[i]->probe(cf);
1503 	for(s=sdev; s; s=s->next)
1504 		s->idno = *spec;
1505 	sdadddevs(sdev);
1506 	return 0;
1507 }
1508 
1509 static int
unconfigure(char * spec)1510 unconfigure(char* spec)
1511 {
1512 	int i;
1513 	SDev *sdev;
1514 	SDunit *unit;
1515 
1516 	if((i = sdindex(*spec)) < 0)
1517 		error(Enonexist);
1518 
1519 	qlock(&devslock);
1520 	if((sdev = devs[i]) == nil){
1521 		qunlock(&devslock);
1522 		error(Enonexist);
1523 	}
1524 	if(sdev->r.ref){
1525 		qunlock(&devslock);
1526 		error(Einuse);
1527 	}
1528 	devs[i] = nil;
1529 	qunlock(&devslock);
1530 
1531 	/* make sure no interrupts arrive anymore before removing resources */
1532 	if(sdev->enabled && sdev->ifc->disable)
1533 		sdev->ifc->disable(sdev);
1534 
1535 	for(i = 0; i != sdev->nunit; i++){
1536 		if(unit = sdev->unit[i]){
1537 			free(unit->name);
1538 			free(unit->user);
1539 			free(unit);
1540 		}
1541 	}
1542 
1543 	if(sdev->ifc->clear)
1544 		sdev->ifc->clear(sdev);
1545 	free(sdev);
1546 	return 0;
1547 }
1548 
1549 static int
sdconfig(int on,char * spec,DevConf * cf)1550 sdconfig(int on, char* spec, DevConf* cf)
1551 {
1552 	if(on)
1553 		return configure(spec, cf);
1554 	return unconfigure(spec);
1555 }
1556 
1557 Dev sddevtab = {
1558 	'S',
1559 	"sd",
1560 
1561 	sdreset,
1562 	devinit,
1563 	devshutdown,
1564 	sdattach,
1565 	sdwalk,
1566 	sdstat,
1567 	sdopen,
1568 	devcreate,
1569 	sdclose,
1570 	sdread,
1571 	devbread,
1572 	sdwrite,
1573 	devbwrite,
1574 	devremove,
1575 	sdwstat,
1576 	devpower,
1577 	sdconfig,	/* probe; only called for pcmcia-like devices */
1578 };
1579 
1580 /*
1581  * This is wrong for so many reasons.  This code must go.
1582  */
1583 typedef struct Confdata Confdata;
1584 struct Confdata {
1585 	int	on;
1586 	char*	spec;
1587 	DevConf	cf;
1588 };
1589 
1590 static void
parseswitch(Confdata * cd,char * option)1591 parseswitch(Confdata* cd, char* option)
1592 {
1593 	if(!strcmp("on", option))
1594 		cd->on = 1;
1595 	else if(!strcmp("off", option))
1596 		cd->on = 0;
1597 	else
1598 		error(Ebadarg);
1599 }
1600 
1601 static void
parsespec(Confdata * cd,char * option)1602 parsespec(Confdata* cd, char* option)
1603 {
1604 	if(strlen(option) > 1)
1605 		error(Ebadarg);
1606 	cd->spec = option;
1607 }
1608 
1609 static Devport*
getnewport(DevConf * dc)1610 getnewport(DevConf* dc)
1611 {
1612 	Devport *p;
1613 
1614 	p = (Devport *)malloc((dc->nports + 1) * sizeof(Devport));
1615 	if(p == nil)
1616 		error(Enomem);
1617 	if(dc->nports > 0){
1618 		memmove(p, dc->ports, dc->nports * sizeof(Devport));
1619 		free(dc->ports);
1620 	}
1621 	dc->ports = p;
1622 	p = &dc->ports[dc->nports++];
1623 	p->size = -1;
1624 	p->port = (ulong)-1;
1625 	return p;
1626 }
1627 
1628 static void
parseport(Confdata * cd,char * option)1629 parseport(Confdata* cd, char* option)
1630 {
1631 	char *e;
1632 	Devport *p;
1633 
1634 	if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].port != (ulong)-1)
1635 		p = getnewport(&cd->cf);
1636 	else
1637 		p = &cd->cf.ports[cd->cf.nports-1];
1638 	p->port = strtol(option, &e, 0);
1639 	if(e == nil || *e != '\0')
1640 		error(Ebadarg);
1641 }
1642 
1643 static void
parsesize(Confdata * cd,char * option)1644 parsesize(Confdata* cd, char* option)
1645 {
1646 	char *e;
1647 	Devport *p;
1648 
1649 	if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].size != -1)
1650 		p = getnewport(&cd->cf);
1651 	else
1652 		p = &cd->cf.ports[cd->cf.nports-1];
1653 	p->size = (int)strtol(option, &e, 0);
1654 	if(e == nil || *e != '\0')
1655 		error(Ebadarg);
1656 }
1657 
1658 static void
parseirq(Confdata * cd,char * option)1659 parseirq(Confdata* cd, char* option)
1660 {
1661 	char *e;
1662 
1663 	cd->cf.intnum = strtoul(option, &e, 0);
1664 	if(e == nil || *e != '\0')
1665 		error(Ebadarg);
1666 }
1667 
1668 static void
parsetype(Confdata * cd,char * option)1669 parsetype(Confdata* cd, char* option)
1670 {
1671 	cd->cf.type = option;
1672 }
1673 
1674 static struct {
1675 	char	*name;
1676 	void	(*parse)(Confdata*, char*);
1677 } options[] = {
1678 	"switch",	parseswitch,
1679 	"spec",		parsespec,
1680 	"port",		parseport,
1681 	"size",		parsesize,
1682 	"irq",		parseirq,
1683 	"type",		parsetype,
1684 };
1685 
1686 static void
legacytopctl(Cmdbuf * cb)1687 legacytopctl(Cmdbuf *cb)
1688 {
1689 	char *opt;
1690 	int i, j;
1691 	Confdata cd;
1692 
1693 	memset(&cd, 0, sizeof cd);
1694 	cd.on = -1;
1695 	for(i=0; i<cb->nf; i+=2){
1696 		if(i+2 > cb->nf)
1697 			error(Ebadarg);
1698 		opt = cb->f[i];
1699 		for(j=0; j<nelem(options); j++)
1700 			if(strcmp(opt, options[j].name) == 0){
1701 				options[j].parse(&cd, cb->f[i+1]);
1702 				break;
1703 			}
1704 		if(j == nelem(options))
1705 			error(Ebadarg);
1706 	}
1707 	/* this has been rewritten to accomodate sdaoe */
1708 	if(cd.on < 0 || cd.spec == 0)
1709 		error(Ebadarg);
1710 	if(cd.on && cd.cf.type == nil)
1711 		error(Ebadarg);
1712 	sdconfig(cd.on, cd.spec, &cd.cf);
1713 }
1714