Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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*
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*
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
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
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
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
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
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
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*
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*
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
652
sdstat(Chan* c, uchar* db, int n)
653
{
654
	return devstat(c, db, n, nil, 0, sdgen);
655
}
656
 
657
static Chan*
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
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
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
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
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
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
953
sdfakescsi(SDreq *r, void *info, int ilen)
954
{
955
	uchar *cmd, *p;
956
	uvlong len;
957
	SDunit *unit;
958
 
959
	cmd = r->cmd;
960
	r->rlen = 0;
961
	unit = r->unit;
962
 
963
	/*
964
	 * Rewrite read(6)/write(6) into read(10)/write(10).
965
	 */
966
	switch(cmd[0]){
967
	case 0x08:	/* read */
968
	case 0x0A:	/* write */
969
		cmd[9] = 0;
970
		cmd[8] = cmd[4];
971
		cmd[7] = 0;
972
		cmd[6] = 0;
973
		cmd[5] = cmd[3];
974
		cmd[4] = cmd[2];
975
		cmd[3] = cmd[1] & 0x0F;
976
		cmd[2] = 0;
977
		cmd[1] &= 0xE0;
978
		cmd[0] |= 0x20;
979
		break;
980
	}
981
 
982
	/*
983
	 * Map SCSI commands into ATA commands for discs.
984
	 * Fail any command with a LUN except INQUIRY which
985
	 * will return 'logical unit not supported'.
986
	 */
987
	if((cmd[1]>>5) && cmd[0] != 0x12)
988
		return sdsetsense(r, SDcheck, 0x05, 0x25, 0);
989
 
990
	switch(cmd[0]){
991
	default:
992
		return sdsetsense(r, SDcheck, 0x05, 0x20, 0);
993
 
994
	case 0x00:	/* test unit ready */
995
		return sdsetsense(r, SDok, 0, 0, 0);
996
 
997
	case 0x03:	/* request sense */
998
		if(cmd[4] < sizeof unit->sense)
999
			len = cmd[4];
1000
		else
1001
			len = sizeof unit->sense;
1002
		if(r->data && r->dlen >= len){
1003
			memmove(r->data, unit->sense, len);
1004
			r->rlen = len;
1005
		}
1006
		return sdsetsense(r, SDok, 0, 0, 0);
1007
 
1008
	case 0x12:	/* inquiry */
1009
		if(cmd[4] < sizeof unit->inquiry)
1010
			len = cmd[4];
1011
		else
1012
			len = sizeof unit->inquiry;
1013
		if(r->data && r->dlen >= len){
1014
			memmove(r->data, unit->inquiry, len);
1015
			r->rlen = len;
1016
		}
1017
		return sdsetsense(r, SDok, 0, 0, 0);
1018
 
1019
	case 0x1B:	/* start/stop unit */
1020
		/*
1021
		 * nop for now, can use power management later.
1022
		 */
1023
		return sdsetsense(r, SDok, 0, 0, 0);
1024
 
1025
	case 0x25:	/* read capacity */
1026
		if((cmd[1] & 0x01) || cmd[2] || cmd[3])
1027
			return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
1028
		if(r->data == nil || r->dlen < 8)
1029
			return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
1030
 
1031
		/*
1032
		 * Read capacity returns the LBA of the last sector.
1033
		 */
1034
		len = unit->sectors - 1;
1035
		p = r->data;
1036
		*p++ = len>>24;
1037
		*p++ = len>>16;
1038
		*p++ = len>>8;
1039
		*p++ = len;
1040
		len = 512;
1041
		*p++ = len>>24;
1042
		*p++ = len>>16;
1043
		*p++ = len>>8;
1044
		*p++ = len;
1045
		r->rlen = p - (uchar*)r->data;
1046
		return sdsetsense(r, SDok, 0, 0, 0);
1047
 
1048
	case 0x9E:	/* long read capacity */
1049
		if((cmd[1] & 0x01) || cmd[2] || cmd[3])
1050
			return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
1051
		if(r->data == nil || r->dlen < 8)
1052
			return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
1053
		/*
1054
		 * Read capcity returns the LBA of the last sector.
1055
		 */
1056
		len = unit->sectors - 1;
1057
		p = r->data;
1058
		*p++ = len>>56;
1059
		*p++ = len>>48;
1060
		*p++ = len>>40;
1061
		*p++ = len>>32;
1062
		*p++ = len>>24;
1063
		*p++ = len>>16;
1064
		*p++ = len>>8;
1065
		*p++ = len;
1066
		len = 512;
1067
		*p++ = len>>24;
1068
		*p++ = len>>16;
1069
		*p++ = len>>8;
1070
		*p++ = len;
1071
		r->rlen = p - (uchar*)r->data;
1072
		return sdsetsense(r, SDok, 0, 0, 0);
1073
 
1074
	case 0x5A:	/* mode sense */
1075
		return sdmodesense(r, cmd, info, ilen);
1076
 
1077
	case 0x28:	/* read */
1078
	case 0x2A:	/* write */
1079
	case 0x88:	/* read16 */
1080
	case 0x8a:	/* write16 */
1081
		return SDnostatus;
1082
	}
1083
}
1084
 
