1 /* $NetBSD: disk.c,v 1.9 2019/01/09 03:28:31 christos 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 <sys/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
device_attach(int type,int unit,int partition)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
dkopen(struct open_file * f,...)123 dkopen(struct open_file *f, ...)
124 {
125
126 return 0;
127 }
128
129 int
dkclose(struct open_file * f)130 dkclose(struct open_file *f)
131 {
132
133 return 0;
134 }
135
136 int
dkstrategy(void * devdata,int rw,daddr_t blk,size_t size,void * buf,size_t * rsize)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
sector_init(void)158 sector_init(void)
159 {
160
161 if (!__disk.active)
162 device_attach(-1, -1, -1);
163 }
164
165 void
sector_fini(void * self)166 sector_fini(void *self)
167 {
168
169 __disk.active = false;
170 }
171
172 bool
sector_read_n(void * self,uint8_t * buf,int sector,int count)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
sector_read(void * self,uint8_t * buf,int sector)182 sector_read(void *self, uint8_t *buf, int sector)
183 {
184
185 return __sector_rw(buf, sector, 0, 1);
186 }
187
188 bool
sector_write_n(void * self,uint8_t * buf,int sector,int count)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
sector_write(void * self,uint8_t * buf,int sector)198 sector_write(void *self, uint8_t *buf, int sector)
199 {
200
201 return __sector_rw(buf, sector, 0x1000, 1);
202 }
203
204 bool
__sector_rw(uint8_t * buf,int block,int flag,int count)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
__hd_rw(uint8_t * buf,int block,int flag,int count)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
__fd_2d_rw(uint8_t * buf,int block,int flag,int count)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
__fd_2hd_rw(uint8_t * buf,int block,int flag,int count)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
__fd_progress_msg(int pos)284 __fd_progress_msg(int pos)
285 {
286 char msg[16];
287
288 snprintf(msg, sizeof(msg), "C%d H%d S%d \r",
289 (pos >> 16) & 0xff, (pos >> 8) & 0xff, pos & 0xff);
290 printf("%s", msg);
291 }
292 #endif
293