Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 3 Nov 2009 11:47:07 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r198851 - head/sys/dev/ahci
Message-ID:  <200911031147.nA3Bl7PF090601@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Tue Nov  3 11:47:07 2009
New Revision: 198851
URL: http://svn.freebsd.org/changeset/base/198851

Log:
  MFp4:
  - Handle timeouts and fatal errors with port hard-reset. The rest of
  recovery will be done by XPT on receiving async event. More gracefull
  per-device soft-reset recovery can be implemented later.
  - Add workaround for ATI SB600/SB700 PMP probe related bug, to speedup boot.

Modified:
  head/sys/dev/ahci/ahci.c
  head/sys/dev/ahci/ahci.h

Modified: head/sys/dev/ahci/ahci.c
==============================================================================
--- head/sys/dev/ahci/ahci.c	Tue Nov  3 11:41:21 2009	(r198850)
+++ head/sys/dev/ahci/ahci.c	Tue Nov  3 11:47:07 2009	(r198851)
@@ -1221,6 +1221,13 @@ ahci_execute_transaction(struct ahci_slo
 				et = AHCI_ERR_TFE;
 				break;
 			}
+			/* Workaround for ATI SB600/SB700 chipsets. */
+			if (ccb->ccb_h.target_id == 15 &&
+			    pci_get_vendor(device_get_parent(dev)) == 0x1002 &&
+			    (ATA_INL(ch->r_mem, AHCI_P_IS) & AHCI_P_IX_IPM)) {
+				et = AHCI_ERR_TIMEOUT;
+				break;
+			}
 		}
 		if (timeout && (count >= timeout)) {
 			device_printf(ch->dev,
@@ -1275,10 +1282,8 @@ ahci_timeout(struct ahci_slot *slot)
 	    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,
 	    ATA_INL(ch->r_mem, AHCI_P_TFD), ATA_INL(ch->r_mem, AHCI_P_SERR));
-	/* Kick controller into sane state. */
-	ahci_stop(ch->dev);
-	ahci_start(ch->dev);
 
+	ch->fatalerr = 1;
 	/* Handle frozen command. */
 	if (ch->frozen) {
 		union ccb *fccb = ch->frozen;
@@ -1360,6 +1365,7 @@ ahci_end_transaction(struct ahci_slot *s
 			ccb->csio.scsi_status = SCSI_STATUS_OK;
 		break;
 	case AHCI_ERR_INVALID:
+		ch->fatalerr = 1;
 		ccb->ccb_h.status |= CAM_REQ_INVALID;
 		break;
 	case AHCI_ERR_INNOCENT:
@@ -1375,6 +1381,7 @@ ahci_end_transaction(struct ahci_slot *s
 		}
 		break;
 	case AHCI_ERR_SATA:
+		ch->fatalerr = 1;
 		if (!ch->readlog) {
 			xpt_freeze_simq(ch->sim, 1);
 			ccb->ccb_h.status &= ~CAM_STATUS_MASK;
@@ -1383,6 +1390,10 @@ ahci_end_transaction(struct ahci_slot *s
 		ccb->ccb_h.status |= CAM_UNCOR_PARITY;
 		break;
 	case AHCI_ERR_TIMEOUT:
+		/* Do no treat soft-reset timeout as fatal here. */
+		if (ccb->ccb_h.func_code != XPT_ATA_IO ||
+	            !(ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL))
+			ch->fatalerr = 1;
 		if (!ch->readlog) {
 			xpt_freeze_simq(ch->sim, 1);
 			ccb->ccb_h.status &= ~CAM_STATUS_MASK;
@@ -1391,6 +1402,7 @@ ahci_end_transaction(struct ahci_slot *s
 		ccb->ccb_h.status |= CAM_CMD_TIMEOUT;
 		break;
 	default:
+		ch->fatalerr = 1;
 		ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
 	}
 	/* Free slot. */
@@ -1414,12 +1426,13 @@ ahci_end_transaction(struct ahci_slot *s
 		ahci_begin_transaction(dev, ccb);
 		return;
 	}
+	/* If it was our READ LOG command - process it. */
+	if (ch->readlog) {
+		ahci_process_read_log(dev, ccb);
 	/* If it was NCQ command error, put result on hold. */
-	if (et == AHCI_ERR_NCQ) {
+	} else if (et == AHCI_ERR_NCQ) {
 		ch->hold[slot->slot] = ccb;
-	} else if (ch->readlog)	/* If it was our READ LOG command - process it. */
-		ahci_process_read_log(dev, ccb);
-	else
+	} else
 		xpt_done(ccb);
 	/* Unfreeze frozen command. */
 	if (ch->frozen && ch->numrslots == 0) {
@@ -1428,6 +1441,13 @@ ahci_end_transaction(struct ahci_slot *s
 		ahci_begin_transaction(dev, fccb);
 		xpt_release_simq(ch->sim, TRUE);
 	}
+	/* If we have no other active commands, ... */
+	if (ch->rslots == 0) {
+		/* if there was fatal error - reset port. */
+		if (ch->fatalerr) {
+			ahci_reset(dev);
+		}
+	}
 	/* Start PM timer. */
 	if (ch->numrslots == 0 && ch->pm_level > 3) {
 		callout_schedule(&ch->pm_timer,
@@ -1674,6 +1694,13 @@ ahci_reset(device_t dev)
 		/* XXX; Commands in loading state. */
 		ahci_end_transaction(&ch->slot[i], AHCI_ERR_INNOCENT);
 	}
+	for (i = 0; i < ch->numslots; i++) {
+		if (!ch->hold[i])
+			continue;
+		xpt_done(ch->hold[i]);
+		ch->hold[i] = NULL;
+	}
+	ch->fatalerr = 0;
 	/* Tell the XPT about the event */
 	xpt_async(AC_BUS_RESET, ch->path, NULL);
 	/* Disable port interrupts */

Modified: head/sys/dev/ahci/ahci.h
==============================================================================
--- head/sys/dev/ahci/ahci.h	Tue Nov  3 11:41:21 2009	(r198850)
+++ head/sys/dev/ahci/ahci.h	Tue Nov  3 11:47:07 2009	(r198851)
@@ -366,6 +366,7 @@ struct ahci_channel {
 	int			numrslots;	/* Number of running slots */
 	int			numtslots;	/* Number of tagged slots */
 	int			readlog;	/* Our READ LOG active */
+	int			fatalerr;	/* Fatal error happend */
 	int			lastslot;	/* Last used slot */
 	int			taggedtarget;	/* Last tagged target */
 	union ccb		*frozen;	/* Frozen command */



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