[RHEL7,COMMIT] ms/libata: Implement support for sense data reporting

Submitted by Konstantin Khorenko on Oct. 1, 2019, 2:49 p.m.

Details

Message ID 201910011449.x91Ens6j015588@finist-ce7.sw.ru
State New
Series "ms/libata: Implement support for sense data reporting"
Headers show

Commit Message

Konstantin Khorenko Oct. 1, 2019, 2:49 p.m.
The commit is pushed to "branch-rh7-3.10.0-957.27.2.vz7.107.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-957.27.2.vz7.107.11
------>
commit 557b459f0af0be0488da745077fa98a7845c2a9f
Author: Hannes Reinecke <hare@suse.de>
Date:   Tue Oct 1 17:49:54 2019 +0300

    ms/libata: Implement support for sense data reporting
    
    ACS-4 defines a sense data reporting feature set.
    This patch implements support for it.
    
    tj: Cosmetic formatting updates.
    
    Signed-off-by: Hannes Reinecke <hare@suse.de>
    Signed-off-by: Tejun Heo <tj@kernel.org>
    
    https://pmc.acronis.com/browse/VSTOR-26930
    (cherry picked from commit e87fd28cf9a2d9018ac4b6dd92f0b417714bc18d)
    Signed-off-by: Ildar Ismagilov <ildar.ismagilov@virtuozzo.com>
    
    =====================
    Patchset description:
    
    Add support of SMR ATA disk
    
    This patchset adds support of SMR ATA disk through SCSI generic interface
    aka /dev/sgX.
    
    The SCSI generic interface is used by libzbc library for communicate
    with SMR disk. These patches allow us to use SMR disk through
    "ata" backend of libzbc ("scsi" and "block" backends aren't supported).
    
    These patches were tested with following command:
     libzbc/test/zbc_test.sh /dev/sgX
    
    JIRA: https://pmc.acronis.com/browse/VSTOR-26930
    
    Damien Le Moal (1):
      libata: Fix ATA request sense
    
    Hannes Reinecke (5):
      libata: Implement ATA_DEV_ZAC
      libata-scsi: Update SATL for ZAC drives
      libata: Implement NCQ autosense
      libata: Implement support for sense data reporting
      libata: fixup ZAC device disabling
---
 drivers/ata/libata-core.c | 20 +++++++++++++-
 drivers/ata/libata-eh.c   | 68 ++++++++++++++++++++++++++++++++++++++++++++---
 include/linux/ata.h       | 16 +++++++++++
 3 files changed, 99 insertions(+), 5 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 913c677073d4..d2272247bf58 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2146,6 +2146,24 @@  static int ata_dev_config_ncq(struct ata_device *dev,
 	return 0;
 }
 
+static void ata_dev_config_sense_reporting(struct ata_device *dev)
+{
+	unsigned int err_mask;
+
+	if (!ata_id_has_sense_reporting(dev->id))
+		return;
+
+	if (ata_id_sense_reporting_enabled(dev->id))
+		return;
+
+	err_mask = ata_dev_set_feature(dev, SETFEATURE_SENSE_DATA, 0x1);
+	if (err_mask) {
+		ata_dev_dbg(dev,
+			    "failed to enable Sense Data Reporting, Emask 0x%x\n",
+			    err_mask);
+	}
+}
+
 /**
  *	ata_dev_configure - Configure the specified ATA/ATAPI device
  *	@dev: Target device to configure
@@ -2368,7 +2386,7 @@  int ata_dev_configure(struct ata_device *dev)
 					dev->devslp_timing[i] = sata_setting[j];
 				}
 		}
-
+		ata_dev_config_sense_reporting(dev);
 		dev->cdb_len = 16;
 	}
 
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index c055ec0c28d5..99c05bf9e071 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1642,6 +1642,56 @@  unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
 	return err_mask;
 }
 
+/**
+ *	ata_eh_request_sense - perform REQUEST_SENSE_DATA_EXT
+ *	@dev: device to perform REQUEST_SENSE_SENSE_DATA_EXT to
+ *	@cmd: scsi command for which the sense code should be set
+ *
+ *	Perform REQUEST_SENSE_DATA_EXT after the device reported CHECK
+ *	SENSE.  This function is an EH helper.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ */
+static void ata_eh_request_sense(struct ata_queued_cmd *qc,
+				 struct scsi_cmnd *cmd)
+{
+	struct ata_device *dev = qc->dev;
+	struct ata_taskfile tf;
+	unsigned int err_mask;
+
+	if (qc->ap->pflags & ATA_PFLAG_FROZEN) {
+		ata_dev_warn(dev, "sense data available but port frozen\n");
+		return;
+	}
+
+	if (!cmd)
+		return;
+
+	if (!ata_id_sense_reporting_enabled(dev->id)) {
+		ata_dev_warn(qc->dev, "sense data reporting disabled\n");
+		return;
+	}
+
+	DPRINTK("ATA request sense\n");
+
+	ata_tf_init(dev, &tf);
+	tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+	tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
+	tf.command = ATA_CMD_REQ_SENSE_DATA;
+	tf.protocol = ATA_PROT_NODATA;
+
+	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+	/* Ignore err_mask; ATA_ERR might be set */
+	if (tf.command & ATA_SENSE) {
+		ata_scsi_set_sense(cmd, tf.lbah, tf.lbam, tf.lbal);
+		qc->flags |= ATA_QCFLAG_SENSE_VALID;
+	} else {
+		ata_dev_warn(dev, "request sense failed stat %02x emask %x\n",
+			     tf.command, err_mask);
+	}
+}
+
 /**
  *	atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
  *	@dev: device to perform REQUEST_SENSE to
@@ -1843,14 +1893,23 @@  static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
 		return ATA_EH_RESET;
 	}
 
-	if (stat & (ATA_ERR | ATA_DF))
+	if (stat & (ATA_ERR | ATA_DF)) {
 		qc->err_mask |= AC_ERR_DEV;
-	else
+		/*
+		 * Sense data reporting does not work if the
+		 * device fault bit is set.
+		 */
+		if (stat & ATA_DF)
+			stat &= ~ATA_SENSE;
+	} else {
 		return 0;
+	}
 
 	switch (qc->dev->class) {
 	case ATA_DEV_ATA:
 	case ATA_DEV_ZAC:
+		if (stat & ATA_SENSE)
+			ata_eh_request_sense(qc, qc->scsicmd);
 		if (err & ATA_ICRC)
 			qc->err_mask |= AC_ERR_ATA_BUS;
 		if (err & (ATA_UNC | ATA_AMNF))
@@ -2585,14 +2644,15 @@  static void ata_eh_link_report(struct ata_link *link)
 
 #ifdef CONFIG_ATA_VERBOSE_ERROR
 		if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ |
-				    ATA_ERR)) {
+				    ATA_SENSE | ATA_ERR)) {
 			if (res->command & ATA_BUSY)
 				ata_dev_err(qc->dev, "status: { Busy }\n");
 			else
-				ata_dev_err(qc->dev, "status: { %s%s%s%s}\n",
+				ata_dev_err(qc->dev, "status: { %s%s%s%s%s}\n",
 				  res->command & ATA_DRDY ? "DRDY " : "",
 				  res->command & ATA_DF ? "DF " : "",
 				  res->command & ATA_DRQ ? "DRQ " : "",
+				  res->command & ATA_SENSE ? "SENSE " : "",
 				  res->command & ATA_ERR ? "ERR " : "");
 		}
 
diff --git a/include/linux/ata.h b/include/linux/ata.h
index ffde13097ed1..78789b15eeae 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -384,6 +384,8 @@  enum {
 	SATA_SSP		= 0x06,	/* Software Settings Preservation */
 	SATA_DEVSLP		= 0x09,	/* Device Sleep */
 
+	SETFEATURE_SENSE_DATA	= 0xC3, /* Sense Data Reporting feature */
+
 	/* feature values for SET_MAX */
 	ATA_SET_MAX_ADDR	= 0x00,
 	ATA_SET_MAX_PASSWD	= 0x01,
@@ -717,6 +719,20 @@  static inline bool ata_id_has_read_log_dma_ext(const u16 *id)
 	return false;
 }
 
+static inline bool ata_id_has_sense_reporting(const u16 *id)
+{
+	if (!(id[ATA_ID_CFS_ENABLE_2] & (1 << 15)))
+		return false;
+	return id[ATA_ID_COMMAND_SET_3] & (1 << 6);
+}
+
+static inline bool ata_id_sense_reporting_enabled(const u16 *id)
+{
+	if (!(id[ATA_ID_CFS_ENABLE_2] & (1 << 15)))
+		return false;
+	return id[ATA_ID_COMMAND_SET_4] & (1 << 6);
+}
+
 /**
  *	ata_id_major_version	-	get ATA level of drive
  *	@id: Identify data