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