summaryrefslogtreecommitdiff
path: root/drivers/ata/libata-eh.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2015-04-20 04:32:26 +0300
committerDave Airlie <airlied@redhat.com>2015-04-20 06:05:20 +0300
commit2c33ce009ca2389dbf0535d0672214d09738e35e (patch)
tree6186a6458c3c160385d794a23eaf07c786a9e61b /drivers/ata/libata-eh.c
parentcec32a47010647e8b0603726ebb75b990a4057a4 (diff)
parent09d51602cf84a1264946711dd4ea0dddbac599a1 (diff)
downloadlinux-2c33ce009ca2389dbf0535d0672214d09738e35e.tar.xz
Merge Linus master into drm-next
The merge is clean, but the arm build fails afterwards, due to API changes in the regulator tree. I've included the patch into the merge to fix the build. Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/ata/libata-eh.c')
-rw-r--r--drivers/ata/libata-eh.c168
1 files changed, 138 insertions, 30 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index d2029a462e2c..07f41be38fbe 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -46,6 +46,7 @@
#include <linux/libata.h>
+#include <trace/events/libata.h>
#include "libata.h"
enum {
@@ -1510,13 +1511,18 @@ unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
DPRINTK("read log page - log 0x%x, page 0x%x\n", log, page);
ata_tf_init(dev, &tf);
- tf.command = ATA_CMD_READ_LOG_EXT;
+ if (dev->dma_mode && ata_id_has_read_log_dma_ext(dev->id)) {
+ tf.command = ATA_CMD_READ_LOG_DMA_EXT;
+ tf.protocol = ATA_PROT_DMA;
+ } else {
+ tf.command = ATA_CMD_READ_LOG_EXT;
+ tf.protocol = ATA_PROT_PIO;
+ }
tf.lbal = log;
tf.lbam = page;
tf.nsect = sectors;
tf.hob_nsect = sectors >> 8;
tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_LBA48 | ATA_TFLAG_DEVICE;
- tf.protocol = ATA_PROT_PIO;
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
buf, sectors * ATA_SECT_SIZE, 0);
@@ -1575,6 +1581,8 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
tf->hob_lbah = buf[10];
tf->nsect = buf[12];
tf->hob_nsect = buf[13];
+ if (ata_id_has_ncq_autosense(dev->id))
+ tf->auxiliary = buf[14] << 16 | buf[15] << 8 | buf[16];
return 0;
}
@@ -1611,6 +1619,70 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
}
/**
+ * ata_eh_request_sense - perform REQUEST_SENSE_DATA_EXT
+ * @dev: device to perform REQUEST_SENSE_SENSE_DATA_EXT to
+ * @sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long)
+ * @dfl_sense_key: default sense key to use
+ *
+ * Perform REQUEST_SENSE_DATA_EXT after the device reported CHECK
+ * SENSE. This function is EH helper.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * encoded sense data on success, 0 on failure or if sense data
+ * is not available.
+ */
+static u32 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 (!cmd)
+ return 0;
+
+ DPRINTK("ATA request sense\n");
+ ata_dev_warn(dev, "request sense\n");
+ if (!ata_id_sense_reporting_enabled(dev->id)) {
+ ata_dev_warn(qc->dev, "sense data reporting disabled\n");
+ return 0;
+ }
+ 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);
+ /*
+ * ACS-4 states:
+ * The device may set the SENSE DATA AVAILABLE bit to one in the
+ * STATUS field and clear the ERROR bit to zero in the STATUS field
+ * to indicate that the command returned completion without an error
+ * and the sense data described in table 306 is available.
+ *
+ * IOW the 'ATA_SENSE' bit might not be set even though valid
+ * sense data is available.
+ * So check for both.
+ */
+ if ((tf.command & ATA_SENSE) ||
+ tf.lbah != 0 || tf.lbam != 0 || tf.lbal != 0) {
+ ata_scsi_set_sense(cmd, tf.lbah, tf.lbam, tf.lbal);
+ qc->flags |= ATA_QCFLAG_SENSE_VALID;
+ ata_dev_warn(dev, "sense data %02x/%02x/%02x\n",
+ tf.lbah, tf.lbam, tf.lbal);
+ } else {
+ ata_dev_warn(dev, "request sense failed stat %02x emask %x\n",
+ tf.command, err_mask);
+ }
+ return err_mask;
+}
+
+/**
* atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
* @dev: device to perform REQUEST_SENSE to
* @sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long)
@@ -1772,6 +1844,19 @@ void ata_eh_analyze_ncq_error(struct ata_link *link)
memcpy(&qc->result_tf, &tf, sizeof(tf));
qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
+ if (qc->result_tf.auxiliary) {
+ char sense_key, asc, ascq;
+
+ sense_key = (qc->result_tf.auxiliary >> 16) & 0xff;
+ asc = (qc->result_tf.auxiliary >> 8) & 0xff;
+ ascq = qc->result_tf.auxiliary & 0xff;
+ ata_dev_dbg(dev, "NCQ Autosense %02x/%02x/%02x\n",
+ sense_key, asc, ascq);
+ ata_scsi_set_sense(qc->scsicmd, sense_key, asc, ascq);
+ ata_scsi_set_sense_information(qc->scsicmd, &qc->result_tf);
+ qc->flags |= ATA_QCFLAG_SENSE_VALID;
+ }
+
ehc->i.err_mask &= ~AC_ERR_DEV;
}
@@ -1801,6 +1886,27 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
return ATA_EH_RESET;
}
+ /*
+ * Sense data reporting does not work if the
+ * device fault bit is set.
+ */
+ if ((stat & ATA_SENSE) && !(stat & ATA_DF) &&
+ !(qc->flags & ATA_QCFLAG_SENSE_VALID)) {
+ if (!(qc->ap->pflags & ATA_PFLAG_FROZEN)) {
+ tmp = ata_eh_request_sense(qc, qc->scsicmd);
+ if (tmp)
+ qc->err_mask |= tmp;
+ else
+ ata_scsi_set_sense_information(qc->scsicmd, tf);
+ } else {
+ ata_dev_warn(qc->dev, "sense data available but port frozen\n");
+ }
+ }
+
+ /* Set by NCQ autosense or request sense above */
+ if (qc->flags & ATA_QCFLAG_SENSE_VALID)
+ return 0;
+
if (stat & (ATA_ERR | ATA_DF))
qc->err_mask |= AC_ERR_DEV;
else
@@ -2186,6 +2292,7 @@ static void ata_eh_link_autopsy(struct ata_link *link)
all_err_mask |= qc->err_mask;
if (qc->flags & ATA_QCFLAG_IO)
eflags |= ATA_EFLAG_IS_IO;
+ trace_ata_eh_link_autopsy_qc(qc);
}
/* enforce default EH actions */
@@ -2220,7 +2327,7 @@ static void ata_eh_link_autopsy(struct ata_link *link)
eflags |= ATA_EFLAG_DUBIOUS_XFER;
ehc->i.action |= ata_eh_speed_down(dev, eflags, all_err_mask);
}
-
+ trace_ata_eh_link_autopsy(dev, ehc->i.action, all_err_mask);
DPRINTK("EXIT\n");
}
@@ -2289,27 +2396,27 @@ const char *ata_get_cmd_descript(u8 command)
const char *text;
} cmd_descr[] = {
{ ATA_CMD_DEV_RESET, "DEVICE RESET" },
- { ATA_CMD_CHK_POWER, "CHECK POWER MODE" },
- { ATA_CMD_STANDBY, "STANDBY" },
- { ATA_CMD_IDLE, "IDLE" },
- { ATA_CMD_EDD, "EXECUTE DEVICE DIAGNOSTIC" },
- { ATA_CMD_DOWNLOAD_MICRO, "DOWNLOAD MICROCODE" },
+ { ATA_CMD_CHK_POWER, "CHECK POWER MODE" },
+ { ATA_CMD_STANDBY, "STANDBY" },
+ { ATA_CMD_IDLE, "IDLE" },
+ { ATA_CMD_EDD, "EXECUTE DEVICE DIAGNOSTIC" },
+ { ATA_CMD_DOWNLOAD_MICRO, "DOWNLOAD MICROCODE" },
{ ATA_CMD_DOWNLOAD_MICRO_DMA, "DOWNLOAD MICROCODE DMA" },
{ ATA_CMD_NOP, "NOP" },
- { ATA_CMD_FLUSH, "FLUSH CACHE" },
- { ATA_CMD_FLUSH_EXT, "FLUSH CACHE EXT" },
- { ATA_CMD_ID_ATA, "IDENTIFY DEVICE" },
- { ATA_CMD_ID_ATAPI, "IDENTIFY PACKET DEVICE" },
- { ATA_CMD_SERVICE, "SERVICE" },
- { ATA_CMD_READ, "READ DMA" },
- { ATA_CMD_READ_EXT, "READ DMA EXT" },
- { ATA_CMD_READ_QUEUED, "READ DMA QUEUED" },
- { ATA_CMD_READ_STREAM_EXT, "READ STREAM EXT" },
+ { ATA_CMD_FLUSH, "FLUSH CACHE" },
+ { ATA_CMD_FLUSH_EXT, "FLUSH CACHE EXT" },
+ { ATA_CMD_ID_ATA, "IDENTIFY DEVICE" },
+ { ATA_CMD_ID_ATAPI, "IDENTIFY PACKET DEVICE" },
+ { ATA_CMD_SERVICE, "SERVICE" },
+ { ATA_CMD_READ, "READ DMA" },
+ { ATA_CMD_READ_EXT, "READ DMA EXT" },
+ { ATA_CMD_READ_QUEUED, "READ DMA QUEUED" },
+ { ATA_CMD_READ_STREAM_EXT, "READ STREAM EXT" },
{ ATA_CMD_READ_STREAM_DMA_EXT, "READ STREAM DMA EXT" },
- { ATA_CMD_WRITE, "WRITE DMA" },
- { ATA_CMD_WRITE_EXT, "WRITE DMA EXT" },
- { ATA_CMD_WRITE_QUEUED, "WRITE DMA QUEUED EXT" },
- { ATA_CMD_WRITE_STREAM_EXT, "WRITE STREAM EXT" },
+ { ATA_CMD_WRITE, "WRITE DMA" },
+ { ATA_CMD_WRITE_EXT, "WRITE DMA EXT" },
+ { ATA_CMD_WRITE_QUEUED, "WRITE DMA QUEUED EXT" },
+ { ATA_CMD_WRITE_STREAM_EXT, "WRITE STREAM EXT" },
{ ATA_CMD_WRITE_STREAM_DMA_EXT, "WRITE STREAM DMA EXT" },
{ ATA_CMD_WRITE_FUA_EXT, "WRITE DMA FUA EXT" },
{ ATA_CMD_WRITE_QUEUED_FUA_EXT, "WRITE DMA QUEUED FUA EXT" },
@@ -2325,7 +2432,7 @@ const char *ata_get_cmd_descript(u8 command)
{ ATA_CMD_READ_MULTI_EXT, "READ MULTIPLE EXT" },
{ ATA_CMD_WRITE_MULTI, "WRITE MULTIPLE" },
{ ATA_CMD_WRITE_MULTI_EXT, "WRITE MULTIPLE EXT" },
- { ATA_CMD_WRITE_MULTI_FUA_EXT, "WRITE MULTIPLE FUA EXT" },
+ { ATA_CMD_WRITE_MULTI_FUA_EXT, "WRITE MULTIPLE FUA EXT" },
{ ATA_CMD_SET_FEATURES, "SET FEATURES" },
{ ATA_CMD_SET_MULTI, "SET MULTIPLE MODE" },
{ ATA_CMD_VERIFY, "READ VERIFY SECTOR(S)" },
@@ -2342,12 +2449,12 @@ const char *ata_get_cmd_descript(u8 command)
{ ATA_CMD_READ_LOG_EXT, "READ LOG EXT" },
{ ATA_CMD_WRITE_LOG_EXT, "WRITE LOG EXT" },
{ ATA_CMD_READ_LOG_DMA_EXT, "READ LOG DMA EXT" },
- { ATA_CMD_WRITE_LOG_DMA_EXT, "WRITE LOG DMA EXT" },
+ { ATA_CMD_WRITE_LOG_DMA_EXT, "WRITE LOG DMA EXT" },
{ ATA_CMD_TRUSTED_NONDATA, "TRUSTED NON-DATA" },
{ ATA_CMD_TRUSTED_RCV, "TRUSTED RECEIVE" },
- { ATA_CMD_TRUSTED_RCV_DMA, "TRUSTED RECEIVE DMA" },
+ { ATA_CMD_TRUSTED_RCV_DMA, "TRUSTED RECEIVE DMA" },
{ ATA_CMD_TRUSTED_SND, "TRUSTED SEND" },
- { ATA_CMD_TRUSTED_SND_DMA, "TRUSTED SEND DMA" },
+ { ATA_CMD_TRUSTED_SND_DMA, "TRUSTED SEND DMA" },
{ ATA_CMD_PMP_READ, "READ BUFFER" },
{ ATA_CMD_PMP_READ_DMA, "READ BUFFER DMA" },
{ ATA_CMD_PMP_WRITE, "WRITE BUFFER" },
@@ -2364,12 +2471,12 @@ const char *ata_get_cmd_descript(u8 command)
{ ATA_CMD_MEDIA_LOCK, "DOOR LOCK" },
{ ATA_CMD_MEDIA_UNLOCK, "DOOR UNLOCK" },
{ ATA_CMD_DSM, "DATA SET MANAGEMENT" },
- { ATA_CMD_CHK_MED_CRD_TYP, "CHECK MEDIA CARD TYPE" },
- { ATA_CMD_CFA_REQ_EXT_ERR, "CFA REQUEST EXTENDED ERROR" },
+ { ATA_CMD_CHK_MED_CRD_TYP, "CHECK MEDIA CARD TYPE" },
+ { ATA_CMD_CFA_REQ_EXT_ERR, "CFA REQUEST EXTENDED ERROR" },
{ ATA_CMD_CFA_WRITE_NE, "CFA WRITE SECTORS WITHOUT ERASE" },
{ ATA_CMD_CFA_TRANS_SECT, "CFA TRANSLATE SECTOR" },
{ ATA_CMD_CFA_ERASE, "CFA ERASE SECTORS" },
- { ATA_CMD_CFA_WRITE_MULT_NE, "CFA WRITE MULTIPLE WITHOUT ERASE" },
+ { ATA_CMD_CFA_WRITE_MULT_NE, "CFA WRITE MULTIPLE WITHOUT ERASE" },
{ ATA_CMD_REQ_SENSE_DATA, "REQUEST SENSE DATA EXT" },
{ ATA_CMD_SANITIZE_DEVICE, "SANITIZE DEVICE" },
{ ATA_CMD_READ_LONG, "READ LONG (with retries)" },
@@ -2543,14 +2650,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 " : "");
}