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