ofw_disk.c revision 84970
1/*
2 * Copyright (C) 2000 Benno Rice.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 * $FreeBSD: head/sys/boot/ofw/libofw/ofw_disk.c 84970 2001-10-15 09:35:40Z robert $
26 */
27
28/*
29 * Disk I/O routines using Open Firmware
30 */
31
32#include <sys/param.h>
33#include <sys/disklabel.h>
34
35#include <netinet/in.h>
36
37#include <machine/stdarg.h>
38
39#include <stand.h>
40
41#include "bootstrap.h"
42#include "libofw.h"
43
44#define	DISKSECSZ	512
45#define	DISKLABELSEC	0
46#define	DISKLABELOFF	128
47
48static int	ofwd_init(void);
49static int	ofwd_strategy(void *devdata, int flag, daddr_t dblk,
50				size_t size, char *buf, size_t *rsize);
51static int	ofwd_open(struct open_file *f, ...);
52static int	ofwd_close(struct open_file *f);
53static void	ofwd_print(int verbose);
54static char *	ofwd_getdevpath(int unit);
55int readdisklabel(struct ofw_devdesc *);
56
57struct devsw ofwdisk = {
58	"disk",
59	DEVT_DISK,
60	ofwd_init,
61	ofwd_strategy,
62	ofwd_open,
63	ofwd_close,
64	noioctl,
65	ofwd_print
66};
67
68static struct ofwdinfo {
69	int	ofwd_unit;
70	char	ofwd_path[255];
71} ofwdinfo[MAXDEV];
72static int nofwdinfo = 0;
73
74static int
75ofwd_init(void)
76{
77	int ret;
78	char devpath[255];
79	ihandle_t instance;
80
81	printf("ofwd_init: searching for block devices\n");
82	ofw_devsearch_init();
83	while ((ret = ofw_devsearch("block", devpath)) != 0) {
84		devpath[sizeof devpath - 1] = 0;
85		printf("ofwd_init: devpath=%s\n", devpath);
86		if (ret == -1) {
87			printf("ofwd_init: ret=%d\n", ret);
88			return (1);
89		}
90#ifdef DEBUG
91		printf("devpath=\"%s\" ret=%d\n", devpath, ret);
92#endif
93
94		if (strcmp(devpath, "/pci@1f,0/pci@1,1/ide@3/cdrom") == 0)
95			continue;
96
97		instance = OF_open(devpath);
98		if (instance != -1) {
99			ofwdinfo[nofwdinfo].ofwd_unit = nofwdinfo;
100			strncpy(ofwdinfo[nofwdinfo].ofwd_path, devpath, 255);
101			printf("disk%d is %s\n", nofwdinfo, ofwdinfo[nofwdinfo].ofwd_path);
102			nofwdinfo++;
103			OF_close(instance);
104		}
105
106		if (nofwdinfo > MAXDEV) {
107			printf("Hit MAXDEV probing disks.\n");
108			return (1);
109		}
110	}
111
112	printf("ofwd_init: return (0)\n");
113	return (0);
114}
115
116static int
117ofwd_strategy(void *devdata, int flag, daddr_t dblk, size_t size, char *buf,
118    size_t *rsize)
119{
120	struct ofw_devdesc *dp = (struct ofw_devdesc *)devdata;
121	unsigned long pos;
122	int n;
123	int i, j;
124
125	pos = (dp->d_kind.ofwdisk.partoff + dblk) * dp->d_kind.ofwdisk.bsize;
126
127	do {
128		if (OF_seek(dp->d_kind.ofwdisk.handle, pos) < 0) {
129			return EIO;
130		}
131		n = OF_read(dp->d_kind.ofwdisk.handle, buf, size);
132		if (n < 0 && n != -2) {
133			return EIO;
134		}
135	} while (n == -2);
136
137	*rsize = size;
138	return 0;
139}
140
141static int
142ofwd_open(struct open_file *f, ...)
143{
144	va_list vl;
145	struct ofw_devdesc *dp;
146	char *devpath;
147	phandle_t diskh;
148	char buf[8192];
149	int i, j;
150
151	va_start(vl, f);
152	dp = va_arg(vl, struct ofw_devdesc *);
153	va_end(vl);
154
155	devpath = ofwd_getdevpath(dp->d_kind.ofwdisk.unit);
156	if ((diskh = OF_open(devpath)) == -1) {
157		printf("ofwd_open: Could not open %s\n", devpath);
158		return 1;
159	}
160	dp->d_kind.ofwdisk.bsize = DISKSECSZ;
161	dp->d_kind.ofwdisk.handle = diskh;
162	readdisklabel(dp);
163
164	return 0;
165}
166
167/* XXX This is a NetBSD header! */
168#include "disklabel.h"
169int
170readdisklabel(struct ofw_devdesc *dp)
171{
172	char buf[DISKSECSZ];
173	struct partition *p;
174	struct disklabel *lp;
175	size_t size;
176	int i;
177
178	dp->d_kind.ofwdisk.partoff = 0;
179
180	dp->d_dev->dv_strategy(dp, 0, DISKLABELSEC, sizeof(buf), buf, &size);
181
182	lp = (struct disklabel *)(buf + DISKLABELOFF);
183	p = lp->d_partitions;
184	for (i = 0; i < MAXPARTITIONS; i++) {
185		if (i == dp->d_kind.ofwdisk.partition) {
186			dp->d_kind.ofwdisk.partoff = p->p_offset;
187			return 0;
188		}
189		p++;
190	}
191	return 1;
192}
193
194static int
195ofwd_close(struct open_file *f)
196{
197	struct ofw_devdesc *dev = f->f_devdata;
198	OF_close(dev->d_kind.ofwdisk.handle);
199
200	return 0;
201}
202
203static void
204ofwd_print(int verbose)
205{
206	int	i;
207	char	line[80];
208
209	for (i = 0; i < nofwdinfo; i++) {
210		sprintf(line, "    disk%d:   %s", i, ofwdinfo[i].ofwd_path);
211		pager_output(line);
212		pager_output("\n");
213	}
214	return;
215}
216
217int
218ofwd_getunit(const char *path)
219{
220	int i;
221
222	for (i = 0; i < nofwdinfo; i++) {
223		if (strcmp(path, ofwdinfo[i].ofwd_path) == 0)
224			return i;
225	}
226
227	return -1;
228}
229
230static char *
231ofwd_getdevpath(int unit)
232{
233	int i;
234
235	for (i = 0; i < nofwdinfo; i++) {
236		if (ofwdinfo[i].ofwd_unit == unit)
237			return ofwdinfo[i].ofwd_path;
238	}
239	return 0;
240}
241