sdcd.c revision 1.1 1 /* $NetBSD: sdcd.c,v 1.1 2001/09/27 10:03:28 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_getpartition (int id, unsigned parttop)
191 {
192 int error, i;
193
194 error = readdisklabel(id);
195 if (error) {
196 printf ("Reading disklabel: %s\n", strerror(error));
197 return -1;
198 }
199
200 for (i = 0; i < current_npart; i++) {
201 if (partitions[i].start == parttop)
202 return i;
203 }
204
205 printf ("Could not determine the boot partition.\n");
206
207 return -1;
208 }
209
210 struct sdcd_softc {
211 int sc_part;
212 struct boot_partinfo sc_partinfo;
213 int sc_blocksize;
214 };
215
216 int
217 sdopen (struct open_file *f, int id, int part)
218 {
219 int error;
220 struct sdcd_softc *sc;
221
222 if (id < 0 || id > 7)
223 return ENXIO;
224 if (current_id != id) {
225 error = readdisklabel(id);
226 if (error)
227 return error;
228 }
229 if (part >= current_npart)
230 return ENXIO;
231
232 sc = alloc (sizeof (struct sdcd_softc));
233 sc->sc_part = part;
234 sc->sc_partinfo = partitions[part];
235 sc->sc_blocksize = current_blklen << 9;
236 f->f_devdata = sc;
237 return 0;
238 }
239
240 int
241 sdclose (struct open_file *f)
242 {
243 free (f->f_devdata, sizeof (struct sdcd_softc));
244 return 0;
245 }
246
247 int
248 sdstrategy (void *arg, int rw, daddr_t dblk, size_t size,
249 void *buf, size_t *rsize)
250 {
251 struct sdcd_softc *sc = arg;
252 u_int32_t start = sc->sc_partinfo.start + dblk;
253 size_t nblks;
254 int error;
255
256 if (size == 0) {
257 if (rsize)
258 *rsize = 0;
259 return 0;
260 }
261 nblks = howmany (size, 256 << current_blklen);
262
263 if (dblk & 0x1fffff == 0x1fffff && (nblks & 0xff) == nblks) {
264 if (rw & F_WRITE)
265 error = IOCS_S_WRITE (start, nblks, current_id,
266 current_blklen, buf);
267 else
268 error = IOCS_S_READ (start, nblks, current_id,
269 current_blklen, buf);
270 } else {
271 if (rw & F_WRITE)
272 error = IOCS_S_WRITEEXT (start, nblks, current_id,
273 current_blklen, buf);
274 else
275 error = IOCS_S_READEXT (start, nblks, current_id,
276 current_blklen, buf);
277 }
278 if (error < 0)
279 return EIO;
280
281 if (rsize)
282 *rsize = size;
283 return 0;
284 }
285
286 int
287 cdopen (struct open_file *f, int id, int part)
288 {
289 int error;
290 struct sdcd_softc *sc;
291
292 if (id < 0 || id > 7)
293 return ENXIO;
294 if (part == 0 || part == 2)
295 return ENXIO;
296 if (current_id != id) {
297 error = check_unit(id);
298 if (error)
299 return error;
300 }
301
302 sc = alloc (sizeof (struct sdcd_softc));
303 current_npart = 3;
304 sc->sc_part = 0;
305 sc->sc_partinfo.size = sc->sc_partinfo.size = current_devsize;
306 sc->sc_blocksize = current_blklen << 9;
307 f->f_devdata = sc;
308 return 0;
309 }
310
311 int
312 cdclose (struct open_file *f)
313 {
314 free (f->f_devdata, sizeof (struct sdcd_softc));
315 return 0;
316 }
317
318 int
319 cdstrategy (void *arg, int rw, daddr_t dblk, size_t size,
320 void *buf, size_t *rsize)
321 {
322 struct sdcd_softc *sc = arg;
323
324 return sdstrategy (arg, rw, dblk * DEV_BSIZE / sc->sc_blocksize,
325 size, buf, rsize);
326 }
327