1/*	$NetBSD: riscosdisk.c,v 1.3 2009/01/12 07:07:07 tsutsui Exp $	*/
2
3/*-
4 * Copyright (c) 2001, 2006 Ben Harris
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 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <sys/types.h>
31#include <sys/param.h>
32#include <sys/disklabel.h>
33#include <lib/libsa/stand.h>
34#include <riscoscalls.h>
35#include <riscosdisk.h>
36#include <riscospart.h>
37
38struct riscosdisk {
39	void	*privword;
40	int	drive;
41	daddr_t	boff;
42};
43
44static void *
45rodisk_getprivateword(char const *fsname)
46{
47	void *privword;
48	char module[20];
49	os_error *err;
50
51	/* XXX The %c dance is because libsa printf can't do %% */
52	snprintf(module, sizeof(module), "FileCore%c%s", '%', fsname);
53	err = xosmodule_lookup(module, NULL, NULL, NULL, &privword, NULL);
54	if (err != NULL)
55		return NULL;
56	return privword;
57}
58
59int
60rodisk_open(struct open_file *f, ... /* char const *fsname, int drive,
61    int partition */)
62{
63	va_list ap;
64	struct disklabel dl;
65	char const *fsname;
66	int drive, partition, nfd, nhd, err;
67	struct riscosdisk *rd;
68	void *privword;
69
70	va_start(ap, f);
71	fsname = va_arg(ap, char const *);
72	drive = va_arg(ap, int);
73	partition = va_arg(ap, int);
74	va_end(ap);
75
76	if ((privword = rodisk_getprivateword(fsname)) == NULL)
77		return ECTLR;
78	if (xfilecore_drives(&privword, NULL, &nfd, &nhd) != NULL)
79		return ECTLR;
80	if (drive < 0 ||
81	    (drive < 4 && drive >= nfd) ||
82	    drive >= nhd + 4)
83		return EUNIT;
84
85	rd = alloc(sizeof(*rd));
86	rd->privword = privword;
87	rd->drive = drive;
88	rd->boff = 0;
89	f->f_devdata = rd;
90	if (partition != RAW_PART) {
91		err = getdisklabel_acorn(f, &dl);
92		if (err != 0) {
93			dealloc(rd, sizeof(*rd));
94			return err;
95		}
96		if (partition >= dl.d_npartitions ||
97		    dl.d_partitions[partition].p_size == 0) {
98			dealloc(rd, sizeof(*rd));
99			return EPART;
100		}
101		rd->boff = dl.d_partitions[partition].p_offset;
102	}
103	return 0;
104}
105
106int
107rodisk_close(struct open_file *f)
108{
109	struct riscosdisk *rd = f->f_devdata;
110
111	dealloc(rd, sizeof *rd);
112	return 0;
113}
114
115int
116rodisk_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
117    void *buf, size_t *rsize)
118{
119	struct riscosdisk *rd = devdata;
120	size_t resid;
121	uint32_t daddr, ndaddr;
122	void *nbuf;
123	os_error *err;
124
125	if (flag != F_READ)
126		return EROFS;
127
128	dblk += rd->boff;
129
130	if (rsize) *rsize = 0;
131	if (dblk < 1 << (29 - DEV_BSHIFT)) {
132		daddr = (dblk * DEV_BSIZE) | (rd->drive << 29);
133		if ((err = xfilecorediscop_read_sectors(0, daddr, buf, size,
134		    &rd->privword, &ndaddr, &nbuf, &resid)) != NULL)
135			goto eio;
136	} else if (dblk < 1 << 29) {
137		daddr = dblk | (rd->drive << 29);
138		if ((err = xfilecoresectorop_read_sectors(0, daddr, buf, size,
139		    &rd->privword, &ndaddr, &nbuf, &resid)) != NULL)
140			goto eio;
141	} else if (dblk < 1LL << (64 - DEV_BSHIFT)){
142		struct filecore_daddr64 daddr64;
143		daddr64.drive = rd->drive;
144		daddr64.daddr = dblk * DEV_BSIZE;
145		if ((err = xfilecorediscop64_read_sectors(0, &daddr64, buf,
146		    size, NULL, &rd->privword, &ndaddr, &nbuf, &resid)) !=
147		    NULL)
148			goto eio;
149	} else
150		return EIO;
151	if (rsize)
152		*rsize = size - resid;
153	return 0;
154eio:
155	printf("Error: %s\n", err->errmess);
156	return EIO;
157}
158