socsvn commit: r257080 - soc2013/zcore/head/usr.sbin/bhyve

zcore at FreeBSD.org zcore at FreeBSD.org
Sat Sep 7 16:04:26 UTC 2013


Author: zcore
Date: Sat Sep  7 16:04:26 2013
New Revision: 257080
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=257080

Log:
  support ATA_READ_DMA

Modified:
  soc2013/zcore/head/usr.sbin/bhyve/block_if.h
  soc2013/zcore/head/usr.sbin/bhyve/pci_ahci.c

Modified: soc2013/zcore/head/usr.sbin/bhyve/block_if.h
==============================================================================
--- soc2013/zcore/head/usr.sbin/bhyve/block_if.h	Sat Sep  7 15:16:30 2013	(r257079)
+++ soc2013/zcore/head/usr.sbin/bhyve/block_if.h	Sat Sep  7 16:04:26 2013	(r257080)
@@ -32,7 +32,9 @@
 #include <sys/uio.h>
 #include <sys/unistd.h>
 
-#define BLOCKIF_IOV_MAX		32	/* XXX */
+#include "ahci.h"
+
+#define BLOCKIF_IOV_MAX		AHCI_SG_ENTRIES /* XXX */
 
 struct blockif_req {
 	struct iovec	br_iov[BLOCKIF_IOV_MAX];

Modified: soc2013/zcore/head/usr.sbin/bhyve/pci_ahci.c
==============================================================================
--- soc2013/zcore/head/usr.sbin/bhyve/pci_ahci.c	Sat Sep  7 15:16:30 2013	(r257079)
+++ soc2013/zcore/head/usr.sbin/bhyve/pci_ahci.c	Sat Sep  7 16:04:26 2013	(r257080)
@@ -79,10 +79,11 @@
 struct ahci_ioreq {
 	struct blockif_req io_req;
 	struct ahci_port *io_pr;
-	uint32_t io_genid;
 	STAILQ_ENTRY(ahci_ioreq) io_list;
-	int io_didx;
-	uint8_t *io_status;
+	uint8_t *cfis;
+	int slot;
+	uint8_t status;
+	uint8_t error;
 };
 
 struct ahci_port {
@@ -93,6 +94,7 @@
 	int atapi;
 	int reset;
 	int mult_sectors;
+	uint32_t unhandled;
 	uint8_t xfermode;
 
 	uint32_t clb;
@@ -212,7 +214,34 @@
 	}
 }
 
-static void ahci_write_fis_d2h(struct ahci_port *p)
+static void ahci_write_fis_d2h(struct ahci_port *p, struct ahci_ioreq *aior)
+{
+	uint8_t fis[20];
+	uint8_t *cfis = aior->cfis;
+
+	memset(fis, 0, sizeof(fis));
+	fis[0] = FIS_TYPE_REGD2H;
+	fis[1] = (1 << 6);
+	fis[2] = aior->status;
+	fis[3] = aior->error;
+	fis[4] = cfis[4];
+	fis[5] = cfis[5];
+	fis[6] = cfis[6];
+	fis[7] = cfis[7];
+	fis[8] = cfis[8];
+	fis[9] = cfis[9];
+	fis[10] = cfis[10];
+	fis[11] = cfis[11];
+	fis[12] = cfis[12];
+	fis[13] = cfis[13];
+	if (aior->error & ATA_S_ERROR)
+		p->is |= AHCI_P_IX_TFE;
+	p->tfd = (aior->error << 8) | aior->status;
+	p->ci &= ~(1 << aior->slot);
+	ahci_write_fis(p, FIS_TYPE_REGD2H, fis);
+}
+
+static void ahci_write_reset_fis_d2h(struct ahci_port *p)
 {
 	uint8_t fis[20];
 
@@ -228,60 +257,6 @@
 	ahci_write_fis(p, FIS_TYPE_REGD2H, fis);
 }
 
