Home | History | Annotate | Line # | Download | only in libsa
sdcd.c revision 1.7
      1 /*	$NetBSD: sdcd.c,v 1.7 2007/11/11 05:20:27 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 <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 *, int, daddr_t, 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 *, int, daddr_t, 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 	dealloc(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 	dealloc(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