ofw_disk.c revision 94749
194749Sbenno/*
294749Sbenno * Copyright (C) 2002 Benno Rice <benno@FreeBSD.org>
394749Sbenno * All rights reserved.
494749Sbenno *
594749Sbenno * Redistribution and use in source and binary forms, with or without
694749Sbenno * modification, are permitted provided that the following conditions
794749Sbenno * are met:
894749Sbenno * 1. Redistributions of source code must retain the above copyright
994749Sbenno *    notice, this list of conditions and the following disclaimer.
1094749Sbenno * 2. Redistributions in binary form must reproduce the above copyright
1194749Sbenno *    notice, this list of conditions and the following disclaimer in the
1294749Sbenno *    documentation and/or other materials provided with the distribution.
1394749Sbenno *
1494749Sbenno * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
1594749Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1694749Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1794749Sbenno * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1894749Sbenno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1994749Sbenno * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2094749Sbenno * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2194749Sbenno * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2294749Sbenno * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
2394749Sbenno * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2494749Sbenno *
2594749Sbenno * $FreeBSD: head/sys/dev/ofw/ofw_disk.c 94749 2002-04-15 10:54:22Z benno $
2694749Sbenno *
2794749Sbenno */
2894749Sbenno
2994749Sbenno#include <sys/param.h>
3094749Sbenno#include <sys/systm.h>
3194749Sbenno#include <sys/bio.h>
3294749Sbenno#include <sys/bus.h>
3394749Sbenno#include <sys/conf.h>
3494749Sbenno#include <sys/disk.h>
3594749Sbenno#include <sys/kernel.h>
3694749Sbenno
3794749Sbenno#include <dev/ofw/openfirm.h>
3894749Sbenno
3994749Sbenno#include <machine/bus.h>
4094749Sbenno#include <machine/md_var.h>
4194749Sbenno#include <machine/nexusvar.h>
4294749Sbenno
4394749Sbenno#define	OFWD_BLOCKSIZE	512
4494749Sbenno
4594749Sbennostruct ofwd_softc
4694749Sbenno{
4794749Sbenno	device_t	ofwd_dev;
4894749Sbenno	dev_t		ofwd_dev_t;
4994749Sbenno	struct		disk ofwd_disk;
5094749Sbenno	phandle_t	ofwd_package;
5194749Sbenno	ihandle_t	ofwd_instance;
5294749Sbenno	u_int		ofwd_flags;
5394749Sbenno#define	OFWD_OPEN	(1<<0)
5494749Sbenno};
5594749Sbenno
5694749Sbenno/*
5794749Sbenno * Disk device bus interface.
5894749Sbenno */
5994749Sbennostatic void	ofwd_identify(driver_t *, device_t);
6094749Sbennostatic int	ofwd_probe(device_t);
6194749Sbennostatic int	ofwd_attach(device_t);
6294749Sbenno
6394749Sbennostatic device_method_t	ofwd_methods[] = {
6494749Sbenno	DEVMETHOD(device_identify,	ofwd_identify),
6594749Sbenno	DEVMETHOD(device_probe, 	ofwd_probe),
6694749Sbenno	DEVMETHOD(device_attach,	ofwd_attach),
6794749Sbenno	{ 0, 0 }
6894749Sbenno};
6994749Sbenno
7094749Sbennostatic driver_t ofwd_driver = {
7194749Sbenno	"ofwd",
7294749Sbenno	ofwd_methods,
7394749Sbenno	sizeof(struct ofwd_softc)
7494749Sbenno};
7594749Sbenno
7694749Sbennostatic devclass_t	ofwd_devclass;
7794749Sbenno
7894749SbennoDRIVER_MODULE(ofwd, nexus, ofwd_driver, ofwd_devclass, 0, 0);
7994749Sbenno
8094749Sbenno/*
8194749Sbenno * Disk device control interface.
8294749Sbenno */
8394749Sbennostatic d_open_t		ofwd_open;
8494749Sbennostatic d_close_t	ofwd_close;
8594749Sbennostatic d_strategy_t	ofwd_strategy;
8694749Sbenno
8794749Sbenno#define	OFWD_CDEV_MAJOR	169
8894749Sbenno
8994749Sbennostatic struct cdevsw ofwd_cdevsw = {
9094749Sbenno	ofwd_open,
9194749Sbenno	ofwd_close,
9294749Sbenno	physread,
9394749Sbenno	physwrite,
9494749Sbenno	noioctl,
9594749Sbenno	nopoll,
9694749Sbenno	nommap,
9794749Sbenno	ofwd_strategy,
9894749Sbenno	"ofwd",
9994749Sbenno	OFWD_CDEV_MAJOR,
10094749Sbenno	nodump,
10194749Sbenno	nopsize,
10294749Sbenno	D_DISK
10394749Sbenno};
10494749Sbenno
10594749Sbennostatic struct cdevsw	ofwddisk_cdevsw;
10694749Sbenno
10794749Sbenno/*
10894749Sbenno * Handle open from generic layer.
10994749Sbenno *
11094749Sbenno * This is typically only called by the diskslice code and not for opens on
11194749Sbenno * subdevices.
11294749Sbenno */
11394749Sbennostatic int
11494749Sbennoofwd_open(dev_t dev, int flags, int fmt, struct thread *td)
11594749Sbenno{
11694749Sbenno	struct	ofwd_softc *sc;
11794749Sbenno	struct	disklabel *label;
11894749Sbenno
11994749Sbenno	sc = (struct ofwd_softc *)dev->si_drv1;
12094749Sbenno	if (sc == NULL)
12194749Sbenno		return (ENXIO);
12294749Sbenno
12394749Sbenno	/*
12494749Sbenno	 * Build synthetic label.
12594749Sbenno	 */
12694749Sbenno	label = &sc->ofwd_disk.d_label;
12794749Sbenno	bzero(label, sizeof(*label));
12894749Sbenno	label->d_type = DTYPE_ESDI;
12994749Sbenno	label->d_secsize = OFWD_BLOCKSIZE;
13094749Sbenno	label->d_nsectors = 33554432;
13194749Sbenno	label->d_ntracks = 1;
13294749Sbenno	label->d_ncylinders = 1024;
13394749Sbenno	label->d_secpercyl = 32768;
13494749Sbenno	label->d_secperunit = 33554432;
13594749Sbenno
13694749Sbenno	sc->ofwd_flags |= OFWD_OPEN;
13794749Sbenno	return (0);
13894749Sbenno}
13994749Sbenno
14094749Sbenno/*
14194749Sbenno * Handle last close of the disk device.
14294749Sbenno */
14394749Sbennostatic int
14494749Sbennoofwd_close(dev_t dev, int flags, int fmt, struct thread *td)
14594749Sbenno{
14694749Sbenno	struct	ofwd_softc *sc;
14794749Sbenno
14894749Sbenno	sc = (struct ofwd_softc *)dev->si_drv1;
14994749Sbenno
15094749Sbenno	if (sc == NULL)
15194749Sbenno		return (ENXIO);
15294749Sbenno
15394749Sbenno	sc->ofwd_flags &= ~OFWD_OPEN;
15494749Sbenno
15594749Sbenno	return (0);
15694749Sbenno}
15794749Sbenno
15894749Sbenno/*
15994749Sbenno * Handle an I/O request.
16094749Sbenno */
16194749Sbennostatic void
16294749Sbennoofwd_strategy(struct bio *bp)
16394749Sbenno{
16494749Sbenno	struct	ofwd_softc *sc;
16594749Sbenno	long	r;
16694749Sbenno
16794749Sbenno	sc = (struct ofwd_softc *)bp->bio_dev->si_drv1;
16894749Sbenno
16994749Sbenno	if (sc == NULL) {
17094749Sbenno		bp->bio_error = EINVAL;
17194749Sbenno		bp->bio_flags |= BIO_ERROR;
17294749Sbenno		printf("ofwd: bio for invalid disk!\n");
17394749Sbenno		biodone(bp);
17494749Sbenno		return;
17594749Sbenno	}
17694749Sbenno
17794749Sbenno	r = OF_seek(sc->ofwd_instance,
17894749Sbenno	    (u_quad_t)(bp->bio_blkno * OFWD_BLOCKSIZE));
17994749Sbenno	if (r == -1) {
18094749Sbenno		bp->bio_resid = bp->bio_bcount;
18194749Sbenno		bp->bio_error = EIO;
18294749Sbenno		bp->bio_flags |= BIO_ERROR;
18394749Sbenno		device_printf(sc->ofwd_dev, "seek failed\n");
18494749Sbenno		biodone(bp);
18594749Sbenno		return;
18694749Sbenno	}
18794749Sbenno
18894749Sbenno	if (bp->bio_cmd == BIO_READ) {
18994749Sbenno		r = OF_read(sc->ofwd_instance, (void *)bp->bio_data,
19094749Sbenno		    bp->bio_bcount);
19194749Sbenno	} else {
19294749Sbenno		r = OF_write(sc->ofwd_instance, (void *)bp->bio_data,
19394749Sbenno			    bp->bio_bcount);
19494749Sbenno	}
19594749Sbenno
19694749Sbenno	if (r < bp->bio_bcount) {
19794749Sbenno		device_printf(sc->ofwd_dev, "r (%ld) < bp->bio_bcount (%ld)\n",
19894749Sbenno		    r, bp->bio_bcount);
19994749Sbenno		if (r != -1)
20094749Sbenno			bp->bio_resid = bp->bio_bcount - r;
20194749Sbenno		bp->bio_error = EIO;
20294749Sbenno		bp->bio_flags |= BIO_ERROR;
20394749Sbenno	} else if (r > bp->bio_bcount)
20494749Sbenno		panic("ofwd: more bytes read/written than requested");
20594749Sbenno
20694749Sbenno	bp->bio_resid -= r;
20794749Sbenno	biodone(bp);
20894749Sbenno
20994749Sbenno	return;
21094749Sbenno}
21194749Sbenno
21294749Sbenno/*
21394749Sbenno * Probe for an OpenFirmware disk.
21494749Sbenno */
21594749Sbennostatic int
21694749Sbennoofwd_probe(device_t dev)
21794749Sbenno{
21894749Sbenno	char		*type;
21994749Sbenno
22094749Sbenno	type = nexus_get_device_type(dev);
22194749Sbenno
22294749Sbenno	if (type == NULL || strcmp(type, "disk") != 0)
22394749Sbenno		return (ENXIO);
22494749Sbenno
22594749Sbenno	device_set_desc(dev, "OpenFirmware disk");
22694749Sbenno	return (0);
22794749Sbenno}
22894749Sbenno
22994749Sbennostatic int
23094749Sbennoofwd_attach(device_t dev)
23194749Sbenno{
23294749Sbenno	struct	ofwd_softc *sc;
23394749Sbenno	char	path[128];
23494749Sbenno	dev_t	dsk;
23594749Sbenno
23694749Sbenno	sc = device_get_softc(dev);
23794749Sbenno	sc->ofwd_dev = dev;
23894749Sbenno
23994749Sbenno	bzero(path, 128);
24094749Sbenno	OF_package_to_path(nexus_get_node(dev), path, 128);
24194749Sbenno	device_printf(dev, "located at %s\n", path);
24294749Sbenno	sc->ofwd_instance = OF_open(path);
24394749Sbenno	if (sc->ofwd_instance == -1) {
24494749Sbenno		device_printf(dev, "could not create instance\n");
24594749Sbenno		return (ENXIO);
24694749Sbenno	}
24794749Sbenno
24894749Sbenno	dsk = disk_create(device_get_unit(dev), &sc->ofwd_disk, 0,
24994749Sbenno	    &ofwd_cdevsw, &ofwddisk_cdevsw);
25094749Sbenno	dsk->si_drv1 = sc;
25194749Sbenno	sc->ofwd_dev_t = dsk;
25294749Sbenno
25394749Sbenno	dsk->si_iosize_max = PAGE_SIZE;
25494749Sbenno
25594749Sbenno	return (0);
25694749Sbenno}
25794749Sbenno
25894749Sbennostatic void
25994749Sbennoofwd_identify(driver_t *driver, device_t parent)
26094749Sbenno{
26194749Sbenno}
262