xref: /netbsd-src/sys/arch/mvme68k/stand/bootst/rawfs.c (revision 2980e352a13e8f0b545a366830c411e7a542ada8)
1 /*	$NetBSD: rawfs.c,v 1.10 2008/01/12 09:54:30 tsutsui Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 Gordon W. Ross
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  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  * 4. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by Gordon W. Ross
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Raw file system - for stream devices like tapes.
35  * No random access, only sequential read allowed.
36  * This exists only to allow upper level code to be
37  * shielded from the fact that the device must be
38  * read only with whole block position and size.
39  */
40 
41 #include <sys/param.h>
42 #include <lib/libsa/stand.h>
43 #include <rawfs.h>
44 
45 extern int debug;
46 
47 #define	RAWFS_BSIZE	8192
48 
49 /*
50  * In-core open file.
51  */
52 struct file {
53 	daddr_t		fs_nextblk;	/* block number to read next */
54 	daddr_t		fs_curblk;	/* block number currently in buffer */
55 	int		fs_len;		/* amount left in f_buf */
56 	char		*fs_ptr;	/* read pointer into f_buf */
57 	char		fs_buf[RAWFS_BSIZE];
58 };
59 
60 static int rawfs_get_block(struct open_file *);
61 
62 int rawfs_open(const char *path, struct open_file *f)
63 {
64 	struct file *fs;
65 
66 	/*
67 	 * The actual PROM driver has already been opened.
68 	 * Just allocate the I/O buffer, etc.
69 	 */
70 	fs = alloc(sizeof(struct file));
71 	fs->fs_nextblk = 0;
72 	fs->fs_curblk = -1;
73 	fs->fs_len = 0;
74 	fs->fs_ptr = fs->fs_buf;
75 
76 	f->f_fsdata = fs;
77 	return 0;
78 }
79 
80 int rawfs_close(struct open_file *f)
81 {
82 	struct file *fs;
83 
84 	fs = (struct file *)f->f_fsdata;
85 	f->f_fsdata = NULL;
86 
87 	if (fs != NULL)
88 		dealloc(fs, sizeof(*fs));
89 
90 	return 0;
91 }
92 
93 int rawfs_read(struct open_file *f, void *start, u_int size, u_int *resid)
94 {
95 	struct file *fs = (struct file *)f->f_fsdata;
96 	char *addr = start;
97 	int error = 0;
98 	size_t csize;
99 
100 	while (size != 0) {
101 
102 		if (fs->fs_len == 0)
103 			if ((error = rawfs_get_block(f)) != 0)
104 				break;
105 
106 		if (fs->fs_len <= 0)
107 			break;	/* EOF */
108 
109 		csize = size;
110 		if (csize > fs->fs_len)
111 			csize = fs->fs_len;
112 
113 		memcpy(addr, fs->fs_ptr, csize);
114 		fs->fs_ptr += csize;
115 		fs->fs_len -= csize;
116 		addr += csize;
117 		size -= csize;
118 	}
119 	if (resid)
120 		*resid = size;
121 
122 	if (error) {
123 		errno = error;
124 		error = -1;
125 	}
126 
127 	return error;
128 }
129 
130 int rawfs_write(struct open_file *f, void *start, size_t size, size_t *resid)
131 {
132 
133 	errno = EROFS;
134 	return -1;
135 }
136 
137 off_t rawfs_seek(struct open_file *f, off_t offset, int where)
138 {
139 	struct file *fs = (struct file *)f->f_fsdata;
140 	daddr_t curblk, targblk;
141 	off_t newoff;
142 	int err, idx;
143 
144 	/*
145 	 * We support a very minimal feature set for lseek(2); just
146 	 * enough to allow loadfile() to work with the parameters
147 	 * we pass to it on boot.
148 	 *
149 	 * In all cases, we can't seek back past the start of the
150 	 * current block.
151 	 */
152 	curblk = (fs->fs_curblk < 0) ? 0 : fs->fs_curblk;
153 
154 	/*
155 	 * Only support SEEK_SET and SEEK_CUR which result in offsets
156 	 * which don't require seeking backwards.
157 	 */
158 	switch (where) {
159 	case SEEK_SET:
160 		newoff = offset;
161 		break;
162 
163 	case SEEK_CUR:
164 		if (fs->fs_curblk < 0)
165 			newoff = 0;
166 		else {
167 			newoff = fs->fs_curblk * RAWFS_BSIZE;
168 			newoff += RAWFS_BSIZE - fs->fs_len;
169 		}
170 		newoff += offset;
171 		break;
172 
173 	default:
174 		errno = EINVAL;
175 		return -1;
176 	}
177 
178 	if (newoff < (curblk * RAWFS_BSIZE)) {
179 		errno = EINVAL;
180 		return -1;
181 	}
182 
183 	targblk = newoff / RAWFS_BSIZE;
184 
185 	/*
186 	 * If necessary, skip blocks until we hit the required target
187 	 */
188 	err = 0;
189 	while (fs->fs_curblk != targblk && (err = rawfs_get_block(f)) == 0)
190 		;
191 
192 	if (err) {
193 		errno = err;
194 		return -1;
195 	}
196 
197 	/*
198 	 * Update the index within the loaded block
199 	 */
200 	idx = newoff % RAWFS_BSIZE;
201 	fs->fs_len = RAWFS_BSIZE - idx;
202 	fs->fs_ptr = &fs->fs_buf[idx];
203 
204 	return newoff;
205 }
206 
207 int rawfs_stat(struct open_file *f, struct stat *sb)
208 {
209 
210 	errno = EFTYPE;
211 	return -1;
212 }
213 
214 
215 /*
216  * Read a block from the underlying stream device
217  * (In our case, a tape drive.)
218  */
219 static int
220 rawfs_get_block(struct open_file *f)
221 {
222 	struct file *fs;
223 	int error;
224 	size_t len;
225 
226 	fs = (struct file *)f->f_fsdata;
227 	fs->fs_ptr = fs->fs_buf;
228 
229 	twiddle();
230 	error = f->f_dev->dv_strategy(f->f_devdata, F_READ,
231 	    fs->fs_nextblk * (RAWFS_BSIZE / DEV_BSIZE),
232 	    RAWFS_BSIZE, fs->fs_buf, &len);
233 
234 	if (error == 0) {
235 		fs->fs_len = len;
236 		fs->fs_curblk = fs->fs_nextblk;
237 		fs->fs_nextblk += 1;
238 	} else {
239 		errno = error;
240 		error = -1;
241 	}
242 
243 	return error;
244 }
245