1085
static long
1086
sdread(Chan *c, void *a, long n, vlong off)
1087
{
1088
	char *p, *e, *buf;
1089
	SDpart *pp;
1090
	SDunit *unit;
1091
	SDev *sdev;
1092
	ulong offset;
1093
	int i, l, m, status;
1094
 
1095
	offset = off;
1096
	switch(TYPE(c->qid)){
1097
	default:
1098
		error(Eperm);
1099
	case Qtopctl:
1100
		m = 64*1024;	/* room for register dumps */
1101
		p = buf = malloc(m);
1102
		if(p == nil)
1103
			error(Enomem);
1104
		e = p + m;
1105
		qlock(&devslock);
1106
		for(i = 0; i < nelem(devs); i++){
1107
			sdev = devs[i];
1108
			if(sdev && sdev->ifc->rtopctl)
1109
				p = sdev->ifc->rtopctl(sdev, p, e);
1110
		}
1111
		qunlock(&devslock);
1112
		n = readstr(off, a, n, buf);
1113
		free(buf);
1114
		return n;
1115
 
1116
	case Qtopdir:
1117
	case Qunitdir:
1118
		return devdirread(c, a, n, 0, 0, sdgen);
1119
 
1120
	case Qctl:
1121
		sdev = sdgetdev(DEV(c->qid));
1122
		if(sdev == nil)
1123
			error(Enonexist);
1124
 
1125
		unit = sdev->unit[UNIT(c->qid)];
1126
		m = 16*1024;	/* room for register dumps */
1127
		p = malloc(m);
1128
		if(p == nil)
1129
			error(Enomem);
1130
		l = snprint(p, m, "inquiry %.48s\n",
1131
			(char*)unit->inquiry+8);
1132
		qlock(&unit->ctl);
1133
		/*
1134
		 * If there's a device specific routine it must
1135
		 * provide all information pertaining to night geometry
1136
		 * and the garscadden trains.
1137
		 */
1138
		if(unit->dev->ifc->rctl)
1139
			l += unit->dev->ifc->rctl(unit, p+l, m-l);
1140
		if(unit->sectors == 0)
1141
			sdinitpart(unit);
1142
		if(unit->sectors){
1143
			if(unit->dev->ifc->rctl == nil)
1144
				l += snprint(p+l, m-l,
1145
					"geometry %llud %lud\n",
1146
					unit->sectors, unit->secsize);
1147
			pp = unit->part;
1148
			for(i = 0; i < unit->npart; i++){
1149
				if(pp->valid)
1150
					l += snprint(p+l, m-l,
1151
						"part %s %llud %llud\n",
1152
						pp->name, pp->start, pp->end);
1153
				pp++;
1154
			}
1155
		}
1156
		qunlock(&unit->ctl);
1157
		decref(&sdev->r);
1158
		l = readstr(offset, a, n, p);
1159
		free(p);
1160
		return l;
1161
 
1162
	case Qraw:
1163
		sdev = sdgetdev(DEV(c->qid));
1164
		if(sdev == nil)
1165
			error(Enonexist);
1166
 
1167
		unit = sdev->unit[UNIT(c->qid)];
1168
		qlock(&unit->raw);
1169
		if(waserror()){
1170
			qunlock(&unit->raw);
1171
			decref(&sdev->r);
1172
			nexterror();
1173
		}
1174
		if(unit->state == Rawdata){
1175
			unit->state = Rawstatus;
1176
			i = sdrio(unit->req, a, n);
1177
		}
1178
		else if(unit->state == Rawstatus){
1179
			status = unit->req->status;
1180
			unit->state = Rawcmd;
1181
			free(unit->req);
1182
			unit->req = nil;
1183
			i = readnum(0, a, n, status, NUMSIZE);
1184
		} else
1185
			i = 0;
1186
		qunlock(&unit->raw);
1187
		decref(&sdev->r);
1188
		poperror();
1189
		return i;
1190
 
1191
	case Qpart:
1192
		return sdbio(c, 0, a, n, off);
1193
	}
1194
}
1195
 
