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