sdcd.c revision 1.9
1/* $NetBSD: sdcd.c,v 1.9 2011/04/11 14:00:02 tsutsui 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 272 dealloc(f->f_devdata, sizeof(struct sdcd_softc)); 273 return 0; 274} 275 276int 277sdstrategy(void *arg, int rw, daddr_t dblk, size_t size, 278 void *buf, size_t *rsize) 279{ 280 struct sdcd_softc *sc = arg; 281 uint32_t start = sc->sc_partinfo.start + dblk; 282 size_t nblks; 283 int error; 284 285 if (size == 0) { 286 if (rsize) 287 *rsize = 0; 288 return 0; 289 } 290 nblks = howmany(size, 256 << current_blklen); 291 292 if ((dblk & 0x1fffff) == 0x1fffff && (nblks & 0xff) == nblks) { 293 if (rw & F_WRITE) 294 error = IOCS_S_WRITE(start, nblks, current_id, 295 current_blklen, buf); 296 else 297 error = IOCS_S_READ(start, nblks, current_id, 298 current_blklen, buf); 299 } else { 300 if (rw & F_WRITE) 301 error = IOCS_S_WRITEEXT(start, nblks, current_id, 302 current_blklen, buf); 303 else 304 error = IOCS_S_READEXT(start, nblks, current_id, 305 current_blklen, buf); 306 } 307 if (error < 0) 308 return EIO; 309 310 if (rsize) 311 *rsize = size; 312 return 0; 313} 314 315/* cdopen(struct open_file *f, int id, int part) */ 316int 317cdopen(struct open_file *f, ...) 318{ 319 int error; 320 struct sdcd_softc *sc; 321 int id, part; 322 va_list ap; 323 324 va_start(ap, f); 325 id = va_arg(ap, int); 326 part = va_arg(ap, int); 327 va_end(ap); 328 329 if (id < 0 || id > 7) 330 return ENXIO; 331 if (part == 0 || part == 2) 332 return ENXIO; 333 if (current_id != id) { 334 error = check_unit(id); 335 if (error) 336 return error; 337 } 338 339 sc = alloc(sizeof(struct sdcd_softc)); 340 current_npart = 3; 341 sc->sc_part = 0; 342 sc->sc_partinfo.size = sc->sc_partinfo.size = current_devsize; 343 sc->sc_blocksize = current_blklen << 9; 344 f->f_devdata = sc; 345 return 0; 346} 347 348int 349cdclose(struct open_file *f) 350{ 351 352 dealloc(f->f_devdata, sizeof(struct sdcd_softc)); 353 return 0; 354} 355 356int 357cdstrategy(void *arg, int rw, daddr_t dblk, size_t size, 358 void *buf, size_t *rsize) 359{ 360 struct sdcd_softc *sc = arg; 361 362 return sdstrategy(arg, rw, dblk * DEV_BSIZE / sc->sc_blocksize, 363 size, buf, rsize); 364} 365