sdcd.c revision 1.4 1 /* $NetBSD: sdcd.c,v 1.4 2001/10/15 16:13:40 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 int sdopen(struct open_file *, int, int);
42 int sdclose(struct open_file*);
43 int sdstrategy(void *devdata, int rw, daddr_t blk, size_t, void*, size_t*);
44 int sd_getbsdpartition(int, int);
45 int cdopen(struct open_file *, int, int);
46 int cdclose(struct open_file*);
47 int cdstrategy(void *devdata, int rw, daddr_t blk, size_t, void*, size_t*);
48
49 static int readdisklabel(int);
50 static int check_unit(int);
51
52 #ifdef DEBUG
53 #define DPRINTF(x) printf x
54 #else
55 #define DPRINTF(x)
56 #endif
57 #define alloca __builtin_alloca
58
59 static int
60 check_unit(int id)
61 {
62 #define BUFFER_SIZE 8192
63 int error;
64 void *buffer = alloca(BUFFER_SIZE);
65
66 if (current_id == id)
67 return 0;
68
69 current_id = -1;
70
71 error = IOCS_S_TESTUNIT(id);
72 if (error < 0) { /* not ready */
73 error = ENXIO;
74 goto out;
75 }
76
77 {
78 struct iocs_inquiry *inqdata = buffer;
79
80 error = IOCS_S_INQUIRY(100, id, inqdata);
81 if (error < 0) { /* WHY??? */
82 error = ENXIO;
83 goto out;
84 }
85 if ((inqdata->unit != 0) && /* direct */
86 (inqdata->unit != 7)) { /* optical */
87 error = EUNIT;
88 goto out;
89 }
90 }
91
92 {
93 struct iocs_readcap *rcdata = buffer;
94
95 error = IOCS_S_READCAP(id, rcdata);
96 if (error < 0) { /* WHY??? */
97 error = EUNIT;
98 goto out;
99 }
100 current_blklen = rcdata->size >> 9;
101 current_devsize = rcdata->block;
102 }
103
104 {
105 error = IOCS_S_READ(0, 1, id, current_blklen, buffer);
106 if (error < 0) {
107 error = EIO;
108 goto out;
109 }
110 if (strncmp((char*) buffer, "X68SCSI1", 8) != 0) {
111 error = EUNLAB;
112 goto out;
113 }
114 }
115
116 out:
117 return error;
118 }
119
120 static int
121 readdisklabel (int id)
122 {
123 int error, i;
124 char *buffer;
125 struct disklabel *label;
126 struct dos_partition *parttbl;
127
128 if (current_id == id)
129 return 0;
130 current_id = -1;
131
132 error = check_unit(id);
133 if (error)
134 return error;
135 if (current_blklen > 4) {
136 printf ("FATAL: Unsupported block size %d.\n",
137 256 << current_blklen);
138 return ERDLAB;
139 }
140
141 /* Try BSD disklabel first */
142 buffer = alloca(2048);
143 error = IOCS_S_READ(LABELSECTOR, 1, id, current_blklen, buffer);
144 if (error < 0)
145 return EIO;
146 label = (void*) (buffer + LABELOFFSET);
147 if (label->d_magic == DISKMAGIC &&
148 label->d_magic2 == DISKMAGIC) {
149 for (i = 0; i < label->d_npartitions; i++) {
150 partitions[i].start = label->d_partitions[i].p_offset;
151 partitions[i].size = label->d_partitions[i].p_size;
152 }
153 current_npart = label->d_npartitions;
154
155 goto done;
156 }
157
158 /* Try Human68K-style partition table */
159 #if 0
160 /* assumes 512byte/sec */
161 error = IOCS_S_READ(DOSPARTOFF, 2, id, current_blklen, buffer);
162 #else
163 error = IOCS_S_READ(8 >> current_blklen, 8 >> current_blklen,
164 id, current_blklen, buffer);
165 #endif
166 if (error < 0)
167 return EIO;
168 parttbl = (void*) (buffer + DOSBBSECTOR);
169 if (strncmp (buffer, "X68K", 4) != 0)
170 return EUNLAB;
171 parttbl++;
172 for (current_npart = 0, i = 0;
173 current_npart < MAXPARTITIONS && i < 15 && parttbl[i].dp_size;
174 i++) {
175 partitions[current_npart].start
176 = parttbl[i].dp_start * 2;
177 partitions[current_npart].size
178 = parttbl[i].dp_size * 2;
179 if (++current_npart == RAW_PART) {
180 partitions[current_npart].start = 0;
181 partitions[current_npart].size = -1; /* XXX */
182 current_npart++;
183 }
184 }
185 done:
186 #ifdef DEBUG
187 for (i = 0; i < current_npart; i++) {
188 printf ("%d: starts %d, size %d\n", i,
189 partitions[i].start,
190 partitions[i].size);
191 }
192 #endif
193 current_id = id;
194
195 return 0;
196 }
197
198 int
199 sd_getbsdpartition (int id, int humanpart)
200 {
201 int error, i;
202 char *buffer;
203 struct dos_partition *parttbl;
204 unsigned parttop;
205
206 if (humanpart < 2)
207 humanpart++;
208
209 error = readdisklabel(id);
210 if (error) {
211 printf ("Reading disklabel: %s\n", strerror(error));
212 return -1;
213 }
214 buffer = alloca(2048);
215 error = IOCS_S_READ(8 >> current_blklen, 8 >> current_blklen,
216 id, current_blklen, buffer);
217 if (error < 0) {
218 printf ("Reading partition table: %s\n", strerror(error));
219 return -1;
220 }
221 parttbl = (void*) (buffer + DOSBBSECTOR);
222 if (strncmp (buffer, "X68K", 4) != 0)
223 return 0;
224 parttop = parttbl[humanpart].dp_start;
225 parttop = parttop<<(2-current_blklen);
226
227 for (i = 0; i < current_npart; i++) {
228 if (partitions[i].start == parttop)
229 return i;
230 }
231
232 printf ("Could not determine the boot partition.\n");
233
234 return -1;
235 }
236
237 struct sdcd_softc {
238 int sc_part;
239 struct boot_partinfo sc_partinfo;
240 int sc_blocksize;
241 };
242
243 int
244 sdopen (struct open_file *f, int id, int part)
245 {
246 int error;
247 struct sdcd_softc *sc;
248
249 if (id < 0 || id > 7)
250 return ENXIO;
251 if (current_id != id) {
252 error = readdisklabel(id);
253 if (error)
254 return error;
255 }
256 if (part >= current_npart)
257 return ENXIO;
258
259 sc = alloc (sizeof (struct sdcd_softc));
260 sc->sc_part = part;
261 sc->sc_partinfo = partitions[part];
262 sc->sc_blocksize = current_blklen << 9;
263 f->f_devdata = sc;
264 return 0;
265 }
266
267 int
268 sdclose (struct open_file *f)
269 {
270 free (f->f_devdata, sizeof (struct sdcd_softc));
271 return 0;
272 }
273
274 int
275 sdstrategy (void *arg, int rw, daddr_t dblk, size_t size,
276 void *buf, size_t *rsize)
277 {
278 struct sdcd_softc *sc = arg;
279 u_int32_t start = sc->sc_partinfo.start + dblk;
280 size_t nblks;
281 int error;
282
283 if (size == 0) {
284 if (rsize)
285 *rsize = 0;
286 return 0;
287 }
288 nblks = howmany (size, 256 << current_blklen);
289
290 if ((dblk & 0x1fffff) == 0x1fffff && (nblks & 0xff) == nblks) {
291 if (rw & F_WRITE)
292 error = IOCS_S_WRITE (start, nblks, current_id,
293 current_blklen, buf);
294 else
295 error = IOCS_S_READ (start, nblks, current_id,
296 current_blklen, buf);
297 } else {
298 if (rw & F_WRITE)
299 error = IOCS_S_WRITEEXT (start, nblks, current_id,
300 current_blklen, buf);
301 else
302 error = IOCS_S_READEXT (start, nblks, current_id,
303 current_blklen, buf);
304 }
305 if (error < 0)
306 return EIO;
307
308 if (rsize)
309 *rsize = size;
310 return 0;
311 }
312
313 int
314 cdopen (struct open_file *f, int id, int part)
315 {
316 int error;
317 struct sdcd_softc *sc;
318
319 if (id < 0 || id > 7)
320 return ENXIO;
321 if (part == 0 || part == 2)
322 return ENXIO;
323 if (current_id != id) {
324 error = check_unit(id);
325 if (error)
326 return error;
327 }
328
329 sc = alloc (sizeof (struct sdcd_softc));
330 current_npart = 3;
331 sc->sc_part = 0;
332 sc->sc_partinfo.size = sc->sc_partinfo.size = current_devsize;
333 sc->sc_blocksize = current_blklen << 9;
334 f->f_devdata = sc;
335 return 0;
336 }
337
338 int
339 cdclose (struct open_file *f)
340 {
341 free (f->f_devdata, sizeof (struct sdcd_softc));
342 return 0;
343 }
344
345 int
346 cdstrategy (void *arg, int rw, daddr_t dblk, size_t size,
347 void *buf, size_t *rsize)
348 {
349 struct sdcd_softc *sc = arg;
350
351 return sdstrategy (arg, rw, dblk * DEV_BSIZE / sc->sc_blocksize,
352 size, buf, rsize);
353 }
354