xref: /netbsd/sys/arch/x68k/stand/libsa/sdcd.c (revision 73055e2f)
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