sdcd.c revision 1.3 1 /* $NetBSD: sdcd.c,v 1.3 2001/10/15 16:07:20 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 goto done;
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 done:
178 #ifdef DEBUG
179 for (i = 0; i < current_npart; i++) {
180 printf ("%d: starts %d, size %d\n", i,
181 partitions[i].start,
182 partitions[i].size);
183 }
184 #endif
185 current_id = id;
186
187 return 0;
188 }
189
190 int
191 sd_getbsdpartition (int id, int humanpart)
192 {
193 int error, i;
194 char *buffer;
195 struct dos_partition *parttbl;
196 unsigned parttop;
197
198 if (humanpart < 2)
199 humanpart++;
200
201 error = readdisklabel(id);
202 if (error) {
203 printf ("Reading disklabel: %s\n", strerror(error));
204 return -1;
205 }
206 buffer = alloca(2048);
207 error = IOCS_S_READ(8 >> current_blklen, 8 >> current_blklen,
208 id, current_blklen, buffer);
209 if (error < 0) {
210 printf ("Reading partition table: %s\n", strerror(error));
211 return -1;
212 }
213 parttbl = (void*) (buffer + DOSBBSECTOR);
214 if (strncmp (buffer, "X68K", 4) != 0)
215 return 0;
216 parttop = parttbl[humanpart].dp_start;
217 parttop = parttop<<(2-current_blklen);
218
219 for (i = 0; i < current_npart; i++) {
220 if (partitions[i].start == parttop)
221 return i;
222 }
223
224 printf ("Could not determine the boot partition.\n");
225
226 return -1;
227 }
228
229 struct sdcd_softc {
230 int sc_part;
231 struct boot_partinfo sc_partinfo;
232 int sc_blocksize;
233 };
234
235 int
236 sdopen (struct open_file *f, int id, int part)
237 {
238 int error;
239 struct sdcd_softc *sc;
240
241 if (id < 0 || id > 7)
242 return ENXIO;
243 if (current_id != id) {
244 error = readdisklabel(id);
245 if (error)
246 return error;
247 }
248 if (part >= current_npart)
249 return ENXIO;
250
251 sc = alloc (sizeof (struct sdcd_softc));
252 sc->sc_part = part;
253 sc->sc_partinfo = partitions[part];
254 sc->sc_blocksize = current_blklen << 9;
255 f->f_devdata = sc;
256 return 0;
257 }
258
259 int
260 sdclose (struct open_file *f)
261 {
262 free (f->f_devdata, sizeof (struct sdcd_softc));
263 return 0;
264 }
265
266 int
267 sdstrategy (void *arg, int rw, daddr_t dblk, size_t size,
268 void *buf, size_t *rsize)
269 {
270 struct sdcd_softc *sc = arg;
271 u_int32_t start = sc->sc_partinfo.start + dblk;
272 size_t nblks;
273 int error;
274
275 if (size == 0) {
276 if (rsize)
277 *rsize = 0;
278 return 0;
279 }
280 nblks = howmany (size, 256 << current_blklen);
281
282 if (dblk & 0x1fffff == 0x1fffff && (nblks & 0xff) == nblks) {
283 if (rw & F_WRITE)
284 error = IOCS_S_WRITE (start, nblks, current_id,
285 current_blklen, buf);
286 else
287 error = IOCS_S_READ (start, nblks, current_id,
288 current_blklen, buf);
289 } else {
290 if (rw & F_WRITE)
291 error = IOCS_S_WRITEEXT (start, nblks, current_id,
292 current_blklen, buf);
293 else
294 error = IOCS_S_READEXT (start, nblks, current_id,
295 current_blklen, buf);
296 }
297 if (error < 0)
298 return EIO;
299
300 if (rsize)
301 *rsize = size;
302 return 0;
303 }
304
305 int
306 cdopen (struct open_file *f, int id, int part)
307 {
308 int error;
309 struct sdcd_softc *sc;
310
311 if (id < 0 || id > 7)
312 return ENXIO;
313 if (part == 0 || part == 2)
314 return ENXIO;
315 if (current_id != id) {
316 error = check_unit(id);
317 if (error)
318 return error;
319 }
320
321 sc = alloc (sizeof (struct sdcd_softc));
322 current_npart = 3;
323 sc->sc_part = 0;
324 sc->sc_partinfo.size = sc->sc_partinfo.size = current_devsize;
325 sc->sc_blocksize = current_blklen << 9;
326 f->f_devdata = sc;
327 return 0;
328 }
329
330 int
331 cdclose (struct open_file *f)
332 {
333 free (f->f_devdata, sizeof (struct sdcd_softc));
334 return 0;
335 }
336
337 int
338 cdstrategy (void *arg, int rw, daddr_t dblk, size_t size,
339 void *buf, size_t *rsize)
340 {
341 struct sdcd_softc *sc = arg;
342
343 return sdstrategy (arg, rw, dblk * DEV_BSIZE / sc->sc_blocksize,
344 size, buf, rsize);
345 }
346