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