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