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