Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 30 Nov 2009 04:32:34 +0000 (UTC)
From:      Kip Macy <kmacy@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r199960 - head/sys/dev/xen/blkfront
Message-ID:  <200911300432.nAU4WYeA018513@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kmacy
Date: Mon Nov 30 04:32:34 2009
New Revision: 199960
URL: http://svn.freebsd.org/changeset/base/199960

Log:
  Merge Scott Long's latest blkfront now that the licensing issues are resolved

Modified:
  head/sys/dev/xen/blkfront/blkfront.c
  head/sys/dev/xen/blkfront/block.h

Modified: head/sys/dev/xen/blkfront/blkfront.c
==============================================================================
--- head/sys/dev/xen/blkfront/blkfront.c	Mon Nov 30 04:20:43 2009	(r199959)
+++ head/sys/dev/xen/blkfront/blkfront.c	Mon Nov 30 04:32:34 2009	(r199960)
@@ -1,6 +1,7 @@
 /*
  * XenBSD block device driver
  *
+ * Copyright (c) 2009 Scott Long, Yahoo!
  * Copyright (c) 2009 Frank Suchomel, Citrix
  * Copyright (c) 2009 Doug F. Rabson, Citrix
  * Copyright (c) 2005 Kip Macy
@@ -46,6 +47,7 @@ __FBSDID("$FreeBSD$");
 #include <machine/resource.h>
 #include <machine/intr_machdep.h>
 #include <machine/vmparam.h>
+#include <sys/bus_dma.h>
 
 #include <machine/xen/xen-os.h>
 #include <machine/xen/xenfunc.h>
@@ -63,27 +65,21 @@ __FBSDID("$FreeBSD$");
 
 #include "xenbus_if.h"
 
-#define    ASSERT(S)       KASSERT(S, (#S))
 /* prototypes */
-struct xb_softc;
+static void xb_free_command(struct xb_command *cm);
 static void xb_startio(struct xb_softc *sc);
-static void connect(device_t, struct blkfront_info *);
+static void connect(struct xb_softc *);
 static void blkfront_closing(device_t);
 static int blkfront_detach(device_t);
-static int talk_to_backend(device_t, struct blkfront_info *);
-static int setup_blkring(device_t, struct blkfront_info *);
+static int talk_to_backend(struct xb_softc *);
+static int setup_blkring(struct xb_softc *);
 static void blkif_int(void *);
-#if 0
-static void blkif_restart_queue(void *arg);
-#endif
-static void blkif_recover(struct blkfront_info *);
-static void blkif_completion(struct blk_shadow *);
-static void blkif_free(struct blkfront_info *, int);
+static void blkif_recover(struct xb_softc *);
+static void blkif_completion(struct xb_command *);
+static void blkif_free(struct xb_softc *, int);
+static void blkif_queue_cb(void *, bus_dma_segment_t *, int, int);
 
 #define GRANT_INVALID_REF 0
-#define BLK_RING_SIZE __RING_SIZE((blkif_sring_t *)0, PAGE_SIZE)
-
-LIST_HEAD(xb_softc_list_head, xb_softc) xbsl_head;
 
 /* Control whether runtime update of vbds is enabled. */
 #define ENABLE_VBD_UPDATE 0
@@ -92,7 +88,6 @@ LIST_HEAD(xb_softc_list_head, xb_softc) 
 static void vbd_update(void);
 #endif
 
-
 #define BLKIF_STATE_DISCONNECTED 0
 #define BLKIF_STATE_CONNECTED    1
 #define BLKIF_STATE_SUSPENDED    2
@@ -111,44 +106,34 @@ static char * blkif_status_name[] = {
 	[BLKIF_INTERFACE_STATUS_CHANGED]      = "changed",
 };
 #endif
-#define WPRINTK(fmt, args...) printf("[XEN] " fmt, ##args)
+
 #if 0
 #define DPRINTK(fmt, args...) printf("[XEN] %s:%d: " fmt ".\n", __func__, __LINE__, ##args)
 #else
 #define DPRINTK(fmt, args...) 
 #endif
 
-static grant_ref_t gref_head;
 #define MAXIMUM_OUTSTANDING_BLOCK_REQS \
     (BLKIF_MAX_SEGMENTS_PER_REQUEST * BLK_RING_SIZE)
 
-static void kick_pending_request_queues(struct blkfront_info *);
+#define BLKIF_MAXIO	(32 * 1024)
+
 static int blkif_open(struct disk *dp);
 static int blkif_close(struct disk *dp);
 static int blkif_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td);
-static int blkif_queue_request(struct bio *bp);
+static int blkif_queue_request(struct xb_softc *sc, struct xb_command *cm);
 static void xb_strategy(struct bio *bp);
 
 // In order to quiesce the device during kernel dumps, outstanding requests to
 // DOM0 for disk reads/writes need to be accounted for.
