xref: /plan9-contrib/sys/src/9/pcboot/sdbios.c (revision fef25afaa1d0de6b039d347a8f0b354a9a54f5ff)
1*25210b06SDavid du Colombier /*
2*25210b06SDavid du Colombier  * read-only sd driver for BIOS devices with partitions.
3*25210b06SDavid du Colombier  * will probably only work with bootstrap kernels, as the normal kernel
4*25210b06SDavid du Colombier  * deals directly with the clock and disk controllers, which seems
5*25210b06SDavid du Colombier  * to confuse many BIOSes.
6*25210b06SDavid du Colombier  *
7*25210b06SDavid du Colombier  * devbios must be initialised first and no disks may be accessed
8*25210b06SDavid du Colombier  * via non-BIOS means.
9*25210b06SDavid du Colombier  */
10*25210b06SDavid du Colombier 
11*25210b06SDavid du Colombier #include	"u.h"
12*25210b06SDavid du Colombier #include	"../port/lib.h"
13*25210b06SDavid du Colombier #include	"mem.h"
14*25210b06SDavid du Colombier #include	"dat.h"
15*25210b06SDavid du Colombier #include	"fns.h"
16*25210b06SDavid du Colombier #include	"io.h"
17*25210b06SDavid du Colombier #include	"ureg.h"
18*25210b06SDavid du Colombier #include	"pool.h"
19*25210b06SDavid du Colombier #include	"../port/error.h"
20*25210b06SDavid du Colombier #include	"../port/netif.h"
21*25210b06SDavid du Colombier #include	"../port/sd.h"
22*25210b06SDavid du Colombier #include	"dosfs.h"
23*25210b06SDavid du Colombier 
24*25210b06SDavid du Colombier long	biosread0(Bootfs *, void *, long);
25*25210b06SDavid du Colombier vlong	biosseek(Bootfs *fs, vlong off);
26*25210b06SDavid du Colombier 
27*25210b06SDavid du Colombier extern SDifc sdbiosifc;
28*25210b06SDavid du Colombier extern int biosndevs;
29*25210b06SDavid du Colombier 
30*25210b06SDavid du Colombier uchar *
putbeul(ulong ul,uchar * p)31*25210b06SDavid du Colombier putbeul(ulong ul, uchar *p)
32*25210b06SDavid du Colombier {
33*25210b06SDavid du Colombier 	*p++ = ul >> 24;
34*25210b06SDavid du Colombier 	*p++ = ul >> 16;
35*25210b06SDavid du Colombier 	*p++ = ul >> 8;
36*25210b06SDavid du Colombier 	*p++ = ul;
37*25210b06SDavid du Colombier 	return p;
38*25210b06SDavid du Colombier }
39*25210b06SDavid du Colombier 
40*25210b06SDavid du Colombier uchar *
putbeuvl(uvlong uvl,uchar * p)41*25210b06SDavid du Colombier putbeuvl(uvlong uvl, uchar *p)
42*25210b06SDavid du Colombier {
43*25210b06SDavid du Colombier 	*p++ = uvl >> 56;
44*25210b06SDavid du Colombier 	*p++ = uvl >> 48;
45*25210b06SDavid du Colombier 	*p++ = uvl >> 40;
46*25210b06SDavid du Colombier 	*p++ = uvl >> 32;
47*25210b06SDavid du Colombier 	*p++ = uvl >> 24;
48*25210b06SDavid du Colombier 	*p++ = uvl >> 16;
49*25210b06SDavid du Colombier 	*p++ = uvl >> 8;
50*25210b06SDavid du Colombier 	*p++ = uvl;
51*25210b06SDavid du Colombier 	return p;
52*25210b06SDavid du Colombier }
53*25210b06SDavid du Colombier 
54*25210b06SDavid du Colombier int
biosverify(SDunit *)55*25210b06SDavid du Colombier biosverify(SDunit* )
56*25210b06SDavid du Colombier {
57*25210b06SDavid du Colombier 	if (!biosinited)
58*25210b06SDavid du Colombier 		return 0;
59*25210b06SDavid du Colombier 	return 1;
60*25210b06SDavid du Colombier }
61*25210b06SDavid du Colombier 
62*25210b06SDavid du Colombier int
biosonline(SDunit * unit)63*25210b06SDavid du Colombier biosonline(SDunit* unit)
64*25210b06SDavid du Colombier {
65*25210b06SDavid du Colombier 	uint subno = unit->subno;
66*25210b06SDavid du Colombier 
67*25210b06SDavid du Colombier 	if (!biosinited)
68*25210b06SDavid du Colombier 		panic("sdbios: biosonline: sdbios not inited");
69*25210b06SDavid du Colombier 	if (unit == nil)
70*25210b06SDavid du Colombier 		return 0;
71*25210b06SDavid du Colombier 	unit->secsize = biossectsz(subno);
72*25210b06SDavid du Colombier 	if (unit->secsize <= 0) {
73*25210b06SDavid du Colombier 		print("sdbios: biosonline: implausible sector size on medium\n");
74*25210b06SDavid du Colombier 		return 0;
75*25210b06SDavid du Colombier 	}
76*25210b06SDavid du Colombier 	unit->sectors = biossize(subno);
77*25210b06SDavid du Colombier 	if (unit->sectors <= 0) {
78*25210b06SDavid du Colombier 		unit->sectors = 0;
79*25210b06SDavid du Colombier 		print("sdbios: biosonline: no sectors on medium\n");
80*25210b06SDavid du Colombier 		return 0;
81*25210b06SDavid du Colombier 	}
82*25210b06SDavid du Colombier 	return 1;
83*25210b06SDavid du Colombier }
84*25210b06SDavid du Colombier 
85*25210b06SDavid du Colombier static int
biosrio(SDreq * r)86*25210b06SDavid du Colombier biosrio(SDreq* r)
87*25210b06SDavid du Colombier {
88*25210b06SDavid du Colombier 	int nb;
89*25210b06SDavid du Colombier 	long got;
90*25210b06SDavid du Colombier 	vlong off;
91*25210b06SDavid du Colombier 	uchar *p;
92*25210b06SDavid du Colombier 	Bootfs fs;			/* just for fs->dev, which is zero */
93*25210b06SDavid du Colombier 	SDunit *unit;
94*25210b06SDavid du Colombier 
95*25210b06SDavid du Colombier 	if (!biosinited)
96*25210b06SDavid du Colombier 		return SDeio;
97*25210b06SDavid du Colombier 	unit = r->unit;
98*25210b06SDavid du Colombier 	/*
99*25210b06SDavid du Colombier 	 * Most SCSI commands can be passed unchanged except for
100*25210b06SDavid du Colombier 	 * the padding on the end. The few which require munging
101*25210b06SDavid du Colombier 	 * are not used internally. Mode select/sense(6) could be
102*25210b06SDavid du Colombier 	 * converted to the 10-byte form but it's not worth the
103*25210b06SDavid du Colombier 	 * effort. Read/write(6) are easy.
104*25210b06SDavid du Colombier 	 */
105*25210b06SDavid du Colombier 	r->rlen = 0;
106*25210b06SDavid du Colombier 	r->status = SDok;
107*25210b06SDavid du Colombier 	switch(r->cmd[0]){
108*25210b06SDavid du Colombier 	case ScmdRead:
109*25210b06SDavid du Colombier 	case ScmdExtread:
110*25210b06SDavid du Colombier 		if (r->cmd[0] == ScmdRead)
111*25210b06SDavid du Colombier 			panic("biosrio: ScmdRead read op");
112*25210b06SDavid du Colombier 		off = r->cmd[2]<<24 | r->cmd[3]<<16 | r->cmd[4]<<8 | r->cmd[5];
113*25210b06SDavid du Colombier 		nb =  r->cmd[7]<<8  | r->cmd[8];	/* often 4 */
114*25210b06SDavid du Colombier 		USED(nb);		/* is nb*unit->secsize == r->dlen? */
115*25210b06SDavid du Colombier 		memset(&fs, 0, sizeof fs);
116*25210b06SDavid du Colombier 		biosseek(&fs, off * unit->secsize);
117*25210b06SDavid du Colombier 		got = biosread0(&fs, r->data, r->dlen);
118*25210b06SDavid du Colombier 		if (got < 0)
119*25210b06SDavid du Colombier 			r->status = SDeio;
120*25210b06SDavid du Colombier 		else
121*25210b06SDavid du Colombier 			r->rlen = got;
122*25210b06SDavid du Colombier 		break;
123*25210b06SDavid du Colombier 	case ScmdWrite:
124*25210b06SDavid du Colombier 	case ScmdExtwrite:
125*25210b06SDavid du Colombier 		r->status = SDeio;	/* boot programs don't write */
126*25210b06SDavid du Colombier 		break;
127*25210b06SDavid du Colombier 
128*25210b06SDavid du Colombier 		/*
129*25210b06SDavid du Colombier 		 * Read capacity returns the LBA of the last sector.
130*25210b06SDavid du Colombier 		 */
131*25210b06SDavid du Colombier 	case ScmdRcapacity:
132*25210b06SDavid du Colombier 		p = putbeul(r->unit->sectors - 1, r->data);
133*25210b06SDavid du Colombier 		r->data = putbeul(r->unit->secsize, p);
134*25210b06SDavid du Colombier 		return SDok;
135*25210b06SDavid du Colombier 	case ScmdRcapacity16:
136*25210b06SDavid du Colombier 		p = putbeuvl(r->unit->sectors - 1, r->data);
137*25210b06SDavid du Colombier 		r->data = putbeul(r->unit->secsize, p);
138*25210b06SDavid du Colombier 		return SDok;
139*25210b06SDavid du Colombier 	/* ignore others */
140*25210b06SDavid du Colombier 	}
141*25210b06SDavid du Colombier 	return r->status;
142*25210b06SDavid du Colombier }
143*25210b06SDavid du Colombier 
144*25210b06SDavid du Colombier /* this is called between biosreset and biosinit */
145*25210b06SDavid du Colombier static SDev*
biospnp(void)146*25210b06SDavid du Colombier biospnp(void)
147*25210b06SDavid du Colombier {
148*25210b06SDavid du Colombier 	SDev *sdev;
149*25210b06SDavid du Colombier 
150*25210b06SDavid du Colombier 	if (!biosinited)
151*25210b06SDavid du Colombier 		panic("sdbios: biospnp: bios devbios not yet inited");
152*25210b06SDavid du Colombier 	if((sdev = malloc(sizeof(SDev))) != nil) {
153*25210b06SDavid du Colombier 		sdev->ifc = &sdbiosifc;
154*25210b06SDavid du Colombier 		sdev->idno = 'B';
155*25210b06SDavid du Colombier 		sdev->nunit = biosndevs;
156*25210b06SDavid du Colombier 		iprint("sdbios: biospnp: %d unit(s) at sd%C0\n",
157*25210b06SDavid du Colombier 			sdev->nunit, sdev->idno);
158*25210b06SDavid du Colombier 	}
159*25210b06SDavid du Colombier 	return sdev;
160*25210b06SDavid du Colombier }
161*25210b06SDavid du Colombier 
162*25210b06SDavid du Colombier SDifc sdbiosifc = {
163*25210b06SDavid du Colombier 	"bios",				/* name */
164*25210b06SDavid du Colombier 
165*25210b06SDavid du Colombier 	biospnp,			/* pnp */
166*25210b06SDavid du Colombier 	nil,				/* legacy */
167*25210b06SDavid du Colombier 	nil,				/* enable */
168*25210b06SDavid du Colombier 	nil,				/* disable */
169*25210b06SDavid du Colombier 
170*25210b06SDavid du Colombier 	biosverify,			/* verify */
171*25210b06SDavid du Colombier 	biosonline,			/* online */
172*25210b06SDavid du Colombier 	biosrio,			/* rio */
173*25210b06SDavid du Colombier 	nil,				/* rctl */
174*25210b06SDavid du Colombier 	nil,				/* wctl */
175*25210b06SDavid du Colombier 
176*25210b06SDavid du Colombier 	scsibio,			/* bio */
177*25210b06SDavid du Colombier 	nil,				/* probe */
178*25210b06SDavid du Colombier 	nil,				/* clear */
179*25210b06SDavid du Colombier 	nil,				/* rtopctl */
180*25210b06SDavid du Colombier 	nil,				/* wtopctl */
181*25210b06SDavid du Colombier };
182