Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 10 Jun 2014 19:00:14 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r267339 - stable/10/usr.sbin/bhyve
Message-ID:  <201406101900.s5AJ0EgH060231@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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);



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