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 37static int current_id = -1; 38static int current_blklen, current_devsize, current_npart; 39static struct boot_partinfo partitions[MAXPARTITIONS]; 40 41int sdopen(struct open_file *, int, int); 42int sdclose(struct open_file*); 43int sdstrategy(void *devdata, int rw, daddr_t blk, size_t, void*, size_t*); 44int sd_getbsdpartition(int, int); 45int cdopen(struct open_file *, int, int); 46int cdclose(struct open_file*); 47int cdstrategy(void *devdata, int rw, daddr_t blk, size_t, void*, size_t*); 48 49static int readdisklabel(int); 50static 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 59static int 60check_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 120static int 121readdisklabel (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 } 185done: 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 198int 199sd_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 237struct sdcd_softc { 238 int sc_part; 239 struct boot_partinfo sc_partinfo; 240 int sc_blocksize; 241}; 242 243int 244sdopen (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 267int 268sdclose (struct open_file *f) 269{ 270 free (f->f_devdata, sizeof (struct sdcd_softc)); 271 return 0; 272} 273 274int 275sdstrategy (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 313int 314cdopen (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 338int 339cdclose (struct open_file *f) 340{ 341 free (f->f_devdata, sizeof (struct sdcd_softc)); 342 return 0; 343} 344 345int 346cdstrategy (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