sdcd.c revision 1.2 1 /* $NetBSD: sdcd.c,v 1.2 2001/09/29 03:50:13 minoura Exp $ */
2
3 /*
4 * Copyright (c) 2001 MINOURA Makoto.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <sys/param.h>
29 #include <sys/disklabel.h>
30 #include <lib/libkern/libkern.h>
31 #include <lib/libsa/stand.h>
32
33 #include "sdcdvar.h"
34 #include "iocs.h"
35
36
37 static int current_id = -1;
38 static int current_blklen, current_devsize, current_npart;
39 static struct boot_partinfo partitions[MAXPARTITIONS];
40
41 static int readdisklabel(int);
42 static int check_unit(int);
43
44 #ifdef DEBUG
45 #define DPRINTF(x) printf x
46 #else
47 #define DPRINTF(x)
48 #endif
49 #define alloca __builtin_alloca
50
51 static int
52 check_unit(int id)
53 {
54 #define BUFFER_SIZE 8192
55 int error;
56 void *buffer = alloca(BUFFER_SIZE);
57
58 if (current_id == id)
59 return 0;
60
61 current_id = -1;
62
63 error = IOCS_S_TESTUNIT(id);
64 if (error < 0) { /* not ready */
65 error = ENXIO;
66 goto out;
67 }
68
69 {
70 struct iocs_inquiry *inqdata = buffer;
71
72 error = IOCS_S_INQUIRY(100, id, inqdata);
73 if (error < 0) { /* WHY??? */
74 error = ENXIO;
75 goto out;
76 }
77 if ((inqdata->unit != 0) && /* direct */
78 (inqdata->unit != 7)) { /* optical */
79 error = EUNIT;
80 goto out;
81 }
82 }
83
84 {
85 struct iocs_readcap *rcdata = buffer;
86
87 error = IOCS_S_READCAP(id, rcdata);
88 if (error < 0) { /* WHY??? */
89 error = EUNIT;
90 goto out;
91 }
92 current_blklen = rcdata->size >> 9;
93 current_devsize = rcdata->block;
94 }
95
96 {
97 error = IOCS_S_READ(0, 1, id, current_blklen, buffer);
98 if (error < 0) {
99 error = EIO;
100 goto out;
101 }
102 if (strncmp((char*) buffer, "X68SCSI1", 8) != 0) {
103 error = EUNLAB;
104 goto out;
105 }
106 }
107
108 out:
109 return error;
110 }
111
112 static int
113 readdisklabel (int id)
114 {
115 int error, i;
116 char *buffer;
117 struct disklabel *label;
118 struct dos_partition *parttbl;
119
120 if (current_id == id)
121 return 0;
122 current_id = -1;
123
124 error = check_unit(id);
125 if (error)
126 return error;
127 if (current_blklen > 4) {
128 printf ("FATAL: Unsupported block size %d.\n",
129 256 << current_blklen);
130 return ERDLAB;
131 }
132
133 /* Try BSD disklabel first */
134 buffer = alloca(2048);
135 error = IOCS_S_READ(LABELSECTOR, 1, id, current_blklen, buffer);
136 if (error < 0)
137 return EIO;
138 label = (void*) (buffer + LABELOFFSET);
139 if (label->d_magic == DISKMAGIC &&
140 label->d_magic2 == DISKMAGIC) {
141 for (i = 0; i < label->d_npartitions; i++) {
142 partitions[i].start = label->d_partitions[i].p_offset;
143 partitions[i].size = label->d_partitions[i].p_size;
144 }
145 current_npart = label->d_npartitions;
146
147 return 0;
148 }
149
150 /* Try Human68K-style partition table */
151 #if 0
152 /* assumes 512byte/sec */
153 error = IOCS_S_READ(DOSPARTOFF, 2, id, current_blklen, buffer);
154 #else
155 error = IOCS_S_READ(8 >> current_blklen, 8 >> current_blklen,
156 id, current_blklen, buffer);
157 #endif
158 if (error < 0)
159 return EIO;
160 parttbl = (void*) (buffer + DOSBBSECTOR);
161 if (strncmp (buffer, "X68K", 4) != 0)
162 return EUNLAB;
163 parttbl++;
164 for (current_npart = 0, i = 0;
165 current_npart < MAXPARTITIONS && i < 15 && parttbl[i].dp_size;
166 i++) {
167 partitions[current_npart].start
168 = parttbl[i].dp_start * 2;
169 partitions[current_npart].size
170 = parttbl[i].dp_size * 2;
171 if (++current_npart == RAW_PART) {
172 partitions[current_npart].start = 0;
173 partitions[current_npart].size = -1; /* XXX */
174 current_npart++;
175 }
176 }
177 #ifdef DEBUG
178 for (i = 0; i < current_npart; i++) {
179 printf ("%d: starts %d, size %d\n", i,
180 partitions[i].start,
181 partitions[i].size);
182 }
183 #endif
184 current_id = id;
185
186 return 0;
187 }
188
189 int
190 sd_getbsdpartition (int id, int humanpart)
191 {
192 int error, i;
193 char *buffer;
194 struct dos_partition *parttbl;
195 unsigned parttop;
196
197 if (humanpart < 2)
198 humanpart++;
199
200 error = readdisklabel(id);
201 if (error) {
202 printf ("Reading disklabel: %s\n", strerror(error));
203 return -1;
204 }
205 buffer = alloca(2048);
206 error = IOCS_S_READ(8 >> current_blklen, 8 >> current_blklen,
207 id, current_blklen, buffer);
208 if (error < 0) {
209 printf ("Reading partition table: %s\n", strerror(error));
210 return -1;
211 }
212 parttbl = (void*) (buffer + DOSBBSECTOR);
213 if (strncmp (buffer, "X68K", 4) != 0)
214 return 0;
215 parttop = parttbl[humanpart].dp_start;
216 parttop = parttop<<(2-current_blklen);
217
218 for (i = 0; i < current_npart; i++) {
219 if (partitions[i].start == parttop)
220 return i;
221 }
222
223 printf ("Could not determine the boot partition.\n");
224
225 return -1;
226 }
227
228 struct sdcd_softc {
229 int sc_part;
230 struct boot_partinfo sc_partinfo;
231 int sc_blocksize;
232 };
233
234 int
235 sdopen (struct open_file *f, int id, int part)
236 {
237 int error;
238 struct sdcd_softc *sc;
239
240 if (id < 0 || id > 7)
241 return ENXIO;
242 if (current_id != id) {
243 error = readdisklabel(id);
244 if (error)
245 return error;
246 }
247 if (part >= current_npart)
248 return ENXIO;
249
250 sc = alloc (sizeof (struct sdcd_softc));
251 sc->sc_part = part;
252 sc->sc_partinfo = partitions[part];
253 sc->sc_blocksize = current_blklen << 9;
254 f->f_devdata = sc;
255 return 0;
256 }
257
258 int
259 sdclose (struct open_file *f)
260 {
261 free (f->f_devdata, sizeof (struct sdcd_softc));
262 return 0;
263 }
264
265 int
266 sdstrategy (void *arg, int rw, daddr_t dblk, size_t size,
267 void *buf, size_t *rsize)
268 {
269 struct sdcd_softc *sc = arg;
270 u_int32_t start = sc->sc_partinfo.start + dblk;
271 size_t nblks;
272 int error;
273
274 if (size == 0) {
275 if (rsize)
276 *rsize = 0;
277 return 0;
278 }
279 nblks = howmany (size, 256 << current_blklen);
280
281 if (dblk & 0x1fffff == 0x1fffff && (nblks & 0xff) == nblks) {
282 if (rw & F_WRITE)
283 error = IOCS_S_WRITE (start, nblks, current_id,
284 current_blklen, buf);
285 else
286 error = IOCS_S_READ (start, nblks, current_id,
287 current_blklen, buf);
288 } else {
289 if (rw & F_WRITE)
290 error = IOCS_S_WRITEEXT (start, nblks, current_id,
291 current_blklen, buf);
292 else
293 error = IOCS_S_READEXT (start, nblks, current_id,
294 current_blklen, buf);
295 }
296 if (error < 0)
297 return EIO;
298
299 if (rsize)
300 *rsize = size;
301 return 0;
302 }
303
304 int
305 cdopen (struct open_file *f, int id, int part)
306 {
307 int error;
308 struct sdcd_softc *sc;
309
310 if (id < 0 || id > 7)
311 return ENXIO;
312 if (part == 0 || part == 2)
313 return ENXIO;
314 if (current_id != id) {
315 error = check_unit(id);
316 if (error)
317 return error;
318 }
319
320 sc = alloc (sizeof (struct sdcd_softc));
321 current_npart = 3;
322 sc->sc_part = 0;
323 sc->sc_partinfo.size = sc->sc_partinfo.size = current_devsize;
324 sc->sc_blocksize = current_blklen << 9;
325 f->f_devdata = sc;
326 return 0;
327 }
328
329 int
330 cdclose (struct open_file *f)
331 {
332 free (f->f_devdata, sizeof (struct sdcd_softc));
333 return 0;
334 }
335
336 int
337 cdstrategy (void *arg, int rw, daddr_t dblk, size_t size,
338 void *buf, size_t *rsize)
339 {
340 struct sdcd_softc *sc = arg;
341
342 return sdstrategy (arg, rw, dblk * DEV_BSIZE / sc->sc_blocksize,
343 size, buf, rsize);
344 }
345