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