-/*
- * blockif callback routine - this runs in the context of the blockif
- * i/o thread, so the mutex needs to be acquired.
- */
-static void
-pci_ahci_ioreq_cb(struct blockif_req *br, int err)
-{
-	struct ahci_port *pr;
-	struct pci_ahci_softc *sc;
-	struct ahci_ioreq *vio;
-
-	vio = br->br_param;
-	pr = vio->io_pr;
-	sc = pr->pr_sc;
-
-	DPRINTF(("ahci_ioreq_cb %d\n", err));
-	pthread_mutex_lock(&sc->mtx);
-
-	/* TODO */
-
-	ahci_generate_intr(sc);
-	/*
-	 * Move the blockif request back to the free list
-	 */
-	STAILQ_INSERT_TAIL(&pr->iofhd, vio, io_list);
-	pr->iofree++;
-
-	pthread_mutex_unlock(&sc->mtx);
-	DPRINTF(("%s exit\n", __func__));
-}
-
-static void
-pci_ahci_ioreq_init(struct ahci_port *pr)
-{
-	struct ahci_ioreq *vr;
-	int i;
-
-	pr->ioqsz = blockif_queuesz(pr->bctx);
-	pr->ioreq = calloc(pr->ioqsz, sizeof(struct ahci_ioreq));
-	STAILQ_INIT(&pr->iofhd);
-
-	/*
-	 * Add all i/o request entries to the free queue
-	 */
-	for (i = 0; i < pr->ioqsz; i++) {
-		vr = &pr->ioreq[i];
-		vr->io_pr = pr;
-		vr->io_req.br_callback = pci_ahci_ioreq_cb;
-		vr->io_req.br_param = vr;
-		STAILQ_INSERT_TAIL(&pr->iofhd, vr, io_list);
-		pr->iofree++;
-	}
-}
-
 static void
 ahci_port_reset(struct ahci_port *pr)
 {
@@ -305,7 +280,7 @@
 		pr->tfd |= ATA_S_READY;
 	} else
 		pr->sig = PxSIG_ATAPI;
-	ahci_write_fis_d2h(pr);
+	ahci_write_reset_fis_d2h(pr);
 }
 
 static void
@@ -336,8 +311,59 @@
 }
 
 static void
-handle_cmd(struct ahci_port *p, int slot, uint8_t *cfis,
-		struct ahci_cmd_hdr *hdr)
+read_dma(struct ahci_port *p, int slot, uint8_t *cfis)
+{
+	int i, err;
+	uint64_t lba;
+	uint32_t len;
+	struct ahci_ioreq *aior;
+	struct blockif_req *breq;
+	struct pci_ahci_softc *sc = p->pr_sc;
+	struct ahci_prdt_entry *prdt = (struct ahci_prdt_entry *)(cfis + 0x80);
+	struct ahci_cmd_hdr *hdr = p->cmd_lst + slot * AHCI_CL_SIZE;
+
+	lba = ((cfis[7] & 0xf) << 24) | (cfis[6] << 16) |
+		(cfis[5] << 8) | cfis[4];
+	lba *= blockif_sectsz(p->bctx);
+
+	if (!cfis[12])
+		len = 256;
+	else
+		len = cfis[12];
+	len *= blockif_sectsz(p->bctx);
+
+	/*
+	 * Pull request off free list
+	 */
+	if (!p->iofree) {
+		p->unhandled |= (1 << slot);
+		return;
+	}
+	aior = STAILQ_FIRST(&p->iofhd);
+	assert(aior != NULL);
+	STAILQ_REMOVE_HEAD(&p->iofhd, io_list);
+	p->iofree--;
+	aior->cfis = cfis;
+	aior->slot = slot;
+	breq = &aior->io_req;
+	breq->br_offset = lba;
+	breq->br_iovcnt = hdr->prdtl;
+
+	/*
+	 * Build up the iovec based on the prdt
+	 */
+	for (i = 0; i < hdr->prdtl; i++) {
+		breq->br_iov[i].iov_base = paddr_guest2host(ahci_ctx(sc),
+				prdt->dba, prdt->dbc + 1);
+		breq->br_iov[i].iov_len = prdt->dbc + 1;
+		prdt++;
+	}
+	err = blockif_read(p->bctx, breq);
+	assert(err == 0);
+}
+
+static void
+handle_cmd(struct ahci_port *p, int slot, uint8_t *cfis)
 {
 	struct pci_ahci_softc *sc = p->pr_sc;
 	struct ahci_prdt_entry *prdt = (struct ahci_prdt_entry *)(cfis + 0x80);
@@ -349,6 +375,7 @@
 		uint64_t sectors;
 		int i, len;
 		void *from;
+		struct ahci_cmd_hdr *hdr;
 
 		sectors = blockif_size(p->bctx) / blockif_sectsz(p->bctx);
 		memset(buf, 0, sizeof(buf));
@@ -392,6 +419,7 @@
 		buf[101] = (sectors >> 16);
 		buf[102] = (sectors >> 32);
 		buf[103] = (sectors >> 48);
+		hdr = p->cmd_lst + slot * AHCI_CL_SIZE;
 		if (hdr->prdtl == 0) {
 			WPRINTF(("wrong prdtl\n"));
 			return;
@@ -409,6 +437,7 @@
 		hdr->prdbc = sizeof(buf) - len;
 		p->tfd = ATA_S_DSC | ATA_S_READY;
 		p->is |= AHCI_P_IX_DP;
+		p->ci &= ~(1 << slot);
 		ahci_generate_intr(sc);
 		break;
 	}
@@ -441,6 +470,7 @@
 			break;
 		}
 		p->is |= AHCI_P_IX_DP;
+		p->ci &= ~(1 << slot);
 		ahci_generate_intr(sc);
 		break;
 	}