-static	int	blkif_queued_requests;
 static	int	xb_dump(void *, void *, vm_offset_t, off_t, size_t);
 
-
 /* XXX move to xb_vbd.c when VBD update support is added */
 #define MAX_VBDS 64
 
 #define XBD_SECTOR_SIZE		512	/* XXX: assume for now */
 #define XBD_SECTOR_SHFT		9
 
-static struct mtx blkif_io_lock;
-
-static vm_paddr_t
-pfn_to_mfn(vm_paddr_t pfn)
-{
-	return (phystomach(pfn << PAGE_SHIFT) >> PAGE_SHIFT);
-}
-
 /*
  * Translate Linux major/minor to an appropriate name and unit
  * number. For HVM guests, this allows us to use the same drive names
@@ -217,23 +202,18 @@ blkfront_vdevice_to_unit(int vdevice, in
 }
 
 int
-xlvbd_add(device_t dev, blkif_sector_t capacity,
-    int vdevice, uint16_t vdisk_info, uint16_t sector_size, 
-    struct blkfront_info *info)
+xlvbd_add(struct xb_softc *sc, blkif_sector_t capacity,
+    int vdevice, uint16_t vdisk_info, uint16_t sector_size)
 {
-	struct xb_softc	*sc;
 	int	unit, error = 0;
 	const char *name;
 
 	blkfront_vdevice_to_unit(vdevice, &unit, &name);
 
-	sc = (struct xb_softc *)malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
 	sc->xb_unit = unit;
-	sc->xb_info = info;
-	info->sc = sc;
 
 	if (strcmp(name, "xbd"))
-		device_printf(dev, "attaching as %s%d\n", name, unit);
+		device_printf(sc->xb_dev, "attaching as %s%d\n", name, unit);
 
 	memset(&sc->xb_disk, 0, sizeof(sc->xb_disk)); 
 	sc->xb_disk = disk_alloc();
@@ -247,31 +227,18 @@ xlvbd_add(device_t dev, blkif_sector_t c
 	sc->xb_disk->d_drv1 = sc;
 	sc->xb_disk->d_sectorsize = sector_size;
 
-	/* XXX */
 	sc->xb_disk->d_mediasize = capacity << XBD_SECTOR_SHFT;
-#if 0
-	sc->xb_disk->d_maxsize = DFLTPHYS;
-#else /* XXX: xen can't handle large single i/o requests */
-	sc->xb_disk->d_maxsize = 4096;
-#endif
-#ifdef notyet
-	XENPRINTF("attaching device 0x%x unit %d capacity %llu\n",
-		  xb_diskinfo[sc->xb_unit].device, sc->xb_unit,
-		  sc->xb_disk->d_mediasize);
-#endif
+	sc->xb_disk->d_maxsize = BLKIF_MAXIO;
 	sc->xb_disk->d_flags = 0;
 	disk_create(sc->xb_disk, DISK_VERSION_00);
-	bioq_init(&sc->xb_bioq);
 
 	return error;
 }
 
 void
-xlvbd_del(struct blkfront_info *info)
+xlvbd_del(struct xb_softc *sc)
 {
-	struct xb_softc	*sc;
 
-	sc = info->sc;
 	disk_destroy(sc->xb_disk);
 }
 /************************ end VBD support *****************/
@@ -289,102 +256,147 @@ xb_strategy(struct bio *bp)
 	if (sc == NULL) {
 		bp->bio_error = EINVAL;
 		bp->bio_flags |= BIO_ERROR;
-		goto bad;
+		bp->bio_resid = bp->bio_bcount;
+		biodone(bp);
+		return;
 	}
 
-	DPRINTK("");
-
 	/*
 	 * Place it in the queue of disk activities for this disk
 	 */
-	mtx_lock(&blkif_io_lock);
+	mtx_lock(&sc->xb_io_lock);
 
-	bioq_disksort(&sc->xb_bioq, bp);
+	xb_enqueue_bio(sc, bp);
 	xb_startio(sc);
 
-	mtx_unlock(&blkif_io_lock);
+	mtx_unlock(&sc->xb_io_lock);
 	return;
+}
 
- bad:
-	/*
-	 * Correctly set the bio to indicate a failed tranfer.
-	 */
-	bp->bio_resid = bp->bio_bcount;
+static void
+xb_bio_complete(struct xb_softc *sc, struct xb_command *cm)
+{
+	struct bio *bp;
+
+	bp = cm->bp;
+
+	if ( unlikely(cm->status != BLKIF_RSP_OKAY) ) {
+		disk_err(bp, "disk error" , -1, 0);
+		printf(" status: %x\n", cm->status);
+		bp->bio_flags |= BIO_ERROR;
+	}
+
+	if (bp->bio_flags & BIO_ERROR)
+		bp->bio_error = EIO;
+	else
+		bp->bio_resid = 0;
+
+	xb_free_command(cm);
 	biodone(bp);
-	return;
 }
 
