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/xen-os.h> 4412678024SDoug Rabson #include <machine/xen/xenfunc.h> 4512678024SDoug Rabson #include <xen/hypervisor.h> 463a6d1fcfSKip Macy #include <xen/xen_intr.h> 473a6d1fcfSKip Macy #include <xen/evtchn.h> 4812678024SDoug Rabson #include <xen/gnttab.h> 4989e0f4d2SKip Macy #include <xen/interface/grant_table.h> 5023dc5621SKip Macy #include <xen/interface/io/protocols.h> 5123dc5621SKip Macy #include <xen/xenbus/xenbusvar.h> 5289e0f4d2SKip Macy 5389e0f4d2SKip Macy #include <geom/geom_disk.h> 5489e0f4d2SKip Macy 5589e0f4d2SKip Macy #include <dev/xen/blkfront/block.h> 5689e0f4d2SKip Macy 5723dc5621SKip Macy #include "xenbus_if.h" 5823dc5621SKip Macy 5989e0f4d2SKip Macy #define ASSERT(S) KASSERT(S, (#S)) 6089e0f4d2SKip Macy /* prototypes */ 6189e0f4d2SKip Macy struct xb_softc; 6289e0f4d2SKip Macy static void xb_startio(struct xb_softc *sc); 6323dc5621SKip Macy static void connect(device_t, struct blkfront_info *); 6423dc5621SKip Macy static void blkfront_closing(device_t); 6523dc5621SKip Macy static int blkfront_detach(device_t); 6623dc5621SKip Macy static int talk_to_backend(device_t, struct blkfront_info *); 6723dc5621SKip Macy static int setup_blkring(device_t, struct blkfront_info *); 6889e0f4d2SKip Macy static void blkif_int(void *); 6989e0f4d2SKip Macy #if 0 7089e0f4d2SKip Macy static void blkif_restart_queue(void *arg); 7189e0f4d2SKip Macy #endif 7289e0f4d2SKip Macy static void blkif_recover(struct blkfront_info *); 7389e0f4d2SKip Macy static void blkif_completion(struct blk_shadow *); 7489e0f4d2SKip Macy static void blkif_free(struct blkfront_info *, int); 7589e0f4d2SKip Macy 7689e0f4d2SKip Macy #define GRANT_INVALID_REF 0 7789e0f4d2SKip Macy #define BLK_RING_SIZE __RING_SIZE((blkif_sring_t *)0, PAGE_SIZE) 7889e0f4d2SKip Macy 7989e0f4d2SKip Macy LIST_HEAD(xb_softc_list_head, xb_softc) xbsl_head; 8089e0f4d2SKip Macy 8189e0f4d2SKip Macy /* Control whether runtime update of vbds is enabled. */ 8289e0f4d2SKip Macy #define ENABLE_VBD_UPDATE 0 8389e0f4d2SKip Macy 8489e0f4d2SKip Macy #if ENABLE_VBD_UPDATE 8589e0f4d2SKip Macy static void vbd_update(void); 8689e0f4d2SKip Macy #endif 8789e0f4d2SKip Macy 8889e0f4d2SKip Macy 8989e0f4d2SKip Macy #define BLKIF_STATE_DISCONNECTED 0 9089e0f4d2SKip Macy #define BLKIF_STATE_CONNECTED 1 9189e0f4d2SKip Macy #define BLKIF_STATE_SUSPENDED 2 9289e0f4d2SKip Macy 9389e0f4d2SKip Macy #ifdef notyet 9489e0f4d2SKip Macy static char *blkif_state_name[] = { 9589e0f4d2SKip Macy [BLKIF_STATE_DISCONNECTED] = "disconnected", 9689e0f4d2SKip Macy [BLKIF_STATE_CONNECTED] = "connected", 9789e0f4d2SKip Macy [BLKIF_STATE_SUSPENDED] = "closed", 9889e0f4d2SKip Macy }; 9989e0f4d2SKip Macy 10089e0f4d2SKip Macy static char * blkif_status_name[] = { 10189e0f4d2SKip Macy [BLKIF_INTERFACE_STATUS_CLOSED] = "closed", 10289e0f4d2SKip Macy [BLKIF_INTERFACE_STATUS_DISCONNECTED] = "disconnected", 10389e0f4d2SKip Macy [BLKIF_INTERFACE_STATUS_CONNECTED] = "connected", 10489e0f4d2SKip Macy [BLKIF_INTERFACE_STATUS_CHANGED] = "changed", 10589e0f4d2SKip Macy }; 10689e0f4d2SKip Macy #endif 10789e0f4d2SKip Macy #define WPRINTK(fmt, args...) printf("[XEN] " fmt, ##args) 10889e0f4d2SKip Macy #if 0 10912678024SDoug Rabson #define DPRINTK(fmt, args...) printf("[XEN] %s:%d: " fmt ".\n", __func__, __LINE__, ##args) 11089e0f4d2SKip Macy #else 11189e0f4d2SKip Macy #define DPRINTK(fmt, args...) 11289e0f4d2SKip Macy #endif 11389e0f4d2SKip Macy 11489e0f4d2SKip Macy static grant_ref_t gref_head; 11589e0f4d2SKip Macy #define MAXIMUM_OUTSTANDING_BLOCK_REQS \ 11689e0f4d2SKip Macy (BLKIF_MAX_SEGMENTS_PER_REQUEST * BLK_RING_SIZE) 11789e0f4d2SKip Macy 11889e0f4d2SKip Macy static void kick_pending_request_queues(struct blkfront_info *); 11989e0f4d2SKip Macy static int blkif_open(struct disk *dp); 12089e0f4d2SKip Macy static int blkif_close(struct disk *dp); 12189e0f4d2SKip Macy static int blkif_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td); 12289e0f4d2SKip Macy static int blkif_queue_request(struct bio *bp); 12389e0f4d2SKip Macy static void xb_strategy(struct bio *bp); 12489e0f4d2SKip Macy 12589e0f4d2SKip Macy 12689e0f4d2SKip Macy 12789e0f4d2SKip Macy /* XXX move to xb_vbd.c when VBD update support is added */ 12889e0f4d2SKip Macy #define MAX_VBDS 64 12989e0f4d2SKip Macy 13089e0f4d2SKip Macy #define XBD_SECTOR_SIZE 512 /* XXX: assume for now */ 13189e0f4d2SKip Macy #define XBD_SECTOR_SHFT 9 13289e0f4d2SKip Macy 13389e0f4d2SKip Macy static struct mtx blkif_io_lock; 13489e0f4d2SKip Macy 1355d254c04SKip Macy static vm_paddr_t 1365d254c04SKip Macy pfn_to_mfn(vm_paddr_t pfn) 13789e0f4d2SKip Macy { 13889e0f4d2SKip Macy return (phystomach(pfn << PAGE_SHIFT) >> PAGE_SHIFT); 13989e0f4d2SKip Macy } 14089e0f4d2SKip Macy 14123dc5621SKip Macy /* 14223dc5621SKip Macy * Translate Linux major/minor to an appropriate name and unit 14323dc5621SKip Macy * number. For HVM guests, this allows us to use the same drive names 14423dc5621SKip Macy * with blkfront as the emulated drives, easing transition slightly. 14523dc5621SKip Macy */ 14623dc5621SKip Macy static void 14723dc5621SKip Macy blkfront_vdevice_to_unit(int vdevice, int *unit, const char **name) 14823dc5621SKip Macy { 14923dc5621SKip Macy static struct vdev_info { 15023dc5621SKip Macy int major; 15123dc5621SKip Macy int shift; 15223dc5621SKip Macy int base; 15323dc5621SKip Macy const char *name; 15423dc5621SKip Macy } info[] = { 15523dc5621SKip Macy {3, 6, 0, "ad"}, /* ide0 */ 15623dc5621SKip Macy {22, 6, 2, "ad"}, /* ide1 */ 15723dc5621SKip Macy {33, 6, 4, "ad"}, /* ide2 */ 15823dc5621SKip Macy {34, 6, 6, "ad"}, /* ide3 */ 15923dc5621SKip Macy {56, 6, 8, "ad"}, /* ide4 */ 16023dc5621SKip Macy {57, 6, 10, "ad"}, /* ide5 */ 16123dc5621SKip Macy {88, 6, 12, "ad"}, /* ide6 */ 16223dc5621SKip Macy {89, 6, 14, "ad"}, /* ide7 */ 16323dc5621SKip Macy {90, 6, 16, "ad"}, /* ide8 */ 16423dc5621SKip Macy {91, 6, 18, "ad"}, /* ide9 */ 16523dc5621SKip Macy 16623dc5621SKip Macy {8, 4, 0, "da"}, /* scsi disk0 */ 16723dc5621SKip Macy {65, 4, 16, "da"}, /* scsi disk1 */ 16823dc5621SKip Macy {66, 4, 32, "da"}, /* scsi disk2 */ 16923dc5621SKip Macy {67, 4, 48, "da"}, /* scsi disk3 */ 17023dc5621SKip Macy {68, 4, 64, "da"}, /* scsi disk4 */ 17123dc5621SKip Macy {69, 4, 80, "da"}, /* scsi disk5 */ 17223dc5621SKip Macy {70, 4, 96, "da"}, /* scsi disk6 */ 17323dc5621SKip Macy {71, 4, 112, "da"}, /* scsi disk7 */ 17423dc5621SKip Macy {128, 4, 128, "da"}, /* scsi disk8 */ 17523dc5621SKip Macy {129, 4, 144, "da"}, /* scsi disk9 */ 17623dc5621SKip Macy {130, 4, 160, "da"}, /* scsi disk10 */ 17723dc5621SKip Macy {131, 4, 176, "da"}, /* scsi disk11 */ 17823dc5621SKip Macy {132, 4, 192, "da"}, /* scsi disk12 */ 17923dc5621SKip Macy {133, 4, 208, "da"}, /* scsi disk13 */ 18023dc5621SKip Macy {134, 4, 224, "da"}, /* scsi disk14 */ 18123dc5621SKip Macy {135, 4, 240, "da"}, /* scsi disk15 */ 18223dc5621SKip Macy 18323dc5621SKip Macy {202, 4, 0, "xbd"}, /* xbd */ 18423dc5621SKip Macy 18523dc5621SKip Macy {0, 0, 0, NULL}, 18623dc5621SKip Macy }; 18723dc5621SKip Macy int major = vdevice >> 8; 18823dc5621SKip Macy int minor = vdevice & 0xff; 18923dc5621SKip Macy int i; 19023dc5621SKip Macy 19123dc5621SKip Macy if (vdevice & (1 << 28)) { 19223dc5621SKip Macy *unit = (vdevice & ((1 << 28) - 1)) >> 8; 19323dc5621SKip Macy *name = "xbd"; 19423dc5621SKip Macy } 19523dc5621SKip Macy 19623dc5621SKip Macy for (i = 0; info[i].major; i++) { 19723dc5621SKip Macy if (info[i].major == major) { 19823dc5621SKip Macy *unit = info[i].base + (minor >> info[i].shift); 19923dc5621SKip Macy *name = info[i].name; 20023dc5621SKip Macy return; 20123dc5621SKip Macy } 20223dc5621SKip Macy } 20323dc5621SKip Macy 20423dc5621SKip Macy *unit = minor >> 4; 20523dc5621SKip Macy *name = "xbd"; 20623dc5621SKip Macy } 20723dc5621SKip Macy 20889e0f4d2SKip Macy int 20923dc5621SKip Macy xlvbd_add(device_t dev, blkif_sector_t capacity, 21023dc5621SKip Macy int vdevice, uint16_t vdisk_info, uint16_t sector_size, 21189e0f4d2SKip Macy struct blkfront_info *info) 21289e0f4d2SKip Macy { 21389e0f4d2SKip Macy struct xb_softc *sc; 21423dc5621SKip Macy int unit, error = 0; 21523dc5621SKip Macy const char *name; 21623dc5621SKip Macy 21723dc5621SKip Macy blkfront_vdevice_to_unit(vdevice, &unit, &name); 21889e0f4d2SKip Macy 21989e0f4d2SKip Macy sc = (struct xb_softc *)malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); 22023dc5621SKip Macy sc->xb_unit = unit; 22189e0f4d2SKip Macy sc->xb_info = info; 22289e0f4d2SKip Macy info->sc = sc; 22389e0f4d2SKip Macy 22423dc5621SKip Macy if (strcmp(name, "xbd")) 22523dc5621SKip Macy device_printf(dev, "attaching as %s%d\n", name, unit); 22623dc5621SKip Macy 22789e0f4d2SKip Macy memset(&sc->xb_disk, 0, sizeof(sc->xb_disk)); 22889e0f4d2SKip Macy sc->xb_disk = disk_alloc(); 2293a6d1fcfSKip Macy sc->xb_disk->d_unit = sc->xb_unit; 23089e0f4d2SKip Macy sc->xb_disk->d_open = blkif_open; 23189e0f4d2SKip Macy sc->xb_disk->d_close = blkif_close; 23289e0f4d2SKip Macy sc->xb_disk->d_ioctl = blkif_ioctl; 23389e0f4d2SKip Macy sc->xb_disk->d_strategy = xb_strategy; 2343a6d1fcfSKip Macy sc->xb_disk->d_name = name; 23589e0f4d2SKip Macy sc->xb_disk->d_drv1 = sc; 23689e0f4d2SKip Macy sc->xb_disk->d_sectorsize = sector_size; 23789e0f4d2SKip Macy 23889e0f4d2SKip Macy /* XXX */ 23989e0f4d2SKip Macy sc->xb_disk->d_mediasize = capacity << XBD_SECTOR_SHFT; 24089e0f4d2SKip Macy #if 0 24189e0f4d2SKip Macy sc->xb_disk->d_maxsize = DFLTPHYS; 24289e0f4d2SKip Macy #else /* XXX: xen can't handle large single i/o requests */ 24389e0f4d2SKip Macy sc->xb_disk->d_maxsize = 4096; 24489e0f4d2SKip Macy #endif 24589e0f4d2SKip Macy #ifdef notyet 24689e0f4d2SKip Macy XENPRINTF("attaching device 0x%x unit %d capacity %llu\n", 24789e0f4d2SKip Macy xb_diskinfo[sc->xb_unit].device, sc->xb_unit, 24889e0f4d2SKip Macy sc->xb_disk->d_mediasize); 24989e0f4d2SKip Macy #endif 25089e0f4d2SKip Macy sc->xb_disk->d_flags = 0; 25189e0f4d2SKip Macy disk_create(sc->xb_disk, DISK_VERSION_00); 25289e0f4d2SKip Macy bioq_init(&sc->xb_bioq); 25389e0f4d2SKip Macy 25489e0f4d2SKip Macy return error; 25589e0f4d2SKip Macy } 25689e0f4d2SKip Macy 25789e0f4d2SKip Macy void 25889e0f4d2SKip Macy xlvbd_del(struct blkfront_info *info) 25989e0f4d2SKip Macy { 26089e0f4d2SKip Macy struct xb_softc *sc; 26189e0f4d2SKip Macy 26289e0f4d2SKip Macy sc = info->sc; 26389e0f4d2SKip Macy disk_destroy(sc->xb_disk); 26489e0f4d2SKip Macy } 26589e0f4d2SKip Macy /************************ end VBD support *****************/ 26689e0f4d2SKip Macy 26789e0f4d2SKip Macy /* 26889e0f4d2SKip Macy * Read/write routine for a buffer. Finds the proper unit, place it on 26989e0f4d2SKip Macy * the sortq and kick the controller. 27089e0f4d2SKip Macy */ 27189e0f4d2SKip Macy static void 27289e0f4d2SKip Macy xb_strategy(struct bio *bp) 27389e0f4d2SKip Macy { 27489e0f4d2SKip Macy struct xb_softc *sc = (struct xb_softc *)bp->bio_disk->d_drv1; 27589e0f4d2SKip Macy 27689e0f4d2SKip Macy /* bogus disk? */ 27789e0f4d2SKip Macy if (sc == NULL) { 27889e0f4d2SKip Macy bp->bio_error = EINVAL; 27989e0f4d2SKip Macy bp->bio_flags |= BIO_ERROR; 28089e0f4d2SKip Macy goto bad; 28189e0f4d2SKip Macy } 28289e0f4d2SKip Macy 28389e0f4d2SKip Macy DPRINTK(""); 28489e0f4d2SKip Macy 28589e0f4d2SKip Macy /* 28689e0f4d2SKip Macy * Place it in the queue of disk activities for this disk 28789e0f4d2SKip Macy */ 28889e0f4d2SKip Macy mtx_lock(&blkif_io_lock); 28989e0f4d2SKip Macy bioq_disksort(&sc->xb_bioq, bp); 29089e0f4d2SKip Macy 29189e0f4d2SKip Macy xb_startio(sc); 29289e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 29389e0f4d2SKip Macy return; 29489e0f4d2SKip Macy 29589e0f4d2SKip Macy bad: 29689e0f4d2SKip Macy /* 29789e0f4d2SKip Macy * Correctly set the bio to indicate a failed tranfer. 29889e0f4d2SKip Macy */ 29989e0f4d2SKip Macy bp->bio_resid = bp->bio_bcount; 30089e0f4d2SKip Macy biodone(bp); 30189e0f4d2SKip Macy return; 30289e0f4d2SKip Macy } 30389e0f4d2SKip Macy 30423dc5621SKip Macy static int 30523dc5621SKip Macy blkfront_probe(device_t dev) 30689e0f4d2SKip Macy { 30723dc5621SKip Macy 30823dc5621SKip Macy if (!strcmp(xenbus_get_type(dev), "vbd")) { 30923dc5621SKip Macy device_set_desc(dev, "Virtual Block Device"); 31023dc5621SKip Macy device_quiet(dev); 31123dc5621SKip Macy return (0); 31223dc5621SKip Macy } 31323dc5621SKip Macy 31423dc5621SKip Macy return (ENXIO); 31523dc5621SKip Macy } 31623dc5621SKip Macy 31723dc5621SKip Macy /* 31823dc5621SKip Macy * Setup supplies the backend dir, virtual device. We place an event 31923dc5621SKip Macy * channel and shared frame entries. We watch backend to wait if it's 32023dc5621SKip Macy * ok. 32123dc5621SKip Macy */ 32223dc5621SKip Macy static int 32323dc5621SKip Macy blkfront_attach(device_t dev) 32423dc5621SKip Macy { 32512678024SDoug Rabson int error, vdevice, i, unit; 32689e0f4d2SKip Macy struct blkfront_info *info; 32723dc5621SKip Macy const char *name; 32889e0f4d2SKip Macy 32989e0f4d2SKip Macy /* FIXME: Use dynamic device id if this is not set. */ 33012678024SDoug Rabson error = xenbus_scanf(XBT_NIL, xenbus_get_node(dev), 3313a6d1fcfSKip Macy "virtual-device", NULL, "%i", &vdevice); 33212678024SDoug Rabson if (error) { 33312678024SDoug Rabson xenbus_dev_fatal(dev, error, "reading virtual-device"); 3345d254c04SKip Macy printf("couldn't find virtual device"); 33512678024SDoug Rabson return (error); 33689e0f4d2SKip Macy } 33789e0f4d2SKip Macy 33823dc5621SKip Macy blkfront_vdevice_to_unit(vdevice, &unit, &name); 33923dc5621SKip Macy if (!strcmp(name, "xbd")) 34023dc5621SKip Macy device_set_unit(dev, unit); 34123dc5621SKip Macy 34223dc5621SKip Macy info = device_get_softc(dev); 34389e0f4d2SKip Macy 34489e0f4d2SKip Macy /* 34589e0f4d2SKip Macy * XXX debug only 34689e0f4d2SKip Macy */ 34789e0f4d2SKip Macy for (i = 0; i < sizeof(*info); i++) 34889e0f4d2SKip Macy if (((uint8_t *)info)[i] != 0) 34989e0f4d2SKip Macy panic("non-null memory"); 35089e0f4d2SKip Macy 35189e0f4d2SKip Macy info->shadow_free = 0; 35289e0f4d2SKip Macy info->xbdev = dev; 35389e0f4d2SKip Macy info->vdevice = vdevice; 35489e0f4d2SKip Macy info->connected = BLKIF_STATE_DISCONNECTED; 35589e0f4d2SKip Macy 35689e0f4d2SKip Macy /* work queue needed ? */ 35789e0f4d2SKip Macy for (i = 0; i < BLK_RING_SIZE; i++) 35889e0f4d2SKip Macy info->shadow[i].req.id = i+1; 35989e0f4d2SKip Macy info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff; 36089e0f4d2SKip Macy 36189e0f4d2SKip Macy /* Front end dir is a number, which is used as the id. */ 36223dc5621SKip Macy info->handle = strtoul(strrchr(xenbus_get_node(dev),'/')+1, NULL, 0); 36389e0f4d2SKip Macy 36412678024SDoug Rabson error = talk_to_backend(dev, info); 36512678024SDoug Rabson if (error) 36612678024SDoug Rabson return (error); 36712678024SDoug Rabson 36812678024SDoug Rabson return (0); 36912678024SDoug Rabson } 37012678024SDoug Rabson 37112678024SDoug Rabson static int 37212678024SDoug Rabson blkfront_suspend(device_t dev) 37312678024SDoug Rabson { 37412678024SDoug Rabson struct blkfront_info *info = device_get_softc(dev); 37512678024SDoug Rabson 37612678024SDoug Rabson /* Prevent new requests being issued until we fix things up. */ 37712678024SDoug Rabson mtx_lock(&blkif_io_lock); 37812678024SDoug Rabson info->connected = BLKIF_STATE_SUSPENDED; 37912678024SDoug Rabson mtx_unlock(&blkif_io_lock); 38089e0f4d2SKip Macy 38123dc5621SKip Macy return (0); 38289e0f4d2SKip Macy } 38389e0f4d2SKip Macy 38423dc5621SKip Macy static int 38523dc5621SKip Macy blkfront_resume(device_t dev) 38689e0f4d2SKip Macy { 38723dc5621SKip Macy struct blkfront_info *info = device_get_softc(dev); 38889e0f4d2SKip Macy int err; 38989e0f4d2SKip Macy 39012678024SDoug Rabson DPRINTK("blkfront_resume: %s\n", xenbus_get_node(dev)); 39189e0f4d2SKip Macy 39289e0f4d2SKip Macy blkif_free(info, 1); 39389e0f4d2SKip Macy err = talk_to_backend(dev, info); 3943a6d1fcfSKip Macy if (info->connected == BLKIF_STATE_SUSPENDED && !err) 39589e0f4d2SKip Macy blkif_recover(info); 39689e0f4d2SKip Macy 39712678024SDoug Rabson return (err); 39889e0f4d2SKip Macy } 39989e0f4d2SKip Macy 40089e0f4d2SKip Macy /* Common code used when first setting up, and when resuming. */ 40123dc5621SKip Macy static int 40223dc5621SKip Macy talk_to_backend(device_t dev, struct blkfront_info *info) 40389e0f4d2SKip Macy { 40489e0f4d2SKip Macy const char *message = NULL; 40589e0f4d2SKip Macy struct xenbus_transaction xbt; 40689e0f4d2SKip Macy int err; 40789e0f4d2SKip Macy 40889e0f4d2SKip Macy /* Create shared ring, alloc event channel. */ 40989e0f4d2SKip Macy err = setup_blkring(dev, info); 41089e0f4d2SKip Macy if (err) 41189e0f4d2SKip Macy goto out; 41289e0f4d2SKip Macy 41389e0f4d2SKip Macy again: 41489e0f4d2SKip Macy err = xenbus_transaction_start(&xbt); 41589e0f4d2SKip Macy if (err) { 41689e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "starting transaction"); 41789e0f4d2SKip Macy goto destroy_blkring; 41889e0f4d2SKip Macy } 41989e0f4d2SKip Macy 42023dc5621SKip Macy err = xenbus_printf(xbt, xenbus_get_node(dev), 42189e0f4d2SKip Macy "ring-ref","%u", info->ring_ref); 42289e0f4d2SKip Macy if (err) { 42389e0f4d2SKip Macy message = "writing ring-ref"; 42489e0f4d2SKip Macy goto abort_transaction; 42589e0f4d2SKip Macy } 42623dc5621SKip Macy err = xenbus_printf(xbt, xenbus_get_node(dev), 42789e0f4d2SKip Macy "event-channel", "%u", irq_to_evtchn_port(info->irq)); 42889e0f4d2SKip Macy if (err) { 42989e0f4d2SKip Macy message = "writing event-channel"; 43089e0f4d2SKip Macy goto abort_transaction; 43189e0f4d2SKip Macy } 43223dc5621SKip Macy err = xenbus_printf(xbt, xenbus_get_node(dev), 43323dc5621SKip Macy "protocol", "%s", XEN_IO_PROTO_ABI_NATIVE); 43423dc5621SKip Macy if (err) { 43523dc5621SKip Macy message = "writing protocol"; 43623dc5621SKip Macy goto abort_transaction; 43723dc5621SKip Macy } 43812678024SDoug Rabson 43989e0f4d2SKip Macy err = xenbus_transaction_end(xbt, 0); 44089e0f4d2SKip Macy if (err) { 4413a6d1fcfSKip Macy if (err == EAGAIN) 44289e0f4d2SKip Macy goto again; 44389e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "completing transaction"); 44489e0f4d2SKip Macy goto destroy_blkring; 44589e0f4d2SKip Macy } 44623dc5621SKip Macy xenbus_set_state(dev, XenbusStateInitialised); 44789e0f4d2SKip Macy 44889e0f4d2SKip Macy return 0; 44989e0f4d2SKip Macy 45089e0f4d2SKip Macy abort_transaction: 45189e0f4d2SKip Macy xenbus_transaction_end(xbt, 1); 45289e0f4d2SKip Macy if (message) 45389e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "%s", message); 45489e0f4d2SKip Macy destroy_blkring: 45589e0f4d2SKip Macy blkif_free(info, 0); 45689e0f4d2SKip Macy out: 45789e0f4d2SKip Macy return err; 45889e0f4d2SKip Macy } 45989e0f4d2SKip Macy 46089e0f4d2SKip Macy static int 46123dc5621SKip Macy setup_blkring(device_t dev, struct blkfront_info *info) 46289e0f4d2SKip Macy { 46389e0f4d2SKip Macy blkif_sring_t *sring; 4643a6d1fcfSKip Macy int error; 46589e0f4d2SKip Macy 46689e0f4d2SKip Macy info->ring_ref = GRANT_INVALID_REF; 46789e0f4d2SKip Macy 46889e0f4d2SKip Macy sring = (blkif_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT|M_ZERO); 46989e0f4d2SKip Macy if (sring == NULL) { 47089e0f4d2SKip Macy xenbus_dev_fatal(dev, ENOMEM, "allocating shared ring"); 47189e0f4d2SKip Macy return ENOMEM; 47289e0f4d2SKip Macy } 47389e0f4d2SKip Macy SHARED_RING_INIT(sring); 47489e0f4d2SKip Macy FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE); 47589e0f4d2SKip Macy 47612678024SDoug Rabson error = xenbus_grant_ring(dev, 47712678024SDoug Rabson (vtomach(info->ring.sring) >> PAGE_SHIFT), &info->ring_ref); 4783a6d1fcfSKip Macy if (error) { 47989e0f4d2SKip Macy free(sring, M_DEVBUF); 48089e0f4d2SKip Macy info->ring.sring = NULL; 48189e0f4d2SKip Macy goto fail; 48289e0f4d2SKip Macy } 48389e0f4d2SKip Macy 4843a6d1fcfSKip Macy error = bind_listening_port_to_irqhandler(xenbus_get_otherend_id(dev), 48589e0f4d2SKip Macy "xbd", (driver_intr_t *)blkif_int, info, 4863a6d1fcfSKip Macy INTR_TYPE_BIO | INTR_MPSAFE, &info->irq); 4873a6d1fcfSKip Macy if (error) { 4883a6d1fcfSKip Macy xenbus_dev_fatal(dev, error, 48989e0f4d2SKip Macy "bind_evtchn_to_irqhandler failed"); 49089e0f4d2SKip Macy goto fail; 49189e0f4d2SKip Macy } 49289e0f4d2SKip Macy 4933a6d1fcfSKip Macy return (0); 49489e0f4d2SKip Macy fail: 49589e0f4d2SKip Macy blkif_free(info, 0); 4963a6d1fcfSKip Macy return (error); 49789e0f4d2SKip Macy } 49889e0f4d2SKip Macy 49989e0f4d2SKip Macy 50089e0f4d2SKip Macy /** 50189e0f4d2SKip Macy * Callback received when the backend's state changes. 50289e0f4d2SKip Macy */ 50323dc5621SKip Macy static void 50423dc5621SKip Macy blkfront_backend_changed(device_t dev, XenbusState backend_state) 50589e0f4d2SKip Macy { 50623dc5621SKip Macy struct blkfront_info *info = device_get_softc(dev); 50789e0f4d2SKip Macy 50812678024SDoug Rabson DPRINTK("backend_state=%d\n", backend_state); 50989e0f4d2SKip Macy 51089e0f4d2SKip Macy switch (backend_state) { 51189e0f4d2SKip Macy case XenbusStateUnknown: 51289e0f4d2SKip Macy case XenbusStateInitialising: 51389e0f4d2SKip Macy case XenbusStateInitWait: 51489e0f4d2SKip Macy case XenbusStateInitialised: 51589e0f4d2SKip Macy case XenbusStateClosed: 516920ba15bSKip Macy case XenbusStateReconfigured: 517920ba15bSKip Macy case XenbusStateReconfiguring: 51889e0f4d2SKip Macy break; 51989e0f4d2SKip Macy 52089e0f4d2SKip Macy case XenbusStateConnected: 52123dc5621SKip Macy connect(dev, info); 52289e0f4d2SKip Macy break; 52389e0f4d2SKip Macy 52489e0f4d2SKip Macy case XenbusStateClosing: 52589e0f4d2SKip Macy if (info->users > 0) 52689e0f4d2SKip Macy xenbus_dev_error(dev, -EBUSY, 52789e0f4d2SKip Macy "Device in use; refusing to close"); 52889e0f4d2SKip Macy else 52989e0f4d2SKip Macy blkfront_closing(dev); 53089e0f4d2SKip Macy #ifdef notyet 53189e0f4d2SKip Macy bd = bdget(info->dev); 53289e0f4d2SKip Macy if (bd == NULL) 53389e0f4d2SKip Macy xenbus_dev_fatal(dev, -ENODEV, "bdget failed"); 53489e0f4d2SKip Macy 53589e0f4d2SKip Macy down(&bd->bd_sem); 53689e0f4d2SKip Macy if (info->users > 0) 53789e0f4d2SKip Macy xenbus_dev_error(dev, -EBUSY, 53889e0f4d2SKip Macy "Device in use; refusing to close"); 53989e0f4d2SKip Macy else 54089e0f4d2SKip Macy blkfront_closing(dev); 54189e0f4d2SKip Macy up(&bd->bd_sem); 54289e0f4d2SKip Macy bdput(bd); 54389e0f4d2SKip Macy #endif 54489e0f4d2SKip Macy } 54589e0f4d2SKip Macy } 54689e0f4d2SKip Macy 54789e0f4d2SKip Macy /* 54889e0f4d2SKip Macy ** Invoked when the backend is finally 'ready' (and has told produced 54989e0f4d2SKip Macy ** the details about the physical device - #sectors, size, etc). 55089e0f4d2SKip Macy */ 55189e0f4d2SKip Macy static void 55223dc5621SKip Macy connect(device_t dev, struct blkfront_info *info) 55389e0f4d2SKip Macy { 55489e0f4d2SKip Macy unsigned long sectors, sector_size; 55589e0f4d2SKip Macy unsigned int binfo; 55689e0f4d2SKip Macy int err; 55789e0f4d2SKip Macy 55889e0f4d2SKip Macy if( (info->connected == BLKIF_STATE_CONNECTED) || 55989e0f4d2SKip Macy (info->connected == BLKIF_STATE_SUSPENDED) ) 56089e0f4d2SKip Macy return; 56189e0f4d2SKip Macy 56223dc5621SKip Macy DPRINTK("blkfront.c:connect:%s.\n", xenbus_get_otherend_path(dev)); 56389e0f4d2SKip Macy 56423dc5621SKip Macy err = xenbus_gather(XBT_NIL, xenbus_get_otherend_path(dev), 56589e0f4d2SKip Macy "sectors", "%lu", §ors, 56689e0f4d2SKip Macy "info", "%u", &binfo, 56789e0f4d2SKip Macy "sector-size", "%lu", §or_size, 56889e0f4d2SKip Macy NULL); 56989e0f4d2SKip Macy if (err) { 57023dc5621SKip Macy xenbus_dev_fatal(dev, err, 57189e0f4d2SKip Macy "reading backend fields at %s", 57223dc5621SKip Macy xenbus_get_otherend_path(dev)); 57389e0f4d2SKip Macy return; 57489e0f4d2SKip Macy } 57523dc5621SKip Macy err = xenbus_gather(XBT_NIL, xenbus_get_otherend_path(dev), 57689e0f4d2SKip Macy "feature-barrier", "%lu", &info->feature_barrier, 57789e0f4d2SKip Macy NULL); 57889e0f4d2SKip Macy if (err) 57989e0f4d2SKip Macy info->feature_barrier = 0; 58089e0f4d2SKip Macy 58123dc5621SKip Macy device_printf(dev, "%juMB <%s> at %s", 58223dc5621SKip Macy (uintmax_t) sectors / (1048576 / sector_size), 58323dc5621SKip Macy device_get_desc(dev), 58423dc5621SKip Macy xenbus_get_node(dev)); 58523dc5621SKip Macy bus_print_child_footer(device_get_parent(dev), dev); 58689e0f4d2SKip Macy 58723dc5621SKip Macy xlvbd_add(dev, sectors, info->vdevice, binfo, sector_size, info); 58823dc5621SKip Macy 58923dc5621SKip Macy (void)xenbus_set_state(dev, XenbusStateConnected); 59089e0f4d2SKip Macy 59189e0f4d2SKip Macy /* Kick pending requests. */ 59289e0f4d2SKip Macy mtx_lock(&blkif_io_lock); 59389e0f4d2SKip Macy info->connected = BLKIF_STATE_CONNECTED; 59489e0f4d2SKip Macy kick_pending_request_queues(info); 59589e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 5964615bad1SKip Macy info->is_ready = 1; 59789e0f4d2SKip Macy 59889e0f4d2SKip Macy #if 0 59989e0f4d2SKip Macy add_disk(info->gd); 60089e0f4d2SKip Macy #endif 60189e0f4d2SKip Macy } 60289e0f4d2SKip Macy 60389e0f4d2SKip Macy /** 60489e0f4d2SKip Macy * Handle the change of state of the backend to Closing. We must delete our 60589e0f4d2SKip Macy * device-layer structures now, to ensure that writes are flushed through to 60689e0f4d2SKip Macy * the backend. Once is this done, we can switch to Closed in 60789e0f4d2SKip Macy * acknowledgement. 60889e0f4d2SKip Macy */ 60923dc5621SKip Macy static void 61023dc5621SKip Macy blkfront_closing(device_t dev) 61189e0f4d2SKip Macy { 61223dc5621SKip Macy struct blkfront_info *info = device_get_softc(dev); 61389e0f4d2SKip Macy 61423dc5621SKip Macy DPRINTK("blkfront_closing: %s removed\n", xenbus_get_node(dev)); 61589e0f4d2SKip Macy 61689e0f4d2SKip Macy if (info->mi) { 61789e0f4d2SKip Macy DPRINTK("Calling xlvbd_del\n"); 61889e0f4d2SKip Macy xlvbd_del(info); 61989e0f4d2SKip Macy info->mi = NULL; 62089e0f4d2SKip Macy } 62189e0f4d2SKip Macy 62223dc5621SKip Macy xenbus_set_state(dev, XenbusStateClosed); 62389e0f4d2SKip Macy } 62489e0f4d2SKip Macy 62589e0f4d2SKip Macy 62623dc5621SKip Macy static int 62723dc5621SKip Macy blkfront_detach(device_t dev) 62889e0f4d2SKip Macy { 62923dc5621SKip Macy struct blkfront_info *info = device_get_softc(dev); 63089e0f4d2SKip Macy 63123dc5621SKip Macy DPRINTK("blkfront_remove: %s removed\n", xenbus_get_node(dev)); 63289e0f4d2SKip Macy 63389e0f4d2SKip Macy blkif_free(info, 0); 63489e0f4d2SKip Macy 63589e0f4d2SKip Macy return 0; 63689e0f4d2SKip Macy } 63789e0f4d2SKip Macy 63889e0f4d2SKip Macy 63989e0f4d2SKip Macy static inline int 64089e0f4d2SKip Macy GET_ID_FROM_FREELIST(struct blkfront_info *info) 64189e0f4d2SKip Macy { 64289e0f4d2SKip Macy unsigned long nfree = info->shadow_free; 64389e0f4d2SKip Macy 64489e0f4d2SKip Macy KASSERT(nfree <= BLK_RING_SIZE, ("free %lu > RING_SIZE", nfree)); 64589e0f4d2SKip Macy info->shadow_free = info->shadow[nfree].req.id; 64689e0f4d2SKip Macy info->shadow[nfree].req.id = 0x0fffffee; /* debug */ 64789e0f4d2SKip Macy return nfree; 64889e0f4d2SKip Macy } 64989e0f4d2SKip Macy 65089e0f4d2SKip Macy static inline void 65189e0f4d2SKip Macy ADD_ID_TO_FREELIST(struct blkfront_info *info, unsigned long id) 65289e0f4d2SKip Macy { 65389e0f4d2SKip Macy info->shadow[id].req.id = info->shadow_free; 65489e0f4d2SKip Macy info->shadow[id].request = 0; 65589e0f4d2SKip Macy info->shadow_free = id; 65689e0f4d2SKip Macy } 65789e0f4d2SKip Macy 65889e0f4d2SKip Macy static inline void 65989e0f4d2SKip Macy flush_requests(struct blkfront_info *info) 66089e0f4d2SKip Macy { 66189e0f4d2SKip Macy int notify; 66289e0f4d2SKip Macy 66389e0f4d2SKip Macy RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->ring, notify); 66489e0f4d2SKip Macy 66589e0f4d2SKip Macy if (notify) 66689e0f4d2SKip Macy notify_remote_via_irq(info->irq); 66789e0f4d2SKip Macy } 66889e0f4d2SKip Macy 66989e0f4d2SKip Macy static void 67089e0f4d2SKip Macy kick_pending_request_queues(struct blkfront_info *info) 67189e0f4d2SKip Macy { 67289e0f4d2SKip Macy /* XXX check if we can't simplify */ 67389e0f4d2SKip Macy #if 0 67489e0f4d2SKip Macy if (!RING_FULL(&info->ring)) { 67589e0f4d2SKip Macy /* Re-enable calldowns. */ 67689e0f4d2SKip Macy blk_start_queue(info->rq); 67789e0f4d2SKip Macy /* Kick things off immediately. */ 67889e0f4d2SKip Macy do_blkif_request(info->rq); 67989e0f4d2SKip Macy } 68089e0f4d2SKip Macy #endif 68189e0f4d2SKip Macy if (!RING_FULL(&info->ring)) { 68289e0f4d2SKip Macy #if 0 68389e0f4d2SKip Macy sc = LIST_FIRST(&xbsl_head); 68489e0f4d2SKip Macy LIST_REMOVE(sc, entry); 68589e0f4d2SKip Macy /* Re-enable calldowns. */ 68689e0f4d2SKip Macy blk_start_queue(di->rq); 68789e0f4d2SKip Macy #endif 68889e0f4d2SKip Macy /* Kick things off immediately. */ 68989e0f4d2SKip Macy xb_startio(info->sc); 69089e0f4d2SKip Macy } 69189e0f4d2SKip Macy } 69289e0f4d2SKip Macy 69389e0f4d2SKip Macy #if 0 69489e0f4d2SKip Macy /* XXX */ 69589e0f4d2SKip Macy static void blkif_restart_queue(void *arg) 69689e0f4d2SKip Macy { 69789e0f4d2SKip Macy struct blkfront_info *info = (struct blkfront_info *)arg; 69889e0f4d2SKip Macy 69989e0f4d2SKip Macy mtx_lock(&blkif_io_lock); 70089e0f4d2SKip Macy kick_pending_request_queues(info); 70189e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 70289e0f4d2SKip Macy } 70389e0f4d2SKip Macy #endif 70489e0f4d2SKip Macy 70589e0f4d2SKip Macy static void blkif_restart_queue_callback(void *arg) 70689e0f4d2SKip Macy { 70789e0f4d2SKip Macy #if 0 70889e0f4d2SKip Macy struct blkfront_info *info = (struct blkfront_info *)arg; 70989e0f4d2SKip Macy /* XXX BSD equiv ? */ 71089e0f4d2SKip Macy 71189e0f4d2SKip Macy schedule_work(&info->work); 71289e0f4d2SKip Macy #endif 71389e0f4d2SKip Macy } 71489e0f4d2SKip Macy 71589e0f4d2SKip Macy static int 71689e0f4d2SKip Macy blkif_open(struct disk *dp) 71789e0f4d2SKip Macy { 71889e0f4d2SKip Macy struct xb_softc *sc = (struct xb_softc *)dp->d_drv1; 71989e0f4d2SKip Macy 72089e0f4d2SKip Macy if (sc == NULL) { 72112678024SDoug Rabson printf("xb%d: not found", sc->xb_unit); 72289e0f4d2SKip Macy return (ENXIO); 72389e0f4d2SKip Macy } 72489e0f4d2SKip Macy 72589e0f4d2SKip Macy sc->xb_flags |= XB_OPEN; 72689e0f4d2SKip Macy sc->xb_info->users++; 72789e0f4d2SKip Macy return (0); 72889e0f4d2SKip Macy } 72989e0f4d2SKip Macy 73089e0f4d2SKip Macy static int 73189e0f4d2SKip Macy blkif_close(struct disk *dp) 73289e0f4d2SKip Macy { 73389e0f4d2SKip Macy struct xb_softc *sc = (struct xb_softc *)dp->d_drv1; 73489e0f4d2SKip Macy 73589e0f4d2SKip Macy if (sc == NULL) 73689e0f4d2SKip Macy return (ENXIO); 73789e0f4d2SKip Macy sc->xb_flags &= ~XB_OPEN; 73889e0f4d2SKip Macy if (--(sc->xb_info->users) == 0) { 73989e0f4d2SKip Macy /* Check whether we have been instructed to close. We will 74089e0f4d2SKip Macy have ignored this request initially, as the device was 74189e0f4d2SKip Macy still mounted. */ 74223dc5621SKip Macy device_t dev = sc->xb_info->xbdev; 74323dc5621SKip Macy XenbusState state = 74423dc5621SKip Macy xenbus_read_driver_state(xenbus_get_otherend_path(dev)); 74589e0f4d2SKip Macy 74689e0f4d2SKip Macy if (state == XenbusStateClosing) 74789e0f4d2SKip Macy blkfront_closing(dev); 74889e0f4d2SKip Macy } 74989e0f4d2SKip Macy return (0); 75089e0f4d2SKip Macy } 75189e0f4d2SKip Macy 75289e0f4d2SKip Macy static int 75389e0f4d2SKip Macy blkif_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td) 75489e0f4d2SKip Macy { 75589e0f4d2SKip Macy struct xb_softc *sc = (struct xb_softc *)dp->d_drv1; 75689e0f4d2SKip Macy 75789e0f4d2SKip Macy if (sc == NULL) 75889e0f4d2SKip Macy return (ENXIO); 75989e0f4d2SKip Macy 76089e0f4d2SKip Macy return (ENOTTY); 76189e0f4d2SKip Macy } 76289e0f4d2SKip Macy 76389e0f4d2SKip Macy 76489e0f4d2SKip Macy /* 76589e0f4d2SKip Macy * blkif_queue_request 76689e0f4d2SKip Macy * 76789e0f4d2SKip Macy * request block io 76889e0f4d2SKip Macy * 76989e0f4d2SKip Macy * id: for guest use only. 77089e0f4d2SKip Macy * operation: BLKIF_OP_{READ,WRITE,PROBE} 77189e0f4d2SKip Macy * buffer: buffer to read/write into. this should be a 77289e0f4d2SKip Macy * virtual address in the guest os. 77389e0f4d2SKip Macy */ 77489e0f4d2SKip Macy static int blkif_queue_request(struct bio *bp) 77589e0f4d2SKip Macy { 77689e0f4d2SKip Macy caddr_t alignbuf; 7775d254c04SKip Macy vm_paddr_t buffer_ma; 77889e0f4d2SKip Macy blkif_request_t *ring_req; 77989e0f4d2SKip Macy unsigned long id; 7805d254c04SKip Macy uint64_t fsect, lsect; 78189e0f4d2SKip Macy struct xb_softc *sc = (struct xb_softc *)bp->bio_disk->d_drv1; 78289e0f4d2SKip Macy struct blkfront_info *info = sc->xb_info; 78389e0f4d2SKip Macy int ref; 78489e0f4d2SKip Macy 78589e0f4d2SKip Macy if (unlikely(sc->xb_info->connected != BLKIF_STATE_CONNECTED)) 78689e0f4d2SKip Macy return 1; 78789e0f4d2SKip Macy 78889e0f4d2SKip Macy if (gnttab_alloc_grant_references( 78989e0f4d2SKip Macy BLKIF_MAX_SEGMENTS_PER_REQUEST, &gref_head) < 0) { 79089e0f4d2SKip Macy gnttab_request_free_callback( 79189e0f4d2SKip Macy &info->callback, 79289e0f4d2SKip Macy blkif_restart_queue_callback, 79389e0f4d2SKip Macy info, 79489e0f4d2SKip Macy BLKIF_MAX_SEGMENTS_PER_REQUEST); 79589e0f4d2SKip Macy return 1; 79689e0f4d2SKip Macy } 79789e0f4d2SKip Macy 79889e0f4d2SKip Macy /* Check if the buffer is properly aligned */ 79989e0f4d2SKip Macy if ((vm_offset_t)bp->bio_data & PAGE_MASK) { 80089e0f4d2SKip Macy int align = (bp->bio_bcount < PAGE_SIZE/2) ? XBD_SECTOR_SIZE : 80189e0f4d2SKip Macy PAGE_SIZE; 80289e0f4d2SKip Macy caddr_t newbuf = malloc(bp->bio_bcount + align, M_DEVBUF, 80389e0f4d2SKip Macy M_NOWAIT); 80489e0f4d2SKip Macy 80589e0f4d2SKip Macy alignbuf = (char *)roundup2((u_long)newbuf, align); 80689e0f4d2SKip Macy 80789e0f4d2SKip Macy /* save a copy of the current buffer */ 80889e0f4d2SKip Macy bp->bio_driver1 = newbuf; 80989e0f4d2SKip Macy bp->bio_driver2 = alignbuf; 81089e0f4d2SKip Macy 81189e0f4d2SKip Macy /* Copy the data for a write */ 81289e0f4d2SKip Macy if (bp->bio_cmd == BIO_WRITE) 81389e0f4d2SKip Macy bcopy(bp->bio_data, alignbuf, bp->bio_bcount); 81489e0f4d2SKip Macy } else 81589e0f4d2SKip Macy alignbuf = bp->bio_data; 81689e0f4d2SKip Macy 81789e0f4d2SKip Macy /* Fill out a communications ring structure. */ 81889e0f4d2SKip Macy ring_req = RING_GET_REQUEST(&info->ring, 81989e0f4d2SKip Macy info->ring.req_prod_pvt); 82089e0f4d2SKip Macy id = GET_ID_FROM_FREELIST(info); 82189e0f4d2SKip Macy info->shadow[id].request = (unsigned long)bp; 82289e0f4d2SKip Macy 82389e0f4d2SKip Macy ring_req->id = id; 82489e0f4d2SKip Macy ring_req->operation = (bp->bio_cmd == BIO_READ) ? BLKIF_OP_READ : 82589e0f4d2SKip Macy BLKIF_OP_WRITE; 82689e0f4d2SKip Macy 82789e0f4d2SKip Macy ring_req->sector_number= (blkif_sector_t)bp->bio_pblkno; 82889e0f4d2SKip Macy ring_req->handle = (blkif_vdev_t)(uintptr_t)sc->xb_disk; 82989e0f4d2SKip Macy 83089e0f4d2SKip Macy ring_req->nr_segments = 0; /* XXX not doing scatter/gather since buffer 83189e0f4d2SKip Macy * chaining is not supported. 83289e0f4d2SKip Macy */ 83389e0f4d2SKip Macy 83489e0f4d2SKip Macy buffer_ma = vtomach(alignbuf); 83589e0f4d2SKip Macy fsect = (buffer_ma & PAGE_MASK) >> XBD_SECTOR_SHFT; 83689e0f4d2SKip Macy lsect = fsect + (bp->bio_bcount >> XBD_SECTOR_SHFT) - 1; 83789e0f4d2SKip Macy /* install a grant reference. */ 83889e0f4d2SKip Macy ref = gnttab_claim_grant_reference(&gref_head); 83989e0f4d2SKip Macy KASSERT( ref != -ENOSPC, ("grant_reference failed") ); 84089e0f4d2SKip Macy 84189e0f4d2SKip Macy gnttab_grant_foreign_access_ref( 84289e0f4d2SKip Macy ref, 84323dc5621SKip Macy xenbus_get_otherend_id(info->xbdev), 84489e0f4d2SKip Macy buffer_ma >> PAGE_SHIFT, 84589e0f4d2SKip Macy ring_req->operation & 1 ); /* ??? */ 84689e0f4d2SKip Macy info->shadow[id].frame[ring_req->nr_segments] = 84789e0f4d2SKip Macy buffer_ma >> PAGE_SHIFT; 84889e0f4d2SKip Macy 84989e0f4d2SKip Macy ring_req->seg[ring_req->nr_segments] = 85089e0f4d2SKip Macy (struct blkif_request_segment) { 85189e0f4d2SKip Macy .gref = ref, 85289e0f4d2SKip Macy .first_sect = fsect, 85389e0f4d2SKip Macy .last_sect = lsect }; 85489e0f4d2SKip Macy 85589e0f4d2SKip Macy ring_req->nr_segments++; 85689e0f4d2SKip Macy KASSERT((buffer_ma & (XBD_SECTOR_SIZE-1)) == 0, 85789e0f4d2SKip Macy ("XEN buffer must be sector aligned")); 85889e0f4d2SKip Macy KASSERT(lsect <= 7, 85989e0f4d2SKip Macy ("XEN disk driver data cannot cross a page boundary")); 86089e0f4d2SKip Macy 86189e0f4d2SKip Macy buffer_ma &= ~PAGE_MASK; 86289e0f4d2SKip Macy 86389e0f4d2SKip Macy info->ring.req_prod_pvt++; 86489e0f4d2SKip Macy 86589e0f4d2SKip Macy /* Keep a private copy so we can reissue requests when recovering. */ 86689e0f4d2SKip Macy info->shadow[id].req = *ring_req; 86789e0f4d2SKip Macy 86889e0f4d2SKip Macy gnttab_free_grant_references(gref_head); 86989e0f4d2SKip Macy 87089e0f4d2SKip Macy return 0; 87189e0f4d2SKip Macy } 87289e0f4d2SKip Macy 87389e0f4d2SKip Macy 87489e0f4d2SKip Macy 87589e0f4d2SKip Macy /* 87689e0f4d2SKip Macy * Dequeue buffers and place them in the shared communication ring. 87789e0f4d2SKip Macy * Return when no more requests can be accepted or all buffers have 87889e0f4d2SKip Macy * been queued. 87989e0f4d2SKip Macy * 88089e0f4d2SKip Macy * Signal XEN once the ring has been filled out. 88189e0f4d2SKip Macy */ 88289e0f4d2SKip Macy static void 88389e0f4d2SKip Macy xb_startio(struct xb_softc *sc) 88489e0f4d2SKip Macy { 88589e0f4d2SKip Macy struct bio *bp; 88689e0f4d2SKip Macy int queued = 0; 88789e0f4d2SKip Macy struct blkfront_info *info = sc->xb_info; 88889e0f4d2SKip Macy DPRINTK(""); 88989e0f4d2SKip Macy 89089e0f4d2SKip Macy mtx_assert(&blkif_io_lock, MA_OWNED); 89189e0f4d2SKip Macy 89289e0f4d2SKip Macy while ((bp = bioq_takefirst(&sc->xb_bioq)) != NULL) { 89389e0f4d2SKip Macy 89489e0f4d2SKip Macy if (RING_FULL(&info->ring)) 89589e0f4d2SKip Macy goto wait; 89689e0f4d2SKip Macy 89789e0f4d2SKip Macy if (blkif_queue_request(bp)) { 89889e0f4d2SKip Macy wait: 89989e0f4d2SKip Macy bioq_insert_head(&sc->xb_bioq, bp); 90089e0f4d2SKip Macy break; 90189e0f4d2SKip Macy } 90289e0f4d2SKip Macy queued++; 90389e0f4d2SKip Macy } 90489e0f4d2SKip Macy 90589e0f4d2SKip Macy if (queued != 0) 90689e0f4d2SKip Macy flush_requests(sc->xb_info); 90789e0f4d2SKip Macy } 90889e0f4d2SKip Macy 90989e0f4d2SKip Macy static void 91089e0f4d2SKip Macy blkif_int(void *xsc) 91189e0f4d2SKip Macy { 91289e0f4d2SKip Macy struct xb_softc *sc = NULL; 91389e0f4d2SKip Macy struct bio *bp; 91489e0f4d2SKip Macy blkif_response_t *bret; 91589e0f4d2SKip Macy RING_IDX i, rp; 91689e0f4d2SKip Macy struct blkfront_info *info = xsc; 91789e0f4d2SKip Macy DPRINTK(""); 91889e0f4d2SKip Macy 91989e0f4d2SKip Macy TRACE_ENTER; 92089e0f4d2SKip Macy 92189e0f4d2SKip Macy mtx_lock(&blkif_io_lock); 92289e0f4d2SKip Macy 92389e0f4d2SKip Macy if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) { 92489e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 92589e0f4d2SKip Macy return; 92689e0f4d2SKip Macy } 92789e0f4d2SKip Macy 92889e0f4d2SKip Macy again: 92989e0f4d2SKip Macy rp = info->ring.sring->rsp_prod; 93089e0f4d2SKip Macy rmb(); /* Ensure we see queued responses up to 'rp'. */ 93189e0f4d2SKip Macy 93289e0f4d2SKip Macy for (i = info->ring.rsp_cons; i != rp; i++) { 93389e0f4d2SKip Macy unsigned long id; 93489e0f4d2SKip Macy 93589e0f4d2SKip Macy bret = RING_GET_RESPONSE(&info->ring, i); 93689e0f4d2SKip Macy id = bret->id; 93789e0f4d2SKip Macy bp = (struct bio *)info->shadow[id].request; 93889e0f4d2SKip Macy 93989e0f4d2SKip Macy blkif_completion(&info->shadow[id]); 94089e0f4d2SKip Macy 94189e0f4d2SKip Macy ADD_ID_TO_FREELIST(info, id); 94289e0f4d2SKip Macy 94389e0f4d2SKip Macy switch (bret->operation) { 94489e0f4d2SKip Macy case BLKIF_OP_READ: 94589e0f4d2SKip Macy /* had an unaligned buffer that needs to be copied */ 94689e0f4d2SKip Macy if (bp->bio_driver1) 94789e0f4d2SKip Macy bcopy(bp->bio_driver2, bp->bio_data, bp->bio_bcount); 94889e0f4d2SKip Macy /* FALLTHROUGH */ 94989e0f4d2SKip Macy case BLKIF_OP_WRITE: 95089e0f4d2SKip Macy 95189e0f4d2SKip Macy /* free the copy buffer */ 95289e0f4d2SKip Macy if (bp->bio_driver1) { 95389e0f4d2SKip Macy free(bp->bio_driver1, M_DEVBUF); 95489e0f4d2SKip Macy bp->bio_driver1 = NULL; 95589e0f4d2SKip Macy } 95689e0f4d2SKip Macy 95789e0f4d2SKip Macy if ( unlikely(bret->status != BLKIF_RSP_OKAY) ) { 9585d254c04SKip Macy printf("Bad return from blkdev data request: %x\n", 95989e0f4d2SKip Macy bret->status); 96089e0f4d2SKip Macy bp->bio_flags |= BIO_ERROR; 96189e0f4d2SKip Macy } 96289e0f4d2SKip Macy 96389e0f4d2SKip Macy sc = (struct xb_softc *)bp->bio_disk->d_drv1; 96489e0f4d2SKip Macy 96589e0f4d2SKip Macy if (bp->bio_flags & BIO_ERROR) 96689e0f4d2SKip Macy bp->bio_error = EIO; 96789e0f4d2SKip Macy else 96889e0f4d2SKip Macy bp->bio_resid = 0; 96989e0f4d2SKip Macy 97089e0f4d2SKip Macy biodone(bp); 97189e0f4d2SKip Macy break; 97289e0f4d2SKip Macy default: 97389e0f4d2SKip Macy panic("received invalid operation"); 97489e0f4d2SKip Macy break; 97589e0f4d2SKip Macy } 97689e0f4d2SKip Macy } 97789e0f4d2SKip Macy 97889e0f4d2SKip Macy info->ring.rsp_cons = i; 97989e0f4d2SKip Macy 98089e0f4d2SKip Macy if (i != info->ring.req_prod_pvt) { 98189e0f4d2SKip Macy int more_to_do; 98289e0f4d2SKip Macy RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do); 98389e0f4d2SKip Macy if (more_to_do) 98489e0f4d2SKip Macy goto again; 98589e0f4d2SKip Macy } else { 98689e0f4d2SKip Macy info->ring.sring->rsp_event = i + 1; 98789e0f4d2SKip Macy } 98889e0f4d2SKip Macy 98989e0f4d2SKip Macy kick_pending_request_queues(info); 99089e0f4d2SKip Macy 99189e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 99289e0f4d2SKip Macy } 99389e0f4d2SKip Macy 99489e0f4d2SKip Macy static void 99589e0f4d2SKip Macy blkif_free(struct blkfront_info *info, int suspend) 99689e0f4d2SKip Macy { 99789e0f4d2SKip Macy 99889e0f4d2SKip Macy /* Prevent new requests being issued until we fix things up. */ 99989e0f4d2SKip Macy mtx_lock(&blkif_io_lock); 100089e0f4d2SKip Macy info->connected = suspend ? 100189e0f4d2SKip Macy BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED; 100289e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 100389e0f4d2SKip Macy 100489e0f4d2SKip Macy /* Free resources associated with old device channel. */ 100589e0f4d2SKip Macy if (info->ring_ref != GRANT_INVALID_REF) { 1006920ba15bSKip Macy gnttab_end_foreign_access(info->ring_ref, 100789e0f4d2SKip Macy info->ring.sring); 100889e0f4d2SKip Macy info->ring_ref = GRANT_INVALID_REF; 100989e0f4d2SKip Macy info->ring.sring = NULL; 101089e0f4d2SKip Macy } 101189e0f4d2SKip Macy if (info->irq) 10123a6d1fcfSKip Macy unbind_from_irqhandler(info->irq); 101389e0f4d2SKip Macy info->irq = 0; 101489e0f4d2SKip Macy 101589e0f4d2SKip Macy } 101689e0f4d2SKip Macy 101789e0f4d2SKip Macy static void 101889e0f4d2SKip Macy blkif_completion(struct blk_shadow *s) 101989e0f4d2SKip Macy { 102089e0f4d2SKip Macy int i; 102189e0f4d2SKip Macy 102289e0f4d2SKip Macy for (i = 0; i < s->req.nr_segments; i++) 1023920ba15bSKip Macy gnttab_end_foreign_access(s->req.seg[i].gref, 0UL); 102489e0f4d2SKip Macy } 102589e0f4d2SKip Macy 102689e0f4d2SKip Macy static void 102789e0f4d2SKip Macy blkif_recover(struct blkfront_info *info) 102889e0f4d2SKip Macy { 102989e0f4d2SKip Macy int i, j; 103089e0f4d2SKip Macy blkif_request_t *req; 103189e0f4d2SKip Macy struct blk_shadow *copy; 103289e0f4d2SKip Macy 103312678024SDoug Rabson if (!info->sc) 103412678024SDoug Rabson return; 103512678024SDoug Rabson 103689e0f4d2SKip Macy /* Stage 1: Make a safe copy of the shadow state. */ 103789e0f4d2SKip Macy copy = (struct blk_shadow *)malloc(sizeof(info->shadow), M_DEVBUF, M_NOWAIT|M_ZERO); 103889e0f4d2SKip Macy memcpy(copy, info->shadow, sizeof(info->shadow)); 103989e0f4d2SKip Macy 104089e0f4d2SKip Macy /* Stage 2: Set up free list. */ 104189e0f4d2SKip Macy memset(&info->shadow, 0, sizeof(info->shadow)); 104289e0f4d2SKip Macy for (i = 0; i < BLK_RING_SIZE; i++) 104389e0f4d2SKip Macy info->shadow[i].req.id = i+1; 104489e0f4d2SKip Macy info->shadow_free = info->ring.req_prod_pvt; 104589e0f4d2SKip Macy info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff; 104689e0f4d2SKip Macy 104789e0f4d2SKip Macy /* Stage 3: Find pending requests and requeue them. */ 104889e0f4d2SKip Macy for (i = 0; i < BLK_RING_SIZE; i++) { 104989e0f4d2SKip Macy /* Not in use? */ 105089e0f4d2SKip Macy if (copy[i].request == 0) 105189e0f4d2SKip Macy continue; 105289e0f4d2SKip Macy 105389e0f4d2SKip Macy /* Grab a request slot and copy shadow state into it. */ 105489e0f4d2SKip Macy req = RING_GET_REQUEST( 105589e0f4d2SKip Macy &info->ring, info->ring.req_prod_pvt); 105689e0f4d2SKip Macy *req = copy[i].req; 105789e0f4d2SKip Macy 105889e0f4d2SKip Macy /* We get a new request id, and must reset the shadow state. */ 105989e0f4d2SKip Macy req->id = GET_ID_FROM_FREELIST(info); 106089e0f4d2SKip Macy memcpy(&info->shadow[req->id], ©[i], sizeof(copy[i])); 106189e0f4d2SKip Macy 106289e0f4d2SKip Macy /* Rewrite any grant references invalidated by suspend/resume. */ 106389e0f4d2SKip Macy for (j = 0; j < req->nr_segments; j++) 106489e0f4d2SKip Macy gnttab_grant_foreign_access_ref( 106589e0f4d2SKip Macy req->seg[j].gref, 106623dc5621SKip Macy xenbus_get_otherend_id(info->xbdev), 106789e0f4d2SKip Macy pfn_to_mfn(info->shadow[req->id].frame[j]), 106889e0f4d2SKip Macy 0 /* assume not readonly */); 106989e0f4d2SKip Macy 107089e0f4d2SKip Macy info->shadow[req->id].req = *req; 107189e0f4d2SKip Macy 107289e0f4d2SKip Macy info->ring.req_prod_pvt++; 107389e0f4d2SKip Macy } 107489e0f4d2SKip Macy 107589e0f4d2SKip Macy free(copy, M_DEVBUF); 107689e0f4d2SKip Macy 107723dc5621SKip Macy xenbus_set_state(info->xbdev, XenbusStateConnected); 107889e0f4d2SKip Macy 107989e0f4d2SKip Macy /* Now safe for us to use the shared ring */ 108089e0f4d2SKip Macy mtx_lock(&blkif_io_lock); 108189e0f4d2SKip Macy info->connected = BLKIF_STATE_CONNECTED; 108289e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 108389e0f4d2SKip Macy 108489e0f4d2SKip Macy /* Send off requeued requests */ 108589e0f4d2SKip Macy mtx_lock(&blkif_io_lock); 108689e0f4d2SKip Macy flush_requests(info); 108789e0f4d2SKip Macy 108889e0f4d2SKip Macy /* Kick any other new requests queued since we resumed */ 108989e0f4d2SKip Macy kick_pending_request_queues(info); 109089e0f4d2SKip Macy mtx_unlock(&blkif_io_lock); 109189e0f4d2SKip Macy } 109289e0f4d2SKip Macy 109323dc5621SKip Macy /* ** Driver registration ** */ 109423dc5621SKip Macy static device_method_t blkfront_methods[] = { 109523dc5621SKip Macy /* Device interface */ 109623dc5621SKip Macy DEVMETHOD(device_probe, blkfront_probe), 109723dc5621SKip Macy DEVMETHOD(device_attach, blkfront_attach), 109823dc5621SKip Macy DEVMETHOD(device_detach, blkfront_detach), 109923dc5621SKip Macy DEVMETHOD(device_shutdown, bus_generic_shutdown), 110012678024SDoug Rabson DEVMETHOD(device_suspend, blkfront_suspend), 110123dc5621SKip Macy DEVMETHOD(device_resume, blkfront_resume), 110289e0f4d2SKip Macy 110323dc5621SKip Macy /* Xenbus interface */ 110423dc5621SKip Macy DEVMETHOD(xenbus_backend_changed, blkfront_backend_changed), 110589e0f4d2SKip Macy 110623dc5621SKip Macy { 0, 0 } 110789e0f4d2SKip Macy }; 110889e0f4d2SKip Macy 110923dc5621SKip Macy static driver_t blkfront_driver = { 111023dc5621SKip Macy "xbd", 111123dc5621SKip Macy blkfront_methods, 111223dc5621SKip Macy sizeof(struct blkfront_info), 111389e0f4d2SKip Macy }; 111423dc5621SKip Macy devclass_t blkfront_devclass; 111589e0f4d2SKip Macy 111623dc5621SKip Macy DRIVER_MODULE(xbd, xenbus, blkfront_driver, blkfront_devclass, 0, 0); 111789e0f4d2SKip Macy 111889e0f4d2SKip Macy MTX_SYSINIT(ioreq, &blkif_io_lock, "BIO LOCK", MTX_NOWITNESS); /* XXX how does one enroll a lock? */ 111989e0f4d2SKip Macy 1120