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