-static void xb_quiesce(struct blkfront_info *info);
 // Quiesce the disk writes for a dump file before allowing the next buffer.
 static void
-xb_quiesce(struct blkfront_info *info)
+xb_quiesce(struct xb_softc *sc)
 {
 	int		mtd;
 
 	// While there are outstanding requests
-	while (blkif_queued_requests) {
-		RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, mtd);
+	while (!TAILQ_EMPTY(&sc->cm_busy)) {
+		RING_FINAL_CHECK_FOR_RESPONSES(&sc->ring, mtd);
 		if (mtd) {
-			// Recieved request completions, update queue.
-			blkif_int(info);
+			/* Recieved request completions, update queue. */
+			blkif_int(sc);
 		}
-		if (blkif_queued_requests) {
-			// Still pending requests, wait for the disk i/o to complete
+		if (!TAILQ_EMPTY(&sc->cm_busy)) {
+			/*
+			 * Still pending requests, wait for the disk i/o
+			 * to complete.
+			 */
 			HYPERVISOR_yield();
 		}
 	}
 }
 
-// Some bio structures for dumping core
-#define DUMP_BIO_NO 16				// 16 * 4KB = 64KB dump block
-static	struct bio		xb_dump_bp[DUMP_BIO_NO];
+/* Kernel dump function for a paravirtualized disk device */
+static void
+xb_dump_complete(struct xb_command *cm)
+{
+
+	xb_enqueue_complete(cm);
+}
 
-// Kernel dump function for a paravirtualized disk device
 static int
 xb_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset,
         size_t length)
 {
-			int				 sbp;
-  			int			     mbp;
-			size_t			 chunk;
-	struct	disk   			*dp = arg;
-	struct	xb_softc		*sc = (struct xb_softc *) dp->d_drv1;
-	        int	    		 rc = 0;
-
-	xb_quiesce(sc->xb_info);		// All quiet on the western front.
-	if (length > 0) {
-		// If this lock is held, then this module is failing, and a successful
-		// kernel dump is highly unlikely anyway.
-		mtx_lock(&blkif_io_lock);
-		// Split the 64KB block into 16 4KB blocks
-		for (sbp=0; length>0 && sbp<DUMP_BIO_NO; sbp++) {
-			chunk = length > PAGE_SIZE ? PAGE_SIZE : length;
-			xb_dump_bp[sbp].bio_disk   = dp;
-			xb_dump_bp[sbp].bio_pblkno = offset / dp->d_sectorsize;
-			xb_dump_bp[sbp].bio_bcount = chunk;
-			xb_dump_bp[sbp].bio_resid  = chunk;
-			xb_dump_bp[sbp].bio_data   = virtual;
-			xb_dump_bp[sbp].bio_cmd    = BIO_WRITE;
-			xb_dump_bp[sbp].bio_done   = NULL;
-
-			bioq_disksort(&sc->xb_bioq, &xb_dump_bp[sbp]);
-
-			length -= chunk;
-			offset += chunk;
-			virtual = (char *) virtual + chunk;
+	struct	disk   	*dp = arg;
+	struct xb_softc	*sc = (struct xb_softc *) dp->d_drv1;
+	struct xb_command *cm;
+	size_t		chunk;
+	int		sbp;
+	int		rc = 0;
+
+	if (length <= 0)
+		return (rc);
+
+	xb_quiesce(sc);	/* All quiet on the western front. */
+
+	/*
+	 * If this lock is held, then this module is failing, and a
+	 * successful kernel dump is highly unlikely anyway.
+	 */
+	mtx_lock(&sc->xb_io_lock);
+
+	/* Split the 64KB block as needed */
+	for (sbp=0; length > 0; sbp++) {
+		cm = xb_dequeue_free(sc);
+		if (cm == NULL) {
+			mtx_unlock(&sc->xb_io_lock);
+			device_printf(sc->xb_dev, "dump: no more commands?\n");
+			return (EBUSY);
 		}
-		// Tell DOM0 to do the I/O
-		xb_startio(sc);
-		mtx_unlock(&blkif_io_lock);
-
-		// Must wait for the completion: the dump routine reuses the same
-		//                               16 x 4KB buffer space.
-		xb_quiesce(sc->xb_info);	// All quite on the eastern front
-		// If there were any errors, bail out...
-		for (mbp=0; mbp<sbp; mbp++) {
-			if ((rc = xb_dump_bp[mbp].bio_error)) break;
+
+		if (gnttab_alloc_grant_references(
+		    BLKIF_MAX_SEGMENTS_PER_REQUEST, &cm->gref_head) < 0) {
+			xb_free_command(cm);
+			mtx_unlock(&sc->xb_io_lock);
+			device_printf(sc->xb_dev, "no more grant allocs?\n");
+			return (EBUSY);
 		}
+
+		chunk = length > BLKIF_MAXIO ? BLKIF_MAXIO : length;
+		cm->data = virtual;
+		cm->datalen = chunk;
+		cm->operation = BLKIF_OP_WRITE;
+		cm->sector_number = offset / dp->d_sectorsize;
+		cm->cm_complete = xb_dump_complete;
+
+		xb_enqueue_ready(cm);
+
+		length -= chunk;
+		offset += chunk;
+		virtual = (char *) virtual + chunk;
 	}
+
+	/* Tell DOM0 to do the I/O */
+	xb_startio(sc);
+	mtx_unlock(&sc->xb_io_lock);
+
+	/* Poll for the completion. */
+	xb_quiesce(sc);	/* All quite on the eastern front */
+
+	/* If there were any errors, bail out... */
+	while ((cm = xb_dequeue_complete(sc)) != NULL) {
+		if (cm->status != BLKIF_RSP_OKAY) {
+			device_printf(sc->xb_dev,
+			    "Dump I/O failed at sector %jd\n",
+			    cm->sector_number);
+			rc = EIO;
+		}
+		xb_free_command(cm);
+	}
+
 	return (rc);
 }
 
@@ -410,9 +422,10 @@ blkfront_probe(device_t dev)
 static int
 blkfront_attach(device_t dev)
 {
-	int error, vdevice, i, unit;
-	struct blkfront_info *info;
+	struct xb_softc *sc;
+	struct xb_command *cm;
 	const char *name;
+	int error, vdevice, i, unit;
 
 	/* FIXME: Use dynamic device id if this is not set. */
 	error = xenbus_scanf(XBT_NIL, xenbus_get_node(dev),
@@ -427,29 +440,56 @@ blkfront_attach(device_t dev)
 	if (!strcmp(name, "xbd"))
 		device_set_unit(dev, unit);
 
-	info = device_get_softc(dev);
-	
-	/*
-	 * XXX debug only
-	 */
-	for (i = 0; i < sizeof(*info); i++)
-			if (((uint8_t *)info)[i] != 0)
-					panic("non-null memory");
-
-	info->shadow_free = 0;
-	info->xbdev = dev;
-	info->vdevice = vdevice;
-	info->connected = BLKIF_STATE_DISCONNECTED;
+	sc = device_get_softc(dev);
+	mtx_init(&sc->xb_io_lock, "blkfront i/o lock", NULL, MTX_DEF);
+	xb_initq_free(sc);
+	xb_initq_busy(sc);
+	xb_initq_ready(sc);
+	xb_initq_complete(sc);
+	xb_initq_bio(sc);
+
+	/* Allocate parent DMA tag */
+	if (bus_dma_tag_create(	NULL,			/* parent */
+				4096, 0,		/* algnmnt, boundary */
+				BUS_SPACE_MAXADDR,	/* lowaddr */
+				BUS_SPACE_MAXADDR,	/* highaddr */
+				NULL, NULL,		/* filter, filterarg */
+				BLKIF_MAXIO,		/* maxsize */
+				BLKIF_MAX_SEGMENTS_PER_REQUEST,	/* nsegments */
+				PAGE_SIZE,		/* maxsegsize */
+				BUS_DMA_ALLOCNOW,	/* flags */
+				busdma_lock_mutex,	/* lockfunc */
+				&sc->xb_io_lock,	/* lockarg */
+				&sc->xb_io_dmat)) {
+		device_printf(dev, "Cannot allocate parent DMA tag\n");
+		return (ENOMEM);
+	}
+#ifdef notyet
+	if (bus_dma_tag_set(sc->xb_io_dmat, BUS_DMA_SET_MINSEGSZ,
+		XBD_SECTOR_SIZE)) {
+		device_printf(dev, "Cannot set sector size\n");
+		return (EINVAL);
+	}
+#endif		
+
+	sc->xb_dev = dev;
+	sc->vdevice = vdevice;
+	sc->connected = BLKIF_STATE_DISCONNECTED;
 
 	/* work queue needed ? */
-	for (i = 0; i < BLK_RING_SIZE; i++)
-		info->shadow[i].req.id = i+1;
-	info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
+	for (i = 0; i < BLK_RING_SIZE; i++) {
+		cm = &sc->shadow[i];
+		cm->req.id = i;
+		cm->cm_sc = sc;
+		if (bus_dmamap_create(sc->xb_io_dmat, 0, &cm->map) != 0)
+			break;
+		xb_free_command(cm);
+	}
 
 	/* Front end dir is a number, which is used as the id. */
-	info->handle = strtoul(strrchr(xenbus_get_node(dev),'/')+1, NULL, 0);
+	sc->handle = strtoul(strrchr(xenbus_get_node(dev),'/')+1, NULL, 0);
 
-	error = talk_to_backend(dev, info);
+	error = talk_to_backend(sc);
 	if (error)
 		return (error);
 
@@ -459,12 +499,12 @@ blkfront_attach(device_t dev)
 static int
 blkfront_suspend(device_t dev)
 {
-	struct blkfront_info *info = device_get_softc(dev);
+	struct xb_softc *sc = device_get_softc(dev);
 
 	/* Prevent new requests being issued until we fix things up. */
-	mtx_lock(&blkif_io_lock);
-	info->connected = BLKIF_STATE_SUSPENDED;
-	mtx_unlock(&blkif_io_lock);
+	mtx_lock(&sc->xb_io_lock);
+	sc->connected = BLKIF_STATE_SUSPENDED;
+	mtx_unlock(&sc->xb_io_lock);
 
 	return (0);
 }
@@ -472,29 +512,31 @@ blkfront_suspend(device_t dev)
 static int
 blkfront_resume(device_t dev)
 {
-	struct blkfront_info *info = device_get_softc(dev);
+	struct xb_softc *sc = device_get_softc(dev);
 	int err;
 
 	DPRINTK("blkfront_resume: %s\n", xenbus_get_node(dev));
 
-	blkif_free(info, 1);
-	err = talk_to_backend(dev, info);
-	if (info->connected == BLKIF_STATE_SUSPENDED && !err)
-		blkif_recover(info);
+	blkif_free(sc, 1);
+	err = talk_to_backend(sc);
+	if (sc->connected == BLKIF_STATE_SUSPENDED && !err)
+		blkif_recover(sc);
 
 	return (err);
 }
 
 /* Common code used when first setting up, and when resuming. */
 static int
-talk_to_backend(device_t dev, struct blkfront_info *info)
+talk_to_backend(struct xb_softc *sc)
 {
-	const char *message = NULL;
+	device_t dev;
 	struct xenbus_transaction xbt;
+	const char *message = NULL;
 	int err;
 
 	/* Create shared ring, alloc event channel. */
-	err = setup_blkring(dev, info);
+	dev = sc->xb_dev;
+	err = setup_blkring(sc);
 	if (err)
 		goto out;
 
@@ -506,13 +548,13 @@ talk_to_backend(device_t dev, struct blk
 	}
 
 	err = xenbus_printf(xbt, xenbus_get_node(dev),
-			    "ring-ref","%u", info->ring_ref);
+			    "ring-ref","%u", sc->ring_ref);
 	if (err) {
 		message = "writing ring-ref";
 		goto abort_transaction;
 	}
 	err = xenbus_printf(xbt, xenbus_get_node(dev),
-		"event-channel", "%u", irq_to_evtchn_port(info->irq));
+		"event-channel", "%u", irq_to_evtchn_port(sc->irq));
 	if (err) {
 		message = "writing event-channel";
 		goto abort_transaction;
@@ -540,47 +582,47 @@ talk_to_backend(device_t dev, struct blk
 	if (message)
 		xenbus_dev_fatal(dev, err, "%s", message);
  destroy_blkring:
-	blkif_free(info, 0);
+	blkif_free(sc, 0);
  out:
 	return err;
 }
 
 static int 
-setup_blkring(device_t dev, struct blkfront_info *info)
+setup_blkring(struct xb_softc *sc)
 {
 	blkif_sring_t *sring;
 	int error;
 
-	info->ring_ref = GRANT_INVALID_REF;
+	sc->ring_ref = GRANT_INVALID_REF;
 
 	sring = (blkif_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT|M_ZERO);
 	if (sring == NULL) {
-		xenbus_dev_fatal(dev, ENOMEM, "allocating shared ring");
+		xenbus_dev_fatal(sc->xb_dev, ENOMEM, "allocating shared ring");
 		return ENOMEM;
 	}
 	SHARED_RING_INIT(sring);
-	FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
+	FRONT_RING_INIT(&sc->ring, sring, PAGE_SIZE);
 
-	error = xenbus_grant_ring(dev,
-	    (vtomach(info->ring.sring) >> PAGE_SHIFT), &info->ring_ref);
+	error = xenbus_grant_ring(sc->xb_dev,
+	    (vtomach(sc->ring.sring) >> PAGE_SHIFT), &sc->ring_ref);
 	if (error) {
 		free(sring, M_DEVBUF);
-		info->ring.sring = NULL;
+		sc->ring.sring = NULL;
 		goto fail;
 	}
 	
-	error = bind_listening_port_to_irqhandler(xenbus_get_otherend_id(dev),
-	    "xbd", (driver_intr_t *)blkif_int, info,
-	    INTR_TYPE_BIO | INTR_MPSAFE, &info->irq);
+	error = bind_listening_port_to_irqhandler(xenbus_get_otherend_id(sc->xb_dev),
+	    "xbd", (driver_intr_t *)blkif_int, sc,
+	    INTR_TYPE_BIO | INTR_MPSAFE, &sc->irq);
 	if (error) {
-		xenbus_dev_fatal(dev, error,
+		xenbus_dev_fatal(sc->xb_dev, error,
 		    "bind_evtchn_to_irqhandler failed");
 		goto fail;
 	}
 
 	return (0);
  fail:
-	blkif_free(info, 0);
+	blkif_free(sc, 0);
 	return (error);
 }
 
@@ -591,7 +633,7 @@ setup_blkring(device_t dev, struct blkfr
 static int
 blkfront_backend_changed(device_t dev, XenbusState backend_state)
 {
-	struct blkfront_info *info = device_get_softc(dev);
+	struct xb_softc *sc = device_get_softc(dev);
 
 	DPRINTK("backend_state=%d\n", backend_state);
 
@@ -606,22 +648,22 @@ blkfront_backend_changed(device_t dev, X
 		break;
 
 	case XenbusStateConnected:
-		connect(dev, info);
+		connect(sc);
 		break;
 
 	case XenbusStateClosing:
-		if (info->users > 0)
+		if (sc->users > 0)
 			xenbus_dev_error(dev, -EBUSY,
 					 "Device in use; refusing to close");
 		else
 			blkfront_closing(dev);
 #ifdef notyet
-		bd = bdget(info->dev);
+		bd = bdget(sc->dev);
 		if (bd == NULL)
 			xenbus_dev_fatal(dev, -ENODEV, "bdget failed");
 
 		down(&bd->bd_sem);
-		if (info->users > 0)
+		if (sc->users > 0)
 			xenbus_dev_error(dev, -EBUSY,
 					 "Device in use; refusing to close");
 		else
@@ -639,14 +681,15 @@ blkfront_backend_changed(device_t dev, X
 ** the details about the physical device - #sectors, size, etc). 
 */
 static void 
-connect(device_t dev, struct blkfront_info *info)
+connect(struct xb_softc *sc)
 {
+	device_t dev = sc->xb_dev;
 	unsigned long sectors, sector_size;
 	unsigned int binfo;
-	int err;
+	int err, feature_barrier;
 
-        if( (info->connected == BLKIF_STATE_CONNECTED) || 
-	    (info->connected == BLKIF_STATE_SUSPENDED) )
+        if( (sc->connected == BLKIF_STATE_CONNECTED) || 
+	    (sc->connected == BLKIF_STATE_SUSPENDED) )
 		return;
 
 	DPRINTK("blkfront.c:connect:%s.\n", xenbus_get_otherend_path(dev));
@@ -663,10 +706,10 @@ connect(device_t dev, struct blkfront_in
 		return;
 	}
 	err = xenbus_gather(XBT_NIL, xenbus_get_otherend_path(dev),
-			    "feature-barrier", "%lu", &info->feature_barrier,
+			    "feature-barrier", "%lu", &feature_barrier,
 			    NULL);
-	if (err)
-		info->feature_barrier = 0;
+	if (!err || feature_barrier)
+		sc->xb_flags |= XB_BARRIER;
 
 	device_printf(dev, "%juMB <%s> at %s",
 	    (uintmax_t) sectors / (1048576 / sector_size),
@@ -674,20 +717,17 @@ connect(device_t dev, struct blkfront_in
 	    xenbus_get_node(dev));
 	bus_print_child_footer(device_get_parent(dev), dev);
 
-	xlvbd_add(dev, sectors, info->vdevice, binfo, sector_size, info);
+	xlvbd_add(sc, sectors, sc->vdevice, binfo, sector_size);
 
 	(void)xenbus_set_state(dev, XenbusStateConnected); 
 
 	/* Kick pending requests. */
-	mtx_lock(&blkif_io_lock);
-	info->connected = BLKIF_STATE_CONNECTED;
-	kick_pending_request_queues(info);
-	mtx_unlock(&blkif_io_lock);
-	info->is_ready = 1;
+	mtx_lock(&sc->xb_io_lock);
+	sc->connected = BLKIF_STATE_CONNECTED;
+	xb_startio(sc);
+	sc->xb_flags |= XB_READY;
+	mtx_unlock(&sc->xb_io_lock);
 	
-#if 0
-	add_disk(info->gd);
-#endif
 }
 
 /**
@@ -699,14 +739,14 @@ connect(device_t dev, struct blkfront_in
 static void
 blkfront_closing(device_t dev)
 {
-	struct blkfront_info *info = device_get_softc(dev);
+	struct xb_softc *sc = device_get_softc(dev);
 
 	DPRINTK("blkfront_closing: %s removed\n", xenbus_get_node(dev));
 
-	if (info->mi) {
+	if (sc->mi) {
 		DPRINTK("Calling xlvbd_del\n");
-		xlvbd_del(info);
-		info->mi = NULL;
+		xlvbd_del(sc);
+		sc->mi = NULL;
 	}
 
 	xenbus_set_state(dev, XenbusStateClosed);
@@ -716,92 +756,33 @@ blkfront_closing(device_t dev)
 static int
 blkfront_detach(device_t dev)
 {
-	struct blkfront_info *info = device_get_softc(dev);
+	struct xb_softc *sc = device_get_softc(dev);
 
 	DPRINTK("blkfront_remove: %s removed\n", xenbus_get_node(dev));
 
-	blkif_free(info, 0);
+	blkif_free(sc, 0);
+	mtx_destroy(&sc->xb_io_lock);
 
 	return 0;
 }
 
 
-static inline int 
-GET_ID_FROM_FREELIST(struct blkfront_info *info)
-{
-	unsigned long nfree = info->shadow_free;
-	
-	KASSERT(nfree <= BLK_RING_SIZE, ("free %lu > RING_SIZE", nfree));
-	info->shadow_free = info->shadow[nfree].req.id;
-	info->shadow[nfree].req.id = 0x0fffffee; /* debug */
-	atomic_add_int(&blkif_queued_requests, 1);
-	return nfree;
-}
-
 static inline void 
-ADD_ID_TO_FREELIST(struct blkfront_info *info, unsigned long id)
-{
-	info->shadow[id].req.id  = info->shadow_free;
-	info->shadow[id].request = 0;
-	info->shadow_free = id;
-	atomic_subtract_int(&blkif_queued_requests, 1);
-}
-
-static inline void 
-flush_requests(struct blkfront_info *info)
+flush_requests(struct xb_softc *sc)
 {
 	int notify;
 
-	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->ring, notify);
+	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->ring, notify);
 
 	if (notify)
-		notify_remote_via_irq(info->irq);
-}
-
-static void 
-kick_pending_request_queues(struct blkfront_info *info)
-{
-	/* XXX check if we can't simplify */
-#if 0
-	if (!RING_FULL(&info->ring)) {
-		/* Re-enable calldowns. */
-		blk_start_queue(info->rq);
-		/* Kick things off immediately. */
-		do_blkif_request(info->rq);
-	}
-#endif
-	if (!RING_FULL(&info->ring)) {
-#if 0
-		sc = LIST_FIRST(&xbsl_head);
-		LIST_REMOVE(sc, entry);
-		/* Re-enable calldowns. */
-		blk_start_queue(di->rq);
-#endif
-		/* Kick things off immediately. */
-		xb_startio(info->sc);
-	}
-}
-
-#if 0
-/* XXX */
-static void blkif_restart_queue(void *arg)
-{
-	struct blkfront_info *info = (struct blkfront_info *)arg;
-
-	mtx_lock(&blkif_io_lock);
-	kick_pending_request_queues(info);
-	mtx_unlock(&blkif_io_lock);
+		notify_remote_via_irq(sc->irq);
 }
-#endif
 
 static void blkif_restart_queue_callback(void *arg)
 {
-#if 0
-	struct blkfront_info *info = (struct blkfront_info *)arg;
-	/* XXX BSD equiv ? */
+	struct xb_softc *sc = arg;
 
-	schedule_work(&info->work);
-#endif
+	xb_startio(sc);
 }
 
 static int
@@ -815,7 +796,7 @@ blkif_open(struct disk *dp)
 	}
 
 	sc->xb_flags |= XB_OPEN;
-	sc->xb_info->users++;
+	sc->users++;
 	return (0);
 }
 
@@ -827,11 +808,11 @@ blkif_close(struct disk *dp)
 	if (sc == NULL)
 		return (ENXIO);
 	sc->xb_flags &= ~XB_OPEN;
-	if (--(sc->xb_info->users) == 0) {
+	if (--(sc->users) == 0) {
 		/* Check whether we have been instructed to close.  We will
 		   have ignored this request initially, as the device was
 		   still mounted. */
-		device_t dev = sc->xb_info->xbdev;
+		device_t dev = sc->xb_dev;
 		XenbusState state =
 			xenbus_read_driver_state(xenbus_get_otherend_path(dev));
 
@@ -852,6 +833,18 @@ blkif_ioctl(struct disk *dp, u_long cmd,
 	return (ENOTTY);
 }
 
+static void
+xb_free_command(struct xb_command *cm)
+{
+
+	KASSERT((cm->cm_flags & XB_ON_XBQ_MASK) == 0,
+	    ("Freeing command that is still on a queue\n"));
+
+	cm->cm_flags = 0;
+	cm->bp = NULL;
+	cm->cm_complete = NULL;
+	xb_enqueue_free(cm);
+}
 
 /*
  * blkif_queue_request
@@ -863,106 +856,152 @@ blkif_ioctl(struct disk *dp, u_long cmd,
  * buffer: buffer to read/write into. this should be a
  *   virtual address in the guest os.
  */
-static int blkif_queue_request(struct bio *bp)
+static struct xb_command *
+xb_bio_command(struct xb_softc *sc)
+{
+	struct xb_command *cm;
+	struct bio *bp;
+
+	if (unlikely(sc->connected != BLKIF_STATE_CONNECTED))
+		return (NULL);
+
+	bp = xb_dequeue_bio(sc);
+	if (bp == NULL)
+		return (NULL);
+
+	if ((cm = xb_dequeue_free(sc)) == NULL) {
+		xb_requeue_bio(sc, bp);
+		return (NULL);
+	}
+
+	if (gnttab_alloc_grant_references(BLKIF_MAX_SEGMENTS_PER_REQUEST,
+	    &cm->gref_head) < 0) {
+		gnttab_request_free_callback(&sc->callback,
+			blkif_restart_queue_callback, sc,
+			BLKIF_MAX_SEGMENTS_PER_REQUEST);
+		xb_requeue_bio(sc, bp);
+		xb_enqueue_free(cm);
+		sc->xb_flags |= XB_FROZEN;
+		return (NULL);
+	}
+
+	/* XXX Can we grab refs before doing the load so that the ref can
+	 * be filled out here?
+	 */
+	cm->bp = bp;
+	cm->data = bp->bio_data;
+	cm->datalen = bp->bio_bcount;
+	cm->operation = (bp->bio_cmd == BIO_READ) ? BLKIF_OP_READ :
+	    BLKIF_OP_WRITE;
+	cm->sector_number = (blkif_sector_t)bp->bio_pblkno;
+
+	return (cm);
+}
+
+static int
+blkif_queue_request(struct xb_softc *sc, struct xb_command *cm)
 {
-	caddr_t alignbuf;
+	int	error;
+
+	error = bus_dmamap_load(sc->xb_io_dmat, cm->map, cm->data, cm->datalen,
+	    blkif_queue_cb, cm, 0);
+	if (error == EINPROGRESS) {
+		printf("EINPROGRESS\n");
+		sc->xb_flags |= XB_FROZEN;
+		cm->cm_flags |= XB_CMD_FROZEN;
+		return (0);
+	}
+
+	return (error);
+}
+
+static void
+blkif_queue_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+	struct xb_softc *sc;
+	struct xb_command *cm;
+	blkif_request_t	*ring_req;
 	vm_paddr_t buffer_ma;
-	blkif_request_t     *ring_req;
-	unsigned long id;
 	uint64_t fsect, lsect;
-	struct xb_softc *sc = (struct xb_softc *)bp->bio_disk->d_drv1;
-	struct blkfront_info *info = sc->xb_info;
-	int ref;
-
-	if (unlikely(sc->xb_info->connected != BLKIF_STATE_CONNECTED))
-		return 1;
-
-	if (gnttab_alloc_grant_references(
-		    BLKIF_MAX_SEGMENTS_PER_REQUEST, &gref_head) < 0) {
-		gnttab_request_free_callback(
-			&info->callback,
-			blkif_restart_queue_callback,
-			info,
-			BLKIF_MAX_SEGMENTS_PER_REQUEST);
-		return 1;
+	int ref, i, op;
+
+	cm = arg;
+	sc = cm->cm_sc;
+
+	if (error) {
+		printf("error %d in blkif_queue_cb\n", error);
+		cm->bp->bio_error = EIO;
+		biodone(cm->bp);
+		xb_free_command(cm);
+		return;
 	}
 
-	/* Check if the buffer is properly aligned */
-	if ((vm_offset_t)bp->bio_data & PAGE_MASK) {
-		int align = (bp->bio_bcount < PAGE_SIZE/2) ? XBD_SECTOR_SIZE : 
-			PAGE_SIZE;
-		caddr_t newbuf = malloc(bp->bio_bcount + align, M_DEVBUF, 
-					M_NOWAIT);
-
-		alignbuf = (char *)roundup2((u_long)newbuf, align);
-
-		/* save a copy of the current buffer */
-		bp->bio_driver1 = newbuf;
-		bp->bio_driver2 = alignbuf;
-
-		/* Copy the data for a write */
-		if (bp->bio_cmd == BIO_WRITE)
-			bcopy(bp->bio_data, alignbuf, bp->bio_bcount);
-	} else
-		alignbuf = bp->bio_data;
-	
 	/* Fill out a communications ring structure. */
-	ring_req 	         = RING_GET_REQUEST(&info->ring, 
-						    info->ring.req_prod_pvt);
-	id		         = GET_ID_FROM_FREELIST(info);
-	info->shadow[id].request = (unsigned long)bp;
-	
-	ring_req->id 	         = id;
-	ring_req->operation 	 = (bp->bio_cmd == BIO_READ) ? BLKIF_OP_READ :
-		BLKIF_OP_WRITE;
-	
-	ring_req->sector_number= (blkif_sector_t)bp->bio_pblkno;
-	ring_req->handle 	  = (blkif_vdev_t)(uintptr_t)sc->xb_disk;
-	
-	ring_req->nr_segments  = 0;	/* XXX not doing scatter/gather since buffer
-					 * chaining is not supported.

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200911300432.nAU4WYeA018513>