sdcd.c revision 1.19 1 1.19 isaki /* $NetBSD: sdcd.c,v 1.19 2024/01/07 07:58:34 isaki 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.17 isaki #include <sys/bitops.h>
30 1.1 minoura #include <sys/disklabel.h>
31 1.1 minoura #include <lib/libkern/libkern.h>
32 1.1 minoura #include <lib/libsa/stand.h>
33 1.1 minoura
34 1.8 isaki #include "libx68k.h"
35 1.1 minoura #include "sdcdvar.h"
36 1.1 minoura #include "iocs.h"
37 1.1 minoura
38 1.1 minoura
39 1.1 minoura static int current_id = -1;
40 1.17 isaki static int current_blkbytes;
41 1.17 isaki static int current_blkshift;
42 1.17 isaki static int current_devsize, current_npart;
43 1.1 minoura static struct boot_partinfo partitions[MAXPARTITIONS];
44 1.1 minoura
45 1.17 isaki static uint human2blk(uint);
46 1.17 isaki static uint human2bsd(uint);
47 1.17 isaki static uint bsd2blk(uint);
48 1.1 minoura static int readdisklabel(int);
49 1.1 minoura static int check_unit(int);
50 1.1 minoura
51 1.1 minoura #ifdef DEBUG
52 1.1 minoura #define DPRINTF(x) printf x
53 1.1 minoura #else
54 1.19 isaki #define DPRINTF(x)
55 1.1 minoura #endif
56 1.1 minoura
57 1.17 isaki /*
58 1.17 isaki * Convert the number of sectors on Human68k
59 1.17 isaki * into the number of blocks on the current device.
60 1.17 isaki */
61 1.17 isaki static uint
62 1.17 isaki human2blk(uint n)
63 1.17 isaki {
64 1.17 isaki uint blk_per_sect;
65 1.17 isaki
66 1.17 isaki /* Human68k uses 1024 byte/sector. */
67 1.17 isaki blk_per_sect = 4 >> current_blkshift;
68 1.17 isaki if (blk_per_sect == 0)
69 1.17 isaki blk_per_sect = 1;
70 1.17 isaki return blk_per_sect * n;
71 1.17 isaki }
72 1.17 isaki
73 1.17 isaki /*
74 1.17 isaki * Convert the number of sectors on Human68k
75 1.17 isaki * into the number of DEV_BSIZE sectors.
76 1.17 isaki */
77 1.17 isaki static uint
78 1.17 isaki human2bsd(uint n)
79 1.17 isaki {
80 1.17 isaki
81 1.17 isaki return n * (1024 / DEV_BSIZE);
82 1.17 isaki }
83 1.17 isaki
84 1.17 isaki /*
85 1.17 isaki * Convert the number of DEV_BSIZE sectors
86 1.17 isaki * into the number of blocks on the current device.
87 1.17 isaki */
88 1.17 isaki static uint
89 1.17 isaki bsd2blk(uint n)
90 1.17 isaki {
91 1.17 isaki
92 1.17 isaki return ((DEV_BSIZE / 256) * n) >> current_blkshift;
93 1.17 isaki }
94 1.17 isaki
95 1.1 minoura static int
96 1.1 minoura check_unit(int id)
97 1.1 minoura {
98 1.1 minoura #define BUFFER_SIZE 8192
99 1.1 minoura int error;
100 1.1 minoura void *buffer = alloca(BUFFER_SIZE);
101 1.1 minoura
102 1.1 minoura if (current_id == id)
103 1.1 minoura return 0;
104 1.1 minoura
105 1.1 minoura current_id = -1;
106 1.1 minoura
107 1.1 minoura error = IOCS_S_TESTUNIT(id);
108 1.1 minoura if (error < 0) { /* not ready */
109 1.1 minoura error = ENXIO;
110 1.1 minoura goto out;
111 1.1 minoura }
112 1.1 minoura
113 1.1 minoura {
114 1.15 tsutsui struct iocs_inquiry *inqdata = buffer;
115 1.1 minoura
116 1.15 tsutsui error = IOCS_S_INQUIRY(sizeof(*inqdata), id, inqdata);
117 1.1 minoura if (error < 0) { /* WHY??? */
118 1.1 minoura error = ENXIO;
119 1.1 minoura goto out;
120 1.1 minoura }
121 1.1 minoura if ((inqdata->unit != 0) && /* direct */
122 1.12 minoura (inqdata->unit != 5) && /* cdrom */
123 1.1 minoura (inqdata->unit != 7)) { /* optical */
124 1.1 minoura error = EUNIT;
125 1.1 minoura goto out;
126 1.1 minoura }
127 1.1 minoura }
128 1.1 minoura
129 1.1 minoura {
130 1.1 minoura struct iocs_readcap *rcdata = buffer;
131 1.1 minoura
132 1.1 minoura error = IOCS_S_READCAP(id, rcdata);
133 1.1 minoura if (error < 0) { /* WHY??? */
134 1.1 minoura error = EUNIT;
135 1.1 minoura goto out;
136 1.1 minoura }
137 1.17 isaki current_blkbytes = rcdata->size;
138 1.17 isaki current_blkshift = fls32(current_blkbytes) - 9;
139 1.1 minoura current_devsize = rcdata->block;
140 1.1 minoura }
141 1.1 minoura
142 1.1 minoura {
143 1.17 isaki error = IOCS_S_READ(0, 1, id, current_blkshift, buffer);
144 1.1 minoura if (error < 0) {
145 1.1 minoura error = EIO;
146 1.1 minoura goto out;
147 1.1 minoura }
148 1.7 isaki if (strncmp((char *)buffer, "X68SCSI1", 8) != 0) {
149 1.1 minoura error = EUNLAB;
150 1.1 minoura goto out;
151 1.1 minoura }
152 1.1 minoura }
153 1.1 minoura
154 1.1 minoura out:
155 1.1 minoura return error;
156 1.1 minoura }
157 1.1 minoura
158 1.1 minoura static int
159 1.7 isaki readdisklabel(int id)
160 1.1 minoura {
161 1.1 minoura int error, i;
162 1.1 minoura char *buffer;
163 1.1 minoura struct disklabel *label;
164 1.1 minoura struct dos_partition *parttbl;
165 1.1 minoura
166 1.1 minoura if (current_id == id)
167 1.1 minoura return 0;
168 1.1 minoura current_id = -1;
169 1.1 minoura
170 1.1 minoura error = check_unit(id);
171 1.1 minoura if (error)
172 1.1 minoura return error;
173 1.17 isaki if (current_blkbytes > 2048) {
174 1.9 tsutsui printf("FATAL: Unsupported block size %d.\n",
175 1.17 isaki current_blkbytes);
176 1.1 minoura return ERDLAB;
177 1.1 minoura }
178 1.1 minoura
179 1.1 minoura /* Try BSD disklabel first */
180 1.1 minoura buffer = alloca(2048);
181 1.17 isaki error = IOCS_S_READ(LABELSECTOR, 1, id, current_blkshift, buffer);
182 1.1 minoura if (error < 0)
183 1.1 minoura return EIO;
184 1.7 isaki label = (void *)(buffer + LABELOFFSET);
185 1.1 minoura if (label->d_magic == DISKMAGIC &&
186 1.1 minoura label->d_magic2 == DISKMAGIC) {
187 1.1 minoura for (i = 0; i < label->d_npartitions; i++) {
188 1.1 minoura partitions[i].start = label->d_partitions[i].p_offset;
189 1.1 minoura partitions[i].size = label->d_partitions[i].p_size;
190 1.1 minoura }
191 1.1 minoura current_npart = label->d_npartitions;
192 1.1 minoura
193 1.3 minoura goto done;
194 1.1 minoura }
195 1.1 minoura
196 1.1 minoura /* Try Human68K-style partition table */
197 1.17 isaki error = IOCS_S_READ(human2blk(2), 1, id, current_blkshift, buffer);
198 1.1 minoura if (error < 0)
199 1.1 minoura return EIO;
200 1.7 isaki parttbl = (void *)(buffer + DOSBBSECTOR);
201 1.7 isaki if (strncmp(buffer, "X68K", 4) != 0)
202 1.1 minoura return EUNLAB;
203 1.1 minoura parttbl++;
204 1.1 minoura for (current_npart = 0, i = 0;
205 1.1 minoura current_npart < MAXPARTITIONS && i < 15 && parttbl[i].dp_size;
206 1.1 minoura i++) {
207 1.1 minoura partitions[current_npart].start
208 1.17 isaki = human2bsd(parttbl[i].dp_start);
209 1.1 minoura partitions[current_npart].size
210 1.17 isaki = human2bsd(parttbl[i].dp_size);
211 1.1 minoura if (++current_npart == RAW_PART) {
212 1.1 minoura partitions[current_npart].start = 0;
213 1.1 minoura partitions[current_npart].size = -1; /* XXX */
214 1.1 minoura current_npart++;
215 1.1 minoura }
216 1.1 minoura }
217 1.3 minoura done:
218 1.1 minoura #ifdef DEBUG
219 1.1 minoura for (i = 0; i < current_npart; i++) {
220 1.1 minoura printf ("%d: starts %d, size %d\n", i,
221 1.1 minoura partitions[i].start,
222 1.1 minoura partitions[i].size);
223 1.1 minoura }
224 1.1 minoura #endif
225 1.1 minoura current_id = id;
226 1.1 minoura
227 1.1 minoura return 0;
228 1.1 minoura }
229 1.1 minoura
230 1.1 minoura int
231 1.7 isaki sd_getbsdpartition(int id, int humanpart)
232 1.1 minoura {
233 1.1 minoura int error, i;
234 1.2 minoura char *buffer;
235 1.2 minoura struct dos_partition *parttbl;
236 1.2 minoura unsigned parttop;
237 1.2 minoura
238 1.2 minoura if (humanpart < 2)
239 1.2 minoura humanpart++;
240 1.1 minoura
241 1.1 minoura error = readdisklabel(id);
242 1.1 minoura if (error) {
243 1.7 isaki printf("Reading disklabel: %s\n", strerror(error));
244 1.1 minoura return -1;
245 1.1 minoura }
246 1.2 minoura buffer = alloca(2048);
247 1.17 isaki error = IOCS_S_READ(human2blk(2), 1, id, current_blkshift, buffer);
248 1.2 minoura if (error < 0) {
249 1.7 isaki printf("Reading partition table: %s\n", strerror(error));
250 1.2 minoura return -1;
251 1.2 minoura }
252 1.7 isaki parttbl = (void *)(buffer + DOSBBSECTOR);
253 1.7 isaki if (strncmp(buffer, "X68K", 4) != 0)
254 1.2 minoura return 0;
255 1.17 isaki parttop = human2bsd(parttbl[humanpart].dp_start);
256 1.1 minoura
257 1.1 minoura for (i = 0; i < current_npart; i++) {
258 1.1 minoura if (partitions[i].start == parttop)
259 1.1 minoura return i;
260 1.1 minoura }
261 1.1 minoura
262 1.7 isaki printf("Could not determine the boot partition.\n");
263 1.1 minoura
264 1.1 minoura return -1;
265 1.1 minoura }
266 1.1 minoura
267 1.1 minoura struct sdcd_softc {
268 1.1 minoura int sc_part;
269 1.1 minoura struct boot_partinfo sc_partinfo;
270 1.1 minoura };
271 1.1 minoura
272 1.8 isaki /* sdopen(struct open_file *f, int id, int part) */
273 1.1 minoura int
274 1.8 isaki sdopen(struct open_file *f, ...)
275 1.1 minoura {
276 1.1 minoura int error;
277 1.1 minoura struct sdcd_softc *sc;
278 1.8 isaki int id, part;
279 1.8 isaki va_list ap;
280 1.8 isaki
281 1.8 isaki va_start(ap, f);
282 1.8 isaki id = va_arg(ap, int);
283 1.8 isaki part = va_arg(ap, int);
284 1.8 isaki va_end(ap);
285 1.1 minoura
286 1.1 minoura if (id < 0 || id > 7)
287 1.1 minoura return ENXIO;
288 1.1 minoura if (current_id != id) {
289 1.1 minoura error = readdisklabel(id);
290 1.1 minoura if (error)
291 1.1 minoura return error;
292 1.1 minoura }
293 1.1 minoura if (part >= current_npart)
294 1.1 minoura return ENXIO;
295 1.1 minoura
296 1.7 isaki sc = alloc(sizeof(struct sdcd_softc));
297 1.1 minoura sc->sc_part = part;
298 1.1 minoura sc->sc_partinfo = partitions[part];
299 1.1 minoura f->f_devdata = sc;
300 1.1 minoura return 0;
301 1.1 minoura }
302 1.1 minoura
303 1.1 minoura int
304 1.18 isaki sdcdclose(struct open_file *f)
305 1.1 minoura {
306 1.9 tsutsui
307 1.7 isaki dealloc(f->f_devdata, sizeof(struct sdcd_softc));
308 1.1 minoura return 0;
309 1.1 minoura }
310 1.1 minoura
311 1.1 minoura int
312 1.18 isaki sdcdstrategy(void *arg, int rw, daddr_t dblk, size_t size,
313 1.7 isaki void *buf, size_t *rsize)
314 1.1 minoura {
315 1.1 minoura struct sdcd_softc *sc = arg;
316 1.9 tsutsui uint32_t start = sc->sc_partinfo.start + dblk;
317 1.1 minoura size_t nblks;
318 1.1 minoura int error;
319 1.1 minoura
320 1.1 minoura if (size == 0) {
321 1.1 minoura if (rsize)
322 1.1 minoura *rsize = 0;
323 1.1 minoura return 0;
324 1.1 minoura }
325 1.17 isaki start = bsd2blk(start);
326 1.17 isaki nblks = howmany(size, current_blkbytes);
327 1.1 minoura
328 1.16 isaki if (start < 0x200000 && nblks < 256) {
329 1.1 minoura if (rw & F_WRITE)
330 1.7 isaki error = IOCS_S_WRITE(start, nblks, current_id,
331 1.17 isaki current_blkshift, buf);
332 1.1 minoura else
333 1.7 isaki error = IOCS_S_READ(start, nblks, current_id,
334 1.17 isaki current_blkshift, buf);
335 1.1 minoura } else {
336 1.1 minoura if (rw & F_WRITE)
337 1.7 isaki error = IOCS_S_WRITEEXT(start, nblks, current_id,
338 1.17 isaki current_blkshift, buf);
339 1.1 minoura else
340 1.7 isaki error = IOCS_S_READEXT(start, nblks, current_id,
341 1.17 isaki current_blkshift, buf);
342 1.1 minoura }
343 1.1 minoura if (error < 0)
344 1.1 minoura return EIO;
345 1.1 minoura
346 1.1 minoura if (rsize)
347 1.1 minoura *rsize = size;
348 1.1 minoura return 0;
349 1.1 minoura }
350 1.1 minoura
351 1.8 isaki /* cdopen(struct open_file *f, int id, int part) */
352 1.1 minoura int
353 1.8 isaki cdopen(struct open_file *f, ...)
354 1.1 minoura {
355 1.1 minoura int error;
356 1.1 minoura struct sdcd_softc *sc;
357 1.8 isaki int id, part;
358 1.8 isaki va_list ap;
359 1.8 isaki
360 1.8 isaki va_start(ap, f);
361 1.8 isaki id = va_arg(ap, int);
362 1.8 isaki part = va_arg(ap, int);
363 1.8 isaki va_end(ap);
364 1.1 minoura
365 1.1 minoura if (id < 0 || id > 7)
366 1.1 minoura return ENXIO;
367 1.12 minoura if (part != 0 && part != 2)
368 1.1 minoura return ENXIO;
369 1.1 minoura if (current_id != id) {
370 1.1 minoura error = check_unit(id);
371 1.1 minoura if (error)
372 1.1 minoura return error;
373 1.1 minoura }
374 1.1 minoura
375 1.7 isaki sc = alloc(sizeof(struct sdcd_softc));
376 1.1 minoura current_npart = 3;
377 1.1 minoura sc->sc_part = 0;
378 1.14 tsutsui sc->sc_partinfo.start = 0;
379 1.10 mrg sc->sc_partinfo.size = current_devsize;
380 1.1 minoura f->f_devdata = sc;
381 1.12 minoura current_id = id;
382 1.12 minoura
383 1.1 minoura return 0;
384 1.1 minoura }
385