1 /* $NetBSD: disk.c,v 1.7 2009/02/04 15:22:13 tsutsui Exp $ */ 2 3 /*- 4 * Copyright (c) 2004, 2005 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <lib/libsa/stand.h> 33 #include <lib/libkern/libkern.h> 34 35 #include <machine/param.h> 36 #include <machine/sbd.h> 37 #include <machine/sector.h> 38 39 #include "local.h" 40 #include "common.h" 41 42 #if defined(LIBSA_NO_TWIDDLE) 43 #define twiddle() 44 #endif 45 46 int dkopen(struct open_file *, ...); 47 int dkclose(struct open_file *); 48 int dkstrategy(void *, int, daddr_t, size_t, void *, size_t *); 49 50 struct devsw dkdevsw = { 51 "dk", dkstrategy, dkopen, dkclose, noioctl 52 }; 53 54 struct disk { 55 bool active; 56 int type; /* FD/HD */ 57 int unit; 58 int format; /* 2D/2HD */ 59 int partition; 60 int offset; 61 int (*rw)(uint8_t *, int, int, int); 62 } __disk; 63 64 void sector_init(void); 65 bool __sector_rw(uint8_t *, int, int, int); 66 int __hd_rw(uint8_t *, int, int, int); 67 int __fd_2d_rw(uint8_t *, int, int, int); 68 int __fd_2hd_rw(uint8_t *, int, int, int); 69 #ifdef DEBUG 70 void __fd_progress_msg(int); 71 #else 72 #define __fd_progress_msg(pos) twiddle() 73 #endif 74 75 bool 76 device_attach(int type, int unit, int partition) 77 { 78 79 /* Inquire boot device type and unit from NVSRAM */ 80 boot_device(&__disk.type, &__disk.unit, &__disk.format); 81 82 if (type >= 0) 83 __disk.type = type; 84 if (unit >= 0) 85 __disk.unit = unit; 86 87 __disk.partition = partition; 88 89 __disk.active = true; 90 __disk.offset = 0; 91 92 if (partition >= 0) { 93 if (!find_partition_start(__disk.partition, &__disk.offset)) { 94 printf("type %d, unit %d partition %d not found.\n", 95 __disk.type, __disk.unit, __disk.partition); 96 return false; 97 } 98 } 99 DEVICE_CAPABILITY.active_device = type; 100 101 /* Set actual read/write routine */ 102 if (__disk.type == NVSRAM_BOOTDEV_HARDDISK) { 103 __disk.rw = __hd_rw; 104 } else if (__disk.type == NVSRAM_BOOTDEV_FLOPPYDISK) { 105 if (__disk.format == FD_FORMAT_2HD) { 106 __disk.rw = __fd_2hd_rw; 107 } else if (__disk.format == FD_FORMAT_2D) { 108 __disk.rw = __fd_2d_rw; 109 } else { 110 printf("unknown floppy disk format %d.\n", 111 __disk.format); 112 return false; 113 } 114 } else { 115 printf("unknown disk type %d.\n", __disk.type); 116 return false; 117 } 118 119 return true; 120 } 121 122 int 123 dkopen(struct open_file *f, ...) 124 { 125 126 return 0; 127 } 128 129 int 130 dkclose(struct open_file *f) 131 { 132 133 return 0; 134 } 135 136 int 137 dkstrategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf, 138 size_t *rsize) 139 { 140 int n; 141 142 if ((int)size < 0) { 143 printf("%s: invalid request block %d size %d base %d\n", 144 __func__, blk, size, __disk.offset); 145 return -1; 146 } 147 148 n = ROUND_SECTOR(size) >> DEV_BSHIFT; 149 if (!sector_read_n(0, buf, __disk.offset + blk, n)) 150 return -1; 151 152 *rsize = size; 153 154 return 0; 155 } 156 157 void 158 sector_init(void) 159 { 160 161 if (!__disk.active) 162 device_attach(-1, -1, -1); 163 } 164 165 void 166 sector_fini(void *self) 167 { 168 169 __disk.active = false; 170 } 171 172 bool 173 sector_read_n(void *self, uint8_t *buf, int sector, int count) 174 { 175 176 if (!__sector_rw(buf, sector, 0, count)) 177 return false; 178 return true; 179 } 180 181 bool 182 sector_read(void *self, uint8_t *buf, int sector) 183 { 184 185 return __sector_rw(buf, sector, 0, 1); 186 } 187 188 bool 189 sector_write_n(void *self, uint8_t *buf, int sector, int count) 190 { 191 192 if (!__sector_rw(buf, sector, 0x1000, count)) 193 return false; 194 return true; 195 } 196 197 bool 198 sector_write(void *self, uint8_t *buf, int sector) 199 { 200 201 return __sector_rw(buf, sector, 0x1000, 1); 202 } 203 204 bool 205 __sector_rw(uint8_t *buf, int block, int flag, int count) 206 { 207 int err; 208 209 if (!__disk.active) 210 sector_init(); 211 212 if ((err = __disk.rw(buf, block, flag, count)) != 0) 213 printf("%s: type=%d unit=%d offset=%d block=%d err=%d\n", 214 __func__, __disk.type, __disk.unit, __disk.offset, 215 block, err); 216 217 return err == 0; 218 } 219 220 int 221 __hd_rw(uint8_t *buf, int block, int flag, int count) 222 { 223 224 return (ROM_DK_RW(flag | __disk.unit, block, count, buf) & 0x7f); 225 } 226 227 int 228 __fd_2d_rw(uint8_t *buf, int block, int flag, int count) 229 { 230 int cnt, err; 231 uint32_t pos; 232 233 while (count > 0) { 234 if (!blk_to_2d_position(block, &pos, &cnt)) { 235 printf("%s: invalid block #%d.\n", __func__, block); 236 return -1; 237 } 238 239 __fd_progress_msg(pos); 240 241 if (cnt > count) 242 cnt = count; 243 244 err = ROM_FD_RW(flag | __disk.unit, pos, cnt * 2, buf); 245 if (err) 246 return err; 247 248 count -= cnt; 249 block += cnt; 250 buf += DEV_BSIZE * cnt; 251 } 252 return 0; 253 } 254 255 int 256 __fd_2hd_rw(uint8_t *buf, int block, int flag, int count) 257 { 258 int cnt, err; 259 uint32_t pos; 260 261 while (count > 0) { 262 if (!blk_to_2hd_position(block, &pos, &cnt)) { 263 printf("%s: invalid block #%d.\n", __func__, block); 264 return -1; 265 } 266 if (cnt > count) 267 cnt = count; 268 269 __fd_progress_msg(pos); 270 271 err = ROM_FD_RW(flag | __disk.unit | 0x1000000, pos, cnt, buf); 272 if (err) 273 return err; 274 275 count -= cnt; 276 block += cnt; 277 buf += DEV_BSIZE * cnt; 278 } 279 return 0; 280 } 281 282 #ifdef DEBUG 283 void 284 __fd_progress_msg(int pos) 285 { 286 char msg[16]; 287 288 memset(msg, 0, sizeof msg); 289 sprintf(msg, "C%d H%d S%d \r", (pos >> 16) & 0xff, (pos >> 8) & 0xff, 290 pos & 0xff); 291 printf("%s", msg); 292 } 293 #endif 294