1196
static void legacytopctl(Cmdbuf*);
1197
 
1198
static long
1199
sdwrite(Chan* c, void* a, long n, vlong off)
1200
{
1201
	char *f0;
1202
	int i;
1203
	uvlong end, start;
1204
	Cmdbuf *cb;
1205
	SDifc *ifc;
1206
	SDreq *req;
1207
	SDunit *unit;
1208
	SDev *sdev;
1209
 
1210
	switch(TYPE(c->qid)){
1211
	default:
1212
		error(Eperm);
1213
	case Qtopctl:
1214
		cb = parsecmd(a, n);
1215
		if(waserror()){
1216
			free(cb);
1217
			nexterror();
1218
		}
1219
		if(cb->nf == 0)
1220
			error("empty control message");
1221
		f0 = cb->f[0];
1222
		cb->f++;
1223
		cb->nf--;
1224
		if(strcmp(f0, "config") == 0){
1225
			/* wormhole into ugly legacy interface */
1226
			legacytopctl(cb);
1227
			poperror();
1228
			free(cb);
1229
			break;
1230
		}
1231
		/*
1232
		 * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb),
1233
		 * where sdifc[i]->name=="ata" and cb contains the args.
1234
		 */
1235
		ifc = nil;
1236
		sdev = nil;
1237
		for(i=0; sdifc[i]; i++){
1238
			if(strcmp(sdifc[i]->name, f0) == 0){
1239
				ifc = sdifc[i];
1240
				sdev = nil;
1241
				goto subtopctl;
1242
			}
1243
		}
1244
		/*
1245
		 * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb),
1246
		 * where sdifc[i] and sdev match controller letter "1",
1247
		 * and cb contains the args.
1248
		 */
1249
		if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){
1250
			if((sdev = sdgetdev(f0[2])) != nil){
1251
				ifc = sdev->ifc;
1252
				goto subtopctl;
1253
			}
1254
		}
1255
		error("unknown interface");
1256
 
1257
	subtopctl:
1258
		if(waserror()){
1259
			if(sdev)
1260
				decref(&sdev->r);
1261
			nexterror();
1262
		}
1263
		if(ifc->wtopctl)
1264
			ifc->wtopctl(sdev, cb);
1265
		else
1266
			error(Ebadctl);
1267
		poperror();
1268
		poperror();
1269
		if (sdev)
1270
			decref(&sdev->r);
1271
		free(cb);
1272
		break;
1273
 
1274
	case Qctl:
1275
		cb = parsecmd(a, n);
1276
		sdev = sdgetdev(DEV(c->qid));
1277
		if(sdev == nil)
1278
			error(Enonexist);
1279
		unit = sdev->unit[UNIT(c->qid)];
1280
 
1281
		qlock(&unit->ctl);
1282
		if(waserror()){
1283
			qunlock(&unit->ctl);
1284
			decref(&sdev->r);
1285
			free(cb);
1286
			nexterror();
1287
		}
1288
		if(unit->vers != c->qid.vers)
1289
			error(Echange);
1290
 
1291
		if(cb->nf < 1)
1292
			error(Ebadctl);
1293
		if(strcmp(cb->f[0], "part") == 0){
1294
			if(cb->nf != 4)
1295
				error(Ebadctl);
1296
			if(unit->sectors == 0 && !sdinitpart(unit))
1297
				error(Eio);
1298
			start = strtoull(cb->f[2], 0, 0);
1299
			end = strtoull(cb->f[3], 0, 0);
1300
			sdaddpart(unit, cb->f[1], start, end);
1301
		}
1302
		else if(strcmp(cb->f[0], "delpart") == 0){
1303
			if(cb->nf != 2 || unit->part == nil)
1304
				error(Ebadctl);
1305
			sddelpart(unit, cb->f[1]);
1306
		}
1307
		else if(unit->dev->ifc->wctl)
1308
			unit->dev->ifc->wctl(unit, cb);
1309
		else
1310
			error(Ebadctl);
1311
		qunlock(&unit->ctl);
1312
		decref(&sdev->r);
1313
		poperror();
1314
		free(cb);
1315
		break;
1316
 
1317
	case Qraw:
1318
		sdev = sdgetdev(DEV(c->qid));
1319
		if(sdev == nil)
1320
			error(Enonexist);
1321
		unit = sdev->unit[UNIT(c->qid)];
1322
		qlock(&unit->raw);
1323
		if(waserror()){
1324
			qunlock(&unit->raw);
1325
			decref(&sdev->r);
1326
			nexterror();
1327
		}
1328
		switch(unit->state){
1329
		case Rawcmd:
1330
			if(n < 6 || n > sizeof(req->cmd))
1331
				error(Ebadarg);
1332
			if((req = malloc(sizeof(SDreq))) == nil)
1333
				error(Enomem);
1334
			req->unit = unit;
1335
			memmove(req->cmd, a, n);
1336
			req->clen = n;
1337
			req->flags = SDnosense;
1338
			req->status = ~0;
1339
 
1340
			unit->req = req;
1341
			unit->state = Rawdata;
1342
			break;
1343
 
1344
		case Rawstatus:
1345
			unit->state = Rawcmd;
1346
			free(unit->req);
1347
			unit->req = nil;
1348
			error(Ebadusefd);
1349
 
1350
		case Rawdata:
1351
			unit->state = Rawstatus;
1352
			unit->req->write = 1;
1353
			n = sdrio(unit->req, a, n);
1354
		}
1355
		qunlock(&unit->raw);
1356
		decref(&sdev->r);
1357
		poperror();
1358
		break;
1359
	case Qpart:
1360
		return sdbio(c, 1, a, n, off);
1361
	}
