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