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