1362
 
1363
	return n;
1364
}
1365
 
1366
static int
1367
sdwstat(Chan* c, uchar* dp, int n)
1368
{
1369
	Dir *d;
1370
	SDpart *pp;
1371
	SDperm *perm;
1372
	SDunit *unit;
1373
	SDev *sdev;
1374
 
1375
	if(c->qid.type & QTDIR)
1376
		error(Eperm);
1377
 
1378
	sdev = sdgetdev(DEV(c->qid));
1379
	if(sdev == nil)
1380
		error(Enonexist);
1381
	unit = sdev->unit[UNIT(c->qid)];
1382
	qlock(&unit->ctl);
1383
	d = nil;
1384
	if(waserror()){
1385
		free(d);
1386
		qunlock(&unit->ctl);
1387
		decref(&sdev->r);
1388
		nexterror();
1389
	}
1390
 
1391
	switch(TYPE(c->qid)){
1392
	default:
1393
		error(Eperm);
1394
	case Qctl:
1395
		perm = &unit->ctlperm;
1396
		break;
1397
	case Qraw:
1398
		perm = &unit->rawperm;
1399
		break;
1400
	case Qpart:
1401
		pp = &unit->part[PART(c->qid)];
1402
		if(unit->vers+pp->vers != c->qid.vers)
1403
			error(Enonexist);
1404
		perm = &pp->SDperm;
1405
		break;
1406
	}
1407
 
1408
	if(strcmp(up->user, perm->user) && !iseve())
1409
		error(Eperm);
1410
 
1411
	d = smalloc(sizeof(Dir)+n);
1412
	n = convM2D(dp, n, &d[0], (char*)&d[1]);
1413
	if(n == 0)
1414
		error(Eshortstat);
1415
	if(!emptystr(d[0].uid))
1416
		kstrdup(&perm->user, d[0].uid);
1417
	if(d[0].mode != ~0UL)
1418
		perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
1419
 
1420
	free(d);
1421
	qunlock(&unit->ctl);
1422
	decref(&sdev->r);
1423
	poperror();
1424
	return n;
1425
}
1426
 
