xref: /freebsd/sys/dev/xen/blkfront/blkfront.c (revision 33eebb6a7591245d4d8c729c1d8a01c01d6c0f3a)
189e0f4d2SKip Macy /*
28698b76cSKip Macy  * XenBSD block device driver
38698b76cSKip Macy  *
4*33eebb6aSJustin T. Gibbs  * Copyright (c) 2010-2013 Spectra Logic Corporation
5e4808c4bSKip Macy  * Copyright (c) 2009 Scott Long, Yahoo!
68698b76cSKip Macy  * Copyright (c) 2009 Frank Suchomel, Citrix
79999d2cbSKip Macy  * Copyright (c) 2009 Doug F. Rabson, Citrix
89999d2cbSKip Macy  * Copyright (c) 2005 Kip Macy
99999d2cbSKip Macy  * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
109999d2cbSKip Macy  * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
119999d2cbSKip Macy  *
129999d2cbSKip Macy  *
139999d2cbSKip Macy  * Permission is hereby granted, free of charge, to any person obtaining a copy
149999d2cbSKip Macy  * of this software and associated documentation files (the "Software"), to
159999d2cbSKip Macy  * deal in the Software without restriction, including without limitation the
169999d2cbSKip Macy  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
179999d2cbSKip Macy  * sell copies of the Software, and to permit persons to whom the Software is
189999d2cbSKip Macy  * furnished to do so, subject to the following conditions:
199999d2cbSKip Macy  *
209999d2cbSKip Macy  * The above copyright notice and this permission notice shall be included in
219999d2cbSKip Macy  * all copies or substantial portions of the Software.
229999d2cbSKip Macy  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
239999d2cbSKip Macy  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
249999d2cbSKip Macy  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
259999d2cbSKip Macy  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
269999d2cbSKip Macy  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
279999d2cbSKip Macy  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
289999d2cbSKip Macy  * DEALINGS IN THE SOFTWARE.
2989e0f4d2SKip Macy  */
3089e0f4d2SKip Macy 
3189e0f4d2SKip Macy #include <sys/cdefs.h>
3289e0f4d2SKip Macy __FBSDID("$FreeBSD$");
3389e0f4d2SKip Macy 
3489e0f4d2SKip Macy #include <sys/param.h>
3589e0f4d2SKip Macy #include <sys/systm.h>
3689e0f4d2SKip Macy #include <sys/malloc.h>
3789e0f4d2SKip Macy #include <sys/kernel.h>
3889e0f4d2SKip Macy #include <vm/vm.h>
3989e0f4d2SKip Macy #include <vm/pmap.h>
4089e0f4d2SKip Macy 
4189e0f4d2SKip Macy #include <sys/bio.h>
4289e0f4d2SKip Macy #include <sys/bus.h>
4389e0f4d2SKip Macy #include <sys/conf.h>
4489e0f4d2SKip Macy #include <sys/module.h>
458b8bfa35SJustin T. Gibbs #include <sys/sysctl.h>
4689e0f4d2SKip Macy 
4789e0f4d2SKip Macy #include <machine/bus.h>
4889e0f4d2SKip Macy #include <sys/rman.h>
4989e0f4d2SKip Macy #include <machine/resource.h>
5089e0f4d2SKip Macy #include <machine/intr_machdep.h>
5189e0f4d2SKip Macy #include <machine/vmparam.h>
52e4808c4bSKip Macy #include <sys/bus_dma.h>
5389e0f4d2SKip Macy 
54ff662b5cSJustin T. Gibbs #include <machine/_inttypes.h>
5589e0f4d2SKip Macy #include <machine/xen/xen-os.h>
562913e88cSRobert Watson #include <machine/xen/xenvar.h>
5712678024SDoug Rabson #include <machine/xen/xenfunc.h>
58ff662b5cSJustin T. Gibbs 
5912678024SDoug Rabson #include <xen/hypervisor.h>
603a6d1fcfSKip Macy #include <xen/xen_intr.h>
613a6d1fcfSKip Macy #include <xen/evtchn.h>
6212678024SDoug Rabson #include <xen/gnttab.h>
6389e0f4d2SKip Macy #include <xen/interface/grant_table.h>
6423dc5621SKip Macy #include <xen/interface/io/protocols.h>
6523dc5621SKip Macy #include <xen/xenbus/xenbusvar.h>
6689e0f4d2SKip Macy 
6789e0f4d2SKip Macy #include <geom/geom_disk.h>
6889e0f4d2SKip Macy 
6989e0f4d2SKip Macy #include <dev/xen/blkfront/block.h>
7089e0f4d2SKip Macy 
7123dc5621SKip Macy #include "xenbus_if.h"
7223dc5621SKip Macy 
7389e0f4d2SKip Macy /* prototypes */
74*33eebb6aSJustin T. Gibbs static void xbd_free_command(struct xbd_command *cm);
75*33eebb6aSJustin T. Gibbs static void xbd_startio(struct xbd_softc *sc);
76*33eebb6aSJustin T. Gibbs static void xbd_connect(struct xbd_softc *);
77*33eebb6aSJustin T. Gibbs static void xbd_closing(device_t);
78*33eebb6aSJustin T. Gibbs static int xbd_detach(device_t);
79*33eebb6aSJustin T. Gibbs static int xbd_setup_ring(struct xbd_softc *);
80*33eebb6aSJustin T. Gibbs static void xbd_int(void *);
81*33eebb6aSJustin T. Gibbs static void xbd_initialize(struct xbd_softc *);
82*33eebb6aSJustin T. Gibbs static int xbd_completion(struct xbd_command *);
83*33eebb6aSJustin T. Gibbs static void xbd_free(struct xbd_softc *);
84*33eebb6aSJustin T. Gibbs static void xbd_queue_cb(void *, bus_dma_segment_t *, int, int);
8589e0f4d2SKip Macy 
86d745c852SEd Schouten static MALLOC_DEFINE(M_XENBLOCKFRONT, "xbd", "Xen Block Front driver data");
87ff662b5cSJustin T. Gibbs 
8889e0f4d2SKip Macy #define GRANT_INVALID_REF 0
8989e0f4d2SKip Macy 
9089e0f4d2SKip Macy /* Control whether runtime update of vbds is enabled. */
9189e0f4d2SKip Macy #define ENABLE_VBD_UPDATE 0
9289e0f4d2SKip Macy 
9389e0f4d2SKip Macy #if ENABLE_VBD_UPDATE
9489e0f4d2SKip Macy static void vbd_update(void);
9589e0f4d2SKip Macy #endif
9689e0f4d2SKip Macy 
97*33eebb6aSJustin T. Gibbs #define XBD_STATE_DISCONNECTED 0
98*33eebb6aSJustin T. Gibbs #define XBD_STATE_CONNECTED    1
99*33eebb6aSJustin T. Gibbs #define XBD_STATE_SUSPENDED    2
10089e0f4d2SKip Macy 
10189e0f4d2SKip Macy #ifdef notyet
102*33eebb6aSJustin T. Gibbs static char *xbd_state_name[] = {
103*33eebb6aSJustin T. Gibbs 	[XBD_STATE_DISCONNECTED] = "disconnected",
104*33eebb6aSJustin T. Gibbs 	[XBD_STATE_CONNECTED]    = "connected",
105*33eebb6aSJustin T. Gibbs 	[XBD_STATE_SUSPENDED]    = "closed",
10689e0f4d2SKip Macy };
10789e0f4d2SKip Macy 
108*33eebb6aSJustin T. Gibbs static char * xbd_status_name[] = {
10989e0f4d2SKip Macy 	[BLKIF_INTERFACE_STATUS_CLOSED]       = "closed",
11089e0f4d2SKip Macy 	[BLKIF_INTERFACE_STATUS_DISCONNECTED] = "disconnected",
11189e0f4d2SKip Macy 	[BLKIF_INTERFACE_STATUS_CONNECTED]    = "connected",
11289e0f4d2SKip Macy 	[BLKIF_INTERFACE_STATUS_CHANGED]      = "changed",
11389e0f4d2SKip Macy };
11489e0f4d2SKip Macy #endif
115e4808c4bSKip Macy 
11689e0f4d2SKip Macy #if 0
11712678024SDoug Rabson #define DPRINTK(fmt, args...) printf("[XEN] %s:%d: " fmt ".\n", __func__, __LINE__, ##args)
11889e0f4d2SKip Macy #else
11989e0f4d2SKip Macy #define DPRINTK(fmt, args...)
12089e0f4d2SKip Macy #endif
12189e0f4d2SKip Macy 
122*33eebb6aSJustin T. Gibbs static int xbd_open(struct disk *dp);
123*33eebb6aSJustin T. Gibbs static int xbd_close(struct disk *dp);
124*33eebb6aSJustin T. Gibbs static int xbd_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td);
125*33eebb6aSJustin T. Gibbs static int xbd_queue_request(struct xbd_softc *sc, struct xbd_command *cm);
126*33eebb6aSJustin T. Gibbs static void xbd_strategy(struct bio *bp);
12789e0f4d2SKip Macy 
1288698b76cSKip Macy // In order to quiesce the device during kernel dumps, outstanding requests to
1298698b76cSKip Macy // DOM0 for disk reads/writes need to be accounted for.
130*33eebb6aSJustin T. Gibbs static	int	xbd_dump(void *, void *, vm_offset_t, off_t, size_t);
13189e0f4d2SKip Macy 
132*33eebb6aSJustin T. Gibbs /* XXX move to xbd_vbd.c when VBD update support is added */
13389e0f4d2SKip Macy #define MAX_VBDS 64
13489e0f4d2SKip Macy 
13589e0f4d2SKip Macy #define XBD_SECTOR_SIZE		512	/* XXX: assume for now */
13689e0f4d2SKip Macy #define XBD_SECTOR_SHFT		9
13789e0f4d2SKip Macy 
13823dc5621SKip Macy /*
13923dc5621SKip Macy  * Translate Linux major/minor to an appropriate name and unit
14023dc5621SKip Macy  * number. For HVM guests, this allows us to use the same drive names
14123dc5621SKip Macy  * with blkfront as the emulated drives, easing transition slightly.
14223dc5621SKip Macy  */
14323dc5621SKip Macy static void
144*33eebb6aSJustin T. Gibbs xbd_vdevice_to_unit(uint32_t vdevice, int *unit, const char **name)
14523dc5621SKip Macy {
14623dc5621SKip Macy 	static struct vdev_info {
14723dc5621SKip Macy 		int major;
14823dc5621SKip Macy 		int shift;
14923dc5621SKip Macy 		int base;
15023dc5621SKip Macy 		const char *name;
15123dc5621SKip Macy 	} info[] = {
1525e58295aSJustin T. Gibbs 		{3,	6,	0,	"ada"},	/* ide0 */
1535e58295aSJustin T. Gibbs 		{22,	6,	2,	"ada"},	/* ide1 */
1545e58295aSJustin T. Gibbs 		{33,	6,	4,	"ada"},	/* ide2 */
1555e58295aSJustin T. Gibbs 		{34,	6,	6,	"ada"},	/* ide3 */
1565e58295aSJustin T. Gibbs 		{56,	6,	8,	"ada"},	/* ide4 */
1575e58295aSJustin T. Gibbs 		{57,	6,	10,	"ada"},	/* ide5 */
1585e58295aSJustin T. Gibbs 		{88,	6,	12,	"ada"},	/* ide6 */
1595e58295aSJustin T. Gibbs 		{89,	6,	14,	"ada"},	/* ide7 */
1605e58295aSJustin T. Gibbs 		{90,	6,	16,	"ada"},	/* ide8 */
1615e58295aSJustin T. Gibbs 		{91,	6,	18,	"ada"},	/* ide9 */
16223dc5621SKip Macy 
16323dc5621SKip Macy 		{8,	4,	0,	"da"},	/* scsi disk0 */
16423dc5621SKip Macy 		{65,	4,	16,	"da"},	/* scsi disk1 */
16523dc5621SKip Macy 		{66,	4,	32,	"da"},	/* scsi disk2 */
16623dc5621SKip Macy 		{67,	4,	48,	"da"},	/* scsi disk3 */
16723dc5621SKip Macy 		{68,	4,	64,	"da"},	/* scsi disk4 */
16823dc5621SKip Macy 		{69,	4,	80,	"da"},	/* scsi disk5 */
16923dc5621SKip Macy 		{70,	4,	96,	"da"},	/* scsi disk6 */
17023dc5621SKip Macy 		{71,	4,	112,	"da"},	/* scsi disk7 */
17123dc5621SKip Macy 		{128,	4,	128,	"da"},	/* scsi disk8 */
17223dc5621SKip Macy 		{129,	4,	144,	"da"},	/* scsi disk9 */
17323dc5621SKip Macy 		{130,	4,	160,	"da"},	/* scsi disk10 */
17423dc5621SKip Macy 		{131,	4,	176,	"da"},	/* scsi disk11 */
17523dc5621SKip Macy 		{132,	4,	192,	"da"},	/* scsi disk12 */
17623dc5621SKip Macy 		{133,	4,	208,	"da"},	/* scsi disk13 */
17723dc5621SKip Macy 		{134,	4,	224,	"da"},	/* scsi disk14 */
17823dc5621SKip Macy 		{135,	4,	240,	"da"},	/* scsi disk15 */
17923dc5621SKip Macy 
18023dc5621SKip Macy 		{202,	4,	0,	"xbd"},	/* xbd */
18123dc5621SKip Macy 
18223dc5621SKip Macy 		{0,	0,	0,	NULL},
18323dc5621SKip Macy 	};
18423dc5621SKip Macy 	int major = vdevice >> 8;
18523dc5621SKip Macy 	int minor = vdevice & 0xff;
18623dc5621SKip Macy 	int i;
18723dc5621SKip Macy 
18823dc5621SKip Macy 	if (vdevice & (1 << 28)) {
18923dc5621SKip Macy 		*unit = (vdevice & ((1 << 28) - 1)) >> 8;
19023dc5621SKip Macy 		*name = "xbd";
1918b8bfa35SJustin T. Gibbs 		return;
19223dc5621SKip Macy 	}
19323dc5621SKip Macy 
19423dc5621SKip Macy 	for (i = 0; info[i].major; i++) {
19523dc5621SKip Macy 		if (info[i].major == major) {
19623dc5621SKip Macy 			*unit = info[i].base + (minor >> info[i].shift);
19723dc5621SKip Macy 			*name = info[i].name;
19823dc5621SKip Macy 			return;
19923dc5621SKip Macy 		}
20023dc5621SKip Macy 	}
20123dc5621SKip Macy 
20223dc5621SKip Macy 	*unit = minor >> 4;
20323dc5621SKip Macy 	*name = "xbd";
20423dc5621SKip Macy }
20523dc5621SKip Macy 
20689e0f4d2SKip Macy int
207*33eebb6aSJustin T. Gibbs xbd_instance_create(struct xbd_softc *sc, blkif_sector_t sectors,
208ff662b5cSJustin T. Gibbs     int vdevice, uint16_t vdisk_info, unsigned long sector_size)
20989e0f4d2SKip Macy {
21023dc5621SKip Macy 	int unit, error = 0;
21123dc5621SKip Macy 	const char *name;
21223dc5621SKip Macy 
213*33eebb6aSJustin T. Gibbs 	xbd_vdevice_to_unit(vdevice, &unit, &name);
21489e0f4d2SKip Macy 
215*33eebb6aSJustin T. Gibbs 	sc->xbd_unit = unit;
21689e0f4d2SKip Macy 
21723dc5621SKip Macy 	if (strcmp(name, "xbd"))
218*33eebb6aSJustin T. Gibbs 		device_printf(sc->xbd_dev, "attaching as %s%d\n", name, unit);
21923dc5621SKip Macy 
220*33eebb6aSJustin T. Gibbs 	sc->xbd_disk = disk_alloc();
221*33eebb6aSJustin T. Gibbs 	sc->xbd_disk->d_unit = sc->xbd_unit;
222*33eebb6aSJustin T. Gibbs 	sc->xbd_disk->d_open = xbd_open;
223*33eebb6aSJustin T. Gibbs 	sc->xbd_disk->d_close = xbd_close;
224*33eebb6aSJustin T. Gibbs 	sc->xbd_disk->d_ioctl = xbd_ioctl;
225*33eebb6aSJustin T. Gibbs 	sc->xbd_disk->d_strategy = xbd_strategy;
226*33eebb6aSJustin T. Gibbs 	sc->xbd_disk->d_dump = xbd_dump;
227*33eebb6aSJustin T. Gibbs 	sc->xbd_disk->d_name = name;
228*33eebb6aSJustin T. Gibbs 	sc->xbd_disk->d_drv1 = sc;
229*33eebb6aSJustin T. Gibbs 	sc->xbd_disk->d_sectorsize = sector_size;
23089e0f4d2SKip Macy 
231*33eebb6aSJustin T. Gibbs 	sc->xbd_disk->d_mediasize = sectors * sector_size;
232*33eebb6aSJustin T. Gibbs 	sc->xbd_disk->d_maxsize = sc->xbd_max_request_size;
233*33eebb6aSJustin T. Gibbs 	sc->xbd_disk->d_flags = 0;
234*33eebb6aSJustin T. Gibbs 	disk_create(sc->xbd_disk, DISK_VERSION);
23589e0f4d2SKip Macy 
23689e0f4d2SKip Macy 	return error;
23789e0f4d2SKip Macy }
23889e0f4d2SKip Macy 
23989e0f4d2SKip Macy /************************ end VBD support *****************/
24089e0f4d2SKip Macy 
24189e0f4d2SKip Macy /*
24289e0f4d2SKip Macy  * Read/write routine for a buffer.  Finds the proper unit, place it on
24389e0f4d2SKip Macy  * the sortq and kick the controller.
24489e0f4d2SKip Macy  */
24589e0f4d2SKip Macy static void
246*33eebb6aSJustin T. Gibbs xbd_strategy(struct bio *bp)
24789e0f4d2SKip Macy {
248*33eebb6aSJustin T. Gibbs 	struct xbd_softc *sc = bp->bio_disk->d_drv1;
24989e0f4d2SKip Macy 
25089e0f4d2SKip Macy 	/* bogus disk? */
25189e0f4d2SKip Macy 	if (sc == NULL) {
25289e0f4d2SKip Macy 		bp->bio_error = EINVAL;
25389e0f4d2SKip Macy 		bp->bio_flags |= BIO_ERROR;
25489e0f4d2SKip Macy 		bp->bio_resid = bp->bio_bcount;
25589e0f4d2SKip Macy 		biodone(bp);
25689e0f4d2SKip Macy 		return;
25789e0f4d2SKip Macy 	}
25889e0f4d2SKip Macy 
259e4808c4bSKip Macy 	/*
260e4808c4bSKip Macy 	 * Place it in the queue of disk activities for this disk
261e4808c4bSKip Macy 	 */
262*33eebb6aSJustin T. Gibbs 	mtx_lock(&sc->xbd_io_lock);
263e4808c4bSKip Macy 
264*33eebb6aSJustin T. Gibbs 	xbd_enqueue_bio(sc, bp);
265*33eebb6aSJustin T. Gibbs 	xbd_startio(sc);
266e4808c4bSKip Macy 
267*33eebb6aSJustin T. Gibbs 	mtx_unlock(&sc->xbd_io_lock);
268e4808c4bSKip Macy 	return;
269e4808c4bSKip Macy }
270e4808c4bSKip Macy 
271e4808c4bSKip Macy static void
272*33eebb6aSJustin T. Gibbs xbd_bio_complete(struct xbd_softc *sc, struct xbd_command *cm)
273e4808c4bSKip Macy {
274e4808c4bSKip Macy 	struct bio *bp;
275e4808c4bSKip Macy 
276*33eebb6aSJustin T. Gibbs 	bp = cm->cm_bp;
277e4808c4bSKip Macy 
278*33eebb6aSJustin T. Gibbs 	if (unlikely(cm->cm_status != BLKIF_RSP_OKAY)) {
279e4808c4bSKip Macy 		disk_err(bp, "disk error" , -1, 0);
280*33eebb6aSJustin T. Gibbs 		printf(" status: %x\n", cm->cm_status);
281e4808c4bSKip Macy 		bp->bio_flags |= BIO_ERROR;
282e4808c4bSKip Macy 	}
283e4808c4bSKip Macy 
284e4808c4bSKip Macy 	if (bp->bio_flags & BIO_ERROR)
285e4808c4bSKip Macy 		bp->bio_error = EIO;
286e4808c4bSKip Macy 	else
287e4808c4bSKip Macy 		bp->bio_resid = 0;
288e4808c4bSKip Macy 
289*33eebb6aSJustin T. Gibbs 	xbd_free_command(cm);
290e4808c4bSKip Macy 	biodone(bp);
291e4808c4bSKip Macy }
292e4808c4bSKip Macy 
2938698b76cSKip Macy // Quiesce the disk writes for a dump file before allowing the next buffer.
2948698b76cSKip Macy static void
295*33eebb6aSJustin T. Gibbs xbd_quiesce(struct xbd_softc *sc)
2968698b76cSKip Macy {
2978698b76cSKip Macy 	int mtd;
2988698b76cSKip Macy 
2998698b76cSKip Macy 	// While there are outstanding requests
300*33eebb6aSJustin T. Gibbs 	while (!TAILQ_EMPTY(&sc->xbd_cm_busy)) {
301*33eebb6aSJustin T. Gibbs 		RING_FINAL_CHECK_FOR_RESPONSES(&sc->xbd_ring, mtd);
3028698b76cSKip Macy 		if (mtd) {
303e4808c4bSKip Macy 			/* Recieved request completions, update queue. */
304*33eebb6aSJustin T. Gibbs 			xbd_int(sc);
3058698b76cSKip Macy 		}
306*33eebb6aSJustin T. Gibbs 		if (!TAILQ_EMPTY(&sc->xbd_cm_busy)) {
307e4808c4bSKip Macy 			/*
308e4808c4bSKip Macy 			 * Still pending requests, wait for the disk i/o
309e4808c4bSKip Macy 			 * to complete.
310e4808c4bSKip Macy 			 */
311be7747b4SKip Macy 			HYPERVISOR_yield();
3128698b76cSKip Macy 		}
3138698b76cSKip Macy 	}
3148698b76cSKip Macy }
3158698b76cSKip Macy 
316e4808c4bSKip Macy /* Kernel dump function for a paravirtualized disk device */
317e4808c4bSKip Macy static void
318*33eebb6aSJustin T. Gibbs xbd_dump_complete(struct xbd_command *cm)
319e4808c4bSKip Macy {
3208698b76cSKip Macy 
321*33eebb6aSJustin T. Gibbs 	xbd_enqueue_complete(cm);
322e4808c4bSKip Macy }
323e4808c4bSKip Macy 
3248698b76cSKip Macy static int
325*33eebb6aSJustin T. Gibbs xbd_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset,
3268698b76cSKip Macy     size_t length)
3278698b76cSKip Macy {
3288698b76cSKip Macy 	struct disk *dp = arg;
329*33eebb6aSJustin T. Gibbs 	struct xbd_softc *sc = dp->d_drv1;
330*33eebb6aSJustin T. Gibbs 	struct xbd_command *cm;
331e4808c4bSKip Macy 	size_t chunk;
332e4808c4bSKip Macy 	int sbp;
3338698b76cSKip Macy 	int rc = 0;
3348698b76cSKip Macy 
335e4808c4bSKip Macy 	if (length <= 0)
336e4808c4bSKip Macy 		return (rc);
3378698b76cSKip Macy 
338*33eebb6aSJustin T. Gibbs 	xbd_quiesce(sc);	/* All quiet on the western front. */
339e4808c4bSKip Macy 
340e4808c4bSKip Macy 	/*
341e4808c4bSKip Macy 	 * If this lock is held, then this module is failing, and a
342e4808c4bSKip Macy 	 * successful kernel dump is highly unlikely anyway.
343e4808c4bSKip Macy 	 */
344*33eebb6aSJustin T. Gibbs 	mtx_lock(&sc->xbd_io_lock);
345e4808c4bSKip Macy 
346e4808c4bSKip Macy 	/* Split the 64KB block as needed */
347e4808c4bSKip Macy 	for (sbp=0; length > 0; sbp++) {
348*33eebb6aSJustin T. Gibbs 		cm = xbd_dequeue_free(sc);
349e4808c4bSKip Macy 		if (cm == NULL) {
350*33eebb6aSJustin T. Gibbs 			mtx_unlock(&sc->xbd_io_lock);
351*33eebb6aSJustin T. Gibbs 			device_printf(sc->xbd_dev, "dump: no more commands?\n");
352e4808c4bSKip Macy 			return (EBUSY);
353e4808c4bSKip Macy 		}
354e4808c4bSKip Macy 
355*33eebb6aSJustin T. Gibbs 		if (gnttab_alloc_grant_references(sc->xbd_max_request_segments,
356*33eebb6aSJustin T. Gibbs 		    &cm->cm_gref_head) != 0) {
357*33eebb6aSJustin T. Gibbs 			xbd_free_command(cm);
358*33eebb6aSJustin T. Gibbs 			mtx_unlock(&sc->xbd_io_lock);
359*33eebb6aSJustin T. Gibbs 			device_printf(sc->xbd_dev, "no more grant allocs?\n");
360e4808c4bSKip Macy 			return (EBUSY);
361e4808c4bSKip Macy 		}
362e4808c4bSKip Macy 
363*33eebb6aSJustin T. Gibbs 		chunk = length > sc->xbd_max_request_size ?
364*33eebb6aSJustin T. Gibbs 		    sc->xbd_max_request_size : length;
365*33eebb6aSJustin T. Gibbs 		cm->cm_data = virtual;
366*33eebb6aSJustin T. Gibbs 		cm->cm_datalen = chunk;
367*33eebb6aSJustin T. Gibbs 		cm->cm_operation = BLKIF_OP_WRITE;
368*33eebb6aSJustin T. Gibbs 		cm->cm_sector_number = offset / dp->d_sectorsize;
369*33eebb6aSJustin T. Gibbs 		cm->cm_complete = xbd_dump_complete;
370e4808c4bSKip Macy 
371*33eebb6aSJustin T. Gibbs 		xbd_enqueue_ready(cm);
3728698b76cSKip Macy 
3738698b76cSKip Macy 		length -= chunk;
3748698b76cSKip Macy 		offset += chunk;
3758698b76cSKip Macy 		virtual = (char *) virtual + chunk;
3768698b76cSKip Macy 	}
3778698b76cSKip Macy 
378e4808c4bSKip Macy 	/* Tell DOM0 to do the I/O */
379*33eebb6aSJustin T. Gibbs 	xbd_startio(sc);
380*33eebb6aSJustin T. Gibbs 	mtx_unlock(&sc->xbd_io_lock);
381e4808c4bSKip Macy 
382e4808c4bSKip Macy 	/* Poll for the completion. */
383*33eebb6aSJustin T. Gibbs 	xbd_quiesce(sc);	/* All quite on the eastern front */
384e4808c4bSKip Macy 
385e4808c4bSKip Macy 	/* If there were any errors, bail out... */
386*33eebb6aSJustin T. Gibbs 	while ((cm = xbd_dequeue_complete(sc)) != NULL) {
387*33eebb6aSJustin T. Gibbs 		if (cm->cm_status != BLKIF_RSP_OKAY) {
388*33eebb6aSJustin T. Gibbs 			device_printf(sc->xbd_dev,
389e4808c4bSKip Macy 			    "Dump I/O failed at sector %jd\n",
390*33eebb6aSJustin T. Gibbs 			    cm->cm_sector_number);
391e4808c4bSKip Macy 			rc = EIO;
3928698b76cSKip Macy 		}
393*33eebb6aSJustin T. Gibbs 		xbd_free_command(cm);
3948698b76cSKip Macy 	}
395e4808c4bSKip Macy 
3968698b76cSKip Macy 	return (rc);
3978698b76cSKip Macy }
3988698b76cSKip Macy 
3998698b76cSKip Macy 
40023dc5621SKip Macy static int
401*33eebb6aSJustin T. Gibbs xbd_probe(device_t dev)
40289e0f4d2SKip Macy {
40323dc5621SKip Macy 
40423dc5621SKip Macy 	if (!strcmp(xenbus_get_type(dev), "vbd")) {
40523dc5621SKip Macy 		device_set_desc(dev, "Virtual Block Device");
40623dc5621SKip Macy 		device_quiet(dev);
40723dc5621SKip Macy 		return (0);
40823dc5621SKip Macy 	}
40923dc5621SKip Macy 
41023dc5621SKip Macy 	return (ENXIO);
41123dc5621SKip Macy }
41223dc5621SKip Macy 
4138b8bfa35SJustin T. Gibbs static void
414*33eebb6aSJustin T. Gibbs xbd_setup_sysctl(struct xbd_softc *xbd)
4158b8bfa35SJustin T. Gibbs {
4168b8bfa35SJustin T. Gibbs 	struct sysctl_ctx_list *sysctl_ctx = NULL;
4178b8bfa35SJustin T. Gibbs 	struct sysctl_oid *sysctl_tree = NULL;
4188b8bfa35SJustin T. Gibbs 
419*33eebb6aSJustin T. Gibbs 	sysctl_ctx = device_get_sysctl_ctx(xbd->xbd_dev);
4208b8bfa35SJustin T. Gibbs 	if (sysctl_ctx == NULL)
4218b8bfa35SJustin T. Gibbs 		return;
4228b8bfa35SJustin T. Gibbs 
423*33eebb6aSJustin T. Gibbs 	sysctl_tree = device_get_sysctl_tree(xbd->xbd_dev);
4248b8bfa35SJustin T. Gibbs 	if (sysctl_tree == NULL)
4258b8bfa35SJustin T. Gibbs 		return;
4268b8bfa35SJustin T. Gibbs 
4278b8bfa35SJustin T. Gibbs 	SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
428*33eebb6aSJustin T. Gibbs 	    "max_requests", CTLFLAG_RD, &xbd->xbd_max_requests, -1,
4298b8bfa35SJustin T. Gibbs 	    "maximum outstanding requests (negotiated)");
4308b8bfa35SJustin T. Gibbs 
4318b8bfa35SJustin T. Gibbs 	SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
4328b8bfa35SJustin T. Gibbs 	    "max_request_segments", CTLFLAG_RD,
433*33eebb6aSJustin T. Gibbs 	    &xbd->xbd_max_request_segments, 0,
4348b8bfa35SJustin T. Gibbs 	    "maximum number of pages per requests (negotiated)");
4358b8bfa35SJustin T. Gibbs 
4368b8bfa35SJustin T. Gibbs 	SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
437*33eebb6aSJustin T. Gibbs 	    "max_request_size", CTLFLAG_RD, &xbd->xbd_max_request_size, 0,
4388b8bfa35SJustin T. Gibbs 	    "maximum size in bytes of a request (negotiated)");
4398b8bfa35SJustin T. Gibbs 
4408b8bfa35SJustin T. Gibbs 	SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
441*33eebb6aSJustin T. Gibbs 	    "ring_pages", CTLFLAG_RD, &xbd->xbd_ring_pages, 0,
4428b8bfa35SJustin T. Gibbs 	    "communication channel pages (negotiated)");
4438b8bfa35SJustin T. Gibbs }
4448b8bfa35SJustin T. Gibbs 
44523dc5621SKip Macy /*
44623dc5621SKip Macy  * Setup supplies the backend dir, virtual device.  We place an event
44723dc5621SKip Macy  * channel and shared frame entries.  We watch backend to wait if it's
44823dc5621SKip Macy  * ok.
44923dc5621SKip Macy  */
45023dc5621SKip Macy static int
451*33eebb6aSJustin T. Gibbs xbd_attach(device_t dev)
45223dc5621SKip Macy {
453*33eebb6aSJustin T. Gibbs 	struct xbd_softc *sc;
45423dc5621SKip Macy 	const char *name;
4558b8bfa35SJustin T. Gibbs 	uint32_t vdevice;
456ff662b5cSJustin T. Gibbs 	int error;
457ff662b5cSJustin T. Gibbs 	int i;
458ff662b5cSJustin T. Gibbs 	int unit;
45989e0f4d2SKip Macy 
46089e0f4d2SKip Macy 	/* FIXME: Use dynamic device id if this is not set. */
461ff662b5cSJustin T. Gibbs 	error = xs_scanf(XST_NIL, xenbus_get_node(dev),
4628b8bfa35SJustin T. Gibbs 	    "virtual-device", NULL, "%" PRIu32, &vdevice);
46312678024SDoug Rabson 	if (error) {
46412678024SDoug Rabson 		xenbus_dev_fatal(dev, error, "reading virtual-device");
465ff662b5cSJustin T. Gibbs 		device_printf(dev, "Couldn't determine virtual device.\n");
46612678024SDoug Rabson 		return (error);
46789e0f4d2SKip Macy 	}
46889e0f4d2SKip Macy 
469*33eebb6aSJustin T. Gibbs 	xbd_vdevice_to_unit(vdevice, &unit, &name);
47023dc5621SKip Macy 	if (!strcmp(name, "xbd"))
47123dc5621SKip Macy 		device_set_unit(dev, unit);
47223dc5621SKip Macy 
473e4808c4bSKip Macy 	sc = device_get_softc(dev);
474*33eebb6aSJustin T. Gibbs 	mtx_init(&sc->xbd_io_lock, "blkfront i/o lock", NULL, MTX_DEF);
475*33eebb6aSJustin T. Gibbs 	xbd_initq_free(sc);
476*33eebb6aSJustin T. Gibbs 	xbd_initq_busy(sc);
477*33eebb6aSJustin T. Gibbs 	xbd_initq_ready(sc);
478*33eebb6aSJustin T. Gibbs 	xbd_initq_complete(sc);
479*33eebb6aSJustin T. Gibbs 	xbd_initq_bio(sc);
480*33eebb6aSJustin T. Gibbs 	for (i = 0; i < XBD_MAX_RING_PAGES; i++)
481*33eebb6aSJustin T. Gibbs 		sc->xbd_ring_ref[i] = GRANT_INVALID_REF;
48289e0f4d2SKip Macy 
483*33eebb6aSJustin T. Gibbs 	sc->xbd_dev = dev;
484*33eebb6aSJustin T. Gibbs 	sc->xbd_vdevice = vdevice;
485*33eebb6aSJustin T. Gibbs 	sc->xbd_connected = XBD_STATE_DISCONNECTED;
48689e0f4d2SKip Macy 
487*33eebb6aSJustin T. Gibbs 	xbd_setup_sysctl(sc);
4888b8bfa35SJustin T. Gibbs 
489ff662b5cSJustin T. Gibbs 	/* Wait for backend device to publish its protocol capabilities. */
490ff662b5cSJustin T. Gibbs 	xenbus_set_state(dev, XenbusStateInitialising);
49112678024SDoug Rabson 
49212678024SDoug Rabson 	return (0);
49312678024SDoug Rabson }
49412678024SDoug Rabson 
49512678024SDoug Rabson static int
496*33eebb6aSJustin T. Gibbs xbd_suspend(device_t dev)
49712678024SDoug Rabson {
498*33eebb6aSJustin T. Gibbs 	struct xbd_softc *sc = device_get_softc(dev);
49906a630f6SJustin T. Gibbs 	int retval;
50006a630f6SJustin T. Gibbs 	int saved_state;
50112678024SDoug Rabson 
50212678024SDoug Rabson 	/* Prevent new requests being issued until we fix things up. */
503*33eebb6aSJustin T. Gibbs 	mtx_lock(&sc->xbd_io_lock);
504*33eebb6aSJustin T. Gibbs 	saved_state = sc->xbd_connected;
505*33eebb6aSJustin T. Gibbs 	sc->xbd_connected = XBD_STATE_SUSPENDED;
50606a630f6SJustin T. Gibbs 
50706a630f6SJustin T. Gibbs 	/* Wait for outstanding I/O to drain. */
50806a630f6SJustin T. Gibbs 	retval = 0;
509*33eebb6aSJustin T. Gibbs 	while (TAILQ_EMPTY(&sc->xbd_cm_busy) == 0) {
510*33eebb6aSJustin T. Gibbs 		if (msleep(&sc->xbd_cm_busy, &sc->xbd_io_lock,
51106a630f6SJustin T. Gibbs 		    PRIBIO, "blkf_susp", 30 * hz) == EWOULDBLOCK) {
51206a630f6SJustin T. Gibbs 			retval = EBUSY;
51306a630f6SJustin T. Gibbs 			break;
51406a630f6SJustin T. Gibbs 		}
51506a630f6SJustin T. Gibbs 	}
516*33eebb6aSJustin T. Gibbs 	mtx_unlock(&sc->xbd_io_lock);
51789e0f4d2SKip Macy 
51806a630f6SJustin T. Gibbs 	if (retval != 0)
519*33eebb6aSJustin T. Gibbs 		sc->xbd_connected = saved_state;
52006a630f6SJustin T. Gibbs 
52106a630f6SJustin T. Gibbs 	return (retval);
52289e0f4d2SKip Macy }
52389e0f4d2SKip Macy 
52423dc5621SKip Macy static int
525*33eebb6aSJustin T. Gibbs xbd_resume(device_t dev)
52689e0f4d2SKip Macy {
527*33eebb6aSJustin T. Gibbs 	struct xbd_softc *sc = device_get_softc(dev);
52889e0f4d2SKip Macy 
529*33eebb6aSJustin T. Gibbs 	DPRINTK("xbd_resume: %s\n", xenbus_get_node(dev));
53089e0f4d2SKip Macy 
531*33eebb6aSJustin T. Gibbs 	xbd_free(sc);
532*33eebb6aSJustin T. Gibbs 	xbd_initialize(sc);
533ff662b5cSJustin T. Gibbs 	return (0);
53489e0f4d2SKip Macy }
53589e0f4d2SKip Macy 
536ff662b5cSJustin T. Gibbs static void
537*33eebb6aSJustin T. Gibbs xbd_initialize(struct xbd_softc *sc)
53889e0f4d2SKip Macy {
539ff662b5cSJustin T. Gibbs 	const char *otherend_path;
540ff662b5cSJustin T. Gibbs 	const char *node_path;
5418b8bfa35SJustin T. Gibbs 	uint32_t max_ring_page_order;
542ff662b5cSJustin T. Gibbs 	int error;
543ff662b5cSJustin T. Gibbs 	int i;
54489e0f4d2SKip Macy 
545*33eebb6aSJustin T. Gibbs 	if (xenbus_get_state(sc->xbd_dev) != XenbusStateInitialising) {
54606a630f6SJustin T. Gibbs 		/* Initialization has already been performed. */
547ff662b5cSJustin T. Gibbs 		return;
54806a630f6SJustin T. Gibbs 	}
54989e0f4d2SKip Macy 
550ff662b5cSJustin T. Gibbs 	/*
551ff662b5cSJustin T. Gibbs 	 * Protocol defaults valid even if negotiation for a
552ff662b5cSJustin T. Gibbs 	 * setting fails.
553ff662b5cSJustin T. Gibbs 	 */
5548b8bfa35SJustin T. Gibbs 	max_ring_page_order = 0;
555*33eebb6aSJustin T. Gibbs 	sc->xbd_ring_pages = 1;
556*33eebb6aSJustin T. Gibbs 	sc->xbd_max_request_segments = BLKIF_MAX_SEGMENTS_PER_HEADER_BLOCK;
557*33eebb6aSJustin T. Gibbs 	sc->xbd_max_request_size =
558*33eebb6aSJustin T. Gibbs 	    XBD_SEGS_TO_SIZE(sc->xbd_max_request_segments);
559*33eebb6aSJustin T. Gibbs 	sc->xbd_max_request_blocks =
560*33eebb6aSJustin T. Gibbs 	    BLKIF_SEGS_TO_BLOCKS(sc->xbd_max_request_segments);
561ff662b5cSJustin T. Gibbs 
562ff662b5cSJustin T. Gibbs 	/*
563ff662b5cSJustin T. Gibbs 	 * Protocol negotiation.
564ff662b5cSJustin T. Gibbs 	 *
565ff662b5cSJustin T. Gibbs 	 * \note xs_gather() returns on the first encountered error, so
566ff662b5cSJustin T. Gibbs 	 *       we must use independant calls in order to guarantee
567ff662b5cSJustin T. Gibbs 	 *       we don't miss information in a sparsly populated back-end
568ff662b5cSJustin T. Gibbs 	 *       tree.
5698b8bfa35SJustin T. Gibbs 	 *
5708b8bfa35SJustin T. Gibbs 	 * \note xs_scanf() does not update variables for unmatched
5718b8bfa35SJustin T. Gibbs 	 *	 fields.
572ff662b5cSJustin T. Gibbs 	 */
573*33eebb6aSJustin T. Gibbs 	otherend_path = xenbus_get_otherend_path(sc->xbd_dev);
574*33eebb6aSJustin T. Gibbs 	node_path = xenbus_get_node(sc->xbd_dev);
5758b8bfa35SJustin T. Gibbs 
5768b8bfa35SJustin T. Gibbs 	/* Support both backend schemes for relaying ring page limits. */
5778b8bfa35SJustin T. Gibbs 	(void)xs_scanf(XST_NIL, otherend_path,
5788b8bfa35SJustin T. Gibbs 	    "max-ring-page-order", NULL, "%" PRIu32,
5798b8bfa35SJustin T. Gibbs 	    &max_ring_page_order);
580*33eebb6aSJustin T. Gibbs 	sc->xbd_ring_pages = 1 << max_ring_page_order;
581ff662b5cSJustin T. Gibbs 	(void)xs_scanf(XST_NIL, otherend_path,
582ff662b5cSJustin T. Gibbs 	    "max-ring-pages", NULL, "%" PRIu32,
583*33eebb6aSJustin T. Gibbs 	    &sc->xbd_ring_pages);
584*33eebb6aSJustin T. Gibbs 	if (sc->xbd_ring_pages < 1)
585*33eebb6aSJustin T. Gibbs 		sc->xbd_ring_pages = 1;
586ff662b5cSJustin T. Gibbs 
587*33eebb6aSJustin T. Gibbs 	sc->xbd_max_requests =
588*33eebb6aSJustin T. Gibbs 	    BLKIF_MAX_RING_REQUESTS(sc->xbd_ring_pages * PAGE_SIZE);
589ff662b5cSJustin T. Gibbs 	(void)xs_scanf(XST_NIL, otherend_path,
590ff662b5cSJustin T. Gibbs 	    "max-requests", NULL, "%" PRIu32,
591*33eebb6aSJustin T. Gibbs 	    &sc->xbd_max_requests);
592ff662b5cSJustin T. Gibbs 
593ff662b5cSJustin T. Gibbs 	(void)xs_scanf(XST_NIL, otherend_path,
594ff662b5cSJustin T. Gibbs 	    "max-request-segments", NULL, "%" PRIu32,
595*33eebb6aSJustin T. Gibbs 	    &sc->xbd_max_request_segments);
596ff662b5cSJustin T. Gibbs 
597ff662b5cSJustin T. Gibbs 	(void)xs_scanf(XST_NIL, otherend_path,
598ff662b5cSJustin T. Gibbs 	    "max-request-size", NULL, "%" PRIu32,
599*33eebb6aSJustin T. Gibbs 	    &sc->xbd_max_request_size);
600ff662b5cSJustin T. Gibbs 
601*33eebb6aSJustin T. Gibbs 	if (sc->xbd_ring_pages > XBD_MAX_RING_PAGES) {
602*33eebb6aSJustin T. Gibbs 		device_printf(sc->xbd_dev,
603*33eebb6aSJustin T. Gibbs 		    "Back-end specified ring-pages of %u "
604*33eebb6aSJustin T. Gibbs 		    "limited to front-end limit of %zu.\n",
605*33eebb6aSJustin T. Gibbs 		    sc->xbd_ring_pages, XBD_MAX_RING_PAGES);
606*33eebb6aSJustin T. Gibbs 		sc->xbd_ring_pages = XBD_MAX_RING_PAGES;
60789e0f4d2SKip Macy 	}
60889e0f4d2SKip Macy 
609*33eebb6aSJustin T. Gibbs 	if (powerof2(sc->xbd_ring_pages) == 0) {
6108b8bfa35SJustin T. Gibbs 		uint32_t new_page_limit;
6118b8bfa35SJustin T. Gibbs 
612*33eebb6aSJustin T. Gibbs 		new_page_limit = 0x01 << (fls(sc->xbd_ring_pages) - 1);
613*33eebb6aSJustin T. Gibbs 		device_printf(sc->xbd_dev,
614*33eebb6aSJustin T. Gibbs 		    "Back-end specified ring-pages of %u "
615*33eebb6aSJustin T. Gibbs 		    "is not a power of 2. Limited to %u.\n",
616*33eebb6aSJustin T. Gibbs 		    sc->xbd_ring_pages, new_page_limit);
617*33eebb6aSJustin T. Gibbs 		sc->xbd_ring_pages = new_page_limit;
6188b8bfa35SJustin T. Gibbs 	}
6198b8bfa35SJustin T. Gibbs 
620*33eebb6aSJustin T. Gibbs 	if (sc->xbd_max_requests > XBD_MAX_REQUESTS) {
621*33eebb6aSJustin T. Gibbs 		device_printf(sc->xbd_dev,
622*33eebb6aSJustin T. Gibbs 		    "Back-end specified max_requests of %u "
623*33eebb6aSJustin T. Gibbs 		    "limited to front-end limit of %u.\n",
624*33eebb6aSJustin T. Gibbs 		    sc->xbd_max_requests, XBD_MAX_REQUESTS);
625*33eebb6aSJustin T. Gibbs 		sc->xbd_max_requests = XBD_MAX_REQUESTS;
62689e0f4d2SKip Macy 	}
627ff662b5cSJustin T. Gibbs 
628*33eebb6aSJustin T. Gibbs 	if (sc->xbd_max_request_segments > XBD_MAX_SEGMENTS_PER_REQUEST) {
629*33eebb6aSJustin T. Gibbs 		device_printf(sc->xbd_dev,
630*33eebb6aSJustin T. Gibbs 		    "Back-end specified max_request_segments of %u "
631*33eebb6aSJustin T. Gibbs 		    "limited to front-end limit of %u.\n",
632*33eebb6aSJustin T. Gibbs 		    sc->xbd_max_request_segments,
633*33eebb6aSJustin T. Gibbs 		    XBD_MAX_SEGMENTS_PER_REQUEST);
634*33eebb6aSJustin T. Gibbs 		sc->xbd_max_request_segments = XBD_MAX_SEGMENTS_PER_REQUEST;
63589e0f4d2SKip Macy 	}
636ff662b5cSJustin T. Gibbs 
637*33eebb6aSJustin T. Gibbs 	if (sc->xbd_max_request_size > XBD_MAX_REQUEST_SIZE) {
638*33eebb6aSJustin T. Gibbs 		device_printf(sc->xbd_dev,
639*33eebb6aSJustin T. Gibbs 		    "Back-end specified max_request_size of %u "
640*33eebb6aSJustin T. Gibbs 		    "limited to front-end limit of %u.\n",
641*33eebb6aSJustin T. Gibbs 		    sc->xbd_max_request_size,
642*33eebb6aSJustin T. Gibbs 		    XBD_MAX_REQUEST_SIZE);
643*33eebb6aSJustin T. Gibbs 		sc->xbd_max_request_size = XBD_MAX_REQUEST_SIZE;
644ff662b5cSJustin T. Gibbs 	}
645443cc4d4SJustin T. Gibbs 
646*33eebb6aSJustin T. Gibbs  	if (sc->xbd_max_request_size >
647*33eebb6aSJustin T. Gibbs 	    XBD_SEGS_TO_SIZE(sc->xbd_max_request_segments)) {
648*33eebb6aSJustin T. Gibbs  		device_printf(sc->xbd_dev,
649*33eebb6aSJustin T. Gibbs 		    "Back-end specified max_request_size of %u "
650*33eebb6aSJustin T. Gibbs 		    "limited to front-end limit of %u.  (Too few segments.)\n",
651*33eebb6aSJustin T. Gibbs 		    sc->xbd_max_request_size,
652*33eebb6aSJustin T. Gibbs 		    XBD_SEGS_TO_SIZE(sc->xbd_max_request_segments));
653*33eebb6aSJustin T. Gibbs  		sc->xbd_max_request_size =
654*33eebb6aSJustin T. Gibbs  		    XBD_SEGS_TO_SIZE(sc->xbd_max_request_segments);
655443cc4d4SJustin T. Gibbs  	}
656443cc4d4SJustin T. Gibbs 
657*33eebb6aSJustin T. Gibbs 	sc->xbd_max_request_blocks =
658*33eebb6aSJustin T. Gibbs 	    BLKIF_SEGS_TO_BLOCKS(sc->xbd_max_request_segments);
659ff662b5cSJustin T. Gibbs 
660ff662b5cSJustin T. Gibbs 	/* Allocate datastructures based on negotiated values. */
661*33eebb6aSJustin T. Gibbs 	error = bus_dma_tag_create(
662*33eebb6aSJustin T. Gibbs 	    bus_get_dma_tag(sc->xbd_dev),	/* parent */
663ff662b5cSJustin T. Gibbs 	    512, PAGE_SIZE,			/* algnmnt, boundary */
664ff662b5cSJustin T. Gibbs 	    BUS_SPACE_MAXADDR,			/* lowaddr */
665ff662b5cSJustin T. Gibbs 	    BUS_SPACE_MAXADDR,			/* highaddr */
666ff662b5cSJustin T. Gibbs 	    NULL, NULL,				/* filter, filterarg */
667*33eebb6aSJustin T. Gibbs 	    sc->xbd_max_request_size,
668*33eebb6aSJustin T. Gibbs 	    sc->xbd_max_request_segments,
669ff662b5cSJustin T. Gibbs 	    PAGE_SIZE,				/* maxsegsize */
670ff662b5cSJustin T. Gibbs 	    BUS_DMA_ALLOCNOW,			/* flags */
671ff662b5cSJustin T. Gibbs 	    busdma_lock_mutex,			/* lockfunc */
672*33eebb6aSJustin T. Gibbs 	    &sc->xbd_io_lock,			/* lockarg */
673*33eebb6aSJustin T. Gibbs 	    &sc->xbd_io_dmat);
674ff662b5cSJustin T. Gibbs 	if (error != 0) {
675*33eebb6aSJustin T. Gibbs 		xenbus_dev_fatal(sc->xbd_dev, error,
676ff662b5cSJustin T. Gibbs 		    "Cannot allocate parent DMA tag\n");
677ff662b5cSJustin T. Gibbs 		return;
678ff662b5cSJustin T. Gibbs 	}
679ff662b5cSJustin T. Gibbs 
680ff662b5cSJustin T. Gibbs 	/* Per-transaction data allocation. */
681*33eebb6aSJustin T. Gibbs 	sc->xbd_shadow = malloc(sizeof(*sc->xbd_shadow) * sc->xbd_max_requests,
682ff662b5cSJustin T. Gibbs 	    M_XENBLOCKFRONT, M_NOWAIT|M_ZERO);
683*33eebb6aSJustin T. Gibbs 	if (sc->xbd_shadow == NULL) {
684*33eebb6aSJustin T. Gibbs 		bus_dma_tag_destroy(sc->xbd_io_dmat);
685*33eebb6aSJustin T. Gibbs 		xenbus_dev_fatal(sc->xbd_dev, error,
686ff662b5cSJustin T. Gibbs 		    "Cannot allocate request structures\n");
68706a630f6SJustin T. Gibbs 		return;
688ff662b5cSJustin T. Gibbs 	}
689ff662b5cSJustin T. Gibbs 
690*33eebb6aSJustin T. Gibbs 	for (i = 0; i < sc->xbd_max_requests; i++) {
691*33eebb6aSJustin T. Gibbs 		struct xbd_command *cm;
692ff662b5cSJustin T. Gibbs 
693*33eebb6aSJustin T. Gibbs 		cm = &sc->xbd_shadow[i];
694*33eebb6aSJustin T. Gibbs 		cm->cm_sg_refs = malloc(
695*33eebb6aSJustin T. Gibbs 		    sizeof(grant_ref_t) * sc->xbd_max_request_segments,
696ff662b5cSJustin T. Gibbs 		    M_XENBLOCKFRONT, M_NOWAIT);
697*33eebb6aSJustin T. Gibbs 		if (cm->cm_sg_refs == NULL)
698ff662b5cSJustin T. Gibbs 			break;
699*33eebb6aSJustin T. Gibbs 		cm->cm_id = i;
700ff662b5cSJustin T. Gibbs 		cm->cm_sc = sc;
701*33eebb6aSJustin T. Gibbs 		if (bus_dmamap_create(sc->xbd_io_dmat, 0, &cm->cm_map) != 0)
702ff662b5cSJustin T. Gibbs 			break;
703*33eebb6aSJustin T. Gibbs 		xbd_free_command(cm);
704ff662b5cSJustin T. Gibbs 	}
705ff662b5cSJustin T. Gibbs 
706*33eebb6aSJustin T. Gibbs 	if (xbd_setup_ring(sc) != 0)
707ff662b5cSJustin T. Gibbs 		return;
708ff662b5cSJustin T. Gibbs 
7098b8bfa35SJustin T. Gibbs 	/* Support both backend schemes for relaying ring page limits. */
710*33eebb6aSJustin T. Gibbs 	if (sc->xbd_ring_pages > 1) {
711ff662b5cSJustin T. Gibbs 		error = xs_printf(XST_NIL, node_path,
712*33eebb6aSJustin T. Gibbs 		    "num-ring-pages","%u",
713*33eebb6aSJustin T. Gibbs 		    sc->xbd_ring_pages);
714ff662b5cSJustin T. Gibbs 		if (error) {
715*33eebb6aSJustin T. Gibbs 			xenbus_dev_fatal(sc->xbd_dev, error,
7168b8bfa35SJustin T. Gibbs 			    "writing %s/num-ring-pages",
7178b8bfa35SJustin T. Gibbs 			    node_path);
7188b8bfa35SJustin T. Gibbs 			return;
7198b8bfa35SJustin T. Gibbs 		}
7200d172324SJustin T. Gibbs 
7218b8bfa35SJustin T. Gibbs 		error = xs_printf(XST_NIL, node_path,
7220d172324SJustin T. Gibbs 		    "ring-page-order", "%u",
723*33eebb6aSJustin T. Gibbs 		    fls(sc->xbd_ring_pages) - 1);
7248b8bfa35SJustin T. Gibbs 		if (error) {
725*33eebb6aSJustin T. Gibbs 			xenbus_dev_fatal(sc->xbd_dev, error,
7268b8bfa35SJustin T. Gibbs 			    "writing %s/ring-page-order",
727ff662b5cSJustin T. Gibbs 			    node_path);
728ff662b5cSJustin T. Gibbs 			return;
729ff662b5cSJustin T. Gibbs 		}
7300d172324SJustin T. Gibbs 	}
731ff662b5cSJustin T. Gibbs 
732ff662b5cSJustin T. Gibbs 	error = xs_printf(XST_NIL, node_path,
733*33eebb6aSJustin T. Gibbs 	    "max-requests","%u",
734*33eebb6aSJustin T. Gibbs 	    sc->xbd_max_requests);
735ff662b5cSJustin T. Gibbs 	if (error) {
736*33eebb6aSJustin T. Gibbs 		xenbus_dev_fatal(sc->xbd_dev, error,
737ff662b5cSJustin T. Gibbs 		    "writing %s/max-requests",
738ff662b5cSJustin T. Gibbs 		    node_path);
739ff662b5cSJustin T. Gibbs 		return;
740ff662b5cSJustin T. Gibbs 	}
741ff662b5cSJustin T. Gibbs 
742ff662b5cSJustin T. Gibbs 	error = xs_printf(XST_NIL, node_path,
743*33eebb6aSJustin T. Gibbs 	    "max-request-segments","%u",
744*33eebb6aSJustin T. Gibbs 	    sc->xbd_max_request_segments);
745ff662b5cSJustin T. Gibbs 	if (error) {
746*33eebb6aSJustin T. Gibbs 		xenbus_dev_fatal(sc->xbd_dev, error,
747ff662b5cSJustin T. Gibbs 		    "writing %s/max-request-segments",
748ff662b5cSJustin T. Gibbs 		    node_path);
749ff662b5cSJustin T. Gibbs 		return;
750ff662b5cSJustin T. Gibbs 	}
751ff662b5cSJustin T. Gibbs 
752ff662b5cSJustin T. Gibbs 	error = xs_printf(XST_NIL, node_path,
753*33eebb6aSJustin T. Gibbs 	    "max-request-size","%u",
754*33eebb6aSJustin T. Gibbs 	    sc->xbd_max_request_size);
755ff662b5cSJustin T. Gibbs 	if (error) {
756*33eebb6aSJustin T. Gibbs 		xenbus_dev_fatal(sc->xbd_dev, error,
757ff662b5cSJustin T. Gibbs 		    "writing %s/max-request-size",
758ff662b5cSJustin T. Gibbs 		    node_path);
759ff662b5cSJustin T. Gibbs 		return;
760ff662b5cSJustin T. Gibbs 	}
761ff662b5cSJustin T. Gibbs 
762ff662b5cSJustin T. Gibbs 	error = xs_printf(XST_NIL, node_path, "event-channel",
763*33eebb6aSJustin T. Gibbs 	    "%u", irq_to_evtchn_port(sc->xbd_irq));
764ff662b5cSJustin T. Gibbs 	if (error) {
765*33eebb6aSJustin T. Gibbs 		xenbus_dev_fatal(sc->xbd_dev, error,
766ff662b5cSJustin T. Gibbs 		    "writing %s/event-channel",
767ff662b5cSJustin T. Gibbs 		    node_path);
768ff662b5cSJustin T. Gibbs 		return;
769ff662b5cSJustin T. Gibbs 	}
770ff662b5cSJustin T. Gibbs 
771*33eebb6aSJustin T. Gibbs 	error = xs_printf(XST_NIL, node_path, "protocol",
772*33eebb6aSJustin T. Gibbs 	    "%s", XEN_IO_PROTO_ABI_NATIVE);
773ff662b5cSJustin T. Gibbs 	if (error) {
774*33eebb6aSJustin T. Gibbs 		xenbus_dev_fatal(sc->xbd_dev, error,
775ff662b5cSJustin T. Gibbs 		    "writing %s/protocol",
776ff662b5cSJustin T. Gibbs 		    node_path);
777ff662b5cSJustin T. Gibbs 		return;
77823dc5621SKip Macy 	}
77912678024SDoug Rabson 
780*33eebb6aSJustin T. Gibbs 	xenbus_set_state(sc->xbd_dev, XenbusStateInitialised);
78189e0f4d2SKip Macy }
78289e0f4d2SKip Macy 
78389e0f4d2SKip Macy static int
784*33eebb6aSJustin T. Gibbs xbd_setup_ring(struct xbd_softc *sc)
78589e0f4d2SKip Macy {
78689e0f4d2SKip Macy 	blkif_sring_t *sring;
787ff662b5cSJustin T. Gibbs 	uintptr_t sring_page_addr;
7883a6d1fcfSKip Macy 	int error;
789ff662b5cSJustin T. Gibbs 	int i;
79089e0f4d2SKip Macy 
791*33eebb6aSJustin T. Gibbs 	sring = malloc(sc->xbd_ring_pages * PAGE_SIZE, M_XENBLOCKFRONT,
792ff662b5cSJustin T. Gibbs 	    M_NOWAIT|M_ZERO);
79389e0f4d2SKip Macy 	if (sring == NULL) {
794*33eebb6aSJustin T. Gibbs 		xenbus_dev_fatal(sc->xbd_dev, ENOMEM, "allocating shared ring");
795ff662b5cSJustin T. Gibbs 		return (ENOMEM);
79689e0f4d2SKip Macy 	}
79789e0f4d2SKip Macy 	SHARED_RING_INIT(sring);
798*33eebb6aSJustin T. Gibbs 	FRONT_RING_INIT(&sc->xbd_ring, sring, sc->xbd_ring_pages * PAGE_SIZE);
799ff662b5cSJustin T. Gibbs 
800ff662b5cSJustin T. Gibbs 	for (i = 0, sring_page_addr = (uintptr_t)sring;
801*33eebb6aSJustin T. Gibbs 	     i < sc->xbd_ring_pages;
802ff662b5cSJustin T. Gibbs 	     i++, sring_page_addr += PAGE_SIZE) {
80389e0f4d2SKip Macy 
804*33eebb6aSJustin T. Gibbs 		error = xenbus_grant_ring(sc->xbd_dev,
805*33eebb6aSJustin T. Gibbs 		    (vtomach(sring_page_addr) >> PAGE_SHIFT),
806*33eebb6aSJustin T. Gibbs 		    &sc->xbd_ring_ref[i]);
8073a6d1fcfSKip Macy 		if (error) {
808*33eebb6aSJustin T. Gibbs 			xenbus_dev_fatal(sc->xbd_dev, error,
809ff662b5cSJustin T. Gibbs 			    "granting ring_ref(%d)", i);
810ff662b5cSJustin T. Gibbs 			return (error);
811ff662b5cSJustin T. Gibbs 		}
812ff662b5cSJustin T. Gibbs 	}
813*33eebb6aSJustin T. Gibbs 	if (sc->xbd_ring_pages == 1) {
814*33eebb6aSJustin T. Gibbs 		error = xs_printf(XST_NIL, xenbus_get_node(sc->xbd_dev),
815*33eebb6aSJustin T. Gibbs 		    "ring-ref", "%u", sc->xbd_ring_ref[0]);
816ff662b5cSJustin T. Gibbs 		if (error) {
817*33eebb6aSJustin T. Gibbs 			xenbus_dev_fatal(sc->xbd_dev, error,
8188b8bfa35SJustin T. Gibbs 			    "writing %s/ring-ref",
819*33eebb6aSJustin T. Gibbs 			    xenbus_get_node(sc->xbd_dev));
820ff662b5cSJustin T. Gibbs 			return (error);
821ff662b5cSJustin T. Gibbs 		}
8228b8bfa35SJustin T. Gibbs 	} else {
823*33eebb6aSJustin T. Gibbs 		for (i = 0; i < sc->xbd_ring_pages; i++) {
824ff662b5cSJustin T. Gibbs 			char ring_ref_name[]= "ring_refXX";
825ff662b5cSJustin T. Gibbs 
8268b8bfa35SJustin T. Gibbs 			snprintf(ring_ref_name, sizeof(ring_ref_name),
8278b8bfa35SJustin T. Gibbs 			    "ring-ref%u", i);
828*33eebb6aSJustin T. Gibbs 			error = xs_printf(XST_NIL, xenbus_get_node(sc->xbd_dev),
829*33eebb6aSJustin T. Gibbs 			     ring_ref_name, "%u", sc->xbd_ring_ref[i]);
830ff662b5cSJustin T. Gibbs 			if (error) {
831*33eebb6aSJustin T. Gibbs 				xenbus_dev_fatal(sc->xbd_dev, error,
8328b8bfa35SJustin T. Gibbs 				    "writing %s/%s",
833*33eebb6aSJustin T. Gibbs 				    xenbus_get_node(sc->xbd_dev),
834ff662b5cSJustin T. Gibbs 				    ring_ref_name);
835ff662b5cSJustin T. Gibbs 				return (error);
836ff662b5cSJustin T. Gibbs 			}
83789e0f4d2SKip Macy 		}
8388b8bfa35SJustin T. Gibbs 	}
83989e0f4d2SKip Macy 
840ff662b5cSJustin T. Gibbs 	error = bind_listening_port_to_irqhandler(
841*33eebb6aSJustin T. Gibbs 	    xenbus_get_otherend_id(sc->xbd_dev),
842*33eebb6aSJustin T. Gibbs 	    "xbd", (driver_intr_t *)xbd_int, sc,
843*33eebb6aSJustin T. Gibbs 	    INTR_TYPE_BIO | INTR_MPSAFE, &sc->xbd_irq);
8443a6d1fcfSKip Macy 	if (error) {
845*33eebb6aSJustin T. Gibbs 		xenbus_dev_fatal(sc->xbd_dev, error,
84689e0f4d2SKip Macy 		    "bind_evtchn_to_irqhandler failed");
8473a6d1fcfSKip Macy 		return (error);
84889e0f4d2SKip Macy 	}
84989e0f4d2SKip Macy 
850ff662b5cSJustin T. Gibbs 	return (0);
851ff662b5cSJustin T. Gibbs }
85289e0f4d2SKip Macy 
85389e0f4d2SKip Macy /**
85489e0f4d2SKip Macy  * Callback received when the backend's state changes.
85589e0f4d2SKip Macy  */
856283d6f72SJustin T. Gibbs static void
857*33eebb6aSJustin T. Gibbs xbd_backend_changed(device_t dev, XenbusState backend_state)
85889e0f4d2SKip Macy {
859*33eebb6aSJustin T. Gibbs 	struct xbd_softc *sc = device_get_softc(dev);
86089e0f4d2SKip Macy 
86112678024SDoug Rabson 	DPRINTK("backend_state=%d\n", backend_state);
86289e0f4d2SKip Macy 
86389e0f4d2SKip Macy 	switch (backend_state) {
86489e0f4d2SKip Macy 	case XenbusStateUnknown:
86589e0f4d2SKip Macy 	case XenbusStateInitialising:
866920ba15bSKip Macy 	case XenbusStateReconfigured:
867920ba15bSKip Macy 	case XenbusStateReconfiguring:
868ff662b5cSJustin T. Gibbs 	case XenbusStateClosed:
86989e0f4d2SKip Macy 		break;
87089e0f4d2SKip Macy 
871ff662b5cSJustin T. Gibbs 	case XenbusStateInitWait:
87206a630f6SJustin T. Gibbs 	case XenbusStateInitialised:
873*33eebb6aSJustin T. Gibbs 		xbd_initialize(sc);
874ff662b5cSJustin T. Gibbs 		break;
875ff662b5cSJustin T. Gibbs 
87689e0f4d2SKip Macy 	case XenbusStateConnected:
877*33eebb6aSJustin T. Gibbs 		xbd_initialize(sc);
878*33eebb6aSJustin T. Gibbs 		xbd_connect(sc);
87989e0f4d2SKip Macy 		break;
88089e0f4d2SKip Macy 
88189e0f4d2SKip Macy 	case XenbusStateClosing:
882*33eebb6aSJustin T. Gibbs 		if (sc->xbd_users > 0)
88389e0f4d2SKip Macy 			xenbus_dev_error(dev, -EBUSY,
88489e0f4d2SKip Macy 			    "Device in use; refusing to close");
88589e0f4d2SKip Macy 		else
886*33eebb6aSJustin T. Gibbs 			xbd_closing(dev);
887ff662b5cSJustin T. Gibbs 		break;
88889e0f4d2SKip Macy 	}
88989e0f4d2SKip Macy }
89089e0f4d2SKip Macy 
89189e0f4d2SKip Macy /*
892*33eebb6aSJustin T. Gibbs  * Invoked when the backend is finally 'ready' (and has published
893*33eebb6aSJustin T. Gibbs  * the details about the physical device - #sectors, size, etc).
89489e0f4d2SKip Macy  */
89589e0f4d2SKip Macy static void
896*33eebb6aSJustin T. Gibbs xbd_connect(struct xbd_softc *sc)
89789e0f4d2SKip Macy {
898*33eebb6aSJustin T. Gibbs 	device_t dev = sc->xbd_dev;
89989e0f4d2SKip Macy 	unsigned long sectors, sector_size;
90089e0f4d2SKip Macy 	unsigned int binfo;
901e4808c4bSKip Macy 	int err, feature_barrier;
90289e0f4d2SKip Macy 
903*33eebb6aSJustin T. Gibbs 	if ((sc->xbd_connected == XBD_STATE_CONNECTED) ||
904*33eebb6aSJustin T. Gibbs 	    (sc->xbd_connected == XBD_STATE_SUSPENDED))
90589e0f4d2SKip Macy 		return;
90689e0f4d2SKip Macy 
90723dc5621SKip Macy 	DPRINTK("blkfront.c:connect:%s.\n", xenbus_get_otherend_path(dev));
90889e0f4d2SKip Macy 
909ff662b5cSJustin T. Gibbs 	err = xs_gather(XST_NIL, xenbus_get_otherend_path(dev),
91089e0f4d2SKip Macy 	    "sectors", "%lu", &sectors,
91189e0f4d2SKip Macy 	    "info", "%u", &binfo,
91289e0f4d2SKip Macy 	    "sector-size", "%lu", &sector_size,
91389e0f4d2SKip Macy 	    NULL);
91489e0f4d2SKip Macy 	if (err) {
91523dc5621SKip Macy 		xenbus_dev_fatal(dev, err,
91689e0f4d2SKip Macy 		    "reading backend fields at %s",
91723dc5621SKip Macy 		    xenbus_get_otherend_path(dev));
91889e0f4d2SKip Macy 		return;
91989e0f4d2SKip Macy 	}
920ff662b5cSJustin T. Gibbs 	err = xs_gather(XST_NIL, xenbus_get_otherend_path(dev),
921e4808c4bSKip Macy 	     "feature-barrier", "%lu", &feature_barrier,
92289e0f4d2SKip Macy 	     NULL);
923e4808c4bSKip Macy 	if (!err || feature_barrier)
924*33eebb6aSJustin T. Gibbs 		sc->xbd_flags |= XBD_BARRIER;
92589e0f4d2SKip Macy 
926*33eebb6aSJustin T. Gibbs 	if (sc->xbd_disk == NULL) {
92723dc5621SKip Macy 		device_printf(dev, "%juMB <%s> at %s",
92823dc5621SKip Macy 		    (uintmax_t) sectors / (1048576 / sector_size),
92923dc5621SKip Macy 		    device_get_desc(dev),
93023dc5621SKip Macy 		    xenbus_get_node(dev));
93123dc5621SKip Macy 		bus_print_child_footer(device_get_parent(dev), dev);
93289e0f4d2SKip Macy 
933*33eebb6aSJustin T. Gibbs 		xbd_instance_create(sc, sectors, sc->xbd_vdevice, binfo,
934*33eebb6aSJustin T. Gibbs 		    sector_size);
93506a630f6SJustin T. Gibbs 	}
93623dc5621SKip Macy 
93723dc5621SKip Macy 	(void)xenbus_set_state(dev, XenbusStateConnected);
93889e0f4d2SKip Macy 
93989e0f4d2SKip Macy 	/* Kick pending requests. */
940*33eebb6aSJustin T. Gibbs 	mtx_lock(&sc->xbd_io_lock);
941*33eebb6aSJustin T. Gibbs 	sc->xbd_connected = XBD_STATE_CONNECTED;
942*33eebb6aSJustin T. Gibbs 	xbd_startio(sc);
943*33eebb6aSJustin T. Gibbs 	sc->xbd_flags |= XBD_READY;
944*33eebb6aSJustin T. Gibbs 	mtx_unlock(&sc->xbd_io_lock);
94589e0f4d2SKip Macy }
94689e0f4d2SKip Macy 
94789e0f4d2SKip Macy /**
94889e0f4d2SKip Macy  * Handle the change of state of the backend to Closing.  We must delete our
94989e0f4d2SKip Macy  * device-layer structures now, to ensure that writes are flushed through to
950a4660d59SJustin T. Gibbs  * the backend.  Once this is done, we can switch to Closed in
95189e0f4d2SKip Macy  * acknowledgement.
95289e0f4d2SKip Macy  */
95323dc5621SKip Macy static void
954*33eebb6aSJustin T. Gibbs xbd_closing(device_t dev)
95589e0f4d2SKip Macy {
956*33eebb6aSJustin T. Gibbs 	struct xbd_softc *sc = device_get_softc(dev);
95789e0f4d2SKip Macy 
958ff662b5cSJustin T. Gibbs 	xenbus_set_state(dev, XenbusStateClosing);
959ff662b5cSJustin T. Gibbs 
960*33eebb6aSJustin T. Gibbs 	DPRINTK("xbd_closing: %s removed\n", xenbus_get_node(dev));
96189e0f4d2SKip Macy 
962*33eebb6aSJustin T. Gibbs 	if (sc->xbd_disk != NULL) {
963*33eebb6aSJustin T. Gibbs 		disk_destroy(sc->xbd_disk);
964*33eebb6aSJustin T. Gibbs 		sc->xbd_disk = NULL;
96589e0f4d2SKip Macy 	}
96689e0f4d2SKip Macy 
96723dc5621SKip Macy 	xenbus_set_state(dev, XenbusStateClosed);
96889e0f4d2SKip Macy }
96989e0f4d2SKip Macy 
97089e0f4d2SKip Macy 
97123dc5621SKip Macy static int
972*33eebb6aSJustin T. Gibbs xbd_detach(device_t dev)
97389e0f4d2SKip Macy {
974*33eebb6aSJustin T. Gibbs 	struct xbd_softc *sc = device_get_softc(dev);
97589e0f4d2SKip Macy 
976*33eebb6aSJustin T. Gibbs 	DPRINTK("xbd_remove: %s removed\n", xenbus_get_node(dev));
97789e0f4d2SKip Macy 
978*33eebb6aSJustin T. Gibbs 	xbd_free(sc);
979*33eebb6aSJustin T. Gibbs 	mtx_destroy(&sc->xbd_io_lock);
98089e0f4d2SKip Macy 
98189e0f4d2SKip Macy 	return 0;
98289e0f4d2SKip Macy }
98389e0f4d2SKip Macy 
98489e0f4d2SKip Macy 
98589e0f4d2SKip Macy static inline void
986*33eebb6aSJustin T. Gibbs flush_requests(struct xbd_softc *sc)
98789e0f4d2SKip Macy {
98889e0f4d2SKip Macy 	int notify;
98989e0f4d2SKip Macy 
990*33eebb6aSJustin T. Gibbs 	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->xbd_ring, notify);
99189e0f4d2SKip Macy 
99289e0f4d2SKip Macy 	if (notify)
993*33eebb6aSJustin T. Gibbs 		notify_remote_via_irq(sc->xbd_irq);
99489e0f4d2SKip Macy }
99589e0f4d2SKip Macy 
996ff662b5cSJustin T. Gibbs static void
997*33eebb6aSJustin T. Gibbs xbd_restart_queue_callback(void *arg)
99889e0f4d2SKip Macy {
999*33eebb6aSJustin T. Gibbs 	struct xbd_softc *sc = arg;
100089e0f4d2SKip Macy 
1001*33eebb6aSJustin T. Gibbs 	mtx_lock(&sc->xbd_io_lock);
1002ff662b5cSJustin T. Gibbs 
1003*33eebb6aSJustin T. Gibbs 	xbd_startio(sc);
1004ff662b5cSJustin T. Gibbs 
1005*33eebb6aSJustin T. Gibbs 	mtx_unlock(&sc->xbd_io_lock);
100689e0f4d2SKip Macy }
100789e0f4d2SKip Macy 
100889e0f4d2SKip Macy static int
1009*33eebb6aSJustin T. Gibbs xbd_open(struct disk *dp)
101089e0f4d2SKip Macy {
1011*33eebb6aSJustin T. Gibbs 	struct xbd_softc *sc = dp->d_drv1;
101289e0f4d2SKip Macy 
101389e0f4d2SKip Macy 	if (sc == NULL) {
1014*33eebb6aSJustin T. Gibbs 		printf("xb%d: not found", sc->xbd_unit);
101589e0f4d2SKip Macy 		return (ENXIO);
101689e0f4d2SKip Macy 	}
101789e0f4d2SKip Macy 
1018*33eebb6aSJustin T. Gibbs 	sc->xbd_flags |= XBD_OPEN;
1019*33eebb6aSJustin T. Gibbs 	sc->xbd_users++;
102089e0f4d2SKip Macy 	return (0);
102189e0f4d2SKip Macy }
102289e0f4d2SKip Macy 
102389e0f4d2SKip Macy static int
1024*33eebb6aSJustin T. Gibbs xbd_close(struct disk *dp)
102589e0f4d2SKip Macy {
1026*33eebb6aSJustin T. Gibbs 	struct xbd_softc *sc = dp->d_drv1;
102789e0f4d2SKip Macy 
102889e0f4d2SKip Macy 	if (sc == NULL)
102989e0f4d2SKip Macy 		return (ENXIO);
1030*33eebb6aSJustin T. Gibbs 	sc->xbd_flags &= ~XBD_OPEN;
1031*33eebb6aSJustin T. Gibbs 	if (--(sc->xbd_users) == 0) {
10328b8bfa35SJustin T. Gibbs 		/*
10338b8bfa35SJustin T. Gibbs 		 * Check whether we have been instructed to close.  We will
10348b8bfa35SJustin T. Gibbs 		 * have ignored this request initially, as the device was
10358b8bfa35SJustin T. Gibbs 		 * still mounted.
10368b8bfa35SJustin T. Gibbs 		 */
1037*33eebb6aSJustin T. Gibbs 		if (xenbus_get_otherend_state(sc->xbd_dev) ==
1038*33eebb6aSJustin T. Gibbs 		    XenbusStateClosing)
1039*33eebb6aSJustin T. Gibbs 			xbd_closing(sc->xbd_dev);
104089e0f4d2SKip Macy 	}
104189e0f4d2SKip Macy 	return (0);
104289e0f4d2SKip Macy }
104389e0f4d2SKip Macy 
104489e0f4d2SKip Macy static int
1045*33eebb6aSJustin T. Gibbs xbd_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
104689e0f4d2SKip Macy {
1047*33eebb6aSJustin T. Gibbs 	struct xbd_softc *sc = dp->d_drv1;
104889e0f4d2SKip Macy 
104989e0f4d2SKip Macy 	if (sc == NULL)
105089e0f4d2SKip Macy 		return (ENXIO);
105189e0f4d2SKip Macy 
105289e0f4d2SKip Macy 	return (ENOTTY);
105389e0f4d2SKip Macy }
105489e0f4d2SKip Macy 
1055e4808c4bSKip Macy static void
1056*33eebb6aSJustin T. Gibbs xbd_free_command(struct xbd_command *cm)
1057e4808c4bSKip Macy {
1058e4808c4bSKip Macy 
1059*33eebb6aSJustin T. Gibbs 	KASSERT((cm->cm_flags & XBD_ON_XBDQ_MASK) == 0,
1060e4808c4bSKip Macy 	    ("Freeing command that is still on a queue\n"));
1061e4808c4bSKip Macy 
1062e4808c4bSKip Macy 	cm->cm_flags = 0;
1063*33eebb6aSJustin T. Gibbs 	cm->cm_bp = NULL;
1064e4808c4bSKip Macy 	cm->cm_complete = NULL;
1065*33eebb6aSJustin T. Gibbs 	xbd_enqueue_free(cm);
1066e4808c4bSKip Macy }
106789e0f4d2SKip Macy 
106889e0f4d2SKip Macy /*
1069*33eebb6aSJustin T. Gibbs  * xbd_queue_request
107089e0f4d2SKip Macy  *
107189e0f4d2SKip Macy  * request block io
107289e0f4d2SKip Macy  *
107389e0f4d2SKip Macy  * id: for guest use only.
107489e0f4d2SKip Macy  * operation: BLKIF_OP_{READ,WRITE,PROBE}
107589e0f4d2SKip Macy  * buffer: buffer to read/write into. this should be a
107689e0f4d2SKip Macy  *   virtual address in the guest os.
107789e0f4d2SKip Macy  */
1078*33eebb6aSJustin T. Gibbs static struct xbd_command *
1079*33eebb6aSJustin T. Gibbs xbd_bio_command(struct xbd_softc *sc)
108089e0f4d2SKip Macy {
1081*33eebb6aSJustin T. Gibbs 	struct xbd_command *cm;
1082e4808c4bSKip Macy 	struct bio *bp;
108389e0f4d2SKip Macy 
1084*33eebb6aSJustin T. Gibbs 	if (unlikely(sc->xbd_connected != XBD_STATE_CONNECTED))
1085e4808c4bSKip Macy 		return (NULL);
108689e0f4d2SKip Macy 
1087*33eebb6aSJustin T. Gibbs 	bp = xbd_dequeue_bio(sc);
1088e4808c4bSKip Macy 	if (bp == NULL)
1089e4808c4bSKip Macy 		return (NULL);
1090e4808c4bSKip Macy 
1091*33eebb6aSJustin T. Gibbs 	if ((cm = xbd_dequeue_free(sc)) == NULL) {
1092*33eebb6aSJustin T. Gibbs 		xbd_requeue_bio(sc, bp);
1093e4808c4bSKip Macy 		return (NULL);
109489e0f4d2SKip Macy 	}
109589e0f4d2SKip Macy 
1096*33eebb6aSJustin T. Gibbs 	if (gnttab_alloc_grant_references(sc->xbd_max_request_segments,
1097*33eebb6aSJustin T. Gibbs 	    &cm->cm_gref_head) != 0) {
1098*33eebb6aSJustin T. Gibbs 		gnttab_request_free_callback(&sc->xbd_callback,
1099*33eebb6aSJustin T. Gibbs 		    xbd_restart_queue_callback, sc,
1100*33eebb6aSJustin T. Gibbs 		    sc->xbd_max_request_segments);
1101*33eebb6aSJustin T. Gibbs 		xbd_requeue_bio(sc, bp);
1102*33eebb6aSJustin T. Gibbs 		xbd_enqueue_free(cm);
1103*33eebb6aSJustin T. Gibbs 		sc->xbd_flags |= XBD_FROZEN;
1104e4808c4bSKip Macy 		return (NULL);
1105e4808c4bSKip Macy 	}
110689e0f4d2SKip Macy 
1107*33eebb6aSJustin T. Gibbs 	cm->cm_bp = bp;
1108*33eebb6aSJustin T. Gibbs 	cm->cm_data = bp->bio_data;
1109*33eebb6aSJustin T. Gibbs 	cm->cm_datalen = bp->bio_bcount;
1110*33eebb6aSJustin T. Gibbs 	cm->cm_operation = (bp->bio_cmd == BIO_READ) ?
1111*33eebb6aSJustin T. Gibbs 	    BLKIF_OP_READ : BLKIF_OP_WRITE;
1112*33eebb6aSJustin T. Gibbs 	cm->cm_sector_number = (blkif_sector_t)bp->bio_pblkno;
111389e0f4d2SKip Macy 
1114e4808c4bSKip Macy 	return (cm);
1115e4808c4bSKip Macy }
111689e0f4d2SKip Macy 
1117e4808c4bSKip Macy static int
1118*33eebb6aSJustin T. Gibbs xbd_queue_request(struct xbd_softc *sc, struct xbd_command *cm)
1119e4808c4bSKip Macy {
1120e4808c4bSKip Macy 	int error;
1121e4808c4bSKip Macy 
1122*33eebb6aSJustin T. Gibbs 	error = bus_dmamap_load(sc->xbd_io_dmat, cm->cm_map, cm->cm_data,
1123*33eebb6aSJustin T. Gibbs 	    cm->cm_datalen, xbd_queue_cb, cm, 0);
1124e4808c4bSKip Macy 	if (error == EINPROGRESS) {
1125e4808c4bSKip Macy 		printf("EINPROGRESS\n");
1126*33eebb6aSJustin T. Gibbs 		sc->xbd_flags |= XBD_FROZEN;
1127*33eebb6aSJustin T. Gibbs 		cm->cm_flags |= XBD_CMD_FROZEN;
1128e4808c4bSKip Macy 		return (0);
1129e4808c4bSKip Macy 	}
1130e4808c4bSKip Macy 
1131e4808c4bSKip Macy 	return (error);
1132e4808c4bSKip Macy }
1133e4808c4bSKip Macy 
1134e4808c4bSKip Macy static void
1135*33eebb6aSJustin T. Gibbs xbd_queue_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
1136e4808c4bSKip Macy {
1137*33eebb6aSJustin T. Gibbs 	struct xbd_softc *sc;
1138*33eebb6aSJustin T. Gibbs 	struct xbd_command *cm;
1139e4808c4bSKip Macy 	blkif_request_t	*ring_req;
1140ff662b5cSJustin T. Gibbs 	struct blkif_request_segment *sg;
1141ff662b5cSJustin T. Gibbs 	struct blkif_request_segment *last_block_sg;
1142ff662b5cSJustin T. Gibbs 	grant_ref_t *sg_ref;
1143e4808c4bSKip Macy 	vm_paddr_t buffer_ma;
1144e4808c4bSKip Macy 	uint64_t fsect, lsect;
1145ff662b5cSJustin T. Gibbs 	int ref;
1146ff662b5cSJustin T. Gibbs 	int op;
1147ff662b5cSJustin T. Gibbs 	int block_segs;
1148e4808c4bSKip Macy 
1149e4808c4bSKip Macy 	cm = arg;
1150e4808c4bSKip Macy 	sc = cm->cm_sc;
1151e4808c4bSKip Macy 
1152e4808c4bSKip Macy 	if (error) {
1153*33eebb6aSJustin T. Gibbs 		printf("error %d in xbd_queue_cb\n", error);
1154*33eebb6aSJustin T. Gibbs 		cm->cm_bp->bio_error = EIO;
1155*33eebb6aSJustin T. Gibbs 		biodone(cm->cm_bp);
1156*33eebb6aSJustin T. Gibbs 		xbd_free_command(cm);
1157e4808c4bSKip Macy 		return;
1158e4808c4bSKip Macy 	}
115989e0f4d2SKip Macy 
116089e0f4d2SKip Macy 	/* Fill out a communications ring structure. */
1161*33eebb6aSJustin T. Gibbs 	ring_req = RING_GET_REQUEST(&sc->xbd_ring, sc->xbd_ring.req_prod_pvt);
1162*33eebb6aSJustin T. Gibbs 	sc->xbd_ring.req_prod_pvt++;
1163*33eebb6aSJustin T. Gibbs 	ring_req->id = cm->cm_id;
1164*33eebb6aSJustin T. Gibbs 	ring_req->operation = cm->cm_operation;
1165*33eebb6aSJustin T. Gibbs 	ring_req->sector_number = cm->cm_sector_number;
1166*33eebb6aSJustin T. Gibbs 	ring_req->handle = (blkif_vdev_t)(uintptr_t)sc->xbd_disk;
1167e4808c4bSKip Macy 	ring_req->nr_segments = nsegs;
1168*33eebb6aSJustin T. Gibbs 	cm->cm_nseg = nsegs;
116989e0f4d2SKip Macy 
1170ff662b5cSJustin T. Gibbs 	block_segs    = MIN(nsegs, BLKIF_MAX_SEGMENTS_PER_HEADER_BLOCK);
1171ff662b5cSJustin T. Gibbs 	sg            = ring_req->seg;
1172ff662b5cSJustin T. Gibbs 	last_block_sg = sg + block_segs;
1173*33eebb6aSJustin T. Gibbs 	sg_ref        = cm->cm_sg_refs;
1174ff662b5cSJustin T. Gibbs 
1175ff662b5cSJustin T. Gibbs 	while (1) {
1176ff662b5cSJustin T. Gibbs 
1177ff662b5cSJustin T. Gibbs 		while (sg < last_block_sg) {
1178ff662b5cSJustin T. Gibbs 			buffer_ma = segs->ds_addr;
117989e0f4d2SKip Macy 			fsect = (buffer_ma & PAGE_MASK) >> XBD_SECTOR_SHFT;
1180ff662b5cSJustin T. Gibbs 			lsect = fsect + (segs->ds_len  >> XBD_SECTOR_SHFT) - 1;
1181e4808c4bSKip Macy 
1182ff662b5cSJustin T. Gibbs 			KASSERT(lsect <= 7, ("XEN disk driver data cannot "
1183ff662b5cSJustin T. Gibbs 			    "cross a page boundary"));
1184e4808c4bSKip Macy 
118589e0f4d2SKip Macy 			/* install a grant reference. */
1186*33eebb6aSJustin T. Gibbs 			ref = gnttab_claim_grant_reference(&cm->cm_gref_head);
1187ff662b5cSJustin T. Gibbs 
1188ff662b5cSJustin T. Gibbs 			/*
1189ff662b5cSJustin T. Gibbs 			 * GNTTAB_LIST_END == 0xffffffff, but it is private
1190ff662b5cSJustin T. Gibbs 			 * to gnttab.c.
1191ff662b5cSJustin T. Gibbs 			 */
1192ff662b5cSJustin T. Gibbs 			KASSERT(ref != ~0, ("grant_reference failed"));
119389e0f4d2SKip Macy 
119489e0f4d2SKip Macy 			gnttab_grant_foreign_access_ref(
119589e0f4d2SKip Macy 			    ref,
1196*33eebb6aSJustin T. Gibbs 			    xenbus_get_otherend_id(sc->xbd_dev),
119789e0f4d2SKip Macy 			    buffer_ma >> PAGE_SHIFT,
1198ff662b5cSJustin T. Gibbs 			    ring_req->operation == BLKIF_OP_WRITE);
119989e0f4d2SKip Macy 
1200ff662b5cSJustin T. Gibbs 			*sg_ref = ref;
1201ff662b5cSJustin T. Gibbs 			*sg = (struct blkif_request_segment) {
120289e0f4d2SKip Macy 				.gref       = ref,
120389e0f4d2SKip Macy 				.first_sect = fsect,
1204*33eebb6aSJustin T. Gibbs 				.last_sect  = lsect
1205*33eebb6aSJustin T. Gibbs 			};
1206ff662b5cSJustin T. Gibbs 			sg++;
1207ff662b5cSJustin T. Gibbs 			sg_ref++;
1208ff662b5cSJustin T. Gibbs 			segs++;
1209ff662b5cSJustin T. Gibbs 			nsegs--;
121089e0f4d2SKip Macy 		}
1211ff662b5cSJustin T. Gibbs 		block_segs = MIN(nsegs, BLKIF_MAX_SEGMENTS_PER_SEGMENT_BLOCK);
1212ff662b5cSJustin T. Gibbs 		if (block_segs == 0)
1213ff662b5cSJustin T. Gibbs 			break;
121489e0f4d2SKip Macy 
1215*33eebb6aSJustin T. Gibbs 		sg = BLKRING_GET_SEG_BLOCK(&sc->xbd_ring,
1216*33eebb6aSJustin T. Gibbs 		    sc->xbd_ring.req_prod_pvt);
1217*33eebb6aSJustin T. Gibbs 		sc->xbd_ring.req_prod_pvt++;
1218ff662b5cSJustin T. Gibbs 		last_block_sg = sg + block_segs;
1219ff662b5cSJustin T. Gibbs 	}
122089e0f4d2SKip Macy 
1221*33eebb6aSJustin T. Gibbs 	if (cm->cm_operation == BLKIF_OP_READ)
1222e4808c4bSKip Macy 		op = BUS_DMASYNC_PREREAD;
1223*33eebb6aSJustin T. Gibbs 	else if (cm->cm_operation == BLKIF_OP_WRITE)
1224e4808c4bSKip Macy 		op = BUS_DMASYNC_PREWRITE;
1225e4808c4bSKip Macy 	else
1226e4808c4bSKip Macy 		op = 0;
1227*33eebb6aSJustin T. Gibbs 	bus_dmamap_sync(sc->xbd_io_dmat, cm->cm_map, op);
1228e4808c4bSKip Macy 
1229*33eebb6aSJustin T. Gibbs 	gnttab_free_grant_references(cm->cm_gref_head);
1230e4808c4bSKip Macy 
1231*33eebb6aSJustin T. Gibbs 	xbd_enqueue_busy(cm);
1232e4808c4bSKip Macy 
1233e4808c4bSKip Macy 	/*
1234e4808c4bSKip Macy 	 * This flag means that we're probably executing in the busdma swi
1235e4808c4bSKip Macy 	 * instead of in the startio context, so an explicit flush is needed.
1236e4808c4bSKip Macy 	 */
1237*33eebb6aSJustin T. Gibbs 	if (cm->cm_flags & XBD_CMD_FROZEN)
1238e4808c4bSKip Macy 		flush_requests(sc);
1239e4808c4bSKip Macy 
1240e4808c4bSKip Macy 	return;
1241e4808c4bSKip Macy }
124289e0f4d2SKip Macy 
124389e0f4d2SKip Macy /*
124489e0f4d2SKip Macy  * Dequeue buffers and place them in the shared communication ring.
124589e0f4d2SKip Macy  * Return when no more requests can be accepted or all buffers have
124689e0f4d2SKip Macy  * been queued.
124789e0f4d2SKip Macy  *
124889e0f4d2SKip Macy  * Signal XEN once the ring has been filled out.
124989e0f4d2SKip Macy  */
125089e0f4d2SKip Macy static void
1251*33eebb6aSJustin T. Gibbs xbd_startio(struct xbd_softc *sc)
125289e0f4d2SKip Macy {
1253*33eebb6aSJustin T. Gibbs 	struct xbd_command *cm;
1254e4808c4bSKip Macy 	int error, queued = 0;
125589e0f4d2SKip Macy 
1256*33eebb6aSJustin T. Gibbs 	mtx_assert(&sc->xbd_io_lock, MA_OWNED);
125789e0f4d2SKip Macy 
1258*33eebb6aSJustin T. Gibbs 	if (sc->xbd_connected != XBD_STATE_CONNECTED)
125906a630f6SJustin T. Gibbs 		return;
126006a630f6SJustin T. Gibbs 
1261*33eebb6aSJustin T. Gibbs 	while (RING_FREE_REQUESTS(&sc->xbd_ring) >=
1262*33eebb6aSJustin T. Gibbs 	    sc->xbd_max_request_blocks) {
1263*33eebb6aSJustin T. Gibbs 		if (sc->xbd_flags & XBD_FROZEN)
1264e4808c4bSKip Macy 			break;
126589e0f4d2SKip Macy 
1266*33eebb6aSJustin T. Gibbs 		cm = xbd_dequeue_ready(sc);
126789e0f4d2SKip Macy 
1268e4808c4bSKip Macy 		if (cm == NULL)
1269*33eebb6aSJustin T. Gibbs 		    cm = xbd_bio_command(sc);
1270e4808c4bSKip Macy 
1271e4808c4bSKip Macy 		if (cm == NULL)
1272e4808c4bSKip Macy 			break;
1273e4808c4bSKip Macy 
1274*33eebb6aSJustin T. Gibbs 		if ((error = xbd_queue_request(sc, cm)) != 0) {
1275*33eebb6aSJustin T. Gibbs 			printf("xbd_queue_request returned %d\n", error);
127689e0f4d2SKip Macy 			break;
127789e0f4d2SKip Macy 		}
127889e0f4d2SKip Macy 		queued++;
127989e0f4d2SKip Macy 	}
128089e0f4d2SKip Macy 
128189e0f4d2SKip Macy 	if (queued != 0)
1282e4808c4bSKip Macy 		flush_requests(sc);
128389e0f4d2SKip Macy }
128489e0f4d2SKip Macy 
128589e0f4d2SKip Macy static void
1286*33eebb6aSJustin T. Gibbs xbd_int(void *xsc)
128789e0f4d2SKip Macy {
1288*33eebb6aSJustin T. Gibbs 	struct xbd_softc *sc = xsc;
1289*33eebb6aSJustin T. Gibbs 	struct xbd_command *cm;
129089e0f4d2SKip Macy 	blkif_response_t *bret;
129189e0f4d2SKip Macy 	RING_IDX i, rp;
1292e4808c4bSKip Macy 	int op;
129389e0f4d2SKip Macy 
1294*33eebb6aSJustin T. Gibbs 	mtx_lock(&sc->xbd_io_lock);
129589e0f4d2SKip Macy 
1296*33eebb6aSJustin T. Gibbs 	if (unlikely(sc->xbd_connected == XBD_STATE_DISCONNECTED)) {
1297*33eebb6aSJustin T. Gibbs 		mtx_unlock(&sc->xbd_io_lock);
129889e0f4d2SKip Macy 		return;
129989e0f4d2SKip Macy 	}
130089e0f4d2SKip Macy 
130189e0f4d2SKip Macy  again:
1302*33eebb6aSJustin T. Gibbs 	rp = sc->xbd_ring.sring->rsp_prod;
130389e0f4d2SKip Macy 	rmb(); /* Ensure we see queued responses up to 'rp'. */
130489e0f4d2SKip Macy 
1305*33eebb6aSJustin T. Gibbs 	for (i = sc->xbd_ring.rsp_cons; i != rp;) {
1306*33eebb6aSJustin T. Gibbs 		bret = RING_GET_RESPONSE(&sc->xbd_ring, i);
1307*33eebb6aSJustin T. Gibbs 		cm   = &sc->xbd_shadow[bret->id];
130889e0f4d2SKip Macy 
1309*33eebb6aSJustin T. Gibbs 		xbd_remove_busy(cm);
1310*33eebb6aSJustin T. Gibbs 		i += xbd_completion(cm);
131189e0f4d2SKip Macy 
1312*33eebb6aSJustin T. Gibbs 		if (cm->cm_operation == BLKIF_OP_READ)
1313e4808c4bSKip Macy 			op = BUS_DMASYNC_POSTREAD;
1314*33eebb6aSJustin T. Gibbs 		else if (cm->cm_operation == BLKIF_OP_WRITE)
1315e4808c4bSKip Macy 			op = BUS_DMASYNC_POSTWRITE;
131689e0f4d2SKip Macy 		else
1317e4808c4bSKip Macy 			op = 0;
1318*33eebb6aSJustin T. Gibbs 		bus_dmamap_sync(sc->xbd_io_dmat, cm->cm_map, op);
1319*33eebb6aSJustin T. Gibbs 		bus_dmamap_unload(sc->xbd_io_dmat, cm->cm_map);
132089e0f4d2SKip Macy 
1321e4808c4bSKip Macy 		/*
1322e4808c4bSKip Macy 		 * If commands are completing then resources are probably
1323e4808c4bSKip Macy 		 * being freed as well.  It's a cheap assumption even when
1324e4808c4bSKip Macy 		 * wrong.
1325e4808c4bSKip Macy 		 */
1326*33eebb6aSJustin T. Gibbs 		sc->xbd_flags &= ~XBD_FROZEN;
1327e4808c4bSKip Macy 
1328e4808c4bSKip Macy 		/*
1329e4808c4bSKip Macy 		 * Directly call the i/o complete routine to save an
1330e4808c4bSKip Macy 		 * an indirection in the common case.
1331e4808c4bSKip Macy 		 */
1332*33eebb6aSJustin T. Gibbs 		cm->cm_status = bret->status;
1333*33eebb6aSJustin T. Gibbs 		if (cm->cm_bp)
1334*33eebb6aSJustin T. Gibbs 			xbd_bio_complete(sc, cm);
1335*33eebb6aSJustin T. Gibbs 		else if (cm->cm_complete != NULL)
1336*33eebb6aSJustin T. Gibbs 			cm->cm_complete(cm);
1337e4808c4bSKip Macy 		else
1338*33eebb6aSJustin T. Gibbs 			xbd_free_command(cm);
133989e0f4d2SKip Macy 	}
134089e0f4d2SKip Macy 
1341*33eebb6aSJustin T. Gibbs 	sc->xbd_ring.rsp_cons = i;
134289e0f4d2SKip Macy 
1343*33eebb6aSJustin T. Gibbs 	if (i != sc->xbd_ring.req_prod_pvt) {
134489e0f4d2SKip Macy 		int more_to_do;
1345*33eebb6aSJustin T. Gibbs 		RING_FINAL_CHECK_FOR_RESPONSES(&sc->xbd_ring, more_to_do);
134689e0f4d2SKip Macy 		if (more_to_do)
134789e0f4d2SKip Macy 			goto again;
134889e0f4d2SKip Macy 	} else {
1349*33eebb6aSJustin T. Gibbs 		sc->xbd_ring.sring->rsp_event = i + 1;
135089e0f4d2SKip Macy 	}
135189e0f4d2SKip Macy 
1352*33eebb6aSJustin T. Gibbs 	xbd_startio(sc);
135389e0f4d2SKip Macy 
1354*33eebb6aSJustin T. Gibbs 	if (unlikely(sc->xbd_connected == XBD_STATE_SUSPENDED))
1355*33eebb6aSJustin T. Gibbs 		wakeup(&sc->xbd_cm_busy);
135606a630f6SJustin T. Gibbs 
1357*33eebb6aSJustin T. Gibbs 	mtx_unlock(&sc->xbd_io_lock);
135889e0f4d2SKip Macy }
135989e0f4d2SKip Macy 
136089e0f4d2SKip Macy static void
1361*33eebb6aSJustin T. Gibbs xbd_free(struct xbd_softc *sc)
136289e0f4d2SKip Macy {
1363ff662b5cSJustin T. Gibbs 	uint8_t *sring_page_ptr;
1364ff662b5cSJustin T. Gibbs 	int i;
136589e0f4d2SKip Macy 
136689e0f4d2SKip Macy 	/* Prevent new requests being issued until we fix things up. */
1367*33eebb6aSJustin T. Gibbs 	mtx_lock(&sc->xbd_io_lock);
1368*33eebb6aSJustin T. Gibbs 	sc->xbd_connected = XBD_STATE_DISCONNECTED;
1369*33eebb6aSJustin T. Gibbs 	mtx_unlock(&sc->xbd_io_lock);
137089e0f4d2SKip Macy 
137189e0f4d2SKip Macy 	/* Free resources associated with old device channel. */
1372*33eebb6aSJustin T. Gibbs 	if (sc->xbd_ring.sring != NULL) {
1373*33eebb6aSJustin T. Gibbs 		sring_page_ptr = (uint8_t *)sc->xbd_ring.sring;
1374*33eebb6aSJustin T. Gibbs 		for (i = 0; i < sc->xbd_ring_pages; i++) {
1375*33eebb6aSJustin T. Gibbs 			grant_ref_t *ref;
1376*33eebb6aSJustin T. Gibbs 
1377*33eebb6aSJustin T. Gibbs 			ref = &sc->xbd_ring_ref[i];
1378*33eebb6aSJustin T. Gibbs 			if (*ref != GRANT_INVALID_REF) {
1379*33eebb6aSJustin T. Gibbs 				gnttab_end_foreign_access_ref(*ref);
1380*33eebb6aSJustin T. Gibbs 				*ref = GRANT_INVALID_REF;
1381ff662b5cSJustin T. Gibbs 			}
1382ff662b5cSJustin T. Gibbs 			sring_page_ptr += PAGE_SIZE;
1383ff662b5cSJustin T. Gibbs 		}
1384*33eebb6aSJustin T. Gibbs 		free(sc->xbd_ring.sring, M_XENBLOCKFRONT);
1385*33eebb6aSJustin T. Gibbs 		sc->xbd_ring.sring = NULL;
138689e0f4d2SKip Macy 	}
1387ff662b5cSJustin T. Gibbs 
1388*33eebb6aSJustin T. Gibbs 	if (sc->xbd_shadow) {
1389ff662b5cSJustin T. Gibbs 
1390*33eebb6aSJustin T. Gibbs 		for (i = 0; i < sc->xbd_max_requests; i++) {
1391*33eebb6aSJustin T. Gibbs 			struct xbd_command *cm;
1392ff662b5cSJustin T. Gibbs 
1393*33eebb6aSJustin T. Gibbs 			cm = &sc->xbd_shadow[i];
1394*33eebb6aSJustin T. Gibbs 			if (cm->cm_sg_refs != NULL) {
1395*33eebb6aSJustin T. Gibbs 				free(cm->cm_sg_refs, M_XENBLOCKFRONT);
1396*33eebb6aSJustin T. Gibbs 				cm->cm_sg_refs = NULL;
1397ff662b5cSJustin T. Gibbs 			}
1398ff662b5cSJustin T. Gibbs 
1399*33eebb6aSJustin T. Gibbs 			bus_dmamap_destroy(sc->xbd_io_dmat, cm->cm_map);
1400ff662b5cSJustin T. Gibbs 		}
1401*33eebb6aSJustin T. Gibbs 		free(sc->xbd_shadow, M_XENBLOCKFRONT);
1402*33eebb6aSJustin T. Gibbs 		sc->xbd_shadow = NULL;
140306a630f6SJustin T. Gibbs 
1404*33eebb6aSJustin T. Gibbs 		bus_dma_tag_destroy(sc->xbd_io_dmat);
140506a630f6SJustin T. Gibbs 
1406*33eebb6aSJustin T. Gibbs 		xbd_initq_free(sc);
1407*33eebb6aSJustin T. Gibbs 		xbd_initq_ready(sc);
1408*33eebb6aSJustin T. Gibbs 		xbd_initq_complete(sc);
1409ff662b5cSJustin T. Gibbs 	}
1410ff662b5cSJustin T. Gibbs 
1411*33eebb6aSJustin T. Gibbs 	if (sc->xbd_irq) {
1412*33eebb6aSJustin T. Gibbs 		unbind_from_irqhandler(sc->xbd_irq);
1413*33eebb6aSJustin T. Gibbs 		sc->xbd_irq = 0;
1414ff662b5cSJustin T. Gibbs 	}
141589e0f4d2SKip Macy }
141689e0f4d2SKip Macy 
1417ff662b5cSJustin T. Gibbs static int
1418*33eebb6aSJustin T. Gibbs xbd_completion(struct xbd_command *cm)
141989e0f4d2SKip Macy {
1420*33eebb6aSJustin T. Gibbs 	gnttab_end_foreign_access_references(cm->cm_nseg, cm->cm_sg_refs);
1421*33eebb6aSJustin T. Gibbs 	return (BLKIF_SEGS_TO_BLOCKS(cm->cm_nseg));
142289e0f4d2SKip Macy }
142389e0f4d2SKip Macy 
142423dc5621SKip Macy /* ** Driver registration ** */
1425*33eebb6aSJustin T. Gibbs static device_method_t xbd_methods[] = {
142623dc5621SKip Macy 	/* Device interface */
1427*33eebb6aSJustin T. Gibbs 	DEVMETHOD(device_probe,         xbd_probe),
1428*33eebb6aSJustin T. Gibbs 	DEVMETHOD(device_attach,        xbd_attach),
1429*33eebb6aSJustin T. Gibbs 	DEVMETHOD(device_detach,        xbd_detach),
143023dc5621SKip Macy 	DEVMETHOD(device_shutdown,      bus_generic_shutdown),
1431*33eebb6aSJustin T. Gibbs 	DEVMETHOD(device_suspend,       xbd_suspend),
1432*33eebb6aSJustin T. Gibbs 	DEVMETHOD(device_resume,        xbd_resume),
143389e0f4d2SKip Macy 
143423dc5621SKip Macy 	/* Xenbus interface */
1435*33eebb6aSJustin T. Gibbs 	DEVMETHOD(xenbus_otherend_changed, xbd_backend_changed),
143689e0f4d2SKip Macy 
143723dc5621SKip Macy 	{ 0, 0 }
143889e0f4d2SKip Macy };
143989e0f4d2SKip Macy 
1440*33eebb6aSJustin T. Gibbs static driver_t xbd_driver = {
144123dc5621SKip Macy 	"xbd",
1442*33eebb6aSJustin T. Gibbs 	xbd_methods,
1443*33eebb6aSJustin T. Gibbs 	sizeof(struct xbd_softc),
144489e0f4d2SKip Macy };
1445*33eebb6aSJustin T. Gibbs devclass_t xbd_devclass;
144689e0f4d2SKip Macy 
1447*33eebb6aSJustin T. Gibbs DRIVER_MODULE(xbd, xenbusb_front, xbd_driver, xbd_devclass, 0, 0);
1448