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;
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to