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