xref: /netbsd-src/sys/arch/mvme68k/stand/bootst/rawfs.c (revision febb7cce65f113332bd6a43f6cb22809175a03b6)
1 /*	$NetBSD: rawfs.c,v 1.11 2009/10/21 23:12:09 snj 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  *
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 /*
29  * Raw file system - for stream devices like tapes.
30  * No random access, only sequential read allowed.
31  * This exists only to allow upper level code to be
32  * shielded from the fact that the device must be
33  * read only with whole block position and size.
34  */
35 
36 #include <sys/param.h>
37 #include <lib/libsa/stand.h>
38 #include <rawfs.h>
39 
40 extern int debug;
41 
42 #define	RAWFS_BSIZE	8192
43 
44 /*
45  * In-core open file.
46  */
47 struct file {
48 	daddr_t		fs_nextblk;	/* block number to read next */
49 	daddr_t		fs_curblk;	/* block number currently in buffer */
50 	int		fs_len;		/* amount left in f_buf */
51 	char		*fs_ptr;	/* read pointer into f_buf */
52 	char		fs_buf[RAWFS_BSIZE];
53 };
54 
55 static int rawfs_get_block(struct open_file *);
56 
rawfs_open(const char * path,struct open_file * f)57 int rawfs_open(const char *path, struct open_file *f)
58 {
59 	struct file *fs;
60 
61 	/*
62 	 * The actual PROM driver has already been opened.
63 	 * Just allocate the I/O buffer, etc.
64 	 */
65 	fs = alloc(sizeof(struct file));
66 	fs->fs_nextblk = 0;
67 	fs->fs_curblk = -1;
68 	fs->fs_len = 0;
69 	fs->fs_ptr = fs->fs_buf;
70 
71 	f->f_fsdata = fs;
72 	return 0;
73 }
74 
rawfs_close(struct open_file * f)75 int rawfs_close(struct open_file *f)
76 {
77 	struct file *fs;
78 
79 	fs = (struct file *)f->f_fsdata;
80 	f->f_fsdata = NULL;
81 
82 	if (fs != NULL)
83 		dealloc(fs, sizeof(*fs));
84 
85 	return 0;
86 }
87 
rawfs_read(struct open_file * f,void * start,u_int size,u_int * resid)88 int rawfs_read(struct open_file *f, void *start, u_int size, u_int *resid)
89 {
90 	struct file *fs = (struct file *)f->f_fsdata;
91 	char *addr = start;
92 	int error = 0;
93 	size_t csize;
94 
95 	while (size != 0) {
96 
97 		if (fs->fs_len == 0)
98 			if ((error = rawfs_get_block(f)) != 0)
99 				break;
100 
101 		if (fs->fs_len <= 0)
102 			break;	/* EOF */
103 
104 		csize = size;
105 		if (csize > fs->fs_len)
106 			csize = fs->fs_len;
107 
108 		memcpy(addr, fs->fs_ptr, csize);
109 		fs->fs_ptr += csize;
110 		fs->fs_len -= csize;
111 		addr += csize;
112 		size -= csize;
113 	}
114 	if (resid)
115 		*resid = size;
116 
117 	if (error) {
118 		errno = error;
119 		error = -1;
120 	}
121 
122 	return error;
123 }
124 
rawfs_write(struct open_file * f,void * start,size_t size,size_t * resid)125 int rawfs_write(struct open_file *f, void *start, size_t size, size_t *resid)
126 {
127 
128 	errno = EROFS;
129 	return -1;
130 }
131 
rawfs_seek(struct open_file * f,off_t offset,int where)132 off_t rawfs_seek(struct open_file *f, off_t offset, int where)
133 {
134 	struct file *fs = (struct file *)f->f_fsdata;
135 	daddr_t curblk, targblk;
136 	off_t newoff;
137 	int err, idx;
138 
139 	/*
140 	 * We support a very minimal feature set for lseek(2); just
141 	 * enough to allow loadfile() to work with the parameters
142 	 * we pass to it on boot.
143 	 *
144 	 * In all cases, we can't seek back past the start of the
145 	 * current block.
146 	 */
147 	curblk = (fs->fs_curblk < 0) ? 0 : fs->fs_curblk;
148 
149 	/*
150 	 * Only support SEEK_SET and SEEK_CUR which result in offsets
151 	 * which don't require seeking backwards.
152 	 */
153 	switch (where) {
154 	case SEEK_SET:
155 		newoff = offset;
156 		break;
157 
158 	case SEEK_CUR:
159 		if (fs->fs_curblk < 0)
160 			newoff = 0;
161 		else {
162 			newoff = fs->fs_curblk * RAWFS_BSIZE;
163 			newoff += RAWFS_BSIZE - fs->fs_len;
164 		}
165 		newoff += offset;
166 		break;
167 
168 	default:
169 		errno = EINVAL;
170 		return -1;
171 	}
172 
173 	if (newoff < (curblk * RAWFS_BSIZE)) {
174 		errno = EINVAL;
175 		return -1;
176 	}
177 
178 	targblk = newoff / RAWFS_BSIZE;
179 
180 	/*
181 	 * If necessary, skip blocks until we hit the required target
182 	 */
183 	err = 0;
184 	while (fs->fs_curblk != targblk && (err = rawfs_get_block(f)) == 0)
185 		;
186 
187 	if (err) {
188 		errno = err;
189 		return -1;
190 	}
191 
192 	/*
193 	 * Update the index within the loaded block
194 	 */
195 	idx = newoff % RAWFS_BSIZE;
196 	fs->fs_len = RAWFS_BSIZE - idx;
197 	fs->fs_ptr = &fs->fs_buf[idx];
198 
199 	return newoff;
200 }
201 
rawfs_stat(struct open_file * f,struct stat * sb)202 int rawfs_stat(struct open_file *f, struct stat *sb)
203 {
204 
205 	errno = EFTYPE;
206 	return -1;
207 }
208 
209 
210 /*
211  * Read a block from the underlying stream device
212  * (In our case, a tape drive.)
213  */
214 static int
rawfs_get_block(struct open_file * f)215 rawfs_get_block(struct open_file *f)
216 {
217 	struct file *fs;
218 	int error;
219 	size_t len;
220 
221 	fs = (struct file *)f->f_fsdata;
222 	fs->fs_ptr = fs->fs_buf;
223 
224 	twiddle();
225 	error = f->f_dev->dv_strategy(f->f_devdata, F_READ,
226 	    fs->fs_nextblk * (RAWFS_BSIZE / DEV_BSIZE),
227 	    RAWFS_BSIZE, fs->fs_buf, &len);
228 
229 	if (error == 0) {
230 		fs->fs_len = len;
231 		fs->fs_curblk = fs->fs_nextblk;
232 		fs->fs_nextblk += 1;
233 	} else {
234 		errno = error;
235 		error = -1;
236 	}
237 
238 	return error;
239 }
240