Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 17 Oct 2014 11:37:51 +0000 (UTC)
From:      Tycho Nightingale <tychon@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r273212 - head/usr.sbin/bhyve
Message-ID:  <201410171137.s9HBbpAq092967@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: tychon
Date: Fri Oct 17 11:37:50 2014
New Revision: 273212
URL: https://svnweb.freebsd.org/changeset/base/273212

Log:
  Support stopping and restarting the AHCI command list via toggling
  PxCMD.ST from '1' to '0' and back.  This allows the driver a chance to
  recover if for instance a timeout occurred due to activity on the
  host.
  
  Reviewed by:	grehan

Modified:
  head/usr.sbin/bhyve/block_if.c
  head/usr.sbin/bhyve/pci_ahci.c

Modified: head/usr.sbin/bhyve/block_if.c
==============================================================================
--- head/usr.sbin/bhyve/block_if.c	Fri Oct 17 09:33:09 2014	(r273211)
+++ head/usr.sbin/bhyve/block_if.c	Fri Oct 17 11:37:50 2014	(r273212)
@@ -55,8 +55,7 @@ __FBSDID("$FreeBSD$");
 enum blockop {
 	BOP_READ,
 	BOP_WRITE,
-	BOP_FLUSH,
-	BOP_CANCEL
+	BOP_FLUSH
 };
 
 enum blockstat {
@@ -159,9 +158,6 @@ blockif_proc(struct blockif_ctxt *bc, st
 		break;
 	case BOP_FLUSH:
 		break;
-	case BOP_CANCEL:
-		err = EINTR;
-		break;
 	default:
 		err = EINVAL;
 		break;
@@ -356,9 +352,28 @@ blockif_flush(struct blockif_ctxt *bc, s
 int
 blockif_cancel(struct blockif_ctxt *bc, struct blockif_req *breq)
 {
+	struct blockif_elem *be;
 
 	assert(bc->bc_magic == BLOCKIF_SIG);
-	return (blockif_request(bc, breq, BOP_CANCEL));
+
+	pthread_mutex_lock(&bc->bc_mtx);
+	TAILQ_FOREACH(be, &bc->bc_inuseq, be_link) {
+		if (be->be_req == breq)
+			break;
+	}
+	if (be == NULL) {
+		pthread_mutex_unlock(&bc->bc_mtx);
+		return (EINVAL);
+	}
+
+	TAILQ_REMOVE(&bc->bc_inuseq, be, be_link);
+	be->be_status = BST_FREE;
+	be->be_req = NULL;
+	TAILQ_INSERT_TAIL(&bc->bc_freeq, be, be_link);
+	bc->bc_req_count--;
+	pthread_mutex_unlock(&bc->bc_mtx);
+
+	return (0);
 }
 
 int

Modified: head/usr.sbin/bhyve/pci_ahci.c
==============================================================================
--- head/usr.sbin/bhyve/pci_ahci.c	Fri Oct 17 09:33:09 2014	(r273211)
+++ head/usr.sbin/bhyve/pci_ahci.c	Fri Oct 17 11:37:50 2014	(r273212)
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
 #include <unistd.h>
 #include <assert.h>
 #include <pthread.h>
+#include <pthread_np.h>
 #include <inttypes.h>
 
 #include "bhyverun.h"
@@ -115,7 +116,8 @@ static FILE *dbg;
 struct ahci_ioreq {
 	struct blockif_req io_req;
 	struct ahci_port *io_pr;
-	STAILQ_ENTRY(ahci_ioreq) io_list;
+	STAILQ_ENTRY(ahci_ioreq) io_flist;
+	TAILQ_ENTRY(ahci_ioreq) io_blist;
 	uint8_t *cfis;
 	uint32_t len;
 	uint32_t done;
@@ -160,6 +162,7 @@ struct ahci_port {
 	struct ahci_ioreq *ioreq;
 	int ioqsz;
 	STAILQ_HEAD(ahci_fhead, ahci_ioreq) iofhd;
+	TAILQ_HEAD(ahci_bhead, ahci_ioreq) iobhd;
 };
 
 struct ahci_cmd_hdr {
@@ -360,6 +363,68 @@ ahci_write_reset_fis_d2h(struct ahci_por
 }
 
 static void
+ahci_check_stopped(struct ahci_port *p)
+{
+	/*
+	 * If we are no longer processing the command list and nothing
+	 * is in-flight, clear the running bit.
+	 */
+	if (!(p->cmd & AHCI_P_CMD_ST)) {
+		if (p->pending == 0)
+			p->cmd &= ~(AHCI_P_CMD_CR | AHCI_P_CMD_CCS_MASK);
+	}
+}
+
+static void
+ahci_port_stop(struct ahci_port *p)
+{
+	struct ahci_ioreq *aior;
+	uint8_t *cfis;
+	int slot;
+	int ncq;
+	int error;
+
+	assert(pthread_mutex_isowned_np(&p->pr_sc->mtx));
+
+	TAILQ_FOREACH(aior, &p->iobhd, io_blist) {
+		/*
+		 * Try to cancel the outstanding blockif request.
+		 */
+		error = blockif_cancel(p->bctx, &aior->io_req);
+		if (error != 0)
+			continue;
+
+		slot = aior->slot;
+		cfis = aior->cfis;
+		if (cfis[2] == ATA_WRITE_FPDMA_QUEUED ||
+		    cfis[2] == ATA_READ_FPDMA_QUEUED)
+			ncq = 1;
+
+		if (ncq)
+			p->sact &= ~(1 << slot);
+		else
+			p->ci &= ~(1 << slot);
+
+		/*
+		 * This command is now done.
+		 */
+		p->pending &= ~(1 << slot);
+
+		/*
+		 * Delete the blockif request from the busy list
+		 */
+		TAILQ_REMOVE(&p->iobhd, aior, io_blist);
+
+		/*
+		 * Move the blockif request back to the free list
+		 */
+		STAILQ_INSERT_TAIL(&p->iofhd, aior, io_flist);
+	}
+
+	ahci_check_stopped(p);
+}
+
+static void
 ahci_port_reset(struct ahci_port *pr)
 {
 	pr->sctl = 0;
@@ -492,7 +557,7 @@ ahci_handle_dma(struct ahci_port *p, int
 	 */
 	aior = STAILQ_FIRST(&p->iofhd);
 	assert(aior != NULL);
-	STAILQ_REMOVE_HEAD(&p->iofhd, io_list);
+	STAILQ_REMOVE_HEAD(&p->iofhd, io_flist);
 	aior->cfis = cfis;
 	aior->slot = slot;
 	aior->len = len;
@@ -503,15 +568,21 @@ ahci_handle_dma(struct ahci_port *p, int
 	if (iovcnt > BLOCKIF_IOV_MAX) {
 		aior->prdtl = iovcnt - BLOCKIF_IOV_MAX;
 		iovcnt = BLOCKIF_IOV_MAX;
-		/*
-		 * Mark this command in-flight.
-		 */
-		p->pending |= 1 << slot;
 	} else
 		aior->prdtl = 0;
 	breq->br_iovcnt = iovcnt;
 
 	/*
+	 * Mark this command in-flight.
+	 */
+	p->pending |= 1 << slot;
+
+	/*
+	 * Stuff request onto busy list
+	 */
+	TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist);
+
+	/*
 	 * Build up the iovec based on the prdt
 	 */
 	for (i = 0; i < iovcnt; i++) {
@@ -546,7 +617,7 @@ ahci_handle_flush(struct ahci_port *p, i
 	 */
 	aior = STAILQ_FIRST(&p->iofhd);
 	assert(aior != NULL);
-	STAILQ_REMOVE_HEAD(&p->iofhd, io_list);
+	STAILQ_REMOVE_HEAD(&p->iofhd, io_flist);
 	aior->cfis = cfis;
 	aior->slot = slot;
 	aior->len = 0;
@@ -554,6 +625,16 @@ ahci_handle_flush(struct ahci_port *p, i
 	aior->prdtl = 0;
 	breq = &aior->io_req;
 
+	/*
+	 * Mark this command in-flight.
+	 */
+	p->pending |= 1 << slot;
+
+	/*
+	 * Stuff request onto busy list
+	 */
+	TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist);
+
 	err = blockif_flush(p->bctx, breq);
 	assert(err == 0);
 }
@@ -961,7 +1042,7 @@ atapi_read(struct ahci_port *p, int slot
 	 */
 	aior = STAILQ_FIRST(&p->iofhd);
 	assert(aior != NULL);
-	STAILQ_REMOVE_HEAD(&p->iofhd, io_list);
+	STAILQ_REMOVE_HEAD(&p->iofhd, io_flist);
 	aior->cfis = cfis;
 	aior->slot = slot;
 	aior->len = len;
@@ -977,6 +1058,16 @@ atapi_read(struct ahci_port *p, int slot
 	breq->br_iovcnt = iovcnt;
 
 	/*
+	 * Mark this command in-flight.
+	 */
+	p->pending |= 1 << slot;
+
+	/*
+	 * Stuff request onto busy list
+	 */
+	TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist);
+
+	/*
 	 * Build up the iovec based on the prdt
 	 */
 	for (i = 0; i < iovcnt; i++) {
@@ -1415,9 +1506,14 @@ ata_ioreq_cb(struct blockif_req *br, int
 	pthread_mutex_lock(&sc->mtx);
 
 	/*
+	 * Delete the blockif request from the busy list
+	 */
+	TAILQ_REMOVE(&p->iobhd, aior, io_blist);
+
+	/*
 	 * Move the blockif request back to the free list
 	 */
-	STAILQ_INSERT_TAIL(&p->iofhd, aior, io_list);
+	STAILQ_INSERT_TAIL(&p->iofhd, aior, io_flist);
 
 	if (pending && !err) {
 		ahci_handle_dma(p, slot, cfis, aior->done,
@@ -1438,17 +1534,18 @@ ata_ioreq_cb(struct blockif_req *br, int
 			p->serr |= (1 << slot);
 	}
 
-	/*
-	 * This command is now complete.
-	 */
-	p->pending &= ~(1 << slot);
-
 	if (ncq) {
 		p->sact &= ~(1 << slot);
 		ahci_write_fis_sdb(p, slot, tfd);
 	} else
 		ahci_write_fis_d2h(p, slot, cfis, tfd);
 
+	/*
+	 * This command is now complete.
+	 */
+	p->pending &= ~(1 << slot);
+
+	ahci_check_stopped(p);
 out:
 	pthread_mutex_unlock(&sc->mtx);
 	DPRINTF("%s exit\n", __func__);
@@ -1478,9 +1575,14 @@ atapi_ioreq_cb(struct blockif_req *br, i
 	pthread_mutex_lock(&sc->mtx);
 
 	/*
+	 * Delete the blockif request from the busy list
+	 */
+	TAILQ_REMOVE(&p->iobhd, aior, io_blist);
+
+	/*
 	 * Move the blockif request back to the free list
 	 */
-	STAILQ_INSERT_TAIL(&p->iofhd, aior, io_list);
+	STAILQ_INSERT_TAIL(&p->iofhd, aior, io_flist);
 
 	if (pending && !err) {
 		atapi_read(p, slot, cfis, aior->done, hdr->prdtl - pending);
@@ -1500,6 +1602,12 @@ atapi_ioreq_cb(struct blockif_req *br, i
 	cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
 	ahci_write_fis_d2h(p, slot, cfis, tfd);
 
+	/*
+	 * This command is now complete.
+	 */
+	p->pending &= ~(1 << slot);
+
+	ahci_check_stopped(p);
 out:
 	pthread_mutex_unlock(&sc->mtx);
 	DPRINTF("%s exit\n", __func__);
@@ -1526,8 +1634,10 @@ pci_ahci_ioreq_init(struct ahci_port *pr
 		else
 			vr->io_req.br_callback = atapi_ioreq_cb;
 		vr->io_req.br_param = vr;
-		STAILQ_INSERT_TAIL(&pr->iofhd, vr, io_list);
+		STAILQ_INSERT_TAIL(&pr->iofhd, vr, io_flist);
 	}
+
+	TAILQ_INIT(&pr->iobhd);
 }
 
 static void
@@ -1565,9 +1675,7 @@ pci_ahci_port_write(struct pci_ahci_soft
 		p->cmd = value;
 		
 		if (!(value & AHCI_P_CMD_ST)) {
-			p->cmd &= ~(AHCI_P_CMD_CR | AHCI_P_CMD_CCS_MASK);
-			p->ci = 0;
-			p->sact = 0;
+			ahci_port_stop(p);
 		} else {
 			uint64_t clb;
 



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