@@ -454,8 +484,12 @@
 			p->tfd = ATA_S_DSC | ATA_S_READY;
 		}
 		p->is |= AHCI_P_IX_DP;
+		p->ci &= ~(1 << slot);
 		ahci_generate_intr(sc);
 		break;
+	case ATA_READ_DMA:
+		read_dma(p, slot, cfis);
+		break;
 	default:
 		break;
 	}
@@ -499,7 +533,7 @@
 
 	if (cfis[1] & 0x80) {
 		dprintf("command cfis\n");
-		handle_cmd(p, slot, cfis, hdr);
+		handle_cmd(p, slot, cfis);
 	} else {
 		dprintf("control cfis\n");
 		if (cfis[15] & (1 << 2))
@@ -508,6 +542,7 @@
 			p->reset = 0;
 			ahci_port_reset(p);
 		}
+		p->ci &= ~(1 << slot);
 	}
 }
 
@@ -515,19 +550,86 @@
 handle_port(struct ahci_port *p)
 {
 	int i;
-	struct pci_ahci_softc *sc;
 
-	if (!(p->cmd & AHCI_P_CMD_ST) || !p->ci)
+	if (!(p->cmd & AHCI_P_CMD_ST))
 		return;
 
-	sc = p->pr_sc;
-
 	for (i = 0; (i < 32) && p->ci; i++) {
-		if (p->ci & (1 << i)) {
+		if (p->ci & (1 << i))
 			handle_slot(p, i);
-			p->ci &= ~(1 << i);
+	}
+}
+
+/*
+ * blockif callback routine - this runs in the context of the blockif
+ * i/o thread, so the mutex needs to be acquired.
+ */
+static void
+pci_ahci_ioreq_cb(struct blockif_req *br, int err)
+{
+	struct ahci_port *p;
+	struct pci_ahci_softc *sc;
+	struct ahci_ioreq *aior;
+
+	aior = br->br_param;
+	p = aior->io_pr;
+	sc = p->pr_sc;
+
+	DPRINTF(("ahci_ioreq_cb %d\n", err));
+	pthread_mutex_lock(&sc->mtx);
+
+	if (err) {
+		aior->status = ATA_S_READY | ATA_S_ERROR;
+		aior->error = ATA_E_ABORT;
+	} else {
+		aior->status = ATA_S_READY | ATA_S_DSC;
+		aior->error = 0;
+	}
+	ahci_write_fis_d2h(p, aior);
+
+	/*
+	 * Move the blockif request back to the free list
+	 */
+	STAILQ_INSERT_TAIL(&p->iofhd, aior, io_list);
+	p->iofree++;
+
+	/*
+	 * If the number of oustanding commands has dropped below the
+	 * threshold, see if more can be queued up
+	 */
+	if (p->ioqsz - p->iofree <= 2 && (p->cmd & AHCI_P_CMD_ST)) {
+		int i;
+		for (i = 0; (i < 32) && p->unhandled; i++) {
+			if (p->unhandled & (1 << i))
+				handle_slot(p, i);
 		}
 	}
+
+	pthread_mutex_unlock(&sc->mtx);
+	DPRINTF(("%s exit\n", __func__));
+}
+
+static void
+pci_ahci_ioreq_init(struct ahci_port *pr)
+{
+	struct ahci_ioreq *vr;
+	int i;
+
+	pr->ioqsz = blockif_queuesz(pr->bctx);
+	pr->ioreq = calloc(pr->ioqsz, sizeof(struct ahci_ioreq));
+	STAILQ_INIT(&pr->iofhd);
+
+	/*
+	 * Add all i/o request entries to the free queue
+	 */
+	for (i = 0; i < pr->ioqsz; i++) {
+		vr = &pr->ioreq[i];
+		vr->io_pr = pr;
+		vr->io_req.br_callback = pci_ahci_ioreq_cb;
+		vr->io_req.br_param = vr;
+		STAILQ_INSERT_TAIL(&pr->iofhd, vr, io_list);
+		pr->iofree++;
+	}
 }
 
 static int
@@ -563,14 +665,17 @@
 	pi->pi_arg = sc;
 	sc->asc_pi = pi;
 
-	for (i = 0; i < AHCI_MAX_PORTS; i++)
-		sc->port[i].pr_sc = sc;
-	/*
-	 * Allocate blockif request structures and add them
-	 * to the free list
-	 */
 	sc->port[0].bctx = bctxt;
-	pci_ahci_ioreq_init(&sc->port[0]);
+
+	for (i = 0; i < AHCI_MAX_PORTS; i++) {
+		sc->port[i].pr_sc = sc;
+		/*
+		 * Allocate blockif request structures and add them
+		 * to the free list
+		 */
+		if (sc->port[i].bctx)
+			pci_ahci_ioreq_init(&sc->port[i]);
+	}
 
 	pthread_mutex_init(&sc->mtx, NULL);
 


More information about the svn-soc-all mailing list