xref: /freebsd/sys/dev/ofw/ofw_disk.c (revision d96118005ffb65efed3dbac369c04f08d62a89ad)
1d9611800SBenno Rice /*
2d9611800SBenno Rice  * Copyright (C) 2002 Benno Rice <benno@FreeBSD.org>
3d9611800SBenno Rice  * All rights reserved.
4d9611800SBenno Rice  *
5d9611800SBenno Rice  * Redistribution and use in source and binary forms, with or without
6d9611800SBenno Rice  * modification, are permitted provided that the following conditions
7d9611800SBenno Rice  * are met:
8d9611800SBenno Rice  * 1. Redistributions of source code must retain the above copyright
9d9611800SBenno Rice  *    notice, this list of conditions and the following disclaimer.
10d9611800SBenno Rice  * 2. Redistributions in binary form must reproduce the above copyright
11d9611800SBenno Rice  *    notice, this list of conditions and the following disclaimer in the
12d9611800SBenno Rice  *    documentation and/or other materials provided with the distribution.
13d9611800SBenno Rice  *
14d9611800SBenno Rice  * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
15d9611800SBenno Rice  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16d9611800SBenno Rice  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17d9611800SBenno Rice  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18d9611800SBenno Rice  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19d9611800SBenno Rice  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20d9611800SBenno Rice  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21d9611800SBenno Rice  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22d9611800SBenno Rice  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23d9611800SBenno Rice  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24d9611800SBenno Rice  *
25d9611800SBenno Rice  * $FreeBSD$
26d9611800SBenno Rice  *
27d9611800SBenno Rice  */
28d9611800SBenno Rice 
29d9611800SBenno Rice #include <sys/param.h>
30d9611800SBenno Rice #include <sys/systm.h>
31d9611800SBenno Rice #include <sys/bio.h>
32d9611800SBenno Rice #include <sys/bus.h>
33d9611800SBenno Rice #include <sys/conf.h>
34d9611800SBenno Rice #include <sys/disk.h>
35d9611800SBenno Rice #include <sys/kernel.h>
36d9611800SBenno Rice 
37d9611800SBenno Rice #include <dev/ofw/openfirm.h>
38d9611800SBenno Rice 
39d9611800SBenno Rice #include <machine/bus.h>
40d9611800SBenno Rice #include <machine/md_var.h>
41d9611800SBenno Rice #include <machine/nexusvar.h>
42d9611800SBenno Rice 
43d9611800SBenno Rice #define	OFWD_BLOCKSIZE	512
44d9611800SBenno Rice 
45d9611800SBenno Rice struct ofwd_softc
46d9611800SBenno Rice {
47d9611800SBenno Rice 	device_t	ofwd_dev;
48d9611800SBenno Rice 	dev_t		ofwd_dev_t;
49d9611800SBenno Rice 	struct		disk ofwd_disk;
50d9611800SBenno Rice 	phandle_t	ofwd_package;
51d9611800SBenno Rice 	ihandle_t	ofwd_instance;
52d9611800SBenno Rice 	u_int		ofwd_flags;
53d9611800SBenno Rice #define	OFWD_OPEN	(1<<0)
54d9611800SBenno Rice };
55d9611800SBenno Rice 
56d9611800SBenno Rice /*
57d9611800SBenno Rice  * Disk device bus interface.
58d9611800SBenno Rice  */
59d9611800SBenno Rice static void	ofwd_identify(driver_t *, device_t);
60d9611800SBenno Rice static int	ofwd_probe(device_t);
61d9611800SBenno Rice static int	ofwd_attach(device_t);
62d9611800SBenno Rice 
63d9611800SBenno Rice static device_method_t	ofwd_methods[] = {
64d9611800SBenno Rice 	DEVMETHOD(device_identify,	ofwd_identify),
65d9611800SBenno Rice 	DEVMETHOD(device_probe, 	ofwd_probe),
66d9611800SBenno Rice 	DEVMETHOD(device_attach,	ofwd_attach),
67d9611800SBenno Rice 	{ 0, 0 }
68d9611800SBenno Rice };
69d9611800SBenno Rice 
70d9611800SBenno Rice static driver_t ofwd_driver = {
71d9611800SBenno Rice 	"ofwd",
72d9611800SBenno Rice 	ofwd_methods,
73d9611800SBenno Rice 	sizeof(struct ofwd_softc)
74d9611800SBenno Rice };
75d9611800SBenno Rice 
76d9611800SBenno Rice static devclass_t	ofwd_devclass;
77d9611800SBenno Rice 
78d9611800SBenno Rice DRIVER_MODULE(ofwd, nexus, ofwd_driver, ofwd_devclass, 0, 0);
79d9611800SBenno Rice 
80d9611800SBenno Rice /*
81d9611800SBenno Rice  * Disk device control interface.
82d9611800SBenno Rice  */
83d9611800SBenno Rice static d_open_t		ofwd_open;
84d9611800SBenno Rice static d_close_t	ofwd_close;
85d9611800SBenno Rice static d_strategy_t	ofwd_strategy;
86d9611800SBenno Rice 
87d9611800SBenno Rice #define	OFWD_CDEV_MAJOR	169
88d9611800SBenno Rice 
89d9611800SBenno Rice static struct cdevsw ofwd_cdevsw = {
90d9611800SBenno Rice 	ofwd_open,
91d9611800SBenno Rice 	ofwd_close,
92d9611800SBenno Rice 	physread,
93d9611800SBenno Rice 	physwrite,
94d9611800SBenno Rice 	noioctl,
95d9611800SBenno Rice 	nopoll,
96d9611800SBenno Rice 	nommap,
97d9611800SBenno Rice 	ofwd_strategy,
98d9611800SBenno Rice 	"ofwd",
99d9611800SBenno Rice 	OFWD_CDEV_MAJOR,
100d9611800SBenno Rice 	nodump,
101d9611800SBenno Rice 	nopsize,
102d9611800SBenno Rice 	D_DISK
103d9611800SBenno Rice };
104d9611800SBenno Rice 
105d9611800SBenno Rice static struct cdevsw	ofwddisk_cdevsw;
106d9611800SBenno Rice 
107d9611800SBenno Rice /*
108d9611800SBenno Rice  * Handle open from generic layer.
109d9611800SBenno Rice  *
110d9611800SBenno Rice  * This is typically only called by the diskslice code and not for opens on
111d9611800SBenno Rice  * subdevices.
112d9611800SBenno Rice  */
113d9611800SBenno Rice static int
114d9611800SBenno Rice ofwd_open(dev_t dev, int flags, int fmt, struct thread *td)
115d9611800SBenno Rice {
116d9611800SBenno Rice 	struct	ofwd_softc *sc;
117d9611800SBenno Rice 	struct	disklabel *label;
118d9611800SBenno Rice 
119d9611800SBenno Rice 	sc = (struct ofwd_softc *)dev->si_drv1;
120d9611800SBenno Rice 	if (sc == NULL)
121d9611800SBenno Rice 		return (ENXIO);
122d9611800SBenno Rice 
123d9611800SBenno Rice 	/*
124d9611800SBenno Rice 	 * Build synthetic label.
125d9611800SBenno Rice 	 */
126d9611800SBenno Rice 	label = &sc->ofwd_disk.d_label;
127d9611800SBenno Rice 	bzero(label, sizeof(*label));
128d9611800SBenno Rice 	label->d_type = DTYPE_ESDI;
129d9611800SBenno Rice 	label->d_secsize = OFWD_BLOCKSIZE;
130d9611800SBenno Rice 	label->d_nsectors = 33554432;
131d9611800SBenno Rice 	label->d_ntracks = 1;
132d9611800SBenno Rice 	label->d_ncylinders = 1024;
133d9611800SBenno Rice 	label->d_secpercyl = 32768;
134d9611800SBenno Rice 	label->d_secperunit = 33554432;
135d9611800SBenno Rice 
136d9611800SBenno Rice 	sc->ofwd_flags |= OFWD_OPEN;
137d9611800SBenno Rice 	return (0);
138d9611800SBenno Rice }
139d9611800SBenno Rice 
140d9611800SBenno Rice /*
141d9611800SBenno Rice  * Handle last close of the disk device.
142d9611800SBenno Rice  */
143d9611800SBenno Rice static int
144d9611800SBenno Rice ofwd_close(dev_t dev, int flags, int fmt, struct thread *td)
145d9611800SBenno Rice {
146d9611800SBenno Rice 	struct	ofwd_softc *sc;
147d9611800SBenno Rice 
148d9611800SBenno Rice 	sc = (struct ofwd_softc *)dev->si_drv1;
149d9611800SBenno Rice 
150d9611800SBenno Rice 	if (sc == NULL)
151d9611800SBenno Rice 		return (ENXIO);
152d9611800SBenno Rice 
153d9611800SBenno Rice 	sc->ofwd_flags &= ~OFWD_OPEN;
154d9611800SBenno Rice 
155d9611800SBenno Rice 	return (0);
156d9611800SBenno Rice }
157d9611800SBenno Rice 
158d9611800SBenno Rice /*
159d9611800SBenno Rice  * Handle an I/O request.
160d9611800SBenno Rice  */
161d9611800SBenno Rice static void
162d9611800SBenno Rice ofwd_strategy(struct bio *bp)
163d9611800SBenno Rice {
164d9611800SBenno Rice 	struct	ofwd_softc *sc;
165d9611800SBenno Rice 	long	r;
166d9611800SBenno Rice 
167d9611800SBenno Rice 	sc = (struct ofwd_softc *)bp->bio_dev->si_drv1;
168d9611800SBenno Rice 
169d9611800SBenno Rice 	if (sc == NULL) {
170d9611800SBenno Rice 		bp->bio_error = EINVAL;
171d9611800SBenno Rice 		bp->bio_flags |= BIO_ERROR;
172d9611800SBenno Rice 		printf("ofwd: bio for invalid disk!\n");
173d9611800SBenno Rice 		biodone(bp);
174d9611800SBenno Rice 		return;
175d9611800SBenno Rice 	}
176d9611800SBenno Rice 
177d9611800SBenno Rice 	r = OF_seek(sc->ofwd_instance,
178d9611800SBenno Rice 	    (u_quad_t)(bp->bio_blkno * OFWD_BLOCKSIZE));
179d9611800SBenno Rice 	if (r == -1) {
180d9611800SBenno Rice 		bp->bio_resid = bp->bio_bcount;
181d9611800SBenno Rice 		bp->bio_error = EIO;
182d9611800SBenno Rice 		bp->bio_flags |= BIO_ERROR;
183d9611800SBenno Rice 		device_printf(sc->ofwd_dev, "seek failed\n");
184d9611800SBenno Rice 		biodone(bp);
185d9611800SBenno Rice 		return;
186d9611800SBenno Rice 	}
187d9611800SBenno Rice 
188d9611800SBenno Rice 	if (bp->bio_cmd == BIO_READ) {
189d9611800SBenno Rice 		r = OF_read(sc->ofwd_instance, (void *)bp->bio_data,
190d9611800SBenno Rice 		    bp->bio_bcount);
191d9611800SBenno Rice 	} else {
192d9611800SBenno Rice 		r = OF_write(sc->ofwd_instance, (void *)bp->bio_data,
193d9611800SBenno Rice 			    bp->bio_bcount);
194d9611800SBenno Rice 	}
195d9611800SBenno Rice 
196d9611800SBenno Rice 	if (r < bp->bio_bcount) {
197d9611800SBenno Rice 		device_printf(sc->ofwd_dev, "r (%ld) < bp->bio_bcount (%ld)\n",
198d9611800SBenno Rice 		    r, bp->bio_bcount);
199d9611800SBenno Rice 		if (r != -1)
200d9611800SBenno Rice 			bp->bio_resid = bp->bio_bcount - r;
201d9611800SBenno Rice 		bp->bio_error = EIO;
202d9611800SBenno Rice 		bp->bio_flags |= BIO_ERROR;
203d9611800SBenno Rice 	} else if (r > bp->bio_bcount)
204d9611800SBenno Rice 		panic("ofwd: more bytes read/written than requested");
205d9611800SBenno Rice 
206d9611800SBenno Rice 	bp->bio_resid -= r;
207d9611800SBenno Rice 	biodone(bp);
208d9611800SBenno Rice 
209d9611800SBenno Rice 	return;
210d9611800SBenno Rice }
211d9611800SBenno Rice 
212d9611800SBenno Rice /*
213d9611800SBenno Rice  * Probe for an OpenFirmware disk.
214d9611800SBenno Rice  */
215d9611800SBenno Rice static int
216d9611800SBenno Rice ofwd_probe(device_t dev)
217d9611800SBenno Rice {
218d9611800SBenno Rice 	char		*type;
219d9611800SBenno Rice 
220d9611800SBenno Rice 	type = nexus_get_device_type(dev);
221d9611800SBenno Rice 
222d9611800SBenno Rice 	if (type == NULL || strcmp(type, "disk") != 0)
223d9611800SBenno Rice 		return (ENXIO);
224d9611800SBenno Rice 
225d9611800SBenno Rice 	device_set_desc(dev, "OpenFirmware disk");
226d9611800SBenno Rice 	return (0);
227d9611800SBenno Rice }
228d9611800SBenno Rice 
229d9611800SBenno Rice static int
230d9611800SBenno Rice ofwd_attach(device_t dev)
231d9611800SBenno Rice {
232d9611800SBenno Rice 	struct	ofwd_softc *sc;
233d9611800SBenno Rice 	char	path[128];
234d9611800SBenno Rice 	dev_t	dsk;
235d9611800SBenno Rice 
236d9611800SBenno Rice 	sc = device_get_softc(dev);
237d9611800SBenno Rice 	sc->ofwd_dev = dev;
238d9611800SBenno Rice 
239d9611800SBenno Rice 	bzero(path, 128);
240d9611800SBenno Rice 	OF_package_to_path(nexus_get_node(dev), path, 128);
241d9611800SBenno Rice 	device_printf(dev, "located at %s\n", path);
242d9611800SBenno Rice 	sc->ofwd_instance = OF_open(path);
243d9611800SBenno Rice 	if (sc->ofwd_instance == -1) {
244d9611800SBenno Rice 		device_printf(dev, "could not create instance\n");
245d9611800SBenno Rice 		return (ENXIO);
246d9611800SBenno Rice 	}
247d9611800SBenno Rice 
248d9611800SBenno Rice 	dsk = disk_create(device_get_unit(dev), &sc->ofwd_disk, 0,
249d9611800SBenno Rice 	    &ofwd_cdevsw, &ofwddisk_cdevsw);
250d9611800SBenno Rice 	dsk->si_drv1 = sc;
251d9611800SBenno Rice 	sc->ofwd_dev_t = dsk;
252d9611800SBenno Rice 
253d9611800SBenno Rice 	dsk->si_iosize_max = PAGE_SIZE;
254d9611800SBenno Rice 
255d9611800SBenno Rice 	return (0);
256d9611800SBenno Rice }
257d9611800SBenno Rice 
258d9611800SBenno Rice static void
259d9611800SBenno Rice ofwd_identify(driver_t *driver, device_t parent)
260d9611800SBenno Rice {
261d9611800SBenno Rice }
262