189e0f4d2SKip Macy /*- 289e0f4d2SKip Macy * All rights reserved. 389e0f4d2SKip Macy * 489e0f4d2SKip Macy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 589e0f4d2SKip Macy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 689e0f4d2SKip Macy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 789e0f4d2SKip Macy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 889e0f4d2SKip Macy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 989e0f4d2SKip Macy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1089e0f4d2SKip Macy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 1189e0f4d2SKip Macy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 1289e0f4d2SKip Macy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 1389e0f4d2SKip Macy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 1489e0f4d2SKip Macy * SUCH DAMAGE. 1589e0f4d2SKip Macy * 1689e0f4d2SKip Macy */ 1789e0f4d2SKip Macy 1889e0f4d2SKip Macy /* 1989e0f4d2SKip Macy * XenoBSD block device driver 2089e0f4d2SKip Macy */ 2189e0f4d2SKip Macy 2289e0f4d2SKip Macy #include <sys/cdefs.h> 2389e0f4d2SKip Macy __FBSDID("$FreeBSD$"); 2489e0f4d2SKip Macy 2589e0f4d2SKip Macy #include <sys/param.h> 2689e0f4d2SKip Macy #include <sys/systm.h> 2789e0f4d2SKip Macy #include <sys/malloc.h> 2889e0f4d2SKip Macy #include <sys/kernel.h> 2989e0f4d2SKip Macy #include <vm/vm.h> 3089e0f4d2SKip Macy #include <vm/pmap.h> 3189e0f4d2SKip Macy 3289e0f4d2SKip Macy #include <sys/bio.h> 3389e0f4d2SKip Macy #include <sys/bus.h> 3489e0f4d2SKip Macy #include <sys/conf.h> 3589e0f4d2SKip Macy #include <sys/module.h> 3689e0f4d2SKip Macy 3789e0f4d2SKip Macy #include <machine/bus.h> 3889e0f4d2SKip Macy #include <sys/rman.h> 3989e0f4d2SKip Macy #include <machine/resource.h> 4089e0f4d2SKip Macy #include <machine/intr_machdep.h> 4189e0f4d2SKip Macy #include <machine/vmparam.h> 4289e0f4d2SKip Macy 4389e0f4d2SKip Macy #include <machine/xen/hypervisor.h> 4489e0f4d2SKip Macy #include <machine/xen/xen-os.h> 4589e0f4d2SKip Macy #include <machine/xen/xen_intr.h> 4689e0f4d2SKip Macy #include <machine/xen/xenbus.h> 4789e0f4d2SKip Macy #include <machine/xen/evtchn.h> 4889e0f4d2SKip Macy #include <xen/interface/grant_table.h> 4989e0f4d2SKip Macy 5089e0f4d2SKip Macy #include <geom/geom_disk.h> 5189e0f4d2SKip Macy #include <machine/xen/xenfunc.h> 5289e0f4d2SKip Macy #include <xen/gnttab.h> 5389e0f4d2SKip Macy 5489e0f4d2SKip Macy #include <dev/xen/blkfront/block.h> 5589e0f4d2SKip Macy 5689e0f4d2SKip Macy #define ASSERT(S) KASSERT(S, (#S)) 5789e0f4d2SKip Macy /* prototypes */ 5889e0f4d2SKip Macy struct xb_softc; 5989e0f4d2SKip Macy static void xb_startio(struct xb_softc *sc); 6089e0f4d2SKip Macy static void connect(struct blkfront_info *); 6189e0f4d2SKip Macy static void blkfront_closing(struct xenbus_device *); 6289e0f4d2SKip Macy static int blkfront_remove(struct xenbus_device *); 6389e0f4d2SKip Macy static int talk_to_backend(struct xenbus_device *, struct blkfront_info *); 6489e0f4d2SKip Macy static int setup_blkring(struct xenbus_device *, struct blkfront_info *); 6589e0f4d2SKip Macy static void blkif_int(void *); 6689e0f4d2SKip Macy #if 0 6789e0f4d2SKip Macy static void blkif_restart_queue(void *arg); 6889e0f4d2SKip Macy #endif 6989e0f4d2SKip Macy static void blkif_recover(struct blkfront_info *); 7089e0f4d2SKip Macy static void blkif_completion(struct blk_shadow *); 7189e0f4d2SKip Macy static void blkif_free(struct blkfront_info *, int); 7289e0f4d2SKip Macy 7389e0f4d2SKip Macy #define GRANT_INVALID_REF 0 7489e0f4d2SKip Macy #define BLK_RING_SIZE __RING_SIZE((blkif_sring_t *)0, PAGE_SIZE) 7589e0f4d2SKip Macy 7689e0f4d2SKip Macy LIST_HEAD(xb_softc_list_head, xb_softc) xbsl_head; 7789e0f4d2SKip Macy 7889e0f4d2SKip Macy /* Control whether runtime update of vbds is enabled. */ 7989e0f4d2SKip Macy #define ENABLE_VBD_UPDATE 0 8089e0f4d2SKip Macy 8189e0f4d2SKip Macy #if ENABLE_VBD_UPDATE 8289e0f4d2SKip Macy static void vbd_update(void); 8389e0f4d2SKip Macy #endif 8489e0f4d2SKip Macy 8589e0f4d2SKip Macy 8689e0f4d2SKip Macy #define BLKIF_STATE_DISCONNECTED 0 8789e0f4d2SKip Macy #define BLKIF_STATE_CONNECTED 1 8889e0f4d2SKip Macy #define BLKIF_STATE_SUSPENDED 2 8989e0f4d2SKip Macy 9089e0f4d2SKip Macy #ifdef notyet 9189e0f4d2SKip Macy static char *blkif_state_name[] = { 9289e0f4d2SKip Macy [BLKIF_STATE_DISCONNECTED] = "disconnected", 9389e0f4d2SKip Macy [BLKIF_STATE_CONNECTED] = "connected", 9489e0f4d2SKip Macy [BLKIF_STATE_SUSPENDED] = "closed", 9589e0f4d2SKip Macy }; 9689e0f4d2SKip Macy 9789e0f4d2SKip Macy static char * blkif_status_name[] = { 9889e0f4d2SKip Macy [BLKIF_INTERFACE_STATUS_CLOSED] = "closed", 9989e0f4d2SKip Macy [BLKIF_INTERFACE_STATUS_DISCONNECTED] = "disconnected", 10089e0f4d2SKip Macy [BLKIF_INTERFACE_STATUS_CONNECTED] = "connected", 10189e0f4d2SKip Macy [BLKIF_INTERFACE_STATUS_CHANGED] = "changed", 10289e0f4d2SKip Macy }; 10389e0f4d2SKip Macy #endif 10489e0f4d2SKip Macy #define WPRINTK(fmt, args...) printf("[XEN] " fmt, ##args) 10589e0f4d2SKip Macy #if 0 10689e0f4d2SKip Macy #define DPRINTK(fmt, args...) printf("[XEN] %s:%d" fmt ".\n", __FUNCTION__, __LINE__,##args) 10789e0f4d2SKip Macy #else 10889e0f4d2SKip Macy #define DPRINTK(fmt, args...) 10989e0f4d2SKip Macy #endif 11089e0f4d2SKip Macy 11189e0f4d2SKip Macy static grant_ref_t gref_head; 11289e0f4d2SKip Macy #define MAXIMUM_OUTSTANDING_BLOCK_REQS \ 11389e0f4d2SKip Macy (BLKIF_MAX_SEGMENTS_PER_REQUEST * BLK_RING_SIZE) 11489e0f4d2SKip Macy 11589e0f4d2SKip Macy static void kick_pending_request_queues(struct blkfront_info *); 11689e0f4d2SKip Macy static int blkif_open(struct disk *dp); 11789e0f4d2SKip Macy static int blkif_close(struct disk *dp); 11889e0f4d2SKip Macy static int blkif_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td); 11989e0f4d2SKip Macy static int blkif_queue_request(struct bio *bp); 12089e0f4d2SKip Macy static void xb_strategy(struct bio *bp); 12189e0f4d2SKip Macy 12289e0f4d2SKip Macy 12389e0f4d2SKip Macy 12489e0f4d2SKip Macy /* XXX move to xb_vbd.c when VBD update support is added */ 12589e0f4d2SKip Macy #define MAX_VBDS 64 12689e0f4d2SKip Macy 12789e0f4d2SKip Macy #define XBD_SECTOR_SIZE 512 /* XXX: assume for now */ 12889e0f4d2SKip Macy #define XBD_SECTOR_SHFT 9 12989e0f4d2SKip Macy 13089e0f4d2SKip Macy static struct mtx blkif_io_lock; 13189e0f4d2SKip Macy 13289e0f4d2SKip Macy static unsigned long 13389e0f4d2SKip Macy pfn_to_mfn(unsigned long pfn) 13489e0f4d2SKip Macy { 13589e0f4d2SKip Macy return (phystomach(pfn << PAGE_SHIFT) >> PAGE_SHIFT); 13689e0f4d2SKip Macy } 13789e0f4d2SKip Macy 13889e0f4d2SKip Macy 13989e0f4d2SKip Macy int 14089e0f4d2SKip Macy xlvbd_add(blkif_sector_t capacity, int unit, uint16_t vdisk_info, uint16_t sector_size, 14189e0f4d2SKip Macy struct blkfront_info *info) 14289e0f4d2SKip Macy { 14389e0f4d2SKip Macy struct xb_softc *sc; 14489e0f4d2SKip Macy int error = 0; 14589e0f4d2SKip Macy 14689e0f4d2SKip Macy sc = (struct xb_softc *)malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); 14789e0f4d2SKip Macy sc->xb_unit = unit; 14889e0f4d2SKip Macy sc->xb_info = info; 14989e0f4d2SKip Macy info->sc = sc; 15089e0f4d2SKip Macy 15189e0f4d2SKip Macy memset(&sc->xb_disk, 0, sizeof(sc->xb_disk)); 15289e0f4d2SKip Macy sc->xb_disk = disk_alloc(); 15389e0f4d2SKip Macy sc->xb_disk->d_unit = unit; 15489e0f4d2SKip Macy sc->xb_disk->d_open = blkif_open; 15589e0f4d2SKip Macy sc->xb_disk->d_close = blkif_close; 15689e0f4d2SKip Macy sc->xb_disk->d_ioctl = blkif_ioctl; 15789e0f4d2SKip Macy sc->xb_disk->d_strategy = xb_strategy; 15889e0f4d2SKip Macy sc->xb_disk->d_name = "xbd"; 15989e0f4d2SKip Macy sc->xb_disk->d_drv1 = sc; 16089e0f4d2SKip Macy sc->xb_disk->d_sectorsize = sector_size; 16189e0f4d2SKip Macy 16289e0f4d2SKip Macy /* XXX */ 16389e0f4d2SKip Macy sc->xb_disk->d_mediasize = capacity << XBD_SECTOR_SHFT; 16489e0f4d2SKip Macy #if 0 16589e0f4d2SKip Macy sc->xb_disk->d_maxsize = DFLTPHYS; 16689e0f4d2SKip Macy #else /* XXX: xen can't handle large single i/o requests */ 16789e0f4d2SKip Macy sc->xb_disk->d_maxsize = 4096; 16889e0f4d2SKip Macy #endif 16989e0f4d2SKip Macy #ifdef notyet 17089e0f4d2SKip Macy XENPRINTF("attaching device 0x%x unit %d capacity %llu\n", 17189e0f4d2SKip Macy xb_diskinfo[sc->xb_unit].device, sc->xb_unit, 17289e0f4d2SKip Macy sc->xb_disk->d_mediasize); 17389e0f4d2SKip Macy #endif 17489e0f4d2SKip Macy sc->xb_disk->d_flags = 0; 17589e0f4d2SKip Macy disk_create(sc->xb_disk, DISK_VERSION_00); 17689e0f4d2SKip Macy bioq_init(&sc->xb_bioq); 17789e0f4d2SKip Macy 17889e0f4d2SKip Macy return error; 17989e0f4d2SKip Macy } 18089e0f4d2SKip Macy 18189e0f4d2SKip Macy void 18289e0f4d2SKip Macy xlvbd_del(struct blkfront_info *info) 18389e0f4d2SKip Macy { 18489e0f4d2SKip Macy struct xb_softc *sc; 18589e0f4d2SKip Macy 18689e0f4d2SKip Macy sc = info->sc; 18789e0f4d2SKip Macy disk_destroy(sc->xb_disk); 18889e0f4d2SKip Macy } 18989e0f4d2SKip Macy /************************ end VBD support *****************/ 19089e0f4d2SKip Macy 19189e0f4d2SKip Macy /* 19289e0f4d2SKip Macy * Read/write routine for a buffer. Finds the proper unit, place it on 19389e0f4d2SKip Macy * the sortq and kick the controller. 19489e0f4d2SKip Macy */ 19589e0f4d2SKip Macy static void 19689e0f4d2SKip Macy xb_strategy(struct bio *bp) 19789e0f4d2SKip Macy { 19889e0f4d2SKip Macy struct xb_softc *sc = (struct xb_softc *)bp->bio_disk->d_drv1; 19989e0f4d2SKip Macy 20089e0f4d2SKip Macy /* bogus disk? */ 20189e0f4d2SKip Macy if (sc == NULL) { 20289e0f4d2SKip Macy bp->bio_error = EINVAL; 20389e0f4d2SKip Macy bp->bio_flags |= BIO_ERROR; 20489e0f4d2SKip Macy goto bad; 20589e0f4d2SKip Macy } 20689e0f4d2SKip Macy 20789e0f4d2SKip Macy DPRINTK(""); 20889e0f4d2SKip Macy 20989e0f4d2SKip Macy /* 21089e0f4d2SKip Macy * Place it in the queue of disk activities for this disk 21189e0f4d2SKip Macy */ 21289e0f4d2SKip Macy mtx_lock(&blkif_io_lock); 21389e0f4d2SKip Macy bioq_disksort(&sc->xb_bioq, bp); 21489e0f4d2SKip Macy 21589e0f4d2SKip Macy xb_startio(sc); 21689e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 21789e0f4d2SKip Macy return; 21889e0f4d2SKip Macy 21989e0f4d2SKip Macy bad: 22089e0f4d2SKip Macy /* 22189e0f4d2SKip Macy * Correctly set the bio to indicate a failed tranfer. 22289e0f4d2SKip Macy */ 22389e0f4d2SKip Macy bp->bio_resid = bp->bio_bcount; 22489e0f4d2SKip Macy biodone(bp); 22589e0f4d2SKip Macy return; 22689e0f4d2SKip Macy } 22789e0f4d2SKip Macy 22889e0f4d2SKip Macy 22989e0f4d2SKip Macy /* Setup supplies the backend dir, virtual device. 23089e0f4d2SKip Macy 23189e0f4d2SKip Macy We place an event channel and shared frame entries. 23289e0f4d2SKip Macy We watch backend to wait if it's ok. */ 23389e0f4d2SKip Macy static int blkfront_probe(struct xenbus_device *dev, 23489e0f4d2SKip Macy const struct xenbus_device_id *id) 23589e0f4d2SKip Macy { 23689e0f4d2SKip Macy int err, vdevice, i; 23789e0f4d2SKip Macy struct blkfront_info *info; 23889e0f4d2SKip Macy 23989e0f4d2SKip Macy /* FIXME: Use dynamic device id if this is not set. */ 24089e0f4d2SKip Macy err = xenbus_scanf(XBT_NIL, dev->nodename, 24189e0f4d2SKip Macy "virtual-device", "%i", &vdevice); 24289e0f4d2SKip Macy if (err != 1) { 24389e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "reading virtual-device"); 24489e0f4d2SKip Macy return err; 24589e0f4d2SKip Macy } 24689e0f4d2SKip Macy 24789e0f4d2SKip Macy info = malloc(sizeof(*info), M_DEVBUF, M_NOWAIT|M_ZERO); 24889e0f4d2SKip Macy if (info == NULL) { 24989e0f4d2SKip Macy xenbus_dev_fatal(dev, ENOMEM, "allocating info structure"); 25089e0f4d2SKip Macy return ENOMEM; 25189e0f4d2SKip Macy } 25289e0f4d2SKip Macy 25389e0f4d2SKip Macy /* 25489e0f4d2SKip Macy * XXX debug only 25589e0f4d2SKip Macy */ 25689e0f4d2SKip Macy for (i = 0; i < sizeof(*info); i++) 25789e0f4d2SKip Macy if (((uint8_t *)info)[i] != 0) 25889e0f4d2SKip Macy panic("non-null memory"); 25989e0f4d2SKip Macy 26089e0f4d2SKip Macy info->shadow_free = 0; 26189e0f4d2SKip Macy info->xbdev = dev; 26289e0f4d2SKip Macy info->vdevice = vdevice; 26389e0f4d2SKip Macy info->connected = BLKIF_STATE_DISCONNECTED; 26489e0f4d2SKip Macy 26589e0f4d2SKip Macy /* work queue needed ? */ 26689e0f4d2SKip Macy for (i = 0; i < BLK_RING_SIZE; i++) 26789e0f4d2SKip Macy info->shadow[i].req.id = i+1; 26889e0f4d2SKip Macy info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff; 26989e0f4d2SKip Macy 27089e0f4d2SKip Macy /* Front end dir is a number, which is used as the id. */ 27189e0f4d2SKip Macy info->handle = strtoul(strrchr(dev->nodename,'/')+1, NULL, 0); 27289e0f4d2SKip Macy dev->dev_driver_data = info; 27389e0f4d2SKip Macy 27489e0f4d2SKip Macy err = talk_to_backend(dev, info); 27589e0f4d2SKip Macy if (err) { 27689e0f4d2SKip Macy free(info, M_DEVBUF); 27789e0f4d2SKip Macy dev->dev_driver_data = NULL; 27889e0f4d2SKip Macy return err; 27989e0f4d2SKip Macy } 28089e0f4d2SKip Macy 28189e0f4d2SKip Macy return 0; 28289e0f4d2SKip Macy } 28389e0f4d2SKip Macy 28489e0f4d2SKip Macy 28589e0f4d2SKip Macy static int blkfront_resume(struct xenbus_device *dev) 28689e0f4d2SKip Macy { 28789e0f4d2SKip Macy struct blkfront_info *info = dev->dev_driver_data; 28889e0f4d2SKip Macy int err; 28989e0f4d2SKip Macy 29089e0f4d2SKip Macy DPRINTK("blkfront_resume: %s\n", dev->nodename); 29189e0f4d2SKip Macy 29289e0f4d2SKip Macy blkif_free(info, 1); 29389e0f4d2SKip Macy 29489e0f4d2SKip Macy err = talk_to_backend(dev, info); 29589e0f4d2SKip Macy if (!err) 29689e0f4d2SKip Macy blkif_recover(info); 29789e0f4d2SKip Macy 29889e0f4d2SKip Macy return err; 29989e0f4d2SKip Macy } 30089e0f4d2SKip Macy 30189e0f4d2SKip Macy /* Common code used when first setting up, and when resuming. */ 30289e0f4d2SKip Macy static int talk_to_backend(struct xenbus_device *dev, 30389e0f4d2SKip Macy struct blkfront_info *info) 30489e0f4d2SKip Macy { 30589e0f4d2SKip Macy const char *message = NULL; 30689e0f4d2SKip Macy struct xenbus_transaction xbt; 30789e0f4d2SKip Macy int err; 30889e0f4d2SKip Macy 30989e0f4d2SKip Macy /* Create shared ring, alloc event channel. */ 31089e0f4d2SKip Macy err = setup_blkring(dev, info); 31189e0f4d2SKip Macy if (err) 31289e0f4d2SKip Macy goto out; 31389e0f4d2SKip Macy 31489e0f4d2SKip Macy again: 31589e0f4d2SKip Macy err = xenbus_transaction_start(&xbt); 31689e0f4d2SKip Macy if (err) { 31789e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "starting transaction"); 31889e0f4d2SKip Macy goto destroy_blkring; 31989e0f4d2SKip Macy } 32089e0f4d2SKip Macy 32189e0f4d2SKip Macy err = xenbus_printf(xbt, dev->nodename, 32289e0f4d2SKip Macy "ring-ref","%u", info->ring_ref); 32389e0f4d2SKip Macy if (err) { 32489e0f4d2SKip Macy message = "writing ring-ref"; 32589e0f4d2SKip Macy goto abort_transaction; 32689e0f4d2SKip Macy } 32789e0f4d2SKip Macy err = xenbus_printf(xbt, dev->nodename, 32889e0f4d2SKip Macy "event-channel", "%u", irq_to_evtchn_port(info->irq)); 32989e0f4d2SKip Macy if (err) { 33089e0f4d2SKip Macy message = "writing event-channel"; 33189e0f4d2SKip Macy goto abort_transaction; 33289e0f4d2SKip Macy } 33389e0f4d2SKip Macy 33489e0f4d2SKip Macy err = xenbus_transaction_end(xbt, 0); 33589e0f4d2SKip Macy if (err) { 33689e0f4d2SKip Macy if (err == -EAGAIN) 33789e0f4d2SKip Macy goto again; 33889e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "completing transaction"); 33989e0f4d2SKip Macy goto destroy_blkring; 34089e0f4d2SKip Macy } 34189e0f4d2SKip Macy xenbus_switch_state(dev, XenbusStateInitialised); 34289e0f4d2SKip Macy 34389e0f4d2SKip Macy return 0; 34489e0f4d2SKip Macy 34589e0f4d2SKip Macy abort_transaction: 34689e0f4d2SKip Macy xenbus_transaction_end(xbt, 1); 34789e0f4d2SKip Macy if (message) 34889e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "%s", message); 34989e0f4d2SKip Macy destroy_blkring: 35089e0f4d2SKip Macy blkif_free(info, 0); 35189e0f4d2SKip Macy out: 35289e0f4d2SKip Macy return err; 35389e0f4d2SKip Macy } 35489e0f4d2SKip Macy 35589e0f4d2SKip Macy static int 35689e0f4d2SKip Macy setup_blkring(struct xenbus_device *dev, struct blkfront_info *info) 35789e0f4d2SKip Macy { 35889e0f4d2SKip Macy blkif_sring_t *sring; 35989e0f4d2SKip Macy int err; 36089e0f4d2SKip Macy 36189e0f4d2SKip Macy info->ring_ref = GRANT_INVALID_REF; 36289e0f4d2SKip Macy 36389e0f4d2SKip Macy sring = (blkif_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT|M_ZERO); 36489e0f4d2SKip Macy if (sring == NULL) { 36589e0f4d2SKip Macy xenbus_dev_fatal(dev, ENOMEM, "allocating shared ring"); 36689e0f4d2SKip Macy return ENOMEM; 36789e0f4d2SKip Macy } 36889e0f4d2SKip Macy SHARED_RING_INIT(sring); 36989e0f4d2SKip Macy FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE); 37089e0f4d2SKip Macy 37189e0f4d2SKip Macy err = xenbus_grant_ring(dev, (vtomach(info->ring.sring) >> PAGE_SHIFT)); 37289e0f4d2SKip Macy if (err < 0) { 37389e0f4d2SKip Macy free(sring, M_DEVBUF); 37489e0f4d2SKip Macy info->ring.sring = NULL; 37589e0f4d2SKip Macy goto fail; 37689e0f4d2SKip Macy } 37789e0f4d2SKip Macy info->ring_ref = err; 37889e0f4d2SKip Macy 37989e0f4d2SKip Macy err = bind_listening_port_to_irqhandler(dev->otherend_id, 38089e0f4d2SKip Macy "xbd", (driver_intr_t *)blkif_int, info, 38189e0f4d2SKip Macy INTR_TYPE_BIO | INTR_MPSAFE, NULL); 38289e0f4d2SKip Macy if (err <= 0) { 38389e0f4d2SKip Macy xenbus_dev_fatal(dev, err, 38489e0f4d2SKip Macy "bind_evtchn_to_irqhandler failed"); 38589e0f4d2SKip Macy goto fail; 38689e0f4d2SKip Macy } 38789e0f4d2SKip Macy info->irq = err; 38889e0f4d2SKip Macy 38989e0f4d2SKip Macy return 0; 39089e0f4d2SKip Macy fail: 39189e0f4d2SKip Macy blkif_free(info, 0); 39289e0f4d2SKip Macy return err; 39389e0f4d2SKip Macy } 39489e0f4d2SKip Macy 39589e0f4d2SKip Macy 39689e0f4d2SKip Macy /** 39789e0f4d2SKip Macy * Callback received when the backend's state changes. 39889e0f4d2SKip Macy */ 39989e0f4d2SKip Macy static void backend_changed(struct xenbus_device *dev, 40089e0f4d2SKip Macy XenbusState backend_state) 40189e0f4d2SKip Macy { 40289e0f4d2SKip Macy struct blkfront_info *info = dev->dev_driver_data; 40389e0f4d2SKip Macy 40489e0f4d2SKip Macy DPRINTK("blkfront:backend_changed.\n"); 40589e0f4d2SKip Macy 40689e0f4d2SKip Macy switch (backend_state) { 40789e0f4d2SKip Macy case XenbusStateUnknown: 40889e0f4d2SKip Macy case XenbusStateInitialising: 40989e0f4d2SKip Macy case XenbusStateInitWait: 41089e0f4d2SKip Macy case XenbusStateInitialised: 41189e0f4d2SKip Macy case XenbusStateClosed: 41289e0f4d2SKip Macy break; 41389e0f4d2SKip Macy 41489e0f4d2SKip Macy case XenbusStateConnected: 41589e0f4d2SKip Macy connect(info); 41689e0f4d2SKip Macy break; 41789e0f4d2SKip Macy 41889e0f4d2SKip Macy case XenbusStateClosing: 41989e0f4d2SKip Macy if (info->users > 0) 42089e0f4d2SKip Macy xenbus_dev_error(dev, -EBUSY, 42189e0f4d2SKip Macy "Device in use; refusing to close"); 42289e0f4d2SKip Macy else 42389e0f4d2SKip Macy blkfront_closing(dev); 42489e0f4d2SKip Macy #ifdef notyet 42589e0f4d2SKip Macy bd = bdget(info->dev); 42689e0f4d2SKip Macy if (bd == NULL) 42789e0f4d2SKip Macy xenbus_dev_fatal(dev, -ENODEV, "bdget failed"); 42889e0f4d2SKip Macy 42989e0f4d2SKip Macy down(&bd->bd_sem); 43089e0f4d2SKip Macy if (info->users > 0) 43189e0f4d2SKip Macy xenbus_dev_error(dev, -EBUSY, 43289e0f4d2SKip Macy "Device in use; refusing to close"); 43389e0f4d2SKip Macy else 43489e0f4d2SKip Macy blkfront_closing(dev); 43589e0f4d2SKip Macy up(&bd->bd_sem); 43689e0f4d2SKip Macy bdput(bd); 43789e0f4d2SKip Macy #endif 43889e0f4d2SKip Macy } 43989e0f4d2SKip Macy } 44089e0f4d2SKip Macy 44189e0f4d2SKip Macy /* 44289e0f4d2SKip Macy ** Invoked when the backend is finally 'ready' (and has told produced 44389e0f4d2SKip Macy ** the details about the physical device - #sectors, size, etc). 44489e0f4d2SKip Macy */ 44589e0f4d2SKip Macy static void 44689e0f4d2SKip Macy connect(struct blkfront_info *info) 44789e0f4d2SKip Macy { 44889e0f4d2SKip Macy unsigned long sectors, sector_size; 44989e0f4d2SKip Macy unsigned int binfo; 45089e0f4d2SKip Macy int err; 45189e0f4d2SKip Macy 45289e0f4d2SKip Macy if( (info->connected == BLKIF_STATE_CONNECTED) || 45389e0f4d2SKip Macy (info->connected == BLKIF_STATE_SUSPENDED) ) 45489e0f4d2SKip Macy return; 45589e0f4d2SKip Macy 45689e0f4d2SKip Macy DPRINTK("blkfront.c:connect:%s.\n", info->xbdev->otherend); 45789e0f4d2SKip Macy 45889e0f4d2SKip Macy err = xenbus_gather(XBT_NIL, info->xbdev->otherend, 45989e0f4d2SKip Macy "sectors", "%lu", §ors, 46089e0f4d2SKip Macy "info", "%u", &binfo, 46189e0f4d2SKip Macy "sector-size", "%lu", §or_size, 46289e0f4d2SKip Macy NULL); 46389e0f4d2SKip Macy if (err) { 46489e0f4d2SKip Macy xenbus_dev_fatal(info->xbdev, err, 46589e0f4d2SKip Macy "reading backend fields at %s", 46689e0f4d2SKip Macy info->xbdev->otherend); 46789e0f4d2SKip Macy return; 46889e0f4d2SKip Macy } 46989e0f4d2SKip Macy err = xenbus_gather(XBT_NIL, info->xbdev->otherend, 47089e0f4d2SKip Macy "feature-barrier", "%lu", &info->feature_barrier, 47189e0f4d2SKip Macy NULL); 47289e0f4d2SKip Macy if (err) 47389e0f4d2SKip Macy info->feature_barrier = 0; 47489e0f4d2SKip Macy 47589e0f4d2SKip Macy xlvbd_add(sectors, info->vdevice, binfo, sector_size, info); 47689e0f4d2SKip Macy 47789e0f4d2SKip Macy (void)xenbus_switch_state(info->xbdev, XenbusStateConnected); 47889e0f4d2SKip Macy 47989e0f4d2SKip Macy /* Kick pending requests. */ 48089e0f4d2SKip Macy mtx_lock(&blkif_io_lock); 48189e0f4d2SKip Macy info->connected = BLKIF_STATE_CONNECTED; 48289e0f4d2SKip Macy kick_pending_request_queues(info); 48389e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 48489e0f4d2SKip Macy 48589e0f4d2SKip Macy #if 0 48689e0f4d2SKip Macy add_disk(info->gd); 48789e0f4d2SKip Macy #endif 48889e0f4d2SKip Macy } 48989e0f4d2SKip Macy 49089e0f4d2SKip Macy /** 49189e0f4d2SKip Macy * Handle the change of state of the backend to Closing. We must delete our 49289e0f4d2SKip Macy * device-layer structures now, to ensure that writes are flushed through to 49389e0f4d2SKip Macy * the backend. Once is this done, we can switch to Closed in 49489e0f4d2SKip Macy * acknowledgement. 49589e0f4d2SKip Macy */ 49689e0f4d2SKip Macy static void blkfront_closing(struct xenbus_device *dev) 49789e0f4d2SKip Macy { 49889e0f4d2SKip Macy struct blkfront_info *info = dev->dev_driver_data; 49989e0f4d2SKip Macy 50089e0f4d2SKip Macy DPRINTK("blkfront_closing: %s removed\n", dev->nodename); 50189e0f4d2SKip Macy 50289e0f4d2SKip Macy if (info->mi) { 50389e0f4d2SKip Macy DPRINTK("Calling xlvbd_del\n"); 50489e0f4d2SKip Macy xlvbd_del(info); 50589e0f4d2SKip Macy info->mi = NULL; 50689e0f4d2SKip Macy } 50789e0f4d2SKip Macy 50889e0f4d2SKip Macy xenbus_switch_state(dev, XenbusStateClosed); 50989e0f4d2SKip Macy } 51089e0f4d2SKip Macy 51189e0f4d2SKip Macy 51289e0f4d2SKip Macy static int blkfront_remove(struct xenbus_device *dev) 51389e0f4d2SKip Macy { 51489e0f4d2SKip Macy struct blkfront_info *info = dev->dev_driver_data; 51589e0f4d2SKip Macy 51689e0f4d2SKip Macy DPRINTK("blkfront_remove: %s removed\n", dev->nodename); 51789e0f4d2SKip Macy 51889e0f4d2SKip Macy blkif_free(info, 0); 51989e0f4d2SKip Macy 52089e0f4d2SKip Macy free(info, M_DEVBUF); 52189e0f4d2SKip Macy 52289e0f4d2SKip Macy return 0; 52389e0f4d2SKip Macy } 52489e0f4d2SKip Macy 52589e0f4d2SKip Macy 52689e0f4d2SKip Macy static inline int 52789e0f4d2SKip Macy GET_ID_FROM_FREELIST(struct blkfront_info *info) 52889e0f4d2SKip Macy { 52989e0f4d2SKip Macy unsigned long nfree = info->shadow_free; 53089e0f4d2SKip Macy 53189e0f4d2SKip Macy KASSERT(nfree <= BLK_RING_SIZE, ("free %lu > RING_SIZE", nfree)); 53289e0f4d2SKip Macy info->shadow_free = info->shadow[nfree].req.id; 53389e0f4d2SKip Macy info->shadow[nfree].req.id = 0x0fffffee; /* debug */ 53489e0f4d2SKip Macy return nfree; 53589e0f4d2SKip Macy } 53689e0f4d2SKip Macy 53789e0f4d2SKip Macy static inline void 53889e0f4d2SKip Macy ADD_ID_TO_FREELIST(struct blkfront_info *info, unsigned long id) 53989e0f4d2SKip Macy { 54089e0f4d2SKip Macy info->shadow[id].req.id = info->shadow_free; 54189e0f4d2SKip Macy info->shadow[id].request = 0; 54289e0f4d2SKip Macy info->shadow_free = id; 54389e0f4d2SKip Macy } 54489e0f4d2SKip Macy 54589e0f4d2SKip Macy static inline void 54689e0f4d2SKip Macy flush_requests(struct blkfront_info *info) 54789e0f4d2SKip Macy { 54889e0f4d2SKip Macy int notify; 54989e0f4d2SKip Macy 55089e0f4d2SKip Macy RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->ring, notify); 55189e0f4d2SKip Macy 55289e0f4d2SKip Macy if (notify) 55389e0f4d2SKip Macy notify_remote_via_irq(info->irq); 55489e0f4d2SKip Macy } 55589e0f4d2SKip Macy 55689e0f4d2SKip Macy static void 55789e0f4d2SKip Macy kick_pending_request_queues(struct blkfront_info *info) 55889e0f4d2SKip Macy { 55989e0f4d2SKip Macy /* XXX check if we can't simplify */ 56089e0f4d2SKip Macy #if 0 56189e0f4d2SKip Macy if (!RING_FULL(&info->ring)) { 56289e0f4d2SKip Macy /* Re-enable calldowns. */ 56389e0f4d2SKip Macy blk_start_queue(info->rq); 56489e0f4d2SKip Macy /* Kick things off immediately. */ 56589e0f4d2SKip Macy do_blkif_request(info->rq); 56689e0f4d2SKip Macy } 56789e0f4d2SKip Macy #endif 56889e0f4d2SKip Macy if (!RING_FULL(&info->ring)) { 56989e0f4d2SKip Macy #if 0 57089e0f4d2SKip Macy sc = LIST_FIRST(&xbsl_head); 57189e0f4d2SKip Macy LIST_REMOVE(sc, entry); 57289e0f4d2SKip Macy /* Re-enable calldowns. */ 57389e0f4d2SKip Macy blk_start_queue(di->rq); 57489e0f4d2SKip Macy #endif 57589e0f4d2SKip Macy /* Kick things off immediately. */ 57689e0f4d2SKip Macy xb_startio(info->sc); 57789e0f4d2SKip Macy } 57889e0f4d2SKip Macy } 57989e0f4d2SKip Macy 58089e0f4d2SKip Macy #if 0 58189e0f4d2SKip Macy /* XXX */ 58289e0f4d2SKip Macy static void blkif_restart_queue(void *arg) 58389e0f4d2SKip Macy { 58489e0f4d2SKip Macy struct blkfront_info *info = (struct blkfront_info *)arg; 58589e0f4d2SKip Macy 58689e0f4d2SKip Macy mtx_lock(&blkif_io_lock); 58789e0f4d2SKip Macy kick_pending_request_queues(info); 58889e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 58989e0f4d2SKip Macy } 59089e0f4d2SKip Macy #endif 59189e0f4d2SKip Macy 59289e0f4d2SKip Macy static void blkif_restart_queue_callback(void *arg) 59389e0f4d2SKip Macy { 59489e0f4d2SKip Macy #if 0 59589e0f4d2SKip Macy struct blkfront_info *info = (struct blkfront_info *)arg; 59689e0f4d2SKip Macy /* XXX BSD equiv ? */ 59789e0f4d2SKip Macy 59889e0f4d2SKip Macy schedule_work(&info->work); 59989e0f4d2SKip Macy #endif 60089e0f4d2SKip Macy } 60189e0f4d2SKip Macy 60289e0f4d2SKip Macy static int 60389e0f4d2SKip Macy blkif_open(struct disk *dp) 60489e0f4d2SKip Macy { 60589e0f4d2SKip Macy struct xb_softc *sc = (struct xb_softc *)dp->d_drv1; 60689e0f4d2SKip Macy 60789e0f4d2SKip Macy if (sc == NULL) { 60889e0f4d2SKip Macy printk("xb%d: not found", sc->xb_unit); 60989e0f4d2SKip Macy return (ENXIO); 61089e0f4d2SKip Macy } 61189e0f4d2SKip Macy 61289e0f4d2SKip Macy sc->xb_flags |= XB_OPEN; 61389e0f4d2SKip Macy sc->xb_info->users++; 61489e0f4d2SKip Macy return (0); 61589e0f4d2SKip Macy } 61689e0f4d2SKip Macy 61789e0f4d2SKip Macy static int 61889e0f4d2SKip Macy blkif_close(struct disk *dp) 61989e0f4d2SKip Macy { 62089e0f4d2SKip Macy struct xb_softc *sc = (struct xb_softc *)dp->d_drv1; 62189e0f4d2SKip Macy 62289e0f4d2SKip Macy if (sc == NULL) 62389e0f4d2SKip Macy return (ENXIO); 62489e0f4d2SKip Macy sc->xb_flags &= ~XB_OPEN; 62589e0f4d2SKip Macy if (--(sc->xb_info->users) == 0) { 62689e0f4d2SKip Macy /* Check whether we have been instructed to close. We will 62789e0f4d2SKip Macy have ignored this request initially, as the device was 62889e0f4d2SKip Macy still mounted. */ 62989e0f4d2SKip Macy struct xenbus_device * dev = sc->xb_info->xbdev; 63089e0f4d2SKip Macy XenbusState state = xenbus_read_driver_state(dev->otherend); 63189e0f4d2SKip Macy 63289e0f4d2SKip Macy if (state == XenbusStateClosing) 63389e0f4d2SKip Macy blkfront_closing(dev); 63489e0f4d2SKip Macy } 63589e0f4d2SKip Macy return (0); 63689e0f4d2SKip Macy } 63789e0f4d2SKip Macy 63889e0f4d2SKip Macy static int 63989e0f4d2SKip Macy blkif_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td) 64089e0f4d2SKip Macy { 64189e0f4d2SKip Macy struct xb_softc *sc = (struct xb_softc *)dp->d_drv1; 64289e0f4d2SKip Macy 64389e0f4d2SKip Macy if (sc == NULL) 64489e0f4d2SKip Macy return (ENXIO); 64589e0f4d2SKip Macy 64689e0f4d2SKip Macy return (ENOTTY); 64789e0f4d2SKip Macy } 64889e0f4d2SKip Macy 64989e0f4d2SKip Macy 65089e0f4d2SKip Macy /* 65189e0f4d2SKip Macy * blkif_queue_request 65289e0f4d2SKip Macy * 65389e0f4d2SKip Macy * request block io 65489e0f4d2SKip Macy * 65589e0f4d2SKip Macy * id: for guest use only. 65689e0f4d2SKip Macy * operation: BLKIF_OP_{READ,WRITE,PROBE} 65789e0f4d2SKip Macy * buffer: buffer to read/write into. this should be a 65889e0f4d2SKip Macy * virtual address in the guest os. 65989e0f4d2SKip Macy */ 66089e0f4d2SKip Macy static int blkif_queue_request(struct bio *bp) 66189e0f4d2SKip Macy { 66289e0f4d2SKip Macy caddr_t alignbuf; 66389e0f4d2SKip Macy unsigned long buffer_ma; 66489e0f4d2SKip Macy blkif_request_t *ring_req; 66589e0f4d2SKip Macy unsigned long id; 66689e0f4d2SKip Macy unsigned int fsect, lsect; 66789e0f4d2SKip Macy struct xb_softc *sc = (struct xb_softc *)bp->bio_disk->d_drv1; 66889e0f4d2SKip Macy struct blkfront_info *info = sc->xb_info; 66989e0f4d2SKip Macy int ref; 67089e0f4d2SKip Macy 67189e0f4d2SKip Macy if (unlikely(sc->xb_info->connected != BLKIF_STATE_CONNECTED)) 67289e0f4d2SKip Macy return 1; 67389e0f4d2SKip Macy 67489e0f4d2SKip Macy if (gnttab_alloc_grant_references( 67589e0f4d2SKip Macy BLKIF_MAX_SEGMENTS_PER_REQUEST, &gref_head) < 0) { 67689e0f4d2SKip Macy gnttab_request_free_callback( 67789e0f4d2SKip Macy &info->callback, 67889e0f4d2SKip Macy blkif_restart_queue_callback, 67989e0f4d2SKip Macy info, 68089e0f4d2SKip Macy BLKIF_MAX_SEGMENTS_PER_REQUEST); 68189e0f4d2SKip Macy return 1; 68289e0f4d2SKip Macy } 68389e0f4d2SKip Macy 68489e0f4d2SKip Macy /* Check if the buffer is properly aligned */ 68589e0f4d2SKip Macy if ((vm_offset_t)bp->bio_data & PAGE_MASK) { 68689e0f4d2SKip Macy int align = (bp->bio_bcount < PAGE_SIZE/2) ? XBD_SECTOR_SIZE : 68789e0f4d2SKip Macy PAGE_SIZE; 68889e0f4d2SKip Macy caddr_t newbuf = malloc(bp->bio_bcount + align, M_DEVBUF, 68989e0f4d2SKip Macy M_NOWAIT); 69089e0f4d2SKip Macy 69189e0f4d2SKip Macy alignbuf = (char *)roundup2((u_long)newbuf, align); 69289e0f4d2SKip Macy 69389e0f4d2SKip Macy /* save a copy of the current buffer */ 69489e0f4d2SKip Macy bp->bio_driver1 = newbuf; 69589e0f4d2SKip Macy bp->bio_driver2 = alignbuf; 69689e0f4d2SKip Macy 69789e0f4d2SKip Macy /* Copy the data for a write */ 69889e0f4d2SKip Macy if (bp->bio_cmd == BIO_WRITE) 69989e0f4d2SKip Macy bcopy(bp->bio_data, alignbuf, bp->bio_bcount); 70089e0f4d2SKip Macy } else 70189e0f4d2SKip Macy alignbuf = bp->bio_data; 70289e0f4d2SKip Macy 70389e0f4d2SKip Macy /* Fill out a communications ring structure. */ 70489e0f4d2SKip Macy ring_req = RING_GET_REQUEST(&info->ring, 70589e0f4d2SKip Macy info->ring.req_prod_pvt); 70689e0f4d2SKip Macy id = GET_ID_FROM_FREELIST(info); 70789e0f4d2SKip Macy info->shadow[id].request = (unsigned long)bp; 70889e0f4d2SKip Macy 70989e0f4d2SKip Macy ring_req->id = id; 71089e0f4d2SKip Macy ring_req->operation = (bp->bio_cmd == BIO_READ) ? BLKIF_OP_READ : 71189e0f4d2SKip Macy BLKIF_OP_WRITE; 71289e0f4d2SKip Macy 71389e0f4d2SKip Macy ring_req->sector_number= (blkif_sector_t)bp->bio_pblkno; 71489e0f4d2SKip Macy ring_req->handle = (blkif_vdev_t)(uintptr_t)sc->xb_disk; 71589e0f4d2SKip Macy 71689e0f4d2SKip Macy ring_req->nr_segments = 0; /* XXX not doing scatter/gather since buffer 71789e0f4d2SKip Macy * chaining is not supported. 71889e0f4d2SKip Macy */ 71989e0f4d2SKip Macy 72089e0f4d2SKip Macy buffer_ma = vtomach(alignbuf); 72189e0f4d2SKip Macy fsect = (buffer_ma & PAGE_MASK) >> XBD_SECTOR_SHFT; 72289e0f4d2SKip Macy lsect = fsect + (bp->bio_bcount >> XBD_SECTOR_SHFT) - 1; 72389e0f4d2SKip Macy /* install a grant reference. */ 72489e0f4d2SKip Macy ref = gnttab_claim_grant_reference(&gref_head); 72589e0f4d2SKip Macy KASSERT( ref != -ENOSPC, ("grant_reference failed") ); 72689e0f4d2SKip Macy 72789e0f4d2SKip Macy gnttab_grant_foreign_access_ref( 72889e0f4d2SKip Macy ref, 72989e0f4d2SKip Macy info->xbdev->otherend_id, 73089e0f4d2SKip Macy buffer_ma >> PAGE_SHIFT, 73189e0f4d2SKip Macy ring_req->operation & 1 ); /* ??? */ 73289e0f4d2SKip Macy info->shadow[id].frame[ring_req->nr_segments] = 73389e0f4d2SKip Macy buffer_ma >> PAGE_SHIFT; 73489e0f4d2SKip Macy 73589e0f4d2SKip Macy ring_req->seg[ring_req->nr_segments] = 73689e0f4d2SKip Macy (struct blkif_request_segment) { 73789e0f4d2SKip Macy .gref = ref, 73889e0f4d2SKip Macy .first_sect = fsect, 73989e0f4d2SKip Macy .last_sect = lsect }; 74089e0f4d2SKip Macy 74189e0f4d2SKip Macy ring_req->nr_segments++; 74289e0f4d2SKip Macy KASSERT((buffer_ma & (XBD_SECTOR_SIZE-1)) == 0, 74389e0f4d2SKip Macy ("XEN buffer must be sector aligned")); 74489e0f4d2SKip Macy KASSERT(lsect <= 7, 74589e0f4d2SKip Macy ("XEN disk driver data cannot cross a page boundary")); 74689e0f4d2SKip Macy 74789e0f4d2SKip Macy buffer_ma &= ~PAGE_MASK; 74889e0f4d2SKip Macy 74989e0f4d2SKip Macy info->ring.req_prod_pvt++; 75089e0f4d2SKip Macy 75189e0f4d2SKip Macy /* Keep a private copy so we can reissue requests when recovering. */ 75289e0f4d2SKip Macy info->shadow[id].req = *ring_req; 75389e0f4d2SKip Macy 75489e0f4d2SKip Macy gnttab_free_grant_references(gref_head); 75589e0f4d2SKip Macy 75689e0f4d2SKip Macy return 0; 75789e0f4d2SKip Macy } 75889e0f4d2SKip Macy 75989e0f4d2SKip Macy 76089e0f4d2SKip Macy 76189e0f4d2SKip Macy /* 76289e0f4d2SKip Macy * Dequeue buffers and place them in the shared communication ring. 76389e0f4d2SKip Macy * Return when no more requests can be accepted or all buffers have 76489e0f4d2SKip Macy * been queued. 76589e0f4d2SKip Macy * 76689e0f4d2SKip Macy * Signal XEN once the ring has been filled out. 76789e0f4d2SKip Macy */ 76889e0f4d2SKip Macy static void 76989e0f4d2SKip Macy xb_startio(struct xb_softc *sc) 77089e0f4d2SKip Macy { 77189e0f4d2SKip Macy struct bio *bp; 77289e0f4d2SKip Macy int queued = 0; 77389e0f4d2SKip Macy struct blkfront_info *info = sc->xb_info; 77489e0f4d2SKip Macy DPRINTK(""); 77589e0f4d2SKip Macy 77689e0f4d2SKip Macy mtx_assert(&blkif_io_lock, MA_OWNED); 77789e0f4d2SKip Macy 77889e0f4d2SKip Macy while ((bp = bioq_takefirst(&sc->xb_bioq)) != NULL) { 77989e0f4d2SKip Macy 78089e0f4d2SKip Macy if (RING_FULL(&info->ring)) 78189e0f4d2SKip Macy goto wait; 78289e0f4d2SKip Macy 78389e0f4d2SKip Macy if (blkif_queue_request(bp)) { 78489e0f4d2SKip Macy wait: 78589e0f4d2SKip Macy bioq_insert_head(&sc->xb_bioq, bp); 78689e0f4d2SKip Macy break; 78789e0f4d2SKip Macy } 78889e0f4d2SKip Macy queued++; 78989e0f4d2SKip Macy } 79089e0f4d2SKip Macy 79189e0f4d2SKip Macy if (queued != 0) 79289e0f4d2SKip Macy flush_requests(sc->xb_info); 79389e0f4d2SKip Macy } 79489e0f4d2SKip Macy 79589e0f4d2SKip Macy static void 79689e0f4d2SKip Macy blkif_int(void *xsc) 79789e0f4d2SKip Macy { 79889e0f4d2SKip Macy struct xb_softc *sc = NULL; 79989e0f4d2SKip Macy struct bio *bp; 80089e0f4d2SKip Macy blkif_response_t *bret; 80189e0f4d2SKip Macy RING_IDX i, rp; 80289e0f4d2SKip Macy struct blkfront_info *info = xsc; 80389e0f4d2SKip Macy DPRINTK(""); 80489e0f4d2SKip Macy 80589e0f4d2SKip Macy TRACE_ENTER; 80689e0f4d2SKip Macy 80789e0f4d2SKip Macy mtx_lock(&blkif_io_lock); 80889e0f4d2SKip Macy 80989e0f4d2SKip Macy if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) { 81089e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 81189e0f4d2SKip Macy return; 81289e0f4d2SKip Macy } 81389e0f4d2SKip Macy 81489e0f4d2SKip Macy again: 81589e0f4d2SKip Macy rp = info->ring.sring->rsp_prod; 81689e0f4d2SKip Macy rmb(); /* Ensure we see queued responses up to 'rp'. */ 81789e0f4d2SKip Macy 81889e0f4d2SKip Macy for (i = info->ring.rsp_cons; i != rp; i++) { 81989e0f4d2SKip Macy unsigned long id; 82089e0f4d2SKip Macy 82189e0f4d2SKip Macy bret = RING_GET_RESPONSE(&info->ring, i); 82289e0f4d2SKip Macy id = bret->id; 82389e0f4d2SKip Macy bp = (struct bio *)info->shadow[id].request; 82489e0f4d2SKip Macy 82589e0f4d2SKip Macy blkif_completion(&info->shadow[id]); 82689e0f4d2SKip Macy 82789e0f4d2SKip Macy ADD_ID_TO_FREELIST(info, id); 82889e0f4d2SKip Macy 82989e0f4d2SKip Macy switch (bret->operation) { 83089e0f4d2SKip Macy case BLKIF_OP_READ: 83189e0f4d2SKip Macy /* had an unaligned buffer that needs to be copied */ 83289e0f4d2SKip Macy if (bp->bio_driver1) 83389e0f4d2SKip Macy bcopy(bp->bio_driver2, bp->bio_data, bp->bio_bcount); 83489e0f4d2SKip Macy /* FALLTHROUGH */ 83589e0f4d2SKip Macy case BLKIF_OP_WRITE: 83689e0f4d2SKip Macy 83789e0f4d2SKip Macy /* free the copy buffer */ 83889e0f4d2SKip Macy if (bp->bio_driver1) { 83989e0f4d2SKip Macy free(bp->bio_driver1, M_DEVBUF); 84089e0f4d2SKip Macy bp->bio_driver1 = NULL; 84189e0f4d2SKip Macy } 84289e0f4d2SKip Macy 84389e0f4d2SKip Macy if ( unlikely(bret->status != BLKIF_RSP_OKAY) ) { 84489e0f4d2SKip Macy XENPRINTF("Bad return from blkdev data request: %x\n", 84589e0f4d2SKip Macy bret->status); 84689e0f4d2SKip Macy bp->bio_flags |= BIO_ERROR; 84789e0f4d2SKip Macy } 84889e0f4d2SKip Macy 84989e0f4d2SKip Macy sc = (struct xb_softc *)bp->bio_disk->d_drv1; 85089e0f4d2SKip Macy 85189e0f4d2SKip Macy if (bp->bio_flags & BIO_ERROR) 85289e0f4d2SKip Macy bp->bio_error = EIO; 85389e0f4d2SKip Macy else 85489e0f4d2SKip Macy bp->bio_resid = 0; 85589e0f4d2SKip Macy 85689e0f4d2SKip Macy biodone(bp); 85789e0f4d2SKip Macy break; 85889e0f4d2SKip Macy default: 85989e0f4d2SKip Macy panic("received invalid operation"); 86089e0f4d2SKip Macy break; 86189e0f4d2SKip Macy } 86289e0f4d2SKip Macy } 86389e0f4d2SKip Macy 86489e0f4d2SKip Macy info->ring.rsp_cons = i; 86589e0f4d2SKip Macy 86689e0f4d2SKip Macy if (i != info->ring.req_prod_pvt) { 86789e0f4d2SKip Macy int more_to_do; 86889e0f4d2SKip Macy RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do); 86989e0f4d2SKip Macy if (more_to_do) 87089e0f4d2SKip Macy goto again; 87189e0f4d2SKip Macy } else { 87289e0f4d2SKip Macy info->ring.sring->rsp_event = i + 1; 87389e0f4d2SKip Macy } 87489e0f4d2SKip Macy 87589e0f4d2SKip Macy kick_pending_request_queues(info); 87689e0f4d2SKip Macy 87789e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 87889e0f4d2SKip Macy } 87989e0f4d2SKip Macy 88089e0f4d2SKip Macy static void 88189e0f4d2SKip Macy blkif_free(struct blkfront_info *info, int suspend) 88289e0f4d2SKip Macy { 88389e0f4d2SKip Macy 88489e0f4d2SKip Macy /* Prevent new requests being issued until we fix things up. */ 88589e0f4d2SKip Macy mtx_lock(&blkif_io_lock); 88689e0f4d2SKip Macy info->connected = suspend ? 88789e0f4d2SKip Macy BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED; 88889e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 88989e0f4d2SKip Macy 89089e0f4d2SKip Macy /* Free resources associated with old device channel. */ 89189e0f4d2SKip Macy if (info->ring_ref != GRANT_INVALID_REF) { 89289e0f4d2SKip Macy gnttab_end_foreign_access(info->ring_ref, 0, 89389e0f4d2SKip Macy info->ring.sring); 89489e0f4d2SKip Macy info->ring_ref = GRANT_INVALID_REF; 89589e0f4d2SKip Macy info->ring.sring = NULL; 89689e0f4d2SKip Macy } 89789e0f4d2SKip Macy if (info->irq) 89889e0f4d2SKip Macy unbind_from_irqhandler(info->irq, info); 89989e0f4d2SKip Macy info->irq = 0; 90089e0f4d2SKip Macy 90189e0f4d2SKip Macy } 90289e0f4d2SKip Macy 90389e0f4d2SKip Macy static void 90489e0f4d2SKip Macy blkif_completion(struct blk_shadow *s) 90589e0f4d2SKip Macy { 90689e0f4d2SKip Macy int i; 90789e0f4d2SKip Macy 90889e0f4d2SKip Macy for (i = 0; i < s->req.nr_segments; i++) 90989e0f4d2SKip Macy gnttab_end_foreign_access(s->req.seg[i].gref, 0, 0UL); 91089e0f4d2SKip Macy } 91189e0f4d2SKip Macy 91289e0f4d2SKip Macy static void 91389e0f4d2SKip Macy blkif_recover(struct blkfront_info *info) 91489e0f4d2SKip Macy { 91589e0f4d2SKip Macy int i, j; 91689e0f4d2SKip Macy blkif_request_t *req; 91789e0f4d2SKip Macy struct blk_shadow *copy; 91889e0f4d2SKip Macy 91989e0f4d2SKip Macy /* Stage 1: Make a safe copy of the shadow state. */ 92089e0f4d2SKip Macy copy = (struct blk_shadow *)malloc(sizeof(info->shadow), M_DEVBUF, M_NOWAIT|M_ZERO); 92189e0f4d2SKip Macy PANIC_IF(copy == NULL); 92289e0f4d2SKip Macy memcpy(copy, info->shadow, sizeof(info->shadow)); 92389e0f4d2SKip Macy 92489e0f4d2SKip Macy /* Stage 2: Set up free list. */ 92589e0f4d2SKip Macy memset(&info->shadow, 0, sizeof(info->shadow)); 92689e0f4d2SKip Macy for (i = 0; i < BLK_RING_SIZE; i++) 92789e0f4d2SKip Macy info->shadow[i].req.id = i+1; 92889e0f4d2SKip Macy info->shadow_free = info->ring.req_prod_pvt; 92989e0f4d2SKip Macy info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff; 93089e0f4d2SKip Macy 93189e0f4d2SKip Macy /* Stage 3: Find pending requests and requeue them. */ 93289e0f4d2SKip Macy for (i = 0; i < BLK_RING_SIZE; i++) { 93389e0f4d2SKip Macy /* Not in use? */ 93489e0f4d2SKip Macy if (copy[i].request == 0) 93589e0f4d2SKip Macy continue; 93689e0f4d2SKip Macy 93789e0f4d2SKip Macy /* Grab a request slot and copy shadow state into it. */ 93889e0f4d2SKip Macy req = RING_GET_REQUEST( 93989e0f4d2SKip Macy &info->ring, info->ring.req_prod_pvt); 94089e0f4d2SKip Macy *req = copy[i].req; 94189e0f4d2SKip Macy 94289e0f4d2SKip Macy /* We get a new request id, and must reset the shadow state. */ 94389e0f4d2SKip Macy req->id = GET_ID_FROM_FREELIST(info); 94489e0f4d2SKip Macy memcpy(&info->shadow[req->id], ©[i], sizeof(copy[i])); 94589e0f4d2SKip Macy 94689e0f4d2SKip Macy /* Rewrite any grant references invalidated by suspend/resume. */ 94789e0f4d2SKip Macy for (j = 0; j < req->nr_segments; j++) 94889e0f4d2SKip Macy gnttab_grant_foreign_access_ref( 94989e0f4d2SKip Macy req->seg[j].gref, 95089e0f4d2SKip Macy info->xbdev->otherend_id, 95189e0f4d2SKip Macy pfn_to_mfn(info->shadow[req->id].frame[j]), 95289e0f4d2SKip Macy 0 /* assume not readonly */); 95389e0f4d2SKip Macy 95489e0f4d2SKip Macy info->shadow[req->id].req = *req; 95589e0f4d2SKip Macy 95689e0f4d2SKip Macy info->ring.req_prod_pvt++; 95789e0f4d2SKip Macy } 95889e0f4d2SKip Macy 95989e0f4d2SKip Macy free(copy, M_DEVBUF); 96089e0f4d2SKip Macy 96189e0f4d2SKip Macy xenbus_switch_state(info->xbdev, XenbusStateConnected); 96289e0f4d2SKip Macy 96389e0f4d2SKip Macy /* Now safe for us to use the shared ring */ 96489e0f4d2SKip Macy mtx_lock(&blkif_io_lock); 96589e0f4d2SKip Macy info->connected = BLKIF_STATE_CONNECTED; 96689e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 96789e0f4d2SKip Macy 96889e0f4d2SKip Macy /* Send off requeued requests */ 96989e0f4d2SKip Macy mtx_lock(&blkif_io_lock); 97089e0f4d2SKip Macy flush_requests(info); 97189e0f4d2SKip Macy 97289e0f4d2SKip Macy /* Kick any other new requests queued since we resumed */ 97389e0f4d2SKip Macy kick_pending_request_queues(info); 97489e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 97589e0f4d2SKip Macy } 97689e0f4d2SKip Macy 97789e0f4d2SKip Macy static int 97889e0f4d2SKip Macy blkfront_is_ready(struct xenbus_device *dev) 97989e0f4d2SKip Macy { 98089e0f4d2SKip Macy struct blkfront_info *info = dev->dev_driver_data; 98189e0f4d2SKip Macy 98289e0f4d2SKip Macy return info->is_ready; 98389e0f4d2SKip Macy } 98489e0f4d2SKip Macy 98589e0f4d2SKip Macy static struct xenbus_device_id blkfront_ids[] = { 98689e0f4d2SKip Macy { "vbd" }, 98789e0f4d2SKip Macy { "" } 98889e0f4d2SKip Macy }; 98989e0f4d2SKip Macy 99089e0f4d2SKip Macy 99189e0f4d2SKip Macy static struct xenbus_driver blkfront = { 99289e0f4d2SKip Macy .name = "vbd", 99389e0f4d2SKip Macy .ids = blkfront_ids, 99489e0f4d2SKip Macy .probe = blkfront_probe, 99589e0f4d2SKip Macy .remove = blkfront_remove, 99689e0f4d2SKip Macy .resume = blkfront_resume, 99789e0f4d2SKip Macy .otherend_changed = backend_changed, 99889e0f4d2SKip Macy .is_ready = blkfront_is_ready, 99989e0f4d2SKip Macy }; 100089e0f4d2SKip Macy 100189e0f4d2SKip Macy 100289e0f4d2SKip Macy 100389e0f4d2SKip Macy static void 100489e0f4d2SKip Macy xenbus_init(void) 100589e0f4d2SKip Macy { 100689e0f4d2SKip Macy xenbus_register_frontend(&blkfront); 100789e0f4d2SKip Macy } 100889e0f4d2SKip Macy 100989e0f4d2SKip Macy MTX_SYSINIT(ioreq, &blkif_io_lock, "BIO LOCK", MTX_NOWITNESS); /* XXX how does one enroll a lock? */ 101089e0f4d2SKip Macy SYSINIT(xbdev, SI_SUB_PSEUDO, SI_ORDER_SECOND, xenbus_init, NULL); 101189e0f4d2SKip Macy 101289e0f4d2SKip Macy 101389e0f4d2SKip Macy /* 101489e0f4d2SKip Macy * Local variables: 101589e0f4d2SKip Macy * mode: C 101689e0f4d2SKip Macy * c-set-style: "BSD" 101789e0f4d2SKip Macy * c-basic-offset: 8 101889e0f4d2SKip Macy * tab-width: 4 101989e0f4d2SKip Macy * indent-tabs-mode: t 102089e0f4d2SKip Macy * End: 102189e0f4d2SKip Macy */ 1022