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