xref: /netbsd-src/sys/arch/mvme68k/stand/bootst/rawfs.c (revision febb7cce65f113332bd6a43f6cb22809175a03b6)
1*febb7cceSsnj /*	$NetBSD: rawfs.c,v 1.11 2009/10/21 23:12:09 snj Exp $	*/
29a628842Schuck 
39a628842Schuck /*
49a628842Schuck  * Copyright (c) 1995 Gordon W. Ross
59a628842Schuck  * All rights reserved.
69a628842Schuck  *
79a628842Schuck  * Redistribution and use in source and binary forms, with or without
89a628842Schuck  * modification, are permitted provided that the following conditions
99a628842Schuck  * are met:
109a628842Schuck  * 1. Redistributions of source code must retain the above copyright
119a628842Schuck  *    notice, this list of conditions and the following disclaimer.
129a628842Schuck  * 2. Redistributions in binary form must reproduce the above copyright
139a628842Schuck  *    notice, this list of conditions and the following disclaimer in the
149a628842Schuck  *    documentation and/or other materials provided with the distribution.
159a628842Schuck  *
169a628842Schuck  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
179a628842Schuck  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
189a628842Schuck  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
199a628842Schuck  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
209a628842Schuck  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
219a628842Schuck  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
229a628842Schuck  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
239a628842Schuck  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
249a628842Schuck  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
259a628842Schuck  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
269a628842Schuck  */
279a628842Schuck 
289a628842Schuck /*
299a628842Schuck  * Raw file system - for stream devices like tapes.
309a628842Schuck  * No random access, only sequential read allowed.
319a628842Schuck  * This exists only to allow upper level code to be
329a628842Schuck  * shielded from the fact that the device must be
339a628842Schuck  * read only with whole block position and size.
349a628842Schuck  */
359a628842Schuck 
369a628842Schuck #include <sys/param.h>
37e63501d2Sjunyoung #include <lib/libsa/stand.h>
389a628842Schuck #include <rawfs.h>
399a628842Schuck 
409a628842Schuck extern int debug;
419a628842Schuck 
422f42a593Sscw #define	RAWFS_BSIZE	8192
439a628842Schuck 
449a628842Schuck /*
459a628842Schuck  * In-core open file.
469a628842Schuck  */
479a628842Schuck struct file {
489a628842Schuck 	daddr_t		fs_nextblk;	/* block number to read next */
492f42a593Sscw 	daddr_t		fs_curblk;	/* block number currently in buffer */
509a628842Schuck 	int		fs_len;		/* amount left in f_buf */
519a628842Schuck 	char		*fs_ptr;	/* read pointer into f_buf */
529a628842Schuck 	char		fs_buf[RAWFS_BSIZE];
539a628842Schuck };
549a628842Schuck 
55a07f7c80Stsutsui static int rawfs_get_block(struct open_file *);
569a628842Schuck 
rawfs_open(const char * path,struct open_file * f)57a07f7c80Stsutsui int rawfs_open(const char *path, struct open_file *f)
589a628842Schuck {
599a628842Schuck 	struct file *fs;
609a628842Schuck 
619a628842Schuck 	/*
629a628842Schuck 	 * The actual PROM driver has already been opened.
639a628842Schuck 	 * Just allocate the I/O buffer, etc.
649a628842Schuck 	 */
659a628842Schuck 	fs = alloc(sizeof(struct file));
669a628842Schuck 	fs->fs_nextblk = 0;
672f42a593Sscw 	fs->fs_curblk = -1;
689a628842Schuck 	fs->fs_len = 0;
699a628842Schuck 	fs->fs_ptr = fs->fs_buf;
709a628842Schuck 
719a628842Schuck 	f->f_fsdata = fs;
72a07f7c80Stsutsui 	return 0;
739a628842Schuck }
749a628842Schuck 
rawfs_close(struct open_file * f)75a07f7c80Stsutsui int rawfs_close(struct open_file *f)
769a628842Schuck {
779a628842Schuck 	struct file *fs;
789a628842Schuck 
799a628842Schuck 	fs = (struct file *)f->f_fsdata;
80a07f7c80Stsutsui 	f->f_fsdata = NULL;
819a628842Schuck 
82a07f7c80Stsutsui 	if (fs != NULL)
83606bb2caSchristos 		dealloc(fs, sizeof(*fs));
849a628842Schuck 
85a07f7c80Stsutsui 	return 0;
869a628842Schuck }
879a628842Schuck 
rawfs_read(struct open_file * f,void * start,u_int size,u_int * resid)88a07f7c80Stsutsui int rawfs_read(struct open_file *f, void *start, u_int size, u_int *resid)
899a628842Schuck {
909a628842Schuck 	struct file *fs = (struct file *)f->f_fsdata;
919a628842Schuck 	char *addr = start;
929a628842Schuck 	int error = 0;
939a628842Schuck 	size_t csize;
949a628842Schuck 
959a628842Schuck 	while (size != 0) {
969a628842Schuck 
979a628842Schuck 		if (fs->fs_len == 0)
989a628842Schuck 			if ((error = rawfs_get_block(f)) != 0)
999a628842Schuck 				break;
1009a628842Schuck 
1019a628842Schuck 		if (fs->fs_len <= 0)
1029a628842Schuck 			break;	/* EOF */
1039a628842Schuck 
1049a628842Schuck 		csize = size;
1059a628842Schuck 		if (csize > fs->fs_len)
1069a628842Schuck 			csize = fs->fs_len;
1079a628842Schuck 
108c1ab2b54Sscw 		memcpy(addr, fs->fs_ptr, csize);
1099a628842Schuck 		fs->fs_ptr += csize;
1109a628842Schuck 		fs->fs_len -= csize;
1119a628842Schuck 		addr += csize;
1129a628842Schuck 		size -= csize;
1139a628842Schuck 	}
1149a628842Schuck 	if (resid)
1159a628842Schuck 		*resid = size;
1162f42a593Sscw 
1172f42a593Sscw 	if (error) {
1182f42a593Sscw 		errno = error;
1192f42a593Sscw 		error = -1;
1202f42a593Sscw 	}
1212f42a593Sscw 
122a07f7c80Stsutsui 	return error;
1239a628842Schuck }
1249a628842Schuck 
rawfs_write(struct open_file * f,void * start,size_t size,size_t * resid)125a07f7c80Stsutsui int rawfs_write(struct open_file *f, void *start, size_t size, size_t *resid)
1269a628842Schuck {
127a07f7c80Stsutsui 
1282f42a593Sscw 	errno = EROFS;
129a07f7c80Stsutsui 	return -1;
1309a628842Schuck }
1319a628842Schuck 
rawfs_seek(struct open_file * f,off_t offset,int where)132a07f7c80Stsutsui off_t rawfs_seek(struct open_file *f, off_t offset, int where)
1339a628842Schuck {
1342f42a593Sscw 	struct file *fs = (struct file *)f->f_fsdata;
1352f42a593Sscw 	daddr_t curblk, targblk;
1362f42a593Sscw 	off_t newoff;
1372f42a593Sscw 	int err, idx;
1382f42a593Sscw 
1392f42a593Sscw 	/*
1402f42a593Sscw 	 * We support a very minimal feature set for lseek(2); just
1412f42a593Sscw 	 * enough to allow loadfile() to work with the parameters
1422f42a593Sscw 	 * we pass to it on boot.
1432f42a593Sscw 	 *
1442f42a593Sscw 	 * In all cases, we can't seek back past the start of the
1452f42a593Sscw 	 * current block.
1462f42a593Sscw 	 */
147439d3ea3Sscw 	curblk = (fs->fs_curblk < 0) ? 0 : fs->fs_curblk;
1482f42a593Sscw 
1492f42a593Sscw 	/*
1502f42a593Sscw 	 * Only support SEEK_SET and SEEK_CUR which result in offsets
1512f42a593Sscw 	 * which don't require seeking backwards.
1522f42a593Sscw 	 */
1532f42a593Sscw 	switch (where) {
1542f42a593Sscw 	case SEEK_SET:
1552f42a593Sscw 		newoff = offset;
1562f42a593Sscw 		break;
1572f42a593Sscw 
1582f42a593Sscw 	case SEEK_CUR:
1592f42a593Sscw 		if (fs->fs_curblk < 0)
1602f42a593Sscw 			newoff = 0;
1612f42a593Sscw 		else {
1622f42a593Sscw 			newoff = fs->fs_curblk * RAWFS_BSIZE;
1632f42a593Sscw 			newoff += RAWFS_BSIZE - fs->fs_len;
1642f42a593Sscw 		}
1652f42a593Sscw 		newoff += offset;
1662f42a593Sscw 		break;
1672f42a593Sscw 
1682f42a593Sscw 	default:
1692f42a593Sscw 		errno = EINVAL;
170a07f7c80Stsutsui 		return -1;
1712f42a593Sscw 	}
1722f42a593Sscw 
1732f42a593Sscw 	if (newoff < (curblk * RAWFS_BSIZE)) {
1742f42a593Sscw 		errno = EINVAL;
175a07f7c80Stsutsui 		return -1;
1762f42a593Sscw 	}
1772f42a593Sscw 
1782f42a593Sscw 	targblk = newoff / RAWFS_BSIZE;
1792f42a593Sscw 
1802f42a593Sscw 	/*
1812f42a593Sscw 	 * If necessary, skip blocks until we hit the required target
1822f42a593Sscw 	 */
1832f42a593Sscw 	err = 0;
1842f42a593Sscw 	while (fs->fs_curblk != targblk && (err = rawfs_get_block(f)) == 0)
1852f42a593Sscw 		;
1862f42a593Sscw 
1872f42a593Sscw 	if (err) {
1882f42a593Sscw 		errno = err;
189a07f7c80Stsutsui 		return -1;
1902f42a593Sscw 	}
1912f42a593Sscw 
1922f42a593Sscw 	/*
1932f42a593Sscw 	 * Update the index within the loaded block
1942f42a593Sscw 	 */
1952f42a593Sscw 	idx = newoff % RAWFS_BSIZE;
1962f42a593Sscw 	fs->fs_len = RAWFS_BSIZE - idx;
1972f42a593Sscw 	fs->fs_ptr = &fs->fs_buf[idx];
1982f42a593Sscw 
199a07f7c80Stsutsui 	return newoff;
2009a628842Schuck }
2019a628842Schuck 
rawfs_stat(struct open_file * f,struct stat * sb)202a07f7c80Stsutsui int rawfs_stat(struct open_file *f, struct stat *sb)
2039a628842Schuck {
204a07f7c80Stsutsui 
2052f42a593Sscw 	errno = EFTYPE;
206a07f7c80Stsutsui 	return -1;
2079a628842Schuck }
2089a628842Schuck 
2099a628842Schuck 
2109a628842Schuck /*
2119a628842Schuck  * Read a block from the underlying stream device
2129a628842Schuck  * (In our case, a tape drive.)
2139a628842Schuck  */
2149a628842Schuck static int
rawfs_get_block(struct open_file * f)215a07f7c80Stsutsui rawfs_get_block(struct open_file *f)
2169a628842Schuck {
2179a628842Schuck 	struct file *fs;
21819ad9e54Smrg 	int error;
21919ad9e54Smrg 	size_t len;
2209a628842Schuck 
2219a628842Schuck 	fs = (struct file *)f->f_fsdata;
2229a628842Schuck 	fs->fs_ptr = fs->fs_buf;
2239a628842Schuck 
2249a628842Schuck 	twiddle();
2259a628842Schuck 	error = f->f_dev->dv_strategy(f->f_devdata, F_READ,
2262f42a593Sscw 	    fs->fs_nextblk * (RAWFS_BSIZE / DEV_BSIZE),
2272f42a593Sscw 	    RAWFS_BSIZE, fs->fs_buf, &len);
2289a628842Schuck 
229a07f7c80Stsutsui 	if (error == 0) {
2309a628842Schuck 		fs->fs_len = len;
2312f42a593Sscw 		fs->fs_curblk = fs->fs_nextblk;
2322f42a593Sscw 		fs->fs_nextblk += 1;
2332f42a593Sscw 	} else {
2342f42a593Sscw 		errno = error;
2352f42a593Sscw 		error = -1;
2369a628842Schuck 	}
2379a628842Schuck 
238a07f7c80Stsutsui 	return error;
2399a628842Schuck }
240