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 /* 198698b76cSKip Macy * XenBSD block device driver 208698b76cSKip Macy * 218698b76cSKip Macy * Copyright (c) 2009 Frank Suchomel, Citrix 2289e0f4d2SKip Macy */ 2389e0f4d2SKip Macy 2489e0f4d2SKip Macy #include <sys/cdefs.h> 2589e0f4d2SKip Macy __FBSDID("$FreeBSD$"); 2689e0f4d2SKip Macy 2789e0f4d2SKip Macy #include <sys/param.h> 2889e0f4d2SKip Macy #include <sys/systm.h> 2989e0f4d2SKip Macy #include <sys/malloc.h> 3089e0f4d2SKip Macy #include <sys/kernel.h> 3189e0f4d2SKip Macy #include <vm/vm.h> 3289e0f4d2SKip Macy #include <vm/pmap.h> 3389e0f4d2SKip Macy 3489e0f4d2SKip Macy #include <sys/bio.h> 3589e0f4d2SKip Macy #include <sys/bus.h> 3689e0f4d2SKip Macy #include <sys/conf.h> 3789e0f4d2SKip Macy #include <sys/module.h> 3889e0f4d2SKip Macy 3989e0f4d2SKip Macy #include <machine/bus.h> 4089e0f4d2SKip Macy #include <sys/rman.h> 4189e0f4d2SKip Macy #include <machine/resource.h> 4289e0f4d2SKip Macy #include <machine/intr_machdep.h> 4389e0f4d2SKip Macy #include <machine/vmparam.h> 4489e0f4d2SKip Macy 4589e0f4d2SKip Macy #include <machine/xen/xen-os.h> 4612678024SDoug Rabson #include <machine/xen/xenfunc.h> 4712678024SDoug Rabson #include <xen/hypervisor.h> 483a6d1fcfSKip Macy #include <xen/xen_intr.h> 493a6d1fcfSKip Macy #include <xen/evtchn.h> 5012678024SDoug Rabson #include <xen/gnttab.h> 5189e0f4d2SKip Macy #include <xen/interface/grant_table.h> 5223dc5621SKip Macy #include <xen/interface/io/protocols.h> 5323dc5621SKip Macy #include <xen/xenbus/xenbusvar.h> 5489e0f4d2SKip Macy 5589e0f4d2SKip Macy #include <geom/geom_disk.h> 5689e0f4d2SKip Macy 5789e0f4d2SKip Macy #include <dev/xen/blkfront/block.h> 5889e0f4d2SKip Macy 5923dc5621SKip Macy #include "xenbus_if.h" 6023dc5621SKip Macy 6189e0f4d2SKip Macy #define ASSERT(S) KASSERT(S, (#S)) 6289e0f4d2SKip Macy /* prototypes */ 6389e0f4d2SKip Macy struct xb_softc; 6489e0f4d2SKip Macy static void xb_startio(struct xb_softc *sc); 6523dc5621SKip Macy static void connect(device_t, struct blkfront_info *); 6623dc5621SKip Macy static void blkfront_closing(device_t); 6723dc5621SKip Macy static int blkfront_detach(device_t); 6823dc5621SKip Macy static int talk_to_backend(device_t, struct blkfront_info *); 6923dc5621SKip Macy static int setup_blkring(device_t, struct blkfront_info *); 7089e0f4d2SKip Macy static void blkif_int(void *); 7189e0f4d2SKip Macy #if 0 7289e0f4d2SKip Macy static void blkif_restart_queue(void *arg); 7389e0f4d2SKip Macy #endif 7489e0f4d2SKip Macy static void blkif_recover(struct blkfront_info *); 7589e0f4d2SKip Macy static void blkif_completion(struct blk_shadow *); 7689e0f4d2SKip Macy static void blkif_free(struct blkfront_info *, int); 7789e0f4d2SKip Macy 7889e0f4d2SKip Macy #define GRANT_INVALID_REF 0 7989e0f4d2SKip Macy #define BLK_RING_SIZE __RING_SIZE((blkif_sring_t *)0, PAGE_SIZE) 8089e0f4d2SKip Macy 8189e0f4d2SKip Macy LIST_HEAD(xb_softc_list_head, xb_softc) xbsl_head; 8289e0f4d2SKip Macy 8389e0f4d2SKip Macy /* Control whether runtime update of vbds is enabled. */ 8489e0f4d2SKip Macy #define ENABLE_VBD_UPDATE 0 8589e0f4d2SKip Macy 8689e0f4d2SKip Macy #if ENABLE_VBD_UPDATE 8789e0f4d2SKip Macy static void vbd_update(void); 8889e0f4d2SKip Macy #endif 8989e0f4d2SKip Macy 9089e0f4d2SKip Macy 9189e0f4d2SKip Macy #define BLKIF_STATE_DISCONNECTED 0 9289e0f4d2SKip Macy #define BLKIF_STATE_CONNECTED 1 9389e0f4d2SKip Macy #define BLKIF_STATE_SUSPENDED 2 9489e0f4d2SKip Macy 9589e0f4d2SKip Macy #ifdef notyet 9689e0f4d2SKip Macy static char *blkif_state_name[] = { 9789e0f4d2SKip Macy [BLKIF_STATE_DISCONNECTED] = "disconnected", 9889e0f4d2SKip Macy [BLKIF_STATE_CONNECTED] = "connected", 9989e0f4d2SKip Macy [BLKIF_STATE_SUSPENDED] = "closed", 10089e0f4d2SKip Macy }; 10189e0f4d2SKip Macy 10289e0f4d2SKip Macy static char * blkif_status_name[] = { 10389e0f4d2SKip Macy [BLKIF_INTERFACE_STATUS_CLOSED] = "closed", 10489e0f4d2SKip Macy [BLKIF_INTERFACE_STATUS_DISCONNECTED] = "disconnected", 10589e0f4d2SKip Macy [BLKIF_INTERFACE_STATUS_CONNECTED] = "connected", 10689e0f4d2SKip Macy [BLKIF_INTERFACE_STATUS_CHANGED] = "changed", 10789e0f4d2SKip Macy }; 10889e0f4d2SKip Macy #endif 10989e0f4d2SKip Macy #define WPRINTK(fmt, args...) printf("[XEN] " fmt, ##args) 11089e0f4d2SKip Macy #if 0 11112678024SDoug Rabson #define DPRINTK(fmt, args...) printf("[XEN] %s:%d: " fmt ".\n", __func__, __LINE__, ##args) 11289e0f4d2SKip Macy #else 11389e0f4d2SKip Macy #define DPRINTK(fmt, args...) 11489e0f4d2SKip Macy #endif 11589e0f4d2SKip Macy 11689e0f4d2SKip Macy static grant_ref_t gref_head; 11789e0f4d2SKip Macy #define MAXIMUM_OUTSTANDING_BLOCK_REQS \ 11889e0f4d2SKip Macy (BLKIF_MAX_SEGMENTS_PER_REQUEST * BLK_RING_SIZE) 11989e0f4d2SKip Macy 12089e0f4d2SKip Macy static void kick_pending_request_queues(struct blkfront_info *); 12189e0f4d2SKip Macy static int blkif_open(struct disk *dp); 12289e0f4d2SKip Macy static int blkif_close(struct disk *dp); 12389e0f4d2SKip Macy static int blkif_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td); 12489e0f4d2SKip Macy static int blkif_queue_request(struct bio *bp); 12589e0f4d2SKip Macy static void xb_strategy(struct bio *bp); 12689e0f4d2SKip Macy 1278698b76cSKip Macy // In order to quiesce the device during kernel dumps, outstanding requests to 1288698b76cSKip Macy // DOM0 for disk reads/writes need to be accounted for. 1298698b76cSKip Macy static int blkif_queued_requests; 1308698b76cSKip Macy static int xb_dump(void *, void *, vm_offset_t, off_t, size_t); 13189e0f4d2SKip Macy 13289e0f4d2SKip Macy 13389e0f4d2SKip Macy /* XXX move to xb_vbd.c when VBD update support is added */ 13489e0f4d2SKip Macy #define MAX_VBDS 64 13589e0f4d2SKip Macy 13689e0f4d2SKip Macy #define XBD_SECTOR_SIZE 512 /* XXX: assume for now */ 13789e0f4d2SKip Macy #define XBD_SECTOR_SHFT 9 13889e0f4d2SKip Macy 13989e0f4d2SKip Macy static struct mtx blkif_io_lock; 14089e0f4d2SKip Macy 1415d254c04SKip Macy static vm_paddr_t 1425d254c04SKip Macy pfn_to_mfn(vm_paddr_t pfn) 14389e0f4d2SKip Macy { 14489e0f4d2SKip Macy return (phystomach(pfn << PAGE_SHIFT) >> PAGE_SHIFT); 14589e0f4d2SKip Macy } 14689e0f4d2SKip Macy 14723dc5621SKip Macy /* 14823dc5621SKip Macy * Translate Linux major/minor to an appropriate name and unit 14923dc5621SKip Macy * number. For HVM guests, this allows us to use the same drive names 15023dc5621SKip Macy * with blkfront as the emulated drives, easing transition slightly. 15123dc5621SKip Macy */ 15223dc5621SKip Macy static void 15323dc5621SKip Macy blkfront_vdevice_to_unit(int vdevice, int *unit, const char **name) 15423dc5621SKip Macy { 15523dc5621SKip Macy static struct vdev_info { 15623dc5621SKip Macy int major; 15723dc5621SKip Macy int shift; 15823dc5621SKip Macy int base; 15923dc5621SKip Macy const char *name; 16023dc5621SKip Macy } info[] = { 16123dc5621SKip Macy {3, 6, 0, "ad"}, /* ide0 */ 16223dc5621SKip Macy {22, 6, 2, "ad"}, /* ide1 */ 16323dc5621SKip Macy {33, 6, 4, "ad"}, /* ide2 */ 16423dc5621SKip Macy {34, 6, 6, "ad"}, /* ide3 */ 16523dc5621SKip Macy {56, 6, 8, "ad"}, /* ide4 */ 16623dc5621SKip Macy {57, 6, 10, "ad"}, /* ide5 */ 16723dc5621SKip Macy {88, 6, 12, "ad"}, /* ide6 */ 16823dc5621SKip Macy {89, 6, 14, "ad"}, /* ide7 */ 16923dc5621SKip Macy {90, 6, 16, "ad"}, /* ide8 */ 17023dc5621SKip Macy {91, 6, 18, "ad"}, /* ide9 */ 17123dc5621SKip Macy 17223dc5621SKip Macy {8, 4, 0, "da"}, /* scsi disk0 */ 17323dc5621SKip Macy {65, 4, 16, "da"}, /* scsi disk1 */ 17423dc5621SKip Macy {66, 4, 32, "da"}, /* scsi disk2 */ 17523dc5621SKip Macy {67, 4, 48, "da"}, /* scsi disk3 */ 17623dc5621SKip Macy {68, 4, 64, "da"}, /* scsi disk4 */ 17723dc5621SKip Macy {69, 4, 80, "da"}, /* scsi disk5 */ 17823dc5621SKip Macy {70, 4, 96, "da"}, /* scsi disk6 */ 17923dc5621SKip Macy {71, 4, 112, "da"}, /* scsi disk7 */ 18023dc5621SKip Macy {128, 4, 128, "da"}, /* scsi disk8 */ 18123dc5621SKip Macy {129, 4, 144, "da"}, /* scsi disk9 */ 18223dc5621SKip Macy {130, 4, 160, "da"}, /* scsi disk10 */ 18323dc5621SKip Macy {131, 4, 176, "da"}, /* scsi disk11 */ 18423dc5621SKip Macy {132, 4, 192, "da"}, /* scsi disk12 */ 18523dc5621SKip Macy {133, 4, 208, "da"}, /* scsi disk13 */ 18623dc5621SKip Macy {134, 4, 224, "da"}, /* scsi disk14 */ 18723dc5621SKip Macy {135, 4, 240, "da"}, /* scsi disk15 */ 18823dc5621SKip Macy 18923dc5621SKip Macy {202, 4, 0, "xbd"}, /* xbd */ 19023dc5621SKip Macy 19123dc5621SKip Macy {0, 0, 0, NULL}, 19223dc5621SKip Macy }; 19323dc5621SKip Macy int major = vdevice >> 8; 19423dc5621SKip Macy int minor = vdevice & 0xff; 19523dc5621SKip Macy int i; 19623dc5621SKip Macy 19723dc5621SKip Macy if (vdevice & (1 << 28)) { 19823dc5621SKip Macy *unit = (vdevice & ((1 << 28) - 1)) >> 8; 19923dc5621SKip Macy *name = "xbd"; 20023dc5621SKip Macy } 20123dc5621SKip Macy 20223dc5621SKip Macy for (i = 0; info[i].major; i++) { 20323dc5621SKip Macy if (info[i].major == major) { 20423dc5621SKip Macy *unit = info[i].base + (minor >> info[i].shift); 20523dc5621SKip Macy *name = info[i].name; 20623dc5621SKip Macy return; 20723dc5621SKip Macy } 20823dc5621SKip Macy } 20923dc5621SKip Macy 21023dc5621SKip Macy *unit = minor >> 4; 21123dc5621SKip Macy *name = "xbd"; 21223dc5621SKip Macy } 21323dc5621SKip Macy 21489e0f4d2SKip Macy int 21523dc5621SKip Macy xlvbd_add(device_t dev, blkif_sector_t capacity, 21623dc5621SKip Macy int vdevice, uint16_t vdisk_info, uint16_t sector_size, 21789e0f4d2SKip Macy struct blkfront_info *info) 21889e0f4d2SKip Macy { 21989e0f4d2SKip Macy struct xb_softc *sc; 22023dc5621SKip Macy int unit, error = 0; 22123dc5621SKip Macy const char *name; 22223dc5621SKip Macy 22323dc5621SKip Macy blkfront_vdevice_to_unit(vdevice, &unit, &name); 22489e0f4d2SKip Macy 22589e0f4d2SKip Macy sc = (struct xb_softc *)malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); 22623dc5621SKip Macy sc->xb_unit = unit; 22789e0f4d2SKip Macy sc->xb_info = info; 22889e0f4d2SKip Macy info->sc = sc; 22989e0f4d2SKip Macy 23023dc5621SKip Macy if (strcmp(name, "xbd")) 23123dc5621SKip Macy device_printf(dev, "attaching as %s%d\n", name, unit); 23223dc5621SKip Macy 23389e0f4d2SKip Macy memset(&sc->xb_disk, 0, sizeof(sc->xb_disk)); 23489e0f4d2SKip Macy sc->xb_disk = disk_alloc(); 2353a6d1fcfSKip Macy sc->xb_disk->d_unit = sc->xb_unit; 23689e0f4d2SKip Macy sc->xb_disk->d_open = blkif_open; 23789e0f4d2SKip Macy sc->xb_disk->d_close = blkif_close; 23889e0f4d2SKip Macy sc->xb_disk->d_ioctl = blkif_ioctl; 23989e0f4d2SKip Macy sc->xb_disk->d_strategy = xb_strategy; 2408698b76cSKip Macy sc->xb_disk->d_dump = xb_dump; 2413a6d1fcfSKip Macy sc->xb_disk->d_name = name; 24289e0f4d2SKip Macy sc->xb_disk->d_drv1 = sc; 24389e0f4d2SKip Macy sc->xb_disk->d_sectorsize = sector_size; 24489e0f4d2SKip Macy 24589e0f4d2SKip Macy /* XXX */ 24689e0f4d2SKip Macy sc->xb_disk->d_mediasize = capacity << XBD_SECTOR_SHFT; 24789e0f4d2SKip Macy #if 0 24889e0f4d2SKip Macy sc->xb_disk->d_maxsize = DFLTPHYS; 24989e0f4d2SKip Macy #else /* XXX: xen can't handle large single i/o requests */ 25089e0f4d2SKip Macy sc->xb_disk->d_maxsize = 4096; 25189e0f4d2SKip Macy #endif 25289e0f4d2SKip Macy #ifdef notyet 25389e0f4d2SKip Macy XENPRINTF("attaching device 0x%x unit %d capacity %llu\n", 25489e0f4d2SKip Macy xb_diskinfo[sc->xb_unit].device, sc->xb_unit, 25589e0f4d2SKip Macy sc->xb_disk->d_mediasize); 25689e0f4d2SKip Macy #endif 25789e0f4d2SKip Macy sc->xb_disk->d_flags = 0; 25889e0f4d2SKip Macy disk_create(sc->xb_disk, DISK_VERSION_00); 25989e0f4d2SKip Macy bioq_init(&sc->xb_bioq); 26089e0f4d2SKip Macy 26189e0f4d2SKip Macy return error; 26289e0f4d2SKip Macy } 26389e0f4d2SKip Macy 26489e0f4d2SKip Macy void 26589e0f4d2SKip Macy xlvbd_del(struct blkfront_info *info) 26689e0f4d2SKip Macy { 26789e0f4d2SKip Macy struct xb_softc *sc; 26889e0f4d2SKip Macy 26989e0f4d2SKip Macy sc = info->sc; 27089e0f4d2SKip Macy disk_destroy(sc->xb_disk); 27189e0f4d2SKip Macy } 27289e0f4d2SKip Macy /************************ end VBD support *****************/ 27389e0f4d2SKip Macy 27489e0f4d2SKip Macy /* 27589e0f4d2SKip Macy * Read/write routine for a buffer. Finds the proper unit, place it on 27689e0f4d2SKip Macy * the sortq and kick the controller. 27789e0f4d2SKip Macy */ 27889e0f4d2SKip Macy static void 27989e0f4d2SKip Macy xb_strategy(struct bio *bp) 28089e0f4d2SKip Macy { 28189e0f4d2SKip Macy struct xb_softc *sc = (struct xb_softc *)bp->bio_disk->d_drv1; 28289e0f4d2SKip Macy 28389e0f4d2SKip Macy /* bogus disk? */ 28489e0f4d2SKip Macy if (sc == NULL) { 28589e0f4d2SKip Macy bp->bio_error = EINVAL; 28689e0f4d2SKip Macy bp->bio_flags |= BIO_ERROR; 28789e0f4d2SKip Macy goto bad; 28889e0f4d2SKip Macy } 28989e0f4d2SKip Macy 29089e0f4d2SKip Macy DPRINTK(""); 29189e0f4d2SKip Macy 29289e0f4d2SKip Macy /* 29389e0f4d2SKip Macy * Place it in the queue of disk activities for this disk 29489e0f4d2SKip Macy */ 29589e0f4d2SKip Macy mtx_lock(&blkif_io_lock); 29689e0f4d2SKip Macy 2978698b76cSKip Macy bioq_disksort(&sc->xb_bioq, bp); 29889e0f4d2SKip Macy xb_startio(sc); 2998698b76cSKip Macy 30089e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 30189e0f4d2SKip Macy return; 30289e0f4d2SKip Macy 30389e0f4d2SKip Macy bad: 30489e0f4d2SKip Macy /* 30589e0f4d2SKip Macy * Correctly set the bio to indicate a failed tranfer. 30689e0f4d2SKip Macy */ 30789e0f4d2SKip Macy bp->bio_resid = bp->bio_bcount; 30889e0f4d2SKip Macy biodone(bp); 30989e0f4d2SKip Macy return; 31089e0f4d2SKip Macy } 31189e0f4d2SKip Macy 3128698b76cSKip Macy static void xb_quiesce(struct blkfront_info *info); 3138698b76cSKip Macy // Quiesce the disk writes for a dump file before allowing the next buffer. 3148698b76cSKip Macy static void 3158698b76cSKip Macy xb_quiesce(struct blkfront_info *info) 3168698b76cSKip Macy { 3178698b76cSKip Macy int mtd; 3188698b76cSKip Macy 3198698b76cSKip Macy // While there are outstanding requests 3208698b76cSKip Macy while (blkif_queued_requests) { 3218698b76cSKip Macy RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, mtd); 3228698b76cSKip Macy if (mtd) { 3238698b76cSKip Macy // Recieved request completions, update queue. 3248698b76cSKip Macy blkif_int(info); 3258698b76cSKip Macy } 3268698b76cSKip Macy if (blkif_queued_requests) { 3278698b76cSKip Macy // Still pending requests, wait for the disk i/o to complete 328be7747b4SKip Macy HYPERVISOR_yield(); 3298698b76cSKip Macy } 3308698b76cSKip Macy } 3318698b76cSKip Macy } 3328698b76cSKip Macy 3338698b76cSKip Macy // Some bio structures for dumping core 3348698b76cSKip Macy #define DUMP_BIO_NO 16 // 16 * 4KB = 64KB dump block 3358698b76cSKip Macy static struct bio xb_dump_bp[DUMP_BIO_NO]; 3368698b76cSKip Macy 3378698b76cSKip Macy // Kernel dump function for a paravirtualized disk device 3388698b76cSKip Macy static int 3398698b76cSKip Macy xb_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, 3408698b76cSKip Macy size_t length) 3418698b76cSKip Macy { 3428698b76cSKip Macy int sbp; 3438698b76cSKip Macy int mbp; 3448698b76cSKip Macy size_t chunk; 3458698b76cSKip Macy struct disk *dp = arg; 3468698b76cSKip Macy struct xb_softc *sc = (struct xb_softc *) dp->d_drv1; 3478698b76cSKip Macy int rc = 0; 3488698b76cSKip Macy 3498698b76cSKip Macy xb_quiesce(sc->xb_info); // All quiet on the western front. 3508698b76cSKip Macy if (length > 0) { 3518698b76cSKip Macy // If this lock is held, then this module is failing, and a successful 3528698b76cSKip Macy // kernel dump is highly unlikely anyway. 3538698b76cSKip Macy mtx_lock(&blkif_io_lock); 3548698b76cSKip Macy // Split the 64KB block into 16 4KB blocks 3558698b76cSKip Macy for (sbp=0; length>0 && sbp<DUMP_BIO_NO; sbp++) { 3568698b76cSKip Macy chunk = length > PAGE_SIZE ? PAGE_SIZE : length; 3578698b76cSKip Macy xb_dump_bp[sbp].bio_disk = dp; 3588698b76cSKip Macy xb_dump_bp[sbp].bio_pblkno = offset / dp->d_sectorsize; 3598698b76cSKip Macy xb_dump_bp[sbp].bio_bcount = chunk; 3608698b76cSKip Macy xb_dump_bp[sbp].bio_resid = chunk; 3618698b76cSKip Macy xb_dump_bp[sbp].bio_data = virtual; 3628698b76cSKip Macy xb_dump_bp[sbp].bio_cmd = BIO_WRITE; 3638698b76cSKip Macy xb_dump_bp[sbp].bio_done = NULL; 3648698b76cSKip Macy 3658698b76cSKip Macy bioq_disksort(&sc->xb_bioq, &xb_dump_bp[sbp]); 3668698b76cSKip Macy 3678698b76cSKip Macy length -= chunk; 3688698b76cSKip Macy offset += chunk; 3698698b76cSKip Macy virtual = (char *) virtual + chunk; 3708698b76cSKip Macy } 3718698b76cSKip Macy // Tell DOM0 to do the I/O 3728698b76cSKip Macy xb_startio(sc); 3738698b76cSKip Macy mtx_unlock(&blkif_io_lock); 3748698b76cSKip Macy 3758698b76cSKip Macy // Must wait for the completion: the dump routine reuses the same 3768698b76cSKip Macy // 16 x 4KB buffer space. 3778698b76cSKip Macy xb_quiesce(sc->xb_info); // All quite on the eastern front 3788698b76cSKip Macy // If there were any errors, bail out... 3798698b76cSKip Macy for (mbp=0; mbp<sbp; mbp++) { 3808698b76cSKip Macy if ((rc = xb_dump_bp[mbp].bio_error)) break; 3818698b76cSKip Macy } 3828698b76cSKip Macy } 3838698b76cSKip Macy return (rc); 3848698b76cSKip Macy } 3858698b76cSKip Macy 3868698b76cSKip Macy 38723dc5621SKip Macy static int 38823dc5621SKip Macy blkfront_probe(device_t dev) 38989e0f4d2SKip Macy { 39023dc5621SKip Macy 39123dc5621SKip Macy if (!strcmp(xenbus_get_type(dev), "vbd")) { 39223dc5621SKip Macy device_set_desc(dev, "Virtual Block Device"); 39323dc5621SKip Macy device_quiet(dev); 39423dc5621SKip Macy return (0); 39523dc5621SKip Macy } 39623dc5621SKip Macy 39723dc5621SKip Macy return (ENXIO); 39823dc5621SKip Macy } 39923dc5621SKip Macy 40023dc5621SKip Macy /* 40123dc5621SKip Macy * Setup supplies the backend dir, virtual device. We place an event 40223dc5621SKip Macy * channel and shared frame entries. We watch backend to wait if it's 40323dc5621SKip Macy * ok. 40423dc5621SKip Macy */ 40523dc5621SKip Macy static int 40623dc5621SKip Macy blkfront_attach(device_t dev) 40723dc5621SKip Macy { 40812678024SDoug Rabson int error, vdevice, i, unit; 40989e0f4d2SKip Macy struct blkfront_info *info; 41023dc5621SKip Macy const char *name; 41189e0f4d2SKip Macy 41289e0f4d2SKip Macy /* FIXME: Use dynamic device id if this is not set. */ 41312678024SDoug Rabson error = xenbus_scanf(XBT_NIL, xenbus_get_node(dev), 4143a6d1fcfSKip Macy "virtual-device", NULL, "%i", &vdevice); 41512678024SDoug Rabson if (error) { 41612678024SDoug Rabson xenbus_dev_fatal(dev, error, "reading virtual-device"); 4175d254c04SKip Macy printf("couldn't find virtual device"); 41812678024SDoug Rabson return (error); 41989e0f4d2SKip Macy } 42089e0f4d2SKip Macy 42123dc5621SKip Macy blkfront_vdevice_to_unit(vdevice, &unit, &name); 42223dc5621SKip Macy if (!strcmp(name, "xbd")) 42323dc5621SKip Macy device_set_unit(dev, unit); 42423dc5621SKip Macy 42523dc5621SKip Macy info = device_get_softc(dev); 42689e0f4d2SKip Macy 42789e0f4d2SKip Macy /* 42889e0f4d2SKip Macy * XXX debug only 42989e0f4d2SKip Macy */ 43089e0f4d2SKip Macy for (i = 0; i < sizeof(*info); i++) 43189e0f4d2SKip Macy if (((uint8_t *)info)[i] != 0) 43289e0f4d2SKip Macy panic("non-null memory"); 43389e0f4d2SKip Macy 43489e0f4d2SKip Macy info->shadow_free = 0; 43589e0f4d2SKip Macy info->xbdev = dev; 43689e0f4d2SKip Macy info->vdevice = vdevice; 43789e0f4d2SKip Macy info->connected = BLKIF_STATE_DISCONNECTED; 43889e0f4d2SKip Macy 43989e0f4d2SKip Macy /* work queue needed ? */ 44089e0f4d2SKip Macy for (i = 0; i < BLK_RING_SIZE; i++) 44189e0f4d2SKip Macy info->shadow[i].req.id = i+1; 44289e0f4d2SKip Macy info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff; 44389e0f4d2SKip Macy 44489e0f4d2SKip Macy /* Front end dir is a number, which is used as the id. */ 44523dc5621SKip Macy info->handle = strtoul(strrchr(xenbus_get_node(dev),'/')+1, NULL, 0); 44689e0f4d2SKip Macy 44712678024SDoug Rabson error = talk_to_backend(dev, info); 44812678024SDoug Rabson if (error) 44912678024SDoug Rabson return (error); 45012678024SDoug Rabson 45112678024SDoug Rabson return (0); 45212678024SDoug Rabson } 45312678024SDoug Rabson 45412678024SDoug Rabson static int 45512678024SDoug Rabson blkfront_suspend(device_t dev) 45612678024SDoug Rabson { 45712678024SDoug Rabson struct blkfront_info *info = device_get_softc(dev); 45812678024SDoug Rabson 45912678024SDoug Rabson /* Prevent new requests being issued until we fix things up. */ 46012678024SDoug Rabson mtx_lock(&blkif_io_lock); 46112678024SDoug Rabson info->connected = BLKIF_STATE_SUSPENDED; 46212678024SDoug Rabson mtx_unlock(&blkif_io_lock); 46389e0f4d2SKip Macy 46423dc5621SKip Macy return (0); 46589e0f4d2SKip Macy } 46689e0f4d2SKip Macy 46723dc5621SKip Macy static int 46823dc5621SKip Macy blkfront_resume(device_t dev) 46989e0f4d2SKip Macy { 47023dc5621SKip Macy struct blkfront_info *info = device_get_softc(dev); 47189e0f4d2SKip Macy int err; 47289e0f4d2SKip Macy 47312678024SDoug Rabson DPRINTK("blkfront_resume: %s\n", xenbus_get_node(dev)); 47489e0f4d2SKip Macy 47589e0f4d2SKip Macy blkif_free(info, 1); 47689e0f4d2SKip Macy err = talk_to_backend(dev, info); 4773a6d1fcfSKip Macy if (info->connected == BLKIF_STATE_SUSPENDED && !err) 47889e0f4d2SKip Macy blkif_recover(info); 47989e0f4d2SKip Macy 48012678024SDoug Rabson return (err); 48189e0f4d2SKip Macy } 48289e0f4d2SKip Macy 48389e0f4d2SKip Macy /* Common code used when first setting up, and when resuming. */ 48423dc5621SKip Macy static int 48523dc5621SKip Macy talk_to_backend(device_t dev, struct blkfront_info *info) 48689e0f4d2SKip Macy { 48789e0f4d2SKip Macy const char *message = NULL; 48889e0f4d2SKip Macy struct xenbus_transaction xbt; 48989e0f4d2SKip Macy int err; 49089e0f4d2SKip Macy 49189e0f4d2SKip Macy /* Create shared ring, alloc event channel. */ 49289e0f4d2SKip Macy err = setup_blkring(dev, info); 49389e0f4d2SKip Macy if (err) 49489e0f4d2SKip Macy goto out; 49589e0f4d2SKip Macy 49689e0f4d2SKip Macy again: 49789e0f4d2SKip Macy err = xenbus_transaction_start(&xbt); 49889e0f4d2SKip Macy if (err) { 49989e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "starting transaction"); 50089e0f4d2SKip Macy goto destroy_blkring; 50189e0f4d2SKip Macy } 50289e0f4d2SKip Macy 50323dc5621SKip Macy err = xenbus_printf(xbt, xenbus_get_node(dev), 50489e0f4d2SKip Macy "ring-ref","%u", info->ring_ref); 50589e0f4d2SKip Macy if (err) { 50689e0f4d2SKip Macy message = "writing ring-ref"; 50789e0f4d2SKip Macy goto abort_transaction; 50889e0f4d2SKip Macy } 50923dc5621SKip Macy err = xenbus_printf(xbt, xenbus_get_node(dev), 51089e0f4d2SKip Macy "event-channel", "%u", irq_to_evtchn_port(info->irq)); 51189e0f4d2SKip Macy if (err) { 51289e0f4d2SKip Macy message = "writing event-channel"; 51389e0f4d2SKip Macy goto abort_transaction; 51489e0f4d2SKip Macy } 51523dc5621SKip Macy err = xenbus_printf(xbt, xenbus_get_node(dev), 51623dc5621SKip Macy "protocol", "%s", XEN_IO_PROTO_ABI_NATIVE); 51723dc5621SKip Macy if (err) { 51823dc5621SKip Macy message = "writing protocol"; 51923dc5621SKip Macy goto abort_transaction; 52023dc5621SKip Macy } 52112678024SDoug Rabson 52289e0f4d2SKip Macy err = xenbus_transaction_end(xbt, 0); 52389e0f4d2SKip Macy if (err) { 5243a6d1fcfSKip Macy if (err == EAGAIN) 52589e0f4d2SKip Macy goto again; 52689e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "completing transaction"); 52789e0f4d2SKip Macy goto destroy_blkring; 52889e0f4d2SKip Macy } 52923dc5621SKip Macy xenbus_set_state(dev, XenbusStateInitialised); 53089e0f4d2SKip Macy 53189e0f4d2SKip Macy return 0; 53289e0f4d2SKip Macy 53389e0f4d2SKip Macy abort_transaction: 53489e0f4d2SKip Macy xenbus_transaction_end(xbt, 1); 53589e0f4d2SKip Macy if (message) 53689e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "%s", message); 53789e0f4d2SKip Macy destroy_blkring: 53889e0f4d2SKip Macy blkif_free(info, 0); 53989e0f4d2SKip Macy out: 54089e0f4d2SKip Macy return err; 54189e0f4d2SKip Macy } 54289e0f4d2SKip Macy 54389e0f4d2SKip Macy static int 54423dc5621SKip Macy setup_blkring(device_t dev, struct blkfront_info *info) 54589e0f4d2SKip Macy { 54689e0f4d2SKip Macy blkif_sring_t *sring; 5473a6d1fcfSKip Macy int error; 54889e0f4d2SKip Macy 54989e0f4d2SKip Macy info->ring_ref = GRANT_INVALID_REF; 55089e0f4d2SKip Macy 55189e0f4d2SKip Macy sring = (blkif_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT|M_ZERO); 55289e0f4d2SKip Macy if (sring == NULL) { 55389e0f4d2SKip Macy xenbus_dev_fatal(dev, ENOMEM, "allocating shared ring"); 55489e0f4d2SKip Macy return ENOMEM; 55589e0f4d2SKip Macy } 55689e0f4d2SKip Macy SHARED_RING_INIT(sring); 55789e0f4d2SKip Macy FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE); 55889e0f4d2SKip Macy 55912678024SDoug Rabson error = xenbus_grant_ring(dev, 56012678024SDoug Rabson (vtomach(info->ring.sring) >> PAGE_SHIFT), &info->ring_ref); 5613a6d1fcfSKip Macy if (error) { 56289e0f4d2SKip Macy free(sring, M_DEVBUF); 56389e0f4d2SKip Macy info->ring.sring = NULL; 56489e0f4d2SKip Macy goto fail; 56589e0f4d2SKip Macy } 56689e0f4d2SKip Macy 5673a6d1fcfSKip Macy error = bind_listening_port_to_irqhandler(xenbus_get_otherend_id(dev), 56889e0f4d2SKip Macy "xbd", (driver_intr_t *)blkif_int, info, 5693a6d1fcfSKip Macy INTR_TYPE_BIO | INTR_MPSAFE, &info->irq); 5703a6d1fcfSKip Macy if (error) { 5713a6d1fcfSKip Macy xenbus_dev_fatal(dev, error, 57289e0f4d2SKip Macy "bind_evtchn_to_irqhandler failed"); 57389e0f4d2SKip Macy goto fail; 57489e0f4d2SKip Macy } 57589e0f4d2SKip Macy 5763a6d1fcfSKip Macy return (0); 57789e0f4d2SKip Macy fail: 57889e0f4d2SKip Macy blkif_free(info, 0); 5793a6d1fcfSKip Macy return (error); 58089e0f4d2SKip Macy } 58189e0f4d2SKip Macy 58289e0f4d2SKip Macy 58389e0f4d2SKip Macy /** 58489e0f4d2SKip Macy * Callback received when the backend's state changes. 58589e0f4d2SKip Macy */ 586cfed3783SKip Macy static int 58723dc5621SKip Macy blkfront_backend_changed(device_t dev, XenbusState backend_state) 58889e0f4d2SKip Macy { 58923dc5621SKip Macy struct blkfront_info *info = device_get_softc(dev); 59089e0f4d2SKip Macy 59112678024SDoug Rabson DPRINTK("backend_state=%d\n", backend_state); 59289e0f4d2SKip Macy 59389e0f4d2SKip Macy switch (backend_state) { 59489e0f4d2SKip Macy case XenbusStateUnknown: 59589e0f4d2SKip Macy case XenbusStateInitialising: 59689e0f4d2SKip Macy case XenbusStateInitWait: 59789e0f4d2SKip Macy case XenbusStateInitialised: 59889e0f4d2SKip Macy case XenbusStateClosed: 599920ba15bSKip Macy case XenbusStateReconfigured: 600920ba15bSKip Macy case XenbusStateReconfiguring: 60189e0f4d2SKip Macy break; 60289e0f4d2SKip Macy 60389e0f4d2SKip Macy case XenbusStateConnected: 60423dc5621SKip Macy connect(dev, info); 60589e0f4d2SKip Macy break; 60689e0f4d2SKip Macy 60789e0f4d2SKip Macy case XenbusStateClosing: 60889e0f4d2SKip Macy if (info->users > 0) 60989e0f4d2SKip Macy xenbus_dev_error(dev, -EBUSY, 61089e0f4d2SKip Macy "Device in use; refusing to close"); 61189e0f4d2SKip Macy else 61289e0f4d2SKip Macy blkfront_closing(dev); 61389e0f4d2SKip Macy #ifdef notyet 61489e0f4d2SKip Macy bd = bdget(info->dev); 61589e0f4d2SKip Macy if (bd == NULL) 61689e0f4d2SKip Macy xenbus_dev_fatal(dev, -ENODEV, "bdget failed"); 61789e0f4d2SKip Macy 61889e0f4d2SKip Macy down(&bd->bd_sem); 61989e0f4d2SKip Macy if (info->users > 0) 62089e0f4d2SKip Macy xenbus_dev_error(dev, -EBUSY, 62189e0f4d2SKip Macy "Device in use; refusing to close"); 62289e0f4d2SKip Macy else 62389e0f4d2SKip Macy blkfront_closing(dev); 62489e0f4d2SKip Macy up(&bd->bd_sem); 62589e0f4d2SKip Macy bdput(bd); 62689e0f4d2SKip Macy #endif 62789e0f4d2SKip Macy } 628cfed3783SKip Macy 629cfed3783SKip Macy return (0); 63089e0f4d2SKip Macy } 63189e0f4d2SKip Macy 63289e0f4d2SKip Macy /* 63389e0f4d2SKip Macy ** Invoked when the backend is finally 'ready' (and has told produced 63489e0f4d2SKip Macy ** the details about the physical device - #sectors, size, etc). 63589e0f4d2SKip Macy */ 63689e0f4d2SKip Macy static void 63723dc5621SKip Macy connect(device_t dev, struct blkfront_info *info) 63889e0f4d2SKip Macy { 63989e0f4d2SKip Macy unsigned long sectors, sector_size; 64089e0f4d2SKip Macy unsigned int binfo; 64189e0f4d2SKip Macy int err; 64289e0f4d2SKip Macy 64389e0f4d2SKip Macy if( (info->connected == BLKIF_STATE_CONNECTED) || 64489e0f4d2SKip Macy (info->connected == BLKIF_STATE_SUSPENDED) ) 64589e0f4d2SKip Macy return; 64689e0f4d2SKip Macy 64723dc5621SKip Macy DPRINTK("blkfront.c:connect:%s.\n", xenbus_get_otherend_path(dev)); 64889e0f4d2SKip Macy 64923dc5621SKip Macy err = xenbus_gather(XBT_NIL, xenbus_get_otherend_path(dev), 65089e0f4d2SKip Macy "sectors", "%lu", §ors, 65189e0f4d2SKip Macy "info", "%u", &binfo, 65289e0f4d2SKip Macy "sector-size", "%lu", §or_size, 65389e0f4d2SKip Macy NULL); 65489e0f4d2SKip Macy if (err) { 65523dc5621SKip Macy xenbus_dev_fatal(dev, err, 65689e0f4d2SKip Macy "reading backend fields at %s", 65723dc5621SKip Macy xenbus_get_otherend_path(dev)); 65889e0f4d2SKip Macy return; 65989e0f4d2SKip Macy } 66023dc5621SKip Macy err = xenbus_gather(XBT_NIL, xenbus_get_otherend_path(dev), 66189e0f4d2SKip Macy "feature-barrier", "%lu", &info->feature_barrier, 66289e0f4d2SKip Macy NULL); 66389e0f4d2SKip Macy if (err) 66489e0f4d2SKip Macy info->feature_barrier = 0; 66589e0f4d2SKip Macy 66623dc5621SKip Macy device_printf(dev, "%juMB <%s> at %s", 66723dc5621SKip Macy (uintmax_t) sectors / (1048576 / sector_size), 66823dc5621SKip Macy device_get_desc(dev), 66923dc5621SKip Macy xenbus_get_node(dev)); 67023dc5621SKip Macy bus_print_child_footer(device_get_parent(dev), dev); 67189e0f4d2SKip Macy 67223dc5621SKip Macy xlvbd_add(dev, sectors, info->vdevice, binfo, sector_size, info); 67323dc5621SKip Macy 67423dc5621SKip Macy (void)xenbus_set_state(dev, XenbusStateConnected); 67589e0f4d2SKip Macy 67689e0f4d2SKip Macy /* Kick pending requests. */ 67789e0f4d2SKip Macy mtx_lock(&blkif_io_lock); 67889e0f4d2SKip Macy info->connected = BLKIF_STATE_CONNECTED; 67989e0f4d2SKip Macy kick_pending_request_queues(info); 68089e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 6814615bad1SKip Macy info->is_ready = 1; 68289e0f4d2SKip Macy 68389e0f4d2SKip Macy #if 0 68489e0f4d2SKip Macy add_disk(info->gd); 68589e0f4d2SKip Macy #endif 68689e0f4d2SKip Macy } 68789e0f4d2SKip Macy 68889e0f4d2SKip Macy /** 68989e0f4d2SKip Macy * Handle the change of state of the backend to Closing. We must delete our 69089e0f4d2SKip Macy * device-layer structures now, to ensure that writes are flushed through to 69189e0f4d2SKip Macy * the backend. Once is this done, we can switch to Closed in 69289e0f4d2SKip Macy * acknowledgement. 69389e0f4d2SKip Macy */ 69423dc5621SKip Macy static void 69523dc5621SKip Macy blkfront_closing(device_t dev) 69689e0f4d2SKip Macy { 69723dc5621SKip Macy struct blkfront_info *info = device_get_softc(dev); 69889e0f4d2SKip Macy 69923dc5621SKip Macy DPRINTK("blkfront_closing: %s removed\n", xenbus_get_node(dev)); 70089e0f4d2SKip Macy 70189e0f4d2SKip Macy if (info->mi) { 70289e0f4d2SKip Macy DPRINTK("Calling xlvbd_del\n"); 70389e0f4d2SKip Macy xlvbd_del(info); 70489e0f4d2SKip Macy info->mi = NULL; 70589e0f4d2SKip Macy } 70689e0f4d2SKip Macy 70723dc5621SKip Macy xenbus_set_state(dev, XenbusStateClosed); 70889e0f4d2SKip Macy } 70989e0f4d2SKip Macy 71089e0f4d2SKip Macy 71123dc5621SKip Macy static int 71223dc5621SKip Macy blkfront_detach(device_t dev) 71389e0f4d2SKip Macy { 71423dc5621SKip Macy struct blkfront_info *info = device_get_softc(dev); 71589e0f4d2SKip Macy 71623dc5621SKip Macy DPRINTK("blkfront_remove: %s removed\n", xenbus_get_node(dev)); 71789e0f4d2SKip Macy 71889e0f4d2SKip Macy blkif_free(info, 0); 71989e0f4d2SKip Macy 72089e0f4d2SKip Macy return 0; 72189e0f4d2SKip Macy } 72289e0f4d2SKip Macy 72389e0f4d2SKip Macy 72489e0f4d2SKip Macy static inline int 72589e0f4d2SKip Macy GET_ID_FROM_FREELIST(struct blkfront_info *info) 72689e0f4d2SKip Macy { 72789e0f4d2SKip Macy unsigned long nfree = info->shadow_free; 72889e0f4d2SKip Macy 72989e0f4d2SKip Macy KASSERT(nfree <= BLK_RING_SIZE, ("free %lu > RING_SIZE", nfree)); 73089e0f4d2SKip Macy info->shadow_free = info->shadow[nfree].req.id; 73189e0f4d2SKip Macy info->shadow[nfree].req.id = 0x0fffffee; /* debug */ 7328698b76cSKip Macy atomic_add_int(&blkif_queued_requests, 1); 73389e0f4d2SKip Macy return nfree; 73489e0f4d2SKip Macy } 73589e0f4d2SKip Macy 73689e0f4d2SKip Macy static inline void 73789e0f4d2SKip Macy ADD_ID_TO_FREELIST(struct blkfront_info *info, unsigned long id) 73889e0f4d2SKip Macy { 73989e0f4d2SKip Macy info->shadow[id].req.id = info->shadow_free; 74089e0f4d2SKip Macy info->shadow[id].request = 0; 74189e0f4d2SKip Macy info->shadow_free = id; 7428698b76cSKip Macy atomic_subtract_int(&blkif_queued_requests, 1); 74389e0f4d2SKip Macy } 74489e0f4d2SKip Macy 74589e0f4d2SKip Macy static inline void 74689e0f4d2SKip Macy flush_requests(struct blkfront_info *info) 74789e0f4d2SKip Macy { 74889e0f4d2SKip Macy int notify; 74989e0f4d2SKip Macy 75089e0f4d2SKip Macy RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->ring, notify); 75189e0f4d2SKip Macy 75289e0f4d2SKip Macy if (notify) 75389e0f4d2SKip Macy notify_remote_via_irq(info->irq); 75489e0f4d2SKip Macy } 75589e0f4d2SKip Macy 75689e0f4d2SKip Macy static void 75789e0f4d2SKip Macy kick_pending_request_queues(struct blkfront_info *info) 75889e0f4d2SKip Macy { 75989e0f4d2SKip Macy /* XXX check if we can't simplify */ 76089e0f4d2SKip Macy #if 0 76189e0f4d2SKip Macy if (!RING_FULL(&info->ring)) { 76289e0f4d2SKip Macy /* Re-enable calldowns. */ 76389e0f4d2SKip Macy blk_start_queue(info->rq); 76489e0f4d2SKip Macy /* Kick things off immediately. */ 76589e0f4d2SKip Macy do_blkif_request(info->rq); 76689e0f4d2SKip Macy } 76789e0f4d2SKip Macy #endif 76889e0f4d2SKip Macy if (!RING_FULL(&info->ring)) { 76989e0f4d2SKip Macy #if 0 77089e0f4d2SKip Macy sc = LIST_FIRST(&xbsl_head); 77189e0f4d2SKip Macy LIST_REMOVE(sc, entry); 77289e0f4d2SKip Macy /* Re-enable calldowns. */ 77389e0f4d2SKip Macy blk_start_queue(di->rq); 77489e0f4d2SKip Macy #endif 77589e0f4d2SKip Macy /* Kick things off immediately. */ 77689e0f4d2SKip Macy xb_startio(info->sc); 77789e0f4d2SKip Macy } 77889e0f4d2SKip Macy } 77989e0f4d2SKip Macy 78089e0f4d2SKip Macy #if 0 78189e0f4d2SKip Macy /* XXX */ 78289e0f4d2SKip Macy static void blkif_restart_queue(void *arg) 78389e0f4d2SKip Macy { 78489e0f4d2SKip Macy struct blkfront_info *info = (struct blkfront_info *)arg; 78589e0f4d2SKip Macy 78689e0f4d2SKip Macy mtx_lock(&blkif_io_lock); 78789e0f4d2SKip Macy kick_pending_request_queues(info); 78889e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 78989e0f4d2SKip Macy } 79089e0f4d2SKip Macy #endif 79189e0f4d2SKip Macy 79289e0f4d2SKip Macy static void blkif_restart_queue_callback(void *arg) 79389e0f4d2SKip Macy { 79489e0f4d2SKip Macy #if 0 79589e0f4d2SKip Macy struct blkfront_info *info = (struct blkfront_info *)arg; 79689e0f4d2SKip Macy /* XXX BSD equiv ? */ 79789e0f4d2SKip Macy 79889e0f4d2SKip Macy schedule_work(&info->work); 79989e0f4d2SKip Macy #endif 80089e0f4d2SKip Macy } 80189e0f4d2SKip Macy 80289e0f4d2SKip Macy static int 80389e0f4d2SKip Macy blkif_open(struct disk *dp) 80489e0f4d2SKip Macy { 80589e0f4d2SKip Macy struct xb_softc *sc = (struct xb_softc *)dp->d_drv1; 80689e0f4d2SKip Macy 80789e0f4d2SKip Macy if (sc == NULL) { 80812678024SDoug Rabson printf("xb%d: not found", sc->xb_unit); 80989e0f4d2SKip Macy return (ENXIO); 81089e0f4d2SKip Macy } 81189e0f4d2SKip Macy 81289e0f4d2SKip Macy sc->xb_flags |= XB_OPEN; 81389e0f4d2SKip Macy sc->xb_info->users++; 81489e0f4d2SKip Macy return (0); 81589e0f4d2SKip Macy } 81689e0f4d2SKip Macy 81789e0f4d2SKip Macy static int 81889e0f4d2SKip Macy blkif_close(struct disk *dp) 81989e0f4d2SKip Macy { 82089e0f4d2SKip Macy struct xb_softc *sc = (struct xb_softc *)dp->d_drv1; 82189e0f4d2SKip Macy 82289e0f4d2SKip Macy if (sc == NULL) 82389e0f4d2SKip Macy return (ENXIO); 82489e0f4d2SKip Macy sc->xb_flags &= ~XB_OPEN; 82589e0f4d2SKip Macy if (--(sc->xb_info->users) == 0) { 82689e0f4d2SKip Macy /* Check whether we have been instructed to close. We will 82789e0f4d2SKip Macy have ignored this request initially, as the device was 82889e0f4d2SKip Macy still mounted. */ 82923dc5621SKip Macy device_t dev = sc->xb_info->xbdev; 83023dc5621SKip Macy XenbusState state = 83123dc5621SKip Macy xenbus_read_driver_state(xenbus_get_otherend_path(dev)); 83289e0f4d2SKip Macy 83389e0f4d2SKip Macy if (state == XenbusStateClosing) 83489e0f4d2SKip Macy blkfront_closing(dev); 83589e0f4d2SKip Macy } 83689e0f4d2SKip Macy return (0); 83789e0f4d2SKip Macy } 83889e0f4d2SKip Macy 83989e0f4d2SKip Macy static int 84089e0f4d2SKip Macy blkif_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td) 84189e0f4d2SKip Macy { 84289e0f4d2SKip Macy struct xb_softc *sc = (struct xb_softc *)dp->d_drv1; 84389e0f4d2SKip Macy 84489e0f4d2SKip Macy if (sc == NULL) 84589e0f4d2SKip Macy return (ENXIO); 84689e0f4d2SKip Macy 84789e0f4d2SKip Macy return (ENOTTY); 84889e0f4d2SKip Macy } 84989e0f4d2SKip Macy 85089e0f4d2SKip Macy 85189e0f4d2SKip Macy /* 85289e0f4d2SKip Macy * blkif_queue_request 85389e0f4d2SKip Macy * 85489e0f4d2SKip Macy * request block io 85589e0f4d2SKip Macy * 85689e0f4d2SKip Macy * id: for guest use only. 85789e0f4d2SKip Macy * operation: BLKIF_OP_{READ,WRITE,PROBE} 85889e0f4d2SKip Macy * buffer: buffer to read/write into. this should be a 85989e0f4d2SKip Macy * virtual address in the guest os. 86089e0f4d2SKip Macy */ 86189e0f4d2SKip Macy static int blkif_queue_request(struct bio *bp) 86289e0f4d2SKip Macy { 86389e0f4d2SKip Macy caddr_t alignbuf; 8645d254c04SKip Macy vm_paddr_t buffer_ma; 86589e0f4d2SKip Macy blkif_request_t *ring_req; 86689e0f4d2SKip Macy unsigned long id; 8675d254c04SKip Macy uint64_t fsect, lsect; 86889e0f4d2SKip Macy struct xb_softc *sc = (struct xb_softc *)bp->bio_disk->d_drv1; 86989e0f4d2SKip Macy struct blkfront_info *info = sc->xb_info; 87089e0f4d2SKip Macy int ref; 87189e0f4d2SKip Macy 87289e0f4d2SKip Macy if (unlikely(sc->xb_info->connected != BLKIF_STATE_CONNECTED)) 87389e0f4d2SKip Macy return 1; 87489e0f4d2SKip Macy 87589e0f4d2SKip Macy if (gnttab_alloc_grant_references( 87689e0f4d2SKip Macy BLKIF_MAX_SEGMENTS_PER_REQUEST, &gref_head) < 0) { 87789e0f4d2SKip Macy gnttab_request_free_callback( 87889e0f4d2SKip Macy &info->callback, 87989e0f4d2SKip Macy blkif_restart_queue_callback, 88089e0f4d2SKip Macy info, 88189e0f4d2SKip Macy BLKIF_MAX_SEGMENTS_PER_REQUEST); 88289e0f4d2SKip Macy return 1; 88389e0f4d2SKip Macy } 88489e0f4d2SKip Macy 88589e0f4d2SKip Macy /* Check if the buffer is properly aligned */ 88689e0f4d2SKip Macy if ((vm_offset_t)bp->bio_data & PAGE_MASK) { 88789e0f4d2SKip Macy int align = (bp->bio_bcount < PAGE_SIZE/2) ? XBD_SECTOR_SIZE : 88889e0f4d2SKip Macy PAGE_SIZE; 88989e0f4d2SKip Macy caddr_t newbuf = malloc(bp->bio_bcount + align, M_DEVBUF, 89089e0f4d2SKip Macy M_NOWAIT); 89189e0f4d2SKip Macy 89289e0f4d2SKip Macy alignbuf = (char *)roundup2((u_long)newbuf, align); 89389e0f4d2SKip Macy 89489e0f4d2SKip Macy /* save a copy of the current buffer */ 89589e0f4d2SKip Macy bp->bio_driver1 = newbuf; 89689e0f4d2SKip Macy bp->bio_driver2 = alignbuf; 89789e0f4d2SKip Macy 89889e0f4d2SKip Macy /* Copy the data for a write */ 89989e0f4d2SKip Macy if (bp->bio_cmd == BIO_WRITE) 90089e0f4d2SKip Macy bcopy(bp->bio_data, alignbuf, bp->bio_bcount); 90189e0f4d2SKip Macy } else 90289e0f4d2SKip Macy alignbuf = bp->bio_data; 90389e0f4d2SKip Macy 90489e0f4d2SKip Macy /* Fill out a communications ring structure. */ 90589e0f4d2SKip Macy ring_req = RING_GET_REQUEST(&info->ring, 90689e0f4d2SKip Macy info->ring.req_prod_pvt); 90789e0f4d2SKip Macy id = GET_ID_FROM_FREELIST(info); 90889e0f4d2SKip Macy info->shadow[id].request = (unsigned long)bp; 90989e0f4d2SKip Macy 91089e0f4d2SKip Macy ring_req->id = id; 91189e0f4d2SKip Macy ring_req->operation = (bp->bio_cmd == BIO_READ) ? BLKIF_OP_READ : 91289e0f4d2SKip Macy BLKIF_OP_WRITE; 91389e0f4d2SKip Macy 91489e0f4d2SKip Macy ring_req->sector_number= (blkif_sector_t)bp->bio_pblkno; 91589e0f4d2SKip Macy ring_req->handle = (blkif_vdev_t)(uintptr_t)sc->xb_disk; 91689e0f4d2SKip Macy 91789e0f4d2SKip Macy ring_req->nr_segments = 0; /* XXX not doing scatter/gather since buffer 91889e0f4d2SKip Macy * chaining is not supported. 91989e0f4d2SKip Macy */ 92089e0f4d2SKip Macy 92189e0f4d2SKip Macy buffer_ma = vtomach(alignbuf); 92289e0f4d2SKip Macy fsect = (buffer_ma & PAGE_MASK) >> XBD_SECTOR_SHFT; 92389e0f4d2SKip Macy lsect = fsect + (bp->bio_bcount >> XBD_SECTOR_SHFT) - 1; 92489e0f4d2SKip Macy /* install a grant reference. */ 92589e0f4d2SKip Macy ref = gnttab_claim_grant_reference(&gref_head); 92689e0f4d2SKip Macy KASSERT( ref != -ENOSPC, ("grant_reference failed") ); 92789e0f4d2SKip Macy 92889e0f4d2SKip Macy gnttab_grant_foreign_access_ref( 92989e0f4d2SKip Macy ref, 93023dc5621SKip Macy xenbus_get_otherend_id(info->xbdev), 93189e0f4d2SKip Macy buffer_ma >> PAGE_SHIFT, 93289e0f4d2SKip Macy ring_req->operation & 1 ); /* ??? */ 93389e0f4d2SKip Macy info->shadow[id].frame[ring_req->nr_segments] = 93489e0f4d2SKip Macy buffer_ma >> PAGE_SHIFT; 93589e0f4d2SKip Macy 93689e0f4d2SKip Macy ring_req->seg[ring_req->nr_segments] = 93789e0f4d2SKip Macy (struct blkif_request_segment) { 93889e0f4d2SKip Macy .gref = ref, 93989e0f4d2SKip Macy .first_sect = fsect, 94089e0f4d2SKip Macy .last_sect = lsect }; 94189e0f4d2SKip Macy 94289e0f4d2SKip Macy ring_req->nr_segments++; 94389e0f4d2SKip Macy KASSERT((buffer_ma & (XBD_SECTOR_SIZE-1)) == 0, 94489e0f4d2SKip Macy ("XEN buffer must be sector aligned")); 94589e0f4d2SKip Macy KASSERT(lsect <= 7, 94689e0f4d2SKip Macy ("XEN disk driver data cannot cross a page boundary")); 94789e0f4d2SKip Macy 94889e0f4d2SKip Macy buffer_ma &= ~PAGE_MASK; 94989e0f4d2SKip Macy 95089e0f4d2SKip Macy info->ring.req_prod_pvt++; 95189e0f4d2SKip Macy 95289e0f4d2SKip Macy /* Keep a private copy so we can reissue requests when recovering. */ 95389e0f4d2SKip Macy info->shadow[id].req = *ring_req; 95489e0f4d2SKip Macy 95589e0f4d2SKip Macy gnttab_free_grant_references(gref_head); 95689e0f4d2SKip Macy 95789e0f4d2SKip Macy return 0; 95889e0f4d2SKip Macy } 95989e0f4d2SKip Macy 96089e0f4d2SKip Macy 96189e0f4d2SKip Macy 96289e0f4d2SKip Macy /* 96389e0f4d2SKip Macy * Dequeue buffers and place them in the shared communication ring. 96489e0f4d2SKip Macy * Return when no more requests can be accepted or all buffers have 96589e0f4d2SKip Macy * been queued. 96689e0f4d2SKip Macy * 96789e0f4d2SKip Macy * Signal XEN once the ring has been filled out. 96889e0f4d2SKip Macy */ 96989e0f4d2SKip Macy static void 97089e0f4d2SKip Macy xb_startio(struct xb_softc *sc) 97189e0f4d2SKip Macy { 97289e0f4d2SKip Macy struct bio *bp; 97389e0f4d2SKip Macy int queued = 0; 97489e0f4d2SKip Macy struct blkfront_info *info = sc->xb_info; 97589e0f4d2SKip Macy DPRINTK(""); 97689e0f4d2SKip Macy 97789e0f4d2SKip Macy mtx_assert(&blkif_io_lock, MA_OWNED); 97889e0f4d2SKip Macy 97989e0f4d2SKip Macy while ((bp = bioq_takefirst(&sc->xb_bioq)) != NULL) { 98089e0f4d2SKip Macy 98189e0f4d2SKip Macy if (RING_FULL(&info->ring)) 98289e0f4d2SKip Macy goto wait; 98389e0f4d2SKip Macy 98489e0f4d2SKip Macy if (blkif_queue_request(bp)) { 98589e0f4d2SKip Macy wait: 98689e0f4d2SKip Macy bioq_insert_head(&sc->xb_bioq, bp); 98789e0f4d2SKip Macy break; 98889e0f4d2SKip Macy } 98989e0f4d2SKip Macy queued++; 99089e0f4d2SKip Macy } 99189e0f4d2SKip Macy 99289e0f4d2SKip Macy if (queued != 0) 99389e0f4d2SKip Macy flush_requests(sc->xb_info); 99489e0f4d2SKip Macy } 99589e0f4d2SKip Macy 99689e0f4d2SKip Macy static void 99789e0f4d2SKip Macy blkif_int(void *xsc) 99889e0f4d2SKip Macy { 99989e0f4d2SKip Macy struct xb_softc *sc = NULL; 100089e0f4d2SKip Macy struct bio *bp; 100189e0f4d2SKip Macy blkif_response_t *bret; 100289e0f4d2SKip Macy RING_IDX i, rp; 100389e0f4d2SKip Macy struct blkfront_info *info = xsc; 100489e0f4d2SKip Macy DPRINTK(""); 100589e0f4d2SKip Macy 100689e0f4d2SKip Macy TRACE_ENTER; 100789e0f4d2SKip Macy 100889e0f4d2SKip Macy mtx_lock(&blkif_io_lock); 100989e0f4d2SKip Macy 101089e0f4d2SKip Macy if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) { 101189e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 101289e0f4d2SKip Macy return; 101389e0f4d2SKip Macy } 101489e0f4d2SKip Macy 101589e0f4d2SKip Macy again: 101689e0f4d2SKip Macy rp = info->ring.sring->rsp_prod; 101789e0f4d2SKip Macy rmb(); /* Ensure we see queued responses up to 'rp'. */ 101889e0f4d2SKip Macy 101989e0f4d2SKip Macy for (i = info->ring.rsp_cons; i != rp; i++) { 102089e0f4d2SKip Macy unsigned long id; 102189e0f4d2SKip Macy 102289e0f4d2SKip Macy bret = RING_GET_RESPONSE(&info->ring, i); 102389e0f4d2SKip Macy id = bret->id; 102489e0f4d2SKip Macy bp = (struct bio *)info->shadow[id].request; 102589e0f4d2SKip Macy 102689e0f4d2SKip Macy blkif_completion(&info->shadow[id]); 102789e0f4d2SKip Macy 102889e0f4d2SKip Macy ADD_ID_TO_FREELIST(info, id); 102989e0f4d2SKip Macy 103089e0f4d2SKip Macy switch (bret->operation) { 103189e0f4d2SKip Macy case BLKIF_OP_READ: 103289e0f4d2SKip Macy /* had an unaligned buffer that needs to be copied */ 103389e0f4d2SKip Macy if (bp->bio_driver1) 103489e0f4d2SKip Macy bcopy(bp->bio_driver2, bp->bio_data, bp->bio_bcount); 103589e0f4d2SKip Macy /* FALLTHROUGH */ 103689e0f4d2SKip Macy case BLKIF_OP_WRITE: 103789e0f4d2SKip Macy 103889e0f4d2SKip Macy /* free the copy buffer */ 103989e0f4d2SKip Macy if (bp->bio_driver1) { 104089e0f4d2SKip Macy free(bp->bio_driver1, M_DEVBUF); 104189e0f4d2SKip Macy bp->bio_driver1 = NULL; 104289e0f4d2SKip Macy } 104389e0f4d2SKip Macy 104489e0f4d2SKip Macy if ( unlikely(bret->status != BLKIF_RSP_OKAY) ) { 10455d254c04SKip Macy printf("Bad return from blkdev data request: %x\n", 104689e0f4d2SKip Macy bret->status); 104789e0f4d2SKip Macy bp->bio_flags |= BIO_ERROR; 104889e0f4d2SKip Macy } 104989e0f4d2SKip Macy 105089e0f4d2SKip Macy sc = (struct xb_softc *)bp->bio_disk->d_drv1; 105189e0f4d2SKip Macy 105289e0f4d2SKip Macy if (bp->bio_flags & BIO_ERROR) 105389e0f4d2SKip Macy bp->bio_error = EIO; 105489e0f4d2SKip Macy else 105589e0f4d2SKip Macy bp->bio_resid = 0; 105689e0f4d2SKip Macy 105789e0f4d2SKip Macy biodone(bp); 105889e0f4d2SKip Macy break; 105989e0f4d2SKip Macy default: 106089e0f4d2SKip Macy panic("received invalid operation"); 106189e0f4d2SKip Macy break; 106289e0f4d2SKip Macy } 106389e0f4d2SKip Macy } 106489e0f4d2SKip Macy 106589e0f4d2SKip Macy info->ring.rsp_cons = i; 106689e0f4d2SKip Macy 106789e0f4d2SKip Macy if (i != info->ring.req_prod_pvt) { 106889e0f4d2SKip Macy int more_to_do; 106989e0f4d2SKip Macy RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do); 107089e0f4d2SKip Macy if (more_to_do) 107189e0f4d2SKip Macy goto again; 107289e0f4d2SKip Macy } else { 107389e0f4d2SKip Macy info->ring.sring->rsp_event = i + 1; 107489e0f4d2SKip Macy } 107589e0f4d2SKip Macy 107689e0f4d2SKip Macy kick_pending_request_queues(info); 107789e0f4d2SKip Macy 107889e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 107989e0f4d2SKip Macy } 108089e0f4d2SKip Macy 108189e0f4d2SKip Macy static void 108289e0f4d2SKip Macy blkif_free(struct blkfront_info *info, int suspend) 108389e0f4d2SKip Macy { 108489e0f4d2SKip Macy 108589e0f4d2SKip Macy /* Prevent new requests being issued until we fix things up. */ 108689e0f4d2SKip Macy mtx_lock(&blkif_io_lock); 108789e0f4d2SKip Macy info->connected = suspend ? 108889e0f4d2SKip Macy BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED; 108989e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 109089e0f4d2SKip Macy 109189e0f4d2SKip Macy /* Free resources associated with old device channel. */ 109289e0f4d2SKip Macy if (info->ring_ref != GRANT_INVALID_REF) { 1093920ba15bSKip Macy gnttab_end_foreign_access(info->ring_ref, 109489e0f4d2SKip Macy info->ring.sring); 109589e0f4d2SKip Macy info->ring_ref = GRANT_INVALID_REF; 109689e0f4d2SKip Macy info->ring.sring = NULL; 109789e0f4d2SKip Macy } 109889e0f4d2SKip Macy if (info->irq) 10993a6d1fcfSKip Macy unbind_from_irqhandler(info->irq); 110089e0f4d2SKip Macy info->irq = 0; 110189e0f4d2SKip Macy 110289e0f4d2SKip Macy } 110389e0f4d2SKip Macy 110489e0f4d2SKip Macy static void 110589e0f4d2SKip Macy blkif_completion(struct blk_shadow *s) 110689e0f4d2SKip Macy { 110789e0f4d2SKip Macy int i; 110889e0f4d2SKip Macy 110989e0f4d2SKip Macy for (i = 0; i < s->req.nr_segments; i++) 1110920ba15bSKip Macy gnttab_end_foreign_access(s->req.seg[i].gref, 0UL); 111189e0f4d2SKip Macy } 111289e0f4d2SKip Macy 111389e0f4d2SKip Macy static void 111489e0f4d2SKip Macy blkif_recover(struct blkfront_info *info) 111589e0f4d2SKip Macy { 111689e0f4d2SKip Macy int i, j; 111789e0f4d2SKip Macy blkif_request_t *req; 111889e0f4d2SKip Macy struct blk_shadow *copy; 111989e0f4d2SKip Macy 112012678024SDoug Rabson if (!info->sc) 112112678024SDoug Rabson return; 112212678024SDoug Rabson 112389e0f4d2SKip Macy /* Stage 1: Make a safe copy of the shadow state. */ 112489e0f4d2SKip Macy copy = (struct blk_shadow *)malloc(sizeof(info->shadow), M_DEVBUF, M_NOWAIT|M_ZERO); 112589e0f4d2SKip Macy memcpy(copy, info->shadow, sizeof(info->shadow)); 112689e0f4d2SKip Macy 112789e0f4d2SKip Macy /* Stage 2: Set up free list. */ 112889e0f4d2SKip Macy memset(&info->shadow, 0, sizeof(info->shadow)); 112989e0f4d2SKip Macy for (i = 0; i < BLK_RING_SIZE; i++) 113089e0f4d2SKip Macy info->shadow[i].req.id = i+1; 113189e0f4d2SKip Macy info->shadow_free = info->ring.req_prod_pvt; 113289e0f4d2SKip Macy info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff; 113389e0f4d2SKip Macy 113489e0f4d2SKip Macy /* Stage 3: Find pending requests and requeue them. */ 113589e0f4d2SKip Macy for (i = 0; i < BLK_RING_SIZE; i++) { 113689e0f4d2SKip Macy /* Not in use? */ 113789e0f4d2SKip Macy if (copy[i].request == 0) 113889e0f4d2SKip Macy continue; 113989e0f4d2SKip Macy 114089e0f4d2SKip Macy /* Grab a request slot and copy shadow state into it. */ 114189e0f4d2SKip Macy req = RING_GET_REQUEST( 114289e0f4d2SKip Macy &info->ring, info->ring.req_prod_pvt); 114389e0f4d2SKip Macy *req = copy[i].req; 114489e0f4d2SKip Macy 114589e0f4d2SKip Macy /* We get a new request id, and must reset the shadow state. */ 114689e0f4d2SKip Macy req->id = GET_ID_FROM_FREELIST(info); 114789e0f4d2SKip Macy memcpy(&info->shadow[req->id], ©[i], sizeof(copy[i])); 114889e0f4d2SKip Macy 114989e0f4d2SKip Macy /* Rewrite any grant references invalidated by suspend/resume. */ 115089e0f4d2SKip Macy for (j = 0; j < req->nr_segments; j++) 115189e0f4d2SKip Macy gnttab_grant_foreign_access_ref( 115289e0f4d2SKip Macy req->seg[j].gref, 115323dc5621SKip Macy xenbus_get_otherend_id(info->xbdev), 115489e0f4d2SKip Macy pfn_to_mfn(info->shadow[req->id].frame[j]), 115589e0f4d2SKip Macy 0 /* assume not readonly */); 115689e0f4d2SKip Macy 115789e0f4d2SKip Macy info->shadow[req->id].req = *req; 115889e0f4d2SKip Macy 115989e0f4d2SKip Macy info->ring.req_prod_pvt++; 116089e0f4d2SKip Macy } 116189e0f4d2SKip Macy 116289e0f4d2SKip Macy free(copy, M_DEVBUF); 116389e0f4d2SKip Macy 116423dc5621SKip Macy xenbus_set_state(info->xbdev, XenbusStateConnected); 116589e0f4d2SKip Macy 116689e0f4d2SKip Macy /* Now safe for us to use the shared ring */ 116789e0f4d2SKip Macy mtx_lock(&blkif_io_lock); 116889e0f4d2SKip Macy info->connected = BLKIF_STATE_CONNECTED; 116989e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 117089e0f4d2SKip Macy 117189e0f4d2SKip Macy /* Send off requeued requests */ 117289e0f4d2SKip Macy mtx_lock(&blkif_io_lock); 117389e0f4d2SKip Macy flush_requests(info); 117489e0f4d2SKip Macy 117589e0f4d2SKip Macy /* Kick any other new requests queued since we resumed */ 117689e0f4d2SKip Macy kick_pending_request_queues(info); 117789e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 117889e0f4d2SKip Macy } 117989e0f4d2SKip Macy 118023dc5621SKip Macy /* ** Driver registration ** */ 118123dc5621SKip Macy static device_method_t blkfront_methods[] = { 118223dc5621SKip Macy /* Device interface */ 118323dc5621SKip Macy DEVMETHOD(device_probe, blkfront_probe), 118423dc5621SKip Macy DEVMETHOD(device_attach, blkfront_attach), 118523dc5621SKip Macy DEVMETHOD(device_detach, blkfront_detach), 118623dc5621SKip Macy DEVMETHOD(device_shutdown, bus_generic_shutdown), 118712678024SDoug Rabson DEVMETHOD(device_suspend, blkfront_suspend), 118823dc5621SKip Macy DEVMETHOD(device_resume, blkfront_resume), 118989e0f4d2SKip Macy 119023dc5621SKip Macy /* Xenbus interface */ 119123dc5621SKip Macy DEVMETHOD(xenbus_backend_changed, blkfront_backend_changed), 119289e0f4d2SKip Macy 119323dc5621SKip Macy { 0, 0 } 119489e0f4d2SKip Macy }; 119589e0f4d2SKip Macy 119623dc5621SKip Macy static driver_t blkfront_driver = { 119723dc5621SKip Macy "xbd", 119823dc5621SKip Macy blkfront_methods, 119923dc5621SKip Macy sizeof(struct blkfront_info), 120089e0f4d2SKip Macy }; 120123dc5621SKip Macy devclass_t blkfront_devclass; 120289e0f4d2SKip Macy 120323dc5621SKip Macy DRIVER_MODULE(xbd, xenbus, blkfront_driver, blkfront_devclass, 0, 0); 120489e0f4d2SKip Macy 120589e0f4d2SKip Macy MTX_SYSINIT(ioreq, &blkif_io_lock, "BIO LOCK", MTX_NOWITNESS); /* XXX how does one enroll a lock? */ 120689e0f4d2SKip Macy 1207