1427
static int
1428
configure(char* spec, DevConf* cf)
1429
{
1430
	SDev *s, *sdev;
1431
	char *p;
1432
	int i;
1433
 
1434
	if(sdindex(*spec) < 0)
1435
		error("bad sd spec");
1436
 
1437
	if((p = strchr(cf->type, '/')) != nil)
1438
		*p++ = '\0';
1439
 
1440
	for(i = 0; sdifc[i] != nil; i++)
1441
		if(strcmp(sdifc[i]->name, cf->type) == 0)
1442
			break;
1443
	if(sdifc[i] == nil)
1444
		error("sd type not found");
1445
	if(p)
1446
		*(p-1) = '/';
1447
 
1448
	if(sdifc[i]->probe == nil)
1449
		error("sd type cannot probe");
1450
 
1451
	sdev = sdifc[i]->probe(cf);
1452
	for(s=sdev; s; s=s->next)
1453
		s->idno = *spec;
1454
	sdadddevs(sdev);
1455
	return 0;
1456
}
1457
 
1458
static int
1459
unconfigure(char* spec)
1460
{
1461
	int i;
1462
	SDev *sdev;
1463
	SDunit *unit;
1464
 
1465
	if((i = sdindex(*spec)) < 0)
1466
		error(Enonexist);
1467
 
1468
	qlock(&devslock);
1469
	if((sdev = devs[i]) == nil){
1470
		qunlock(&devslock);
1471
		error(Enonexist);
1472
	}
1473
	if(sdev->r.ref){
1474
		qunlock(&devslock);
1475
		error(Einuse);
1476
	}
1477
	devs[i] = nil;
1478
	qunlock(&devslock);
1479
 
1480
	/* make sure no interrupts arrive anymore before removing resources */
1481
	if(sdev->enabled && sdev->ifc->disable)
1482
		sdev->ifc->disable(sdev);
1483
 
1484
	for(i = 0; i != sdev->nunit; i++){
1485
		if(unit = sdev->unit[i]){
1486
			free(unit->name);
1487
			free(unit->user);
1488
			free(unit);
1489
		}
1490
	}
1491
 
1492
	if(sdev->ifc->clear)
1493
		sdev->ifc->clear(sdev);
1494
	free(sdev);
1495
	return 0;
1496
}
1497
 
1498
static int
1499
sdconfig(int on, char* spec, DevConf* cf)
1500
{
1501
	if(on)
1502
		return configure(spec, cf);
1503
	return unconfigure(spec);
1504
}
1505
 
1506
Dev sddevtab = {
1507
	'S',
1508
	"sd",
1509
 
1510
	sdreset,
1511
	devinit,
1512
	devshutdown,
1513
	sdattach,
1514
	sdwalk,
1515
	sdstat,
1516
	sdopen,
1517
	devcreate,
1518
	sdclose,
1519
	sdread,
1520
	devbread,
1521
	sdwrite,
1522
	devbwrite,
1523
	devremove,
1524
	sdwstat,
1525
	devpower,
1526
	sdconfig,	/* probe; only called for pcmcia-like devices */
1527
};
1528
 
1529
/*
1530
 * This is wrong for so many reasons.  This code must go.
1531
 */
1532
typedef struct Confdata Confdata;
1533
struct Confdata {
1534
	int	on;
1535
	char*	spec;
1536
	DevConf	cf;
1537
};
1538
 
