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