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