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