1539
static void
1540
parseswitch(Confdata* cd, char* option)
1541
{
1542
	if(!strcmp("on", option))
1543
		cd->on = 1;
1544
	else if(!strcmp("off", option))
1545
		cd->on = 0;
1546
	else
1547
		error(Ebadarg);
1548
}
1549
 
1550
static void
1551
parsespec(Confdata* cd, char* option)
1552
{
1553
	if(strlen(option) > 1)
1554
		error(Ebadarg);
1555
	cd->spec = option;
1556
}
1557
 
1558
static Devport*
1559
getnewport(DevConf* dc)
1560
{
1561
	Devport *p;
1562
 
1563
	p = (Devport *)malloc((dc->nports + 1) * sizeof(Devport));
1564
	if(p == nil)
1565
		error(Enomem);
1566
	if(dc->nports > 0){
1567
		memmove(p, dc->ports, dc->nports * sizeof(Devport));
1568
		free(dc->ports);
1569
	}
1570
	dc->ports = p;
1571
	p = &dc->ports[dc->nports++];
1572
	p->size = -1;
1573
	p->port = (ulong)-1;
1574
	return p;
1575
}
1576
 
1577
static void
1578
parseport(Confdata* cd, char* option)
1579
{
1580
	char *e;
1581
	Devport *p;
1582
 
1583
	if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].port != (ulong)-1)
1584
		p = getnewport(&cd->cf);
1585
	else
1586
		p = &cd->cf.ports[cd->cf.nports-1];
1587
	p->port = strtol(option, &e, 0);
1588
	if(e == nil || *e != '\0')
1589
		error(Ebadarg);
1590
}
1591
 
1592
static void
1593
parsesize(Confdata* cd, char* option)
1594
{
1595
	char *e;
1596
	Devport *p;
1597
 
1598
	if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].size != -1)
1599
		p = getnewport(&cd->cf);
1600
	else
1601
		p = &cd->cf.ports[cd->cf.nports-1];
1602
	p->size = (int)strtol(option, &e, 0);
1603
	if(e == nil || *e != '\0')
1604
		error(Ebadarg);
1605
}
1606
 
1607
static void
1608
parseirq(Confdata* cd, char* option)
1609
{
1610
	char *e;
1611
 
1612
	cd->cf.intnum = strtoul(option, &e, 0);
1613
	if(e == nil || *e != '\0')
1614
		error(Ebadarg);
1615
}
1616
 
1617
static void
1618
parsetype(Confdata* cd, char* option)
1619
{
1620
	cd->cf.type = option;
1621
}
1622
 
1623
static struct {
1624
	char	*name;
1625
	void	(*parse)(Confdata*, char*);
1626
} options[] = {
1627
	"switch",	parseswitch,
1628
	"spec",		parsespec,
1629
	"port",		parseport,
1630
	"size",		parsesize,
1631
	"irq",		parseirq,
1632
	"type",		parsetype,
1633
};
1634
 
1635
static void
1636
legacytopctl(Cmdbuf *cb)
1637
{
1638
	char *opt;
1639
	int i, j;
1640
	Confdata cd;
1641
 
1642
	memset(&cd, 0, sizeof cd);
1643
	cd.on = -1;
1644
	for(i=0; i<cb->nf; i+=2){
1645
		if(i+2 > cb->nf)
1646
			error(Ebadarg);
1647
		opt = cb->f[i];
1648
		for(j=0; j<nelem(options); j++)
1649
			if(strcmp(opt, options[j].name) == 0){
1650
				options[j].parse(&cd, cb->f[i+1]);
1651
				break;
1652
			}
1653
		if(j == nelem(options))
1654
			error(Ebadarg);
1655
	}
1656
	/* this has been rewritten to accomodate sdaoe */
1657
	if(cd.on < 0 || cd.spec == 0)
1658
		error(Ebadarg);
1659
	if(cd.on && cd.cf.type == nil)
1660
		error(Ebadarg);
1661
	sdconfig(cd.on, cd.spec, &cd.cf);
1662
}