ofw_disk.c revision 125435
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 * 2694749Sbenno */ 2794749Sbenno 28119418Sobrien#include <sys/cdefs.h> 29119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/ofw/ofw_disk.c 125435 2004-02-04 12:52:57Z grehan $"); 30119418Sobrien 3194749Sbenno#include <sys/param.h> 3294749Sbenno#include <sys/systm.h> 3394749Sbenno#include <sys/bio.h> 3494749Sbenno#include <sys/bus.h> 3594749Sbenno#include <sys/conf.h> 3694749Sbenno#include <sys/kernel.h> 37125435Sgrehan#include <sys/limits.h> 38113020Sdes#include <geom/geom_disk.h> 3994749Sbenno 4094749Sbenno#include <dev/ofw/openfirm.h> 4194749Sbenno 4294749Sbenno#include <machine/bus.h> 4394749Sbenno#include <machine/md_var.h> 4494749Sbenno#include <machine/nexusvar.h> 4594749Sbenno 4694749Sbenno#define OFWD_BLOCKSIZE 512 4794749Sbenno 4894749Sbennostruct ofwd_softc 4994749Sbenno{ 5094749Sbenno device_t ofwd_dev; 5194749Sbenno struct disk ofwd_disk; 5294749Sbenno phandle_t ofwd_package; 5394749Sbenno ihandle_t ofwd_instance; 5494749Sbenno}; 5594749Sbenno 5694749Sbenno/* 5794749Sbenno * Disk device bus interface. 5894749Sbenno */ 59125435Sgrehanstatic 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[] = { 64125435Sgrehan 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 */ 83111340Sphkstatic disk_strategy_t ofwd_strategy; 8494749Sbenno 8594749Sbenno/* 8694749Sbenno * Handle an I/O request. 8794749Sbenno */ 8894749Sbennostatic void 8994749Sbennoofwd_strategy(struct bio *bp) 9094749Sbenno{ 9194749Sbenno struct ofwd_softc *sc; 9294749Sbenno long r; 9394749Sbenno 94111340Sphk sc = (struct ofwd_softc *)bp->bio_disk->d_drv1; 9594749Sbenno 9694749Sbenno if (sc == NULL) { 9794749Sbenno printf("ofwd: bio for invalid disk!\n"); 98111340Sphk biofinish(bp, NULL, EINVAL); 9994749Sbenno return; 10094749Sbenno } 10194749Sbenno 102121209Sphk r = OF_seek(sc->ofwd_instance, bp->bio_offset); 10394749Sbenno if (r == -1) { 10494749Sbenno bp->bio_resid = bp->bio_bcount; 10594749Sbenno device_printf(sc->ofwd_dev, "seek failed\n"); 106111340Sphk biofinish(bp, NULL, EIO); 10794749Sbenno return; 10894749Sbenno } 10994749Sbenno 11094749Sbenno if (bp->bio_cmd == BIO_READ) { 11194749Sbenno r = OF_read(sc->ofwd_instance, (void *)bp->bio_data, 11294749Sbenno bp->bio_bcount); 11394749Sbenno } else { 11494749Sbenno r = OF_write(sc->ofwd_instance, (void *)bp->bio_data, 11594749Sbenno bp->bio_bcount); 11694749Sbenno } 11794749Sbenno 118111340Sphk if (r > bp->bio_bcount) 119111340Sphk panic("ofwd: more bytes read/written than requested"); 120111340Sphk if (r == -1) { 12194749Sbenno device_printf(sc->ofwd_dev, "r (%ld) < bp->bio_bcount (%ld)\n", 12294749Sbenno r, bp->bio_bcount); 123111340Sphk biofinish(bp, NULL, EIO); 124111340Sphk return; 125111340Sphk } 12694749Sbenno 12794749Sbenno bp->bio_resid -= r; 128125435Sgrehan 129111340Sphk if (r < bp->bio_bcount) { 130111340Sphk device_printf(sc->ofwd_dev, "r (%ld) < bp->bio_bcount (%ld)\n", 131111340Sphk r, bp->bio_bcount); 132111340Sphk biofinish(bp, NULL, EIO); /* XXX: probably not an error */ 133111340Sphk return; 134125435Sgrehan } 135111979Sphk biodone(bp); 13694749Sbenno return; 13794749Sbenno} 13894749Sbenno 13994749Sbenno/* 140125435Sgrehan * Attach the OpenFirmware disk to nexus if present 141125435Sgrehan */ 142125435Sgrehanstatic void 143125435Sgrehanofwd_identify(driver_t *driver, device_t parent) 144125435Sgrehan{ 145125435Sgrehan device_t child; 146125435Sgrehan phandle_t ofd; 147125435Sgrehan static char type[8]; 148125435Sgrehan 149125435Sgrehan ofd = OF_finddevice("ofwdisk"); 150125435Sgrehan if (ofd == -1) 151125435Sgrehan return; 152125435Sgrehan 153125435Sgrehan OF_getprop(ofd, "device_type", type, sizeof(type)); 154125435Sgrehan 155125435Sgrehan child = BUS_ADD_CHILD(parent, INT_MAX, "ofwd", 0); 156125435Sgrehan if (child != NULL) { 157125435Sgrehan nexus_set_device_type(child, type); 158125435Sgrehan nexus_set_node(child, ofd); 159125435Sgrehan } 160125435Sgrehan} 161125435Sgrehan 162125435Sgrehan/* 16394749Sbenno * Probe for an OpenFirmware disk. 16494749Sbenno */ 16594749Sbennostatic int 16694749Sbennoofwd_probe(device_t dev) 16794749Sbenno{ 16894749Sbenno char *type; 169123543Sgrehan char fname[32]; 170123543Sgrehan phandle_t node; 17194749Sbenno 17294749Sbenno type = nexus_get_device_type(dev); 173123543Sgrehan node = nexus_get_node(dev); 17494749Sbenno 175125435Sgrehan if (type == NULL || 176123490Sgrehan (strcmp(type, "disk") != 0 && strcmp(type, "block") != 0)) 17794749Sbenno return (ENXIO); 17894749Sbenno 179123543Sgrehan if (OF_getprop(node, "file", fname, sizeof(fname)) == -1) 180123543Sgrehan return (ENXIO); 181123543Sgrehan 18294749Sbenno device_set_desc(dev, "OpenFirmware disk"); 18394749Sbenno return (0); 18494749Sbenno} 18594749Sbenno 18694749Sbennostatic int 18794749Sbennoofwd_attach(device_t dev) 18894749Sbenno{ 18994749Sbenno struct ofwd_softc *sc; 19094749Sbenno char path[128]; 191123543Sgrehan char fname[32]; 19294749Sbenno 19394749Sbenno sc = device_get_softc(dev); 19494749Sbenno sc->ofwd_dev = dev; 19594749Sbenno 19694749Sbenno bzero(path, 128); 19794749Sbenno OF_package_to_path(nexus_get_node(dev), path, 128); 198123543Sgrehan OF_getprop(nexus_get_node(dev), "file", fname, sizeof(fname)); 199123543Sgrehan device_printf(dev, "located at %s, file %s\n", path, fname); 20094749Sbenno sc->ofwd_instance = OF_open(path); 20194749Sbenno if (sc->ofwd_instance == -1) { 20294749Sbenno device_printf(dev, "could not create instance\n"); 20394749Sbenno return (ENXIO); 20494749Sbenno } 20594749Sbenno 206111340Sphk sc->ofwd_disk.d_strategy = ofwd_strategy; 207111340Sphk sc->ofwd_disk.d_name = "ofwd"; 208111340Sphk sc->ofwd_disk.d_sectorsize = OFWD_BLOCKSIZE; 209111340Sphk sc->ofwd_disk.d_mediasize = (off_t)33554432 * OFWD_BLOCKSIZE; 210111340Sphk sc->ofwd_disk.d_fwsectors = 0; 211111340Sphk sc->ofwd_disk.d_fwheads = 0; 212111340Sphk sc->ofwd_disk.d_drv1 = sc; 213111340Sphk sc->ofwd_disk.d_maxsize = PAGE_SIZE; 214111340Sphk disk_create(device_get_unit(dev), &sc->ofwd_disk, 0, NULL, NULL); 21594749Sbenno 21694749Sbenno return (0); 21794749Sbenno} 218