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