Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 8 Jul 2019 10:18:11 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r349830 - stable/12/sys/dev/ahci
Message-ID:  <201907081018.x68AIBpV059640@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Mon Jul  8 10:18:11 2019
New Revision: 349830
URL: https://svnweb.freebsd.org/changeset/base/349830

Log:
  MFC r340092 (by imp): Implement ability to turn on/off PHYs for AHCI devices.
  
  As part of Chuck's work on fixing kernel crashes caused by disk I/O
  errors, it is useful to be able to trigger various kinds of
  errors. This patch allows causing an AHCI-attached disk to disappear,
  by having the driver keep the PHY disabled when the driver would
  otherwise enable the PHY. It also allows making the disk reappear by
  having the driver go back to setting the PHY enable/disable state as
  it normal would and simulating the hardware event that causes a bus
  rescan.
  
  Submitted by: Chuck Silvers
  Differential Revision: https://reviews.freebsd.org/D16043

Modified:
  stable/12/sys/dev/ahci/ahci.c
  stable/12/sys/dev/ahci/ahci.h
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/dev/ahci/ahci.c
==============================================================================
--- stable/12/sys/dev/ahci/ahci.c	Mon Jul  8 10:17:00 2019	(r349829)
+++ stable/12/sys/dev/ahci/ahci.c	Mon Jul  8 10:18:11 2019	(r349830)
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/malloc.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
+#include <sys/sysctl.h>
 #include <machine/stdarg.h>
 #include <machine/resource.h>
 #include <machine/bus.h>
@@ -80,6 +81,8 @@ static void ahci_stop(struct ahci_channel *ch);
 static void ahci_clo(struct ahci_channel *ch);
 static void ahci_start_fr(struct ahci_channel *ch);
 static void ahci_stop_fr(struct ahci_channel *ch);
+static int ahci_phy_check_events(struct ahci_channel *ch, u_int32_t serr);
+static uint32_t ahci_ch_detval(struct ahci_channel *ch, uint32_t val);
 
 static int ahci_sata_connect(struct ahci_channel *ch);
 static int ahci_sata_phy_reset(struct ahci_channel *ch);
@@ -100,6 +103,13 @@ static MALLOC_DEFINE(M_AHCI, "AHCI driver", "AHCI driv
 #define RECOVERY_REQUEST_SENSE	2
 #define recovery_slot		spriv_field1
 
+static uint32_t
+ahci_ch_detval(struct ahci_channel *ch, uint32_t val)
+{
+
+	return ch->disablephy ? ATA_SC_DET_DISABLE : val;
+}
+
 int
 ahci_ctlr_setup(device_t dev)
 {
@@ -665,11 +675,38 @@ ahci_ch_probe(device_t dev)
 }
 
 static int
+ahci_ch_disablephy_proc(SYSCTL_HANDLER_ARGS)
+{
+	struct ahci_channel *ch;
+	int error, value;
+
+	ch = arg1;
+	value = ch->disablephy;
+	error = sysctl_handle_int(oidp, &value, 0, req);
+	if (error != 0 || req->newptr == NULL || (value != 0 && value != 1))
+		return (error);
+
+	mtx_lock(&ch->mtx);
+	ch->disablephy = value;
+	if (value) {
+		ahci_ch_deinit(ch->dev);
+	} else {
+		ahci_ch_init(ch->dev);
+		ahci_phy_check_events(ch, ATA_SE_PHY_CHANGED | ATA_SE_EXCHANGED);
+	}
+	mtx_unlock(&ch->mtx);
+
+	return (0);
+}
+
+static int
 ahci_ch_attach(device_t dev)
 {
 	struct ahci_controller *ctlr = device_get_softc(device_get_parent(dev));
 	struct ahci_channel *ch = device_get_softc(dev);
 	struct cam_devq *devq;
+	struct sysctl_ctx_list *ctx;
+	struct sysctl_oid *tree;
 	int rid, error, i, sata_rev = 0;
 	u_int32_t version;
 
@@ -787,6 +824,11 @@ ahci_ch_attach(device_t dev)
 		    ahci_ch_pm, ch);
 	}
 	mtx_unlock(&ch->mtx);
+	ctx = device_get_sysctl_ctx(dev);
+	tree = device_get_sysctl_tree(dev);
+	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "disable_phy",
+	    CTLFLAG_RW | CTLTYPE_UINT, ch, 0, ahci_ch_disablephy_proc, "IU",
+	    "Disable PHY");
 	return (0);
 
 err3:
@@ -2505,7 +2547,7 @@ static int
 ahci_sata_phy_reset(struct ahci_channel *ch)
 {
 	int sata_rev;
-	uint32_t val;
+	uint32_t val, detval;
 
 	if (ch->listening) {
 		val = ATA_INL(ch->r_mem, AHCI_P_CMD);
@@ -2522,12 +2564,14 @@ ahci_sata_phy_reset(struct ahci_channel *ch)
 		val = ATA_SC_SPD_SPEED_GEN3;
 	else
 		val = 0;
+	detval = ahci_ch_detval(ch, ATA_SC_DET_RESET);
 	ATA_OUTL(ch->r_mem, AHCI_P_SCTL,
-	    ATA_SC_DET_RESET | val |
+	    detval | val |
 	    ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER);
 	DELAY(1000);
+	detval = ahci_ch_detval(ch, ATA_SC_DET_IDLE);
 	ATA_OUTL(ch->r_mem, AHCI_P_SCTL,
-	    ATA_SC_DET_IDLE | val | ((ch->pm_level > 0) ? 0 :
+	    detval | val | ((ch->pm_level > 0) ? 0 :
 	    (ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER)));
 	if (!ahci_sata_connect(ch)) {
 		if (ch->caps & AHCI_CAP_SSS) {

Modified: stable/12/sys/dev/ahci/ahci.h
==============================================================================
--- stable/12/sys/dev/ahci/ahci.h	Mon Jul  8 10:17:00 2019	(r349829)
+++ stable/12/sys/dev/ahci/ahci.h	Mon Jul  8 10:18:11 2019	(r349830)
@@ -461,6 +461,8 @@ struct ahci_channel {
 	struct mtx_padalign	mtx;		/* state lock */
 	STAILQ_HEAD(, ccb_hdr)	doneq;		/* queue of completed CCBs */
 	int			batch;		/* doneq is in use */
+
+	int			disablephy;	/* keep PHY disabled */
 };
 
 struct ahci_enclosure {



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