xref: /netbsd/sys/arch/ews4800mips/stand/common/disk.c (revision 6550d01e)
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