1*8a8c2d74SCharles.Forsyth /*
2*8a8c2d74SCharles.Forsyth * boot driver for BIOS devices with partitions
3*8a8c2d74SCharles.Forsyth * devbios must be called first
4*8a8c2d74SCharles.Forsyth */
5*8a8c2d74SCharles.Forsyth #include "u.h"
6*8a8c2d74SCharles.Forsyth #include "lib.h"
7*8a8c2d74SCharles.Forsyth #include "mem.h"
8*8a8c2d74SCharles.Forsyth #include "dat.h"
9*8a8c2d74SCharles.Forsyth #include "fns.h"
10*8a8c2d74SCharles.Forsyth #include "io.h"
11*8a8c2d74SCharles.Forsyth #include "ureg.h"
12*8a8c2d74SCharles.Forsyth #include "error.h"
13*8a8c2d74SCharles.Forsyth
14*8a8c2d74SCharles.Forsyth #include "sd.h"
15*8a8c2d74SCharles.Forsyth #include "fs.h"
16*8a8c2d74SCharles.Forsyth
17*8a8c2d74SCharles.Forsyth long biosread(Fs *, void *, long);
18*8a8c2d74SCharles.Forsyth vlong biosseek(Fs *fs, vlong off);
19*8a8c2d74SCharles.Forsyth
20*8a8c2d74SCharles.Forsyth extern SDifc sdbiosifc;
21*8a8c2d74SCharles.Forsyth extern int onlybios0, biosinited;
22*8a8c2d74SCharles.Forsyth
23*8a8c2d74SCharles.Forsyth int
biosverify(SDunit *)24*8a8c2d74SCharles.Forsyth biosverify(SDunit* )
25*8a8c2d74SCharles.Forsyth {
26*8a8c2d74SCharles.Forsyth if (onlybios0 || !biosinited)
27*8a8c2d74SCharles.Forsyth return 0;
28*8a8c2d74SCharles.Forsyth return 1;
29*8a8c2d74SCharles.Forsyth }
30*8a8c2d74SCharles.Forsyth
31*8a8c2d74SCharles.Forsyth int
biosonline(SDunit * unit)32*8a8c2d74SCharles.Forsyth biosonline(SDunit* unit)
33*8a8c2d74SCharles.Forsyth {
34*8a8c2d74SCharles.Forsyth if (onlybios0 || !biosinited || !unit)
35*8a8c2d74SCharles.Forsyth return 0;
36*8a8c2d74SCharles.Forsyth unit->sectors = 1UL << 30; /* a bunch */
37*8a8c2d74SCharles.Forsyth unit->secsize = 512; /* conventional */
38*8a8c2d74SCharles.Forsyth return 1;
39*8a8c2d74SCharles.Forsyth }
40*8a8c2d74SCharles.Forsyth
41*8a8c2d74SCharles.Forsyth static int
biosrio(SDreq * r)42*8a8c2d74SCharles.Forsyth biosrio(SDreq* r)
43*8a8c2d74SCharles.Forsyth {
44*8a8c2d74SCharles.Forsyth int nb;
45*8a8c2d74SCharles.Forsyth long got;
46*8a8c2d74SCharles.Forsyth vlong len, off;
47*8a8c2d74SCharles.Forsyth uchar *p;
48*8a8c2d74SCharles.Forsyth Fs fs; /* just for fs->dev, which is zero */
49*8a8c2d74SCharles.Forsyth
50*8a8c2d74SCharles.Forsyth if (onlybios0 || !biosinited)
51*8a8c2d74SCharles.Forsyth return SDeio;
52*8a8c2d74SCharles.Forsyth /*
53*8a8c2d74SCharles.Forsyth * Most SCSI commands can be passed unchanged except for
54*8a8c2d74SCharles.Forsyth * the padding on the end. The few which require munging
55*8a8c2d74SCharles.Forsyth * are not used internally. Mode select/sense(6) could be
56*8a8c2d74SCharles.Forsyth * converted to the 10-byte form but it's not worth the
57*8a8c2d74SCharles.Forsyth * effort. Read/write(6) are easy.
58*8a8c2d74SCharles.Forsyth */
59*8a8c2d74SCharles.Forsyth r->rlen = 0;
60*8a8c2d74SCharles.Forsyth r->status = SDok;
61*8a8c2d74SCharles.Forsyth switch(r->cmd[0]){
62*8a8c2d74SCharles.Forsyth case 0x08: /* read */
63*8a8c2d74SCharles.Forsyth case 0x28: /* read */
64*8a8c2d74SCharles.Forsyth if (r->cmd[0] == 0x08)
65*8a8c2d74SCharles.Forsyth panic("biosrio: 0x08 read op\n");
66*8a8c2d74SCharles.Forsyth off = r->cmd[2]<<24 | r->cmd[3]<<16 | r->cmd[4]<<8 | r->cmd[5];
67*8a8c2d74SCharles.Forsyth nb = r->cmd[7]<<8 | r->cmd[8]; /* often 4 */
68*8a8c2d74SCharles.Forsyth USED(nb); /* is nb*512 == r->dlen? */
69*8a8c2d74SCharles.Forsyth memset(&fs, 0, sizeof fs);
70*8a8c2d74SCharles.Forsyth biosseek(&fs, off*512);
71*8a8c2d74SCharles.Forsyth got = biosread(&fs, r->data, r->dlen);
72*8a8c2d74SCharles.Forsyth if (got < 0)
73*8a8c2d74SCharles.Forsyth r->status = SDeio;
74*8a8c2d74SCharles.Forsyth else
75*8a8c2d74SCharles.Forsyth r->rlen = got;
76*8a8c2d74SCharles.Forsyth break;
77*8a8c2d74SCharles.Forsyth case 0x0A: /* write */
78*8a8c2d74SCharles.Forsyth case 0x2A: /* write */
79*8a8c2d74SCharles.Forsyth r->status = SDeio; /* boot programs don't write */
80*8a8c2d74SCharles.Forsyth break;
81*8a8c2d74SCharles.Forsyth case 0x25: /* read capacity */
82*8a8c2d74SCharles.Forsyth /*
83*8a8c2d74SCharles.Forsyth * Read capacity returns the LBA of the last sector.
84*8a8c2d74SCharles.Forsyth */
85*8a8c2d74SCharles.Forsyth len = r->unit->sectors - 1;
86*8a8c2d74SCharles.Forsyth p = r->data;
87*8a8c2d74SCharles.Forsyth *p++ = len>>24;
88*8a8c2d74SCharles.Forsyth *p++ = len>>16;
89*8a8c2d74SCharles.Forsyth *p++ = len>>8;
90*8a8c2d74SCharles.Forsyth *p++ = len;
91*8a8c2d74SCharles.Forsyth len = r->unit->secsize;
92*8a8c2d74SCharles.Forsyth *p++ = len>>24;
93*8a8c2d74SCharles.Forsyth *p++ = len>>16;
94*8a8c2d74SCharles.Forsyth *p++ = len>>8;
95*8a8c2d74SCharles.Forsyth *p = len;
96*8a8c2d74SCharles.Forsyth r->data = (char *)r->data + 8;
97*8a8c2d74SCharles.Forsyth return SDok;
98*8a8c2d74SCharles.Forsyth case 0x9E: /* long read capacity */
99*8a8c2d74SCharles.Forsyth /*
100*8a8c2d74SCharles.Forsyth * Read capacity returns the LBA of the last sector.
101*8a8c2d74SCharles.Forsyth */
102*8a8c2d74SCharles.Forsyth len = r->unit->sectors - 1;
103*8a8c2d74SCharles.Forsyth p = r->data;
104*8a8c2d74SCharles.Forsyth *p++ = len>>56;
105*8a8c2d74SCharles.Forsyth *p++ = len>>48;
106*8a8c2d74SCharles.Forsyth *p++ = len>>40;
107*8a8c2d74SCharles.Forsyth *p++ = len>>32;
108*8a8c2d74SCharles.Forsyth *p++ = len>>24;
109*8a8c2d74SCharles.Forsyth *p++ = len>>16;
110*8a8c2d74SCharles.Forsyth *p++ = len>>8;
111*8a8c2d74SCharles.Forsyth *p++ = len;
112*8a8c2d74SCharles.Forsyth len = r->unit->secsize;
113*8a8c2d74SCharles.Forsyth *p++ = len>>24;
114*8a8c2d74SCharles.Forsyth *p++ = len>>16;
115*8a8c2d74SCharles.Forsyth *p++ = len>>8;
116*8a8c2d74SCharles.Forsyth *p = len;
117*8a8c2d74SCharles.Forsyth r->data = (char *)r->data + 8;
118*8a8c2d74SCharles.Forsyth return SDok;
119*8a8c2d74SCharles.Forsyth /* ignore others */
120*8a8c2d74SCharles.Forsyth }
121*8a8c2d74SCharles.Forsyth return r->status;
122*8a8c2d74SCharles.Forsyth }
123*8a8c2d74SCharles.Forsyth
124*8a8c2d74SCharles.Forsyth SDev*
biosid(SDev * sdev)125*8a8c2d74SCharles.Forsyth biosid(SDev* sdev)
126*8a8c2d74SCharles.Forsyth {
127*8a8c2d74SCharles.Forsyth for (; sdev; sdev = sdev->next)
128*8a8c2d74SCharles.Forsyth if (sdev->ifc == &sdbiosifc)
129*8a8c2d74SCharles.Forsyth sdev->idno = 'B';
130*8a8c2d74SCharles.Forsyth return sdev;
131*8a8c2d74SCharles.Forsyth }
132*8a8c2d74SCharles.Forsyth
133*8a8c2d74SCharles.Forsyth static SDev*
biospnp(void)134*8a8c2d74SCharles.Forsyth biospnp(void)
135*8a8c2d74SCharles.Forsyth {
136*8a8c2d74SCharles.Forsyth SDev *sdev;
137*8a8c2d74SCharles.Forsyth
138*8a8c2d74SCharles.Forsyth /* 9pxeload can't use bios int 13 calls; they wedge the machine */
139*8a8c2d74SCharles.Forsyth if (pxe || getconf("*nobiosload") != nil || onlybios0 || !biosinited)
140*8a8c2d74SCharles.Forsyth return nil;
141*8a8c2d74SCharles.Forsyth if((sdev = malloc(sizeof(SDev))) != nil) {
142*8a8c2d74SCharles.Forsyth sdev->ifc = &sdbiosifc;
143*8a8c2d74SCharles.Forsyth sdev->index = -1;
144*8a8c2d74SCharles.Forsyth sdev->nunit = 1;
145*8a8c2d74SCharles.Forsyth }
146*8a8c2d74SCharles.Forsyth return sdev;
147*8a8c2d74SCharles.Forsyth }
148*8a8c2d74SCharles.Forsyth
149*8a8c2d74SCharles.Forsyth SDifc sdbiosifc = {
150*8a8c2d74SCharles.Forsyth "bios", /* name */
151*8a8c2d74SCharles.Forsyth
152*8a8c2d74SCharles.Forsyth biospnp, /* pnp */
153*8a8c2d74SCharles.Forsyth nil, /* legacy */
154*8a8c2d74SCharles.Forsyth biosid, /* id */
155*8a8c2d74SCharles.Forsyth nil, /* enable */
156*8a8c2d74SCharles.Forsyth nil, /* disable */
157*8a8c2d74SCharles.Forsyth
158*8a8c2d74SCharles.Forsyth biosverify, /* verify */
159*8a8c2d74SCharles.Forsyth biosonline, /* online */
160*8a8c2d74SCharles.Forsyth biosrio, /* rio */
161*8a8c2d74SCharles.Forsyth nil, /* rctl */
162*8a8c2d74SCharles.Forsyth nil, /* wctl */
163*8a8c2d74SCharles.Forsyth
164*8a8c2d74SCharles.Forsyth scsibio, /* bio */
165*8a8c2d74SCharles.Forsyth };
166