Author: jhb
Date: Tue Jun 10 19:00:14 2014
New Revision: 267339
URL: http://svnweb.freebsd.org/changeset/base/267339

Log:
  MFC 261000,261785,263238,263322,264302:
  Various AHCI fixes:
  - Fix issue with stale fields from a recycled request pulled off the
    freelist.
  - Provide an indication a "PIO Setup Device to Host FIS" occurred while
    executing the IDENTIFY DEVICE and IDENTIFY PACKET DEVICE commands.
  - Provide an indication a "D2H Register FIS" occurred during a SET FEATURES
    command.
  - Though there currently isn't a way to insert new media into an ATAPI
    drive, at least pretend to support Asynchronous Notification (AN) to
    avoid a guest needlessly polling for it.
  - Don't reissue in-flight commands.
  - Constrain the amount of data returned to what is actually available
    not the size of the buffer.

Modified:
  stable/10/usr.sbin/bhyve/pci_ahci.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/usr.sbin/bhyve/pci_ahci.c
==============================================================================
--- stable/10/usr.sbin/bhyve/pci_ahci.c Tue Jun 10 18:46:00 2014        
(r267338)
+++ stable/10/usr.sbin/bhyve/pci_ahci.c Tue Jun 10 19:00:14 2014        
(r267339)
@@ -95,6 +95,13 @@ enum sata_fis_type {
 #define        MODEPAGE_CD_CAPABILITIES        0x2A
 
 /*
+ * ATA commands
+ */
+#define        ATA_SF_ENAB_SATA_SF             0x10
+#define                ATA_SATA_SF_AN          0x05
+#define        ATA_SF_DIS_SATA_SF              0x90
+
+/*
  * Debug printf
  */
 #ifdef AHCI_DEBUG
@@ -127,6 +134,7 @@ struct ahci_port {
        uint8_t xfermode;
        uint8_t sense_key;
        uint8_t asc;
+       uint32_t pending;
 
        uint32_t clb;
        uint32_t clbu;
@@ -254,6 +262,16 @@ ahci_write_fis(struct ahci_port *p, enum
 }
 
 static void
+ahci_write_fis_piosetup(struct ahci_port *p)
+{
+       uint8_t fis[20];
+
+       memset(fis, 0, sizeof(fis));
+       fis[0] = FIS_TYPE_PIOSETUP;
+       ahci_write_fis(p, FIS_TYPE_PIOSETUP, fis);
+}
+
+static void
 ahci_write_fis_sdb(struct ahci_port *p, int slot, uint32_t tfd)
 {
        uint8_t fis[8];
@@ -454,6 +472,10 @@ 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;
@@ -477,7 +499,7 @@ ahci_handle_dma(struct ahci_port *p, int
                err = blockif_write(p->bctx, breq);
        assert(err == 0);
 
-       if (!aior->prdtl && ncq)
+       if (ncq)
                p->ci &= ~(1 << slot);
 }
 
@@ -497,6 +519,8 @@ ahci_handle_flush(struct ahci_port *p, i
        aior->cfis = cfis;
        aior->slot = slot;
        aior->len = 0;
+       aior->done = 0;
+       aior->prdtl = 0;
        breq = &aior->io_req;
 
        err = blockif_flush(p->bctx, breq);
@@ -519,12 +543,14 @@ write_prdt(struct ahci_port *p, int slot
        for (i = 0; i < hdr->prdtl && len; i++) {
                uint8_t *ptr;
                uint32_t dbcsz;
+               int sublen;
 
                dbcsz = (prdt->dbc & DBCMASK) + 1;
                ptr = paddr_guest2host(ahci_ctx(p->pr_sc), prdt->dba, dbcsz);
-               memcpy(ptr, from, dbcsz);
-               len -= dbcsz;
-               from += dbcsz;
+               sublen = len < dbcsz ? len : dbcsz;
+               memcpy(ptr, from, sublen);
+               len -= sublen;
+               from += sublen;
                prdt++;
        }
        hdr->prdbc = size - len;
@@ -585,6 +611,7 @@ handle_identify(struct ahci_port *p, int
                buf[101] = (sectors >> 16);
                buf[102] = (sectors >> 32);
                buf[103] = (sectors >> 48);
+               ahci_write_fis_piosetup(p);
                write_prdt(p, slot, cfis, (void *)buf, sizeof(buf));
                p->tfd = ATA_S_DSC | ATA_S_READY;
                p->is |= AHCI_P_IX_DP;
@@ -627,6 +654,7 @@ handle_atapi_identify(struct ahci_port *
                buf[85] = (1 << 4);
                buf[87] = (1 << 14);
                buf[88] = (1 << 14 | 0x7f);
+               ahci_write_fis_piosetup(p);
                write_prdt(p, slot, cfis, (void *)buf, sizeof(buf));
                p->tfd = ATA_S_DSC | ATA_S_READY;
                p->is |= AHCI_P_IX_DHR;
@@ -1155,6 +1183,17 @@ ahci_handle_cmd(struct ahci_port *p, int
        case ATA_SETFEATURES:
        {
                switch (cfis[3]) {
+               case ATA_SF_ENAB_SATA_SF:
+                       switch (cfis[12]) {
+                       case ATA_SATA_SF_AN:
+                               p->tfd = ATA_S_DSC | ATA_S_READY;
+                               break;
+                       default:
+                               p->tfd = ATA_S_ERROR | ATA_S_READY;
+                               p->tfd |= (ATA_ERROR_ABORT << 8);
+                               break;
+                       }
+                       break;
                case ATA_SF_ENAB_WCACHE:
                case ATA_SF_DIS_WCACHE:
                case ATA_SF_ENAB_RCACHE:
@@ -1180,9 +1219,7 @@ ahci_handle_cmd(struct ahci_port *p, int
                        p->tfd |= (ATA_ERROR_ABORT << 8);
                        break;
                }
-               p->is |= AHCI_P_IX_DP;
-               p->ci &= ~(1 << slot);
-               ahci_generate_intr(p->pr_sc);
+               ahci_write_fis_d2h(p, slot, cfis, p->tfd);
                break;
        }
        case ATA_SET_MULTI:
@@ -1297,8 +1334,12 @@ ahci_handle_port(struct ahci_port *p)
        if (!(p->cmd & AHCI_P_CMD_ST))
                return;
 
+       /*
+        * Search for any new commands to issue ignoring those that
+        * are already in-flight.
+        */
        for (i = 0; (i < 32) && p->ci; i++) {
-               if (p->ci & (1 << i))
+               if ((p->ci & (1 << i)) && !(p->pending & (1 << i)))
                        ahci_handle_slot(p, i);
        }
 }
@@ -1359,6 +1400,11 @@ 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);
_______________________________________________
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