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 39static int current_id = -1; 40static int current_blklen, current_devsize, current_npart; 41static struct boot_partinfo partitions[MAXPARTITIONS]; 42 43static int readdisklabel(int); 44static int check_unit(int); 45 46#ifdef DEBUG 47#define DPRINTF(x) printf x 48#else 49#define DPRINTF(x) 50#endif 51 52static int 53check_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 113static int 114readdisklabel(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 } 178done: 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 191int 192sd_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 230struct 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) */ 237int 238sdopen(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 268int 269sdclose(struct open_file *f) 270{ 271 dealloc(f->f_devdata, sizeof(struct sdcd_softc)); 272 return 0; 273} 274 275int 276sdstrategy(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) */ 315int 316cdopen(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 347int 348cdclose(struct open_file *f) 349{ 350 dealloc(f->f_devdata, sizeof(struct sdcd_softc)); 351 return 0; 352} 353 354int 355cdstrategy(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