svn commit: r222918 - stable/8/sys/dev/ahci

Alexander Motin mav at FreeBSD.org
Fri Jun 10 08:58:13 UTC 2011


Author: mav
Date: Fri Jun 10 08:58:13 2011
New Revision: 222918
URL: http://svn.freebsd.org/changeset/base/222918

Log:
  MFC r222304:
  Marvell 88SE91xx controllers are known to report soft-reset completion
  without waiting for device readiness (or at least not updating FIS receive
  area in time). To workaround that, special quirk was added earlier to wait
  for the FIS receive area update. But it was found that under same PCI ID
  0x91231b4b and revision 0x11 there are two completely different chip
  versions (firmware?): HBA and RAID. The problem is that RAID version in
  some cases, such as hot-plug, does not update FIS receive area at all!
  
  To workaround that, differentiate the chip versions by their capabilities,
  and, if RAID version found, skip FIS receive area update waiting and read
  device signature from the PxSIG register instead. This method doesn't work
  for HBA version when PMP attached, so keep using previous workaround there.

Modified:
  stable/8/sys/dev/ahci/ahci.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sys/dev/ahci/ahci.c
==============================================================================
--- stable/8/sys/dev/ahci/ahci.c	Fri Jun 10 08:54:52 2011	(r222917)
+++ stable/8/sys/dev/ahci/ahci.c	Fri Jun 10 08:58:13 2011	(r222918)
@@ -119,6 +119,7 @@ static struct {
 #define AHCI_Q_NOBSYRES	256
 #define AHCI_Q_NOAA	512
 #define AHCI_Q_NOCOUNT	1024
+#define AHCI_Q_ALTSIG	2048
 } ahci_ids[] = {
 	{0x43801002, 0x00, "ATI IXP600",	0},
 	{0x43901002, 0x00, "ATI IXP700",	0},
@@ -192,7 +193,7 @@ static struct {
 	{0x614511ab, 0x00, "Marvell 88SX6145",	AHCI_Q_NOFORCE | AHCI_Q_4CH |
 	    AHCI_Q_EDGEIS | AHCI_Q_NONCQ | AHCI_Q_NOCOUNT},
 	{0x91201b4b, 0x00, "Marvell 88SE912x",	AHCI_Q_EDGEIS|AHCI_Q_NOBSYRES},
-	{0x91231b4b, 0x11, "Marvell 88SE912x",	AHCI_Q_NOBSYRES},
+	{0x91231b4b, 0x11, "Marvell 88SE912x",	AHCI_Q_NOBSYRES|AHCI_Q_ALTSIG},
 	{0x91231b4b, 0x00, "Marvell 88SE912x",	AHCI_Q_EDGEIS|AHCI_Q_SATA2|AHCI_Q_NOBSYRES},
 	{0x91821b4b, 0x00, "Marvell 88SE9182",	AHCI_Q_NOBSYRES},
 	{0x06201103, 0x00, "HighPoint RocketRAID 620",	AHCI_Q_NOBSYRES},
@@ -398,6 +399,13 @@ ahci_attach(device_t dev)
 	if (ctlr->caps & AHCI_CAP_EMS)
 		ctlr->capsem = ATA_INL(ctlr->r_mem, AHCI_EM_CTL);
 	ctlr->ichannels = ATA_INL(ctlr->r_mem, AHCI_PI);
+
+	/* Identify and set separate quirks for HBA and RAID f/w Marvells. */
+	if ((ctlr->quirks & AHCI_Q_NOBSYRES) &&
+	    (ctlr->quirks & AHCI_Q_ALTSIG) &&
+	    (ctlr->caps & AHCI_CAP_SPM) == 0)
+		ctlr->quirks &= ~AHCI_Q_NOBSYRES;
+
 	if (ctlr->quirks & AHCI_Q_1CH) {
 		ctlr->caps &= ~AHCI_CAP_NPMASK;
 		ctlr->ichannels &= 0x01;
@@ -1758,7 +1766,7 @@ ahci_execute_transaction(struct ahci_slo
 	struct ahci_cmd_list *clp;
 	union ccb *ccb = slot->ccb;
 	int port = ccb->ccb_h.target_id & 0x0f;
-	int fis_size, i;
+	int fis_size, i, softreset;
 	uint8_t *fis = ch->dma.rfis + 0x40;
 	uint8_t val;
 
@@ -1785,17 +1793,20 @@ ahci_execute_transaction(struct ahci_slo
 	if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
 	    (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL)) {
 		if (ccb->ataio.cmd.control & ATA_A_RESET) {
+			softreset = 1;
 			/* Kick controller into sane state */
 			ahci_stop(dev);
 			ahci_clo(dev);
 			ahci_start(dev, 0);
 			clp->cmd_flags |= AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY;
 		} else {
+			softreset = 2;
 			/* Prepare FIS receive area for check. */
 			for (i = 0; i < 20; i++)
 				fis[i] = 0xff;
 		}
-	}
+	} else
+		softreset = 0;
 	clp->bytecount = 0;
 	clp->cmd_table_phys = htole64(ch->dma.work_bus + AHCI_CT_OFFSET +
 				  (AHCI_CT_SIZE * slot->slot));
@@ -1819,8 +1830,7 @@ ahci_execute_transaction(struct ahci_slo
 	ATA_OUTL(ch->r_mem, AHCI_P_CI, (1 << slot->slot));
 	/* Device reset commands doesn't interrupt. Poll them. */
 	if (ccb->ccb_h.func_code == XPT_ATA_IO &&
-	    (ccb->ataio.cmd.command == ATA_DEVICE_RESET ||
-	    (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL))) {
+	    (ccb->ataio.cmd.command == ATA_DEVICE_RESET || softreset)) {
 		int count, timeout = ccb->ccb_h.timeout * 100;
 		enum ahci_err_type et = AHCI_ERR_NONE;
 
@@ -1828,7 +1838,8 @@ ahci_execute_transaction(struct ahci_slo
 			DELAY(10);
 			if (!(ATA_INL(ch->r_mem, AHCI_P_CI) & (1 << slot->slot)))
 				break;
-			if (ATA_INL(ch->r_mem, AHCI_P_TFD) & ATA_S_ERROR) {
+			if ((ATA_INL(ch->r_mem, AHCI_P_TFD) & ATA_S_ERROR) &&
+			    softreset != 1) {
 #if 0
 				device_printf(ch->dev,
 				    "Poll error on slot %d, TFD: %04x\n",
@@ -1845,9 +1856,20 @@ ahci_execute_transaction(struct ahci_slo
 				break;
 			}
 		}
+
+		/* Marvell controllers do not wait for readyness. */
+		if ((ch->quirks & AHCI_Q_NOBSYRES) && softreset == 2 &&
+		    et == AHCI_ERR_NONE) {
+			while ((val = fis[2]) & ATA_S_BUSY) {
+				DELAY(10);
+				if (count++ >= timeout)
+					break;
+			}
+		}
+
 		if (timeout && (count >= timeout)) {
-			device_printf(ch->dev,
-			    "Poll timeout on slot %d\n", slot->slot);
+			device_printf(dev, "Poll timeout on slot %d port %d\n",
+			    slot->slot, port);
 			device_printf(dev, "is %08x cs %08x ss %08x "
 			    "rs %08x tfd %02x serr %08x\n",
 			    ATA_INL(ch->r_mem, AHCI_P_IS),
@@ -1857,26 +1879,9 @@ ahci_execute_transaction(struct ahci_slo
 			    ATA_INL(ch->r_mem, AHCI_P_SERR));
 			et = AHCI_ERR_TIMEOUT;
 		}
-		/* Marvell controllers do not wait for readyness. */
-		if ((ch->quirks & AHCI_Q_NOBSYRES) &&
-		    (ccb->ccb_h.func_code == XPT_ATA_IO) &&
-		    (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) &&
-		    (ccb->ataio.cmd.control & ATA_A_RESET) == 0) {
-			while ((val = fis[2]) & (ATA_S_BUSY | ATA_S_DRQ)) {
-				DELAY(10);
-				if (count++ >= timeout) {
-					device_printf(dev, "device is not "
-					    "ready after soft-reset: "
-					    "tfd = %08x\n", val);
-	    				et = AHCI_ERR_TIMEOUT;
-	    				break;
-				}
-			} 
-		}
+
 		/* Kick controller into sane state and enable FBS. */
-		if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
-		    (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) &&
-		    (ccb->ataio.cmd.control & ATA_A_RESET) == 0)
+		if (softreset == 2)
 			ch->eslots |= (1 << slot->slot);
 		ahci_end_transaction(slot, et);
 		return;
@@ -1956,7 +1961,8 @@ ahci_timeout(struct ahci_slot *slot)
 		return;
 	}
 
-	device_printf(dev, "Timeout on slot %d\n", slot->slot);
+	device_printf(dev, "Timeout on slot %d port %d\n",
+	    slot->slot, slot->ccb->ccb_h.target_id & 0x0f);
 	device_printf(dev, "is %08x cs %08x ss %08x rs %08x tfd %02x serr %08x\n",
 	    ATA_INL(ch->r_mem, AHCI_P_IS), ATA_INL(ch->r_mem, AHCI_P_CI),
 	    ATA_INL(ch->r_mem, AHCI_P_SACT), ch->rslots,
@@ -2007,6 +2013,7 @@ ahci_end_transaction(struct ahci_slot *s
 	union ccb *ccb = slot->ccb;
 	struct ahci_cmd_list *clp;
 	int lastto;
+	uint32_t sig;
 
 	bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map,
 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
@@ -2044,6 +2051,20 @@ ahci_end_transaction(struct ahci_slot *s
 			res->lba_high_exp = fis[10];
 			res->sector_count = fis[12];
 			res->sector_count_exp = fis[13];
+
+			/*
+			 * Some weird controllers do not return signature in
+			 * FIS receive area. Read it from PxSIG register.
+			 */
+			if ((ch->quirks & AHCI_Q_ALTSIG) &&
+			    (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) &&
+			    (ccb->ataio.cmd.control & ATA_A_RESET) == 0) {
+				sig = ATA_INL(ch->r_mem,  AHCI_P_SIG);
+				res->lba_high = sig >> 24;
+				res->lba_mid = sig >> 16;
+				res->lba_low = sig >> 8;
+				res->sector_count = sig;
+			}
 		} else
 			bzero(res, sizeof(*res));
 		if ((ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA) == 0 &&


More information about the svn-src-stable-8 mailing list