xref: /plan9-contrib/sys/src/9/port/devsd.c (revision 5a0d9eb88ca55781e08c555cdd7c85653de80b34)
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 ScmdRead:
968 	case ScmdWrite:
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] != ScmdInq)
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 ScmdTur:		/* test unit ready */
995 		return sdsetsense(r, SDok, 0, 0, 0);
996 
997 	case ScmdRsense:	/* 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 ScmdInq:		/* 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 ScmdStart:		/* 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 ScmdRcapacity:	/* 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 ScmdRcapacity16:	/* 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 ScmdMsense10:	/* mode sense */
1075 		return sdmodesense(r, cmd, info, ilen);
1076 
1077 	case ScmdExtread:
1078 	case ScmdExtwrite:
1079 	case ScmdRead16:
1080 	case ScmdWrite16:
1081 		return SDnostatus;
1082 	}
1083 }
1084 
1085 int
sdfakescsirw(SDreq * r,uvlong * llba,int * nsec,int * rwp)1086 sdfakescsirw(SDreq *r, uvlong *llba, int *nsec, int *rwp)
1087 {
1088 	uchar *c;
1089 	int rw, count;
1090 	uvlong lba;
1091 
1092 	c = r->cmd;
1093 	rw = 0;
1094 	if((c[0] & 0xf) == 0xa)
1095 		rw = 1;
1096 	switch(c[0]){
1097 	case 0x08:	/* read6 */
1098 	case 0x0a:
1099 		lba = (c[1] & 0xf)<<16 | c[2]<<8 | c[3];
1100 		count = c[4];
1101 		break;
1102 	case 0x28:	/* read10 */
1103 	case 0x2a:
1104 		lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1105 		count = c[7]<<8 | c[8];
1106 		break;
1107 	case 0xa8:	/* read12 */
1108 	case 0xaa:
1109 		lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1110 		count = c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1111 		break;
1112 	case 0x88:	/* read16 */
1113 	case 0x8a:
1114 		/* ata commands only go to 48-bit lba */
1115 		if(c[2] || c[3])
1116 			return sdsetsense(r, SDcheck, 3, 0xc, 2);
1117 		lba = (uvlong)c[4]<<40 | (uvlong)c[5]<<32;
1118 		lba |= c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1119 		count = c[10]<<24 | c[11]<<16 | c[12]<<8 | c[13];
1120 		break;
1121 	default:
1122 		print("%s: bad cmd 0x%.2ux\n", r->unit->name, c[0]);
1123 		r->status  = sdsetsense(r, SDcheck, 0x05, 0x20, 0);
1124 		return SDcheck;
1125 	}
1126 	if(r->data == nil)
1127 		return SDok;
1128 	if(r->dlen < count * r->unit->secsize)
1129 		count = r->dlen/r->unit->secsize;
1130 	if(rwp)
1131 		*rwp = rw;
1132 	*llba = lba;
1133 	*nsec = count;
1134 	return SDnostatus;
1135 }
1136 
1137 static long
sdread(Chan * c,void * a,long n,vlong off)1138 sdread(Chan *c, void *a, long n, vlong off)
1139 {
1140 	char *p, *e, *buf;
1141 	SDpart *pp;
1142 	SDunit *unit;
1143 	SDev *sdev;
1144 	ulong offset;
1145 	int i, l, m, status;
1146 
1147 	offset = off;
1148 	switch(TYPE(c->qid)){
1149 	default:
1150 		error(Eperm);
1151 	case Qtopctl:
1152 		m = 64*1024;	/* room for register dumps */
1153 		p = buf = malloc(m);
1154 		if(p == nil)
1155 			error(Enomem);
1156 		e = p + m;
1157 		qlock(&devslock);
1158 		for(i = 0; i < nelem(devs); i++){
1159 			sdev = devs[i];
1160 			if(sdev && sdev->ifc->rtopctl)
1161 				p = sdev->ifc->rtopctl(sdev, p, e);
1162 		}
1163 		qunlock(&devslock);
1164 		n = readstr(off, a, n, buf);
1165 		free(buf);
1166 		return n;
1167 
1168 	case Qtopdir:
1169 	case Qunitdir:
1170 		return devdirread(c, a, n, 0, 0, sdgen);
1171 
1172 	case Qctl:
1173 		sdev = sdgetdev(DEV(c->qid));
1174 		if(sdev == nil)
1175 			error(Enonexist);
1176 
1177 		unit = sdev->unit[UNIT(c->qid)];
1178 		m = 16*1024;	/* room for register dumps */
1179 		p = malloc(m);
1180 		if(p == nil)
1181 			error(Enomem);
1182 		l = snprint(p, m, "inquiry %.48s\n",
1183 			(char*)unit->inquiry+8);
1184 		qlock(&unit->ctl);
1185 		/*
1186 		 * If there's a device specific routine it must
1187 		 * provide all information pertaining to night geometry
1188 		 * and the garscadden trains.
1189 		 */
1190 		if(unit->dev->ifc->rctl)
1191 			l += unit->dev->ifc->rctl(unit, p+l, m-l);
1192 		if(unit->sectors == 0)
1193 			sdinitpart(unit);
1194 		if(unit->sectors){
1195 			if(unit->dev->ifc->rctl == nil)
1196 				l += snprint(p+l, m-l,
1197 					"geometry %llud %lud\n",
1198 					unit->sectors, unit->secsize);
1199 			pp = unit->part;
1200 			for(i = 0; i < unit->npart; i++){
1201 				if(pp->valid)
1202 					l += snprint(p+l, m-l,
1203 						"part %s %llud %llud\n",
1204 						pp->name, pp->start, pp->end);
1205 				pp++;
1206 			}
1207 		}
1208 		qunlock(&unit->ctl);
1209 		decref(&sdev->r);
1210 		l = readstr(offset, a, n, p);
1211 		free(p);
1212 		return l;
1213 
1214 	case Qraw:
1215 		sdev = sdgetdev(DEV(c->qid));
1216 		if(sdev == nil)
1217 			error(Enonexist);
1218 
1219 		unit = sdev->unit[UNIT(c->qid)];
1220 		qlock(&unit->raw);
1221 		if(waserror()){
1222 			qunlock(&unit->raw);
1223 			decref(&sdev->r);
1224 			nexterror();
1225 		}
1226 		if(unit->state == Rawdata){
1227 			unit->state = Rawstatus;
1228 			i = sdrio(unit->req, a, n);
1229 		}
1230 		else if(unit->state == Rawstatus){
1231 			status = unit->req->status;
1232 			unit->state = Rawcmd;
1233 			free(unit->req);
1234 			unit->req = nil;
1235 			i = readnum(0, a, n, status, NUMSIZE);
1236 		} else
1237 			i = 0;
1238 		qunlock(&unit->raw);
1239 		decref(&sdev->r);
1240 		poperror();
1241 		return i;
1242 
1243 	case Qpart:
1244 		return sdbio(c, 0, a, n, off);
1245 	}
1246 }
1247 
1248 static void legacytopctl(Cmdbuf*);
1249 
1250 static long
sdwrite(Chan * c,void * a,long n,vlong off)1251 sdwrite(Chan* c, void* a, long n, vlong off)
1252 {
1253 	char *f0;
1254 	int i;
1255 	uvlong end, start;
1256 	Cmdbuf *cb;
1257 	SDifc *ifc;
1258 	SDreq *req;
1259 	SDunit *unit;
1260 	SDev *sdev;
1261 
1262 	switch(TYPE(c->qid)){
1263 	default:
1264 		error(Eperm);
1265 	case Qtopctl:
1266 		cb = parsecmd(a, n);
1267 		if(waserror()){
1268 			free(cb);
1269 			nexterror();
1270 		}
1271 		if(cb->nf == 0)
1272 			error("empty control message");
1273 		f0 = cb->f[0];
1274 		cb->f++;
1275 		cb->nf--;
1276 		if(strcmp(f0, "config") == 0){
1277 			/* wormhole into ugly legacy interface */
1278 			legacytopctl(cb);
1279 			poperror();
1280 			free(cb);
1281 			break;
1282 		}
1283 		/*
1284 		 * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb),
1285 		 * where sdifc[i]->name=="ata" and cb contains the args.
1286 		 */
1287 		ifc = nil;
1288 		sdev = nil;
1289 		for(i=0; sdifc[i]; i++){
1290 			if(strcmp(sdifc[i]->name, f0) == 0){
1291 				ifc = sdifc[i];
1292 				sdev = nil;
1293 				goto subtopctl;
1294 			}
1295 		}
1296 		/*
1297 		 * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb),
1298 		 * where sdifc[i] and sdev match controller letter "1",
1299 		 * and cb contains the args.
1300 		 */
1301 		if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){
1302 			if((sdev = sdgetdev(f0[2])) != nil){
1303 				ifc = sdev->ifc;
1304 				goto subtopctl;
1305 			}
1306 		}
1307 		error("unknown interface");
1308 
1309 	subtopctl:
1310 		if(waserror()){
1311 			if(sdev)
1312 				decref(&sdev->r);
1313 			nexterror();
1314 		}
1315 		if(ifc->wtopctl)
1316 			ifc->wtopctl(sdev, cb);
1317 		else
1318 			error(Ebadctl);
1319 		poperror();
1320 		poperror();
1321 		if (sdev)
1322 			decref(&sdev->r);
1323 		free(cb);
1324 		break;
1325 
1326 	case Qctl:
1327 		cb = parsecmd(a, n);
1328 		sdev = sdgetdev(DEV(c->qid));
1329 		if(sdev == nil)
1330 			error(Enonexist);
1331 		unit = sdev->unit[UNIT(c->qid)];
1332 
1333 		qlock(&unit->ctl);
1334 		if(waserror()){
1335 			qunlock(&unit->ctl);
1336 			decref(&sdev->r);
1337 			free(cb);
1338 			nexterror();
1339 		}
1340 		if(unit->vers != c->qid.vers)
1341 			error(Echange);
1342 
1343 		if(cb->nf < 1)
1344 			error(Ebadctl);
1345 		if(strcmp(cb->f[0], "part") == 0){
1346 			if(cb->nf != 4)
1347 				error(Ebadctl);
1348 			if(unit->sectors == 0 && !sdinitpart(unit))
1349 				error(Eio);
1350 			start = strtoull(cb->f[2], 0, 0);
1351 			end = strtoull(cb->f[3], 0, 0);
1352 			sdaddpart(unit, cb->f[1], start, end);
1353 		}
1354 		else if(strcmp(cb->f[0], "delpart") == 0){
1355 			if(cb->nf != 2 || unit->part == nil)
1356 				error(Ebadctl);
1357 			sddelpart(unit, cb->f[1]);
1358 		}
1359 		else if(unit->dev->ifc->wctl)
1360 			unit->dev->ifc->wctl(unit, cb);
1361 		else
1362 			error(Ebadctl);
1363 		qunlock(&unit->ctl);
1364 		decref(&sdev->r);
1365 		poperror();
1366 		free(cb);
1367 		break;
1368 
1369 	case Qraw:
1370 		sdev = sdgetdev(DEV(c->qid));
1371 		if(sdev == nil)
1372 			error(Enonexist);
1373 		unit = sdev->unit[UNIT(c->qid)];
1374 		qlock(&unit->raw);
1375 		if(waserror()){
1376 			qunlock(&unit->raw);
1377 			decref(&sdev->r);
1378 			nexterror();
1379 		}
1380 		switch(unit->state){
1381 		case Rawcmd:
1382 			if(n < 6 || n > sizeof(req->cmd))
1383 				error(Ebadarg);
1384 			if((req = malloc(sizeof(SDreq))) == nil)
1385 				error(Enomem);
1386 			req->unit = unit;
1387 			memmove(req->cmd, a, n);
1388 			req->clen = n;
1389 			req->flags = SDnosense;
1390 			req->status = ~0;
1391 
1392 			unit->req = req;
1393 			unit->state = Rawdata;
1394 			break;
1395 
1396 		case Rawstatus:
1397 			unit->state = Rawcmd;
1398 			free(unit->req);
1399 			unit->req = nil;
1400 			error(Ebadusefd);
1401 
1402 		case Rawdata:
1403 			unit->state = Rawstatus;
1404 			unit->req->write = 1;
1405 			n = sdrio(unit->req, a, n);
1406 		}
1407 		qunlock(&unit->raw);
1408 		decref(&sdev->r);
1409 		poperror();
1410 		break;
1411 	case Qpart:
1412 		return sdbio(c, 1, a, n, off);
1413 	}
1414 
1415 	return n;
1416 }
1417 
1418 static int
sdwstat(Chan * c,uchar * dp,int n)1419 sdwstat(Chan* c, uchar* dp, int n)
1420 {
1421 	Dir *d;
1422 	SDpart *pp;
1423 	SDperm *perm;
1424 	SDunit *unit;
1425 	SDev *sdev;
1426 
1427 	if(c->qid.type & QTDIR)
1428 		error(Eperm);
1429 
1430 	sdev = sdgetdev(DEV(c->qid));
1431 	if(sdev == nil)
1432 		error(Enonexist);
1433 	unit = sdev->unit[UNIT(c->qid)];
1434 	qlock(&unit->ctl);
1435 	d = nil;
1436 	if(waserror()){
1437 		free(d);
1438 		qunlock(&unit->ctl);
1439 		decref(&sdev->r);
1440 		nexterror();
1441 	}
1442 
1443 	switch(TYPE(c->qid)){
1444 	default:
1445 		error(Eperm);
1446 	case Qctl:
1447 		perm = &unit->ctlperm;
1448 		break;
1449 	case Qraw:
1450 		perm = &unit->rawperm;
1451 		break;
1452 	case Qpart:
1453 		pp = &unit->part[PART(c->qid)];
1454 		if(unit->vers+pp->vers != c->qid.vers)
1455 			error(Enonexist);
1456 		perm = &pp->SDperm;
1457 		break;
1458 	}
1459 
1460 	if(strcmp(up->user, perm->user) && !iseve())
1461 		error(Eperm);
1462 
1463 	d = smalloc(sizeof(Dir)+n);
1464 	n = convM2D(dp, n, &d[0], (char*)&d[1]);
1465 	if(n == 0)
1466 		error(Eshortstat);
1467 	if(!emptystr(d[0].uid))
1468 		kstrdup(&perm->user, d[0].uid);
1469 	if(d[0].mode != ~0UL)
1470 		perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
1471 
1472 	free(d);
1473 	qunlock(&unit->ctl);
1474 	decref(&sdev->r);
1475 	poperror();
1476 	return n;
1477 }
1478 
1479 static int
configure(char * spec,DevConf * cf)1480 configure(char* spec, DevConf* cf)
1481 {
1482 	SDev *s, *sdev;
1483 	char *p;
1484 	int i;
1485 
1486 	if(sdindex(*spec) < 0)
1487 		error("bad sd spec");
1488 
1489 	if((p = strchr(cf->type, '/')) != nil)
1490 		*p++ = '\0';
1491 
1492 	for(i = 0; sdifc[i] != nil; i++)
1493 		if(strcmp(sdifc[i]->name, cf->type) == 0)
1494 			break;
1495 	if(sdifc[i] == nil)
1496 		error("sd type not found");
1497 	if(p)
1498 		*(p-1) = '/';
1499 
1500 	if(sdifc[i]->probe == nil)
1501 		error("sd type cannot probe");
1502 
1503 	sdev = sdifc[i]->probe(cf);
1504 	for(s=sdev; s; s=s->next)
1505 		s->idno = *spec;
1506 	sdadddevs(sdev);
1507 	return 0;
1508 }
1509 
1510 static int
unconfigure(char * spec)1511 unconfigure(char* spec)
1512 {
1513 	int i;
1514 	SDev *sdev;
1515 	SDunit *unit;
1516 
1517 	if((i = sdindex(*spec)) < 0)
1518 		error(Enonexist);
1519 
1520 	qlock(&devslock);
1521 	if((sdev = devs[i]) == nil){
1522 		qunlock(&devslock);
1523 		error(Enonexist);
1524 	}
1525 	if(sdev->r.ref){
1526 		qunlock(&devslock);
1527 		error(Einuse);
1528 	}
1529 	devs[i] = nil;
1530 	qunlock(&devslock);
1531 
1532 	/* make sure no interrupts arrive anymore before removing resources */
1533 	if(sdev->enabled && sdev->ifc->disable)
1534 		sdev->ifc->disable(sdev);
1535 
1536 	for(i = 0; i != sdev->nunit; i++){
1537 		if(unit = sdev->unit[i]){
1538 			free(unit->name);
1539 			free(unit->user);
1540 			free(unit);
1541 		}
1542 	}
1543 
1544 	if(sdev->ifc->clear)
1545 		sdev->ifc->clear(sdev);
1546 	free(sdev);
1547 	return 0;
1548 }
1549 
1550 static int
sdconfig(int on,char * spec,DevConf * cf)1551 sdconfig(int on, char* spec, DevConf* cf)
1552 {
1553 	if(on)
1554 		return configure(spec, cf);
1555 	return unconfigure(spec);
1556 }
1557 
1558 Dev sddevtab = {
1559 	'S',
1560 	"sd",
1561 
1562 	sdreset,
1563 	devinit,
1564 	devshutdown,
1565 	sdattach,
1566 	sdwalk,
1567 	sdstat,
1568 	sdopen,
1569 	devcreate,
1570 	sdclose,
1571 	sdread,
1572 	devbread,
1573 	sdwrite,
1574 	devbwrite,
1575 	devremove,
1576 	sdwstat,
1577 	devpower,
1578 	sdconfig,	/* probe; only called for pcmcia-like devices */
1579 };
1580 
1581 /*
1582  * This is wrong for so many reasons.  This code must go.
1583  */
1584 typedef struct Confdata Confdata;
1585 struct Confdata {
1586 	int	on;
1587 	char*	spec;
1588 	DevConf	cf;
1589 };
1590 
1591 static void
parseswitch(Confdata * cd,char * option)1592 parseswitch(Confdata* cd, char* option)
1593 {
1594 	if(!strcmp("on", option))
1595 		cd->on = 1;
1596 	else if(!strcmp("off", option))
1597 		cd->on = 0;
1598 	else
1599 		error(Ebadarg);
1600 }
1601 
1602 static void
parsespec(Confdata * cd,char * option)1603 parsespec(Confdata* cd, char* option)
1604 {
1605 	if(strlen(option) > 1)
1606 		error(Ebadarg);
1607 	cd->spec = option;
1608 }
1609 
1610 static Devport*
getnewport(DevConf * dc)1611 getnewport(DevConf* dc)
1612 {
1613 	Devport *p;
1614 
1615 	p = (Devport *)malloc((dc->nports + 1) * sizeof(Devport));
1616 	if(p == nil)
1617 		error(Enomem);
1618 	if(dc->nports > 0){
1619 		memmove(p, dc->ports, dc->nports * sizeof(Devport));
1620 		free(dc->ports);
1621 	}
1622 	dc->ports = p;
1623 	p = &dc->ports[dc->nports++];
1624 	p->size = -1;
1625 	p->port = (ulong)-1;
1626 	return p;
1627 }
1628 
1629 static void
parseport(Confdata * cd,char * option)1630 parseport(Confdata* cd, char* option)
1631 {
1632 	char *e;
1633 	Devport *p;
1634 
1635 	if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].port != (ulong)-1)
1636 		p = getnewport(&cd->cf);
1637 	else
1638 		p = &cd->cf.ports[cd->cf.nports-1];
1639 	p->port = strtol(option, &e, 0);
1640 	if(e == nil || *e != '\0')
1641 		error(Ebadarg);
1642 }
1643 
1644 static void
parsesize(Confdata * cd,char * option)1645 parsesize(Confdata* cd, char* option)
1646 {
1647 	char *e;
1648 	Devport *p;
1649 
1650 	if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].size != -1)
1651 		p = getnewport(&cd->cf);
1652 	else
1653 		p = &cd->cf.ports[cd->cf.nports-1];
1654 	p->size = (int)strtol(option, &e, 0);
1655 	if(e == nil || *e != '\0')
1656 		error(Ebadarg);
1657 }
1658 
1659 static void
parseirq(Confdata * cd,char * option)1660 parseirq(Confdata* cd, char* option)
1661 {
1662 	char *e;
1663 
1664 	cd->cf.intnum = strtoul(option, &e, 0);
1665 	if(e == nil || *e != '\0')
1666 		error(Ebadarg);
1667 }
1668 
1669 static void
parsetype(Confdata * cd,char * option)1670 parsetype(Confdata* cd, char* option)
1671 {
1672 	cd->cf.type = option;
1673 }
1674 
1675 static struct {
1676 	char	*name;
1677 	void	(*parse)(Confdata*, char*);
1678 } options[] = {
1679 	"switch",	parseswitch,
1680 	"spec",		parsespec,
1681 	"port",		parseport,
1682 	"size",		parsesize,
1683 	"irq",		parseirq,
1684 	"type",		parsetype,
1685 };
1686 
1687 static void
legacytopctl(Cmdbuf * cb)1688 legacytopctl(Cmdbuf *cb)
1689 {
1690 	char *opt;
1691 	int i, j;
1692 	Confdata cd;
1693 
1694 	memset(&cd, 0, sizeof cd);
1695 	cd.on = -1;
1696 	for(i=0; i<cb->nf; i+=2){
1697 		if(i+2 > cb->nf)
1698 			error(Ebadarg);
1699 		opt = cb->f[i];
1700 		for(j=0; j<nelem(options); j++)
1701 			if(strcmp(opt, options[j].name) == 0){
1702 				options[j].parse(&cd, cb->f[i+1]);
1703 				break;
1704 			}
1705 		if(j == nelem(options))
1706 			error(Ebadarg);
1707 	}
1708 	/* this has been rewritten to accomodate sdaoe */
1709 	if(cd.on < 0 || cd.spec == 0)
1710 		error(Ebadarg);
1711 	if(cd.on && cd.cf.type == nil)
1712 		error(Ebadarg);
1713 	sdconfig(cd.on, cd.spec, &cd.cf);
1714 }
1715