aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHannes Reinecke <hare@suse.de>2015-03-27 11:46:37 -0400
committerTejun Heo <tj@kernel.org>2015-03-27 11:59:22 -0400
commita1524f226a02aa6edebd90ae0752e97cfd78b159 (patch)
tree3b694223de3a939c51271f779966f1a11c74c74b
parentfe7173c206de63fc28475ee6ae42ff95c05692de (diff)
libata-eh: Set 'information' field for autosense
If NCQ autosense or the sense data reporting feature is enabled the LBA of the offending command should be stored in the sense data 'information' field. Signed-off-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Tejun Heo <tj@kernel.org>
-rw-r--r--drivers/ata/libata-core.c4
-rw-r--r--drivers/ata/libata-eh.c3
-rw-r--r--drivers/ata/libata-scsi.c12
-rw-r--r--drivers/ata/libata.h5
-rw-r--r--drivers/scsi/scsi_error.c31
-rw-r--r--include/scsi/scsi_eh.h1
6 files changed, 53 insertions, 3 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index aebb7e305874..ff57367f5f0c 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -691,11 +691,11 @@ static int ata_rwcmd_protocol(struct ata_taskfile *tf, struct ata_device *dev)
691 * RETURNS: 691 * RETURNS:
692 * Block address read from @tf. 692 * Block address read from @tf.
693 */ 693 */
694u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev) 694u64 ata_tf_read_block(const struct ata_taskfile *tf, struct ata_device *dev)
695{ 695{
696 u64 block = 0; 696 u64 block = 0;
697 697
698 if (tf->flags & ATA_TFLAG_LBA) { 698 if (!dev || tf->flags & ATA_TFLAG_LBA) {
699 if (tf->flags & ATA_TFLAG_LBA48) { 699 if (tf->flags & ATA_TFLAG_LBA48) {
700 block |= (u64)tf->hob_lbah << 40; 700 block |= (u64)tf->hob_lbah << 40;
701 block |= (u64)tf->hob_lbam << 32; 701 block |= (u64)tf->hob_lbam << 32;
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 9fa81d91f6ad..77ef43e320ea 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1852,6 +1852,7 @@ void ata_eh_analyze_ncq_error(struct ata_link *link)
1852 ata_dev_dbg(dev, "NCQ Autosense %02x/%02x/%02x\n", 1852 ata_dev_dbg(dev, "NCQ Autosense %02x/%02x/%02x\n",
1853 sense_key, asc, ascq); 1853 sense_key, asc, ascq);
1854 ata_scsi_set_sense(qc->scsicmd, sense_key, asc, ascq); 1854 ata_scsi_set_sense(qc->scsicmd, sense_key, asc, ascq);
1855 ata_scsi_set_sense_information(qc->scsicmd, &qc->result_tf);
1855 qc->flags |= ATA_QCFLAG_SENSE_VALID; 1856 qc->flags |= ATA_QCFLAG_SENSE_VALID;
1856 } 1857 }
1857 1858
@@ -1894,6 +1895,8 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
1894 tmp = ata_eh_request_sense(qc, qc->scsicmd); 1895 tmp = ata_eh_request_sense(qc, qc->scsicmd);
1895 if (tmp) 1896 if (tmp)
1896 qc->err_mask |= tmp; 1897 qc->err_mask |= tmp;
1898 else
1899 ata_scsi_set_sense_information(qc->scsicmd, tf);
1897 } else { 1900 } else {
1898 ata_dev_warn(qc->dev, "sense data available but port frozen\n"); 1901 ata_dev_warn(qc->dev, "sense data available but port frozen\n");
1899 } 1902 }
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 3ac5be3acdbe..3131adcc1f87 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -280,6 +280,18 @@ void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
280 scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq); 280 scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq);
281} 281}
282 282
283void ata_scsi_set_sense_information(struct scsi_cmnd *cmd,
284 const struct ata_taskfile *tf)
285{
286 u64 information;
287
288 if (!cmd)
289 return;
290
291 information = ata_tf_read_block(tf, NULL);
292 scsi_set_sense_information(cmd->sense_buffer, information);
293}
294
283static ssize_t 295static ssize_t
284ata_scsi_em_message_store(struct device *dev, struct device_attribute *attr, 296ata_scsi_em_message_store(struct device *dev, struct device_attribute *attr,
285 const char *buf, size_t count) 297 const char *buf, size_t count)
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 8cfdd9616d16..a998a175f9f1 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -67,7 +67,8 @@ extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev, int tag);
67extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev, 67extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
68 u64 block, u32 n_block, unsigned int tf_flags, 68 u64 block, u32 n_block, unsigned int tf_flags,
69 unsigned int tag); 69 unsigned int tag);
70extern u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev); 70extern u64 ata_tf_read_block(const struct ata_taskfile *tf,
71 struct ata_device *dev);
71extern unsigned ata_exec_internal(struct ata_device *dev, 72extern unsigned ata_exec_internal(struct ata_device *dev,
72 struct ata_taskfile *tf, const u8 *cdb, 73 struct ata_taskfile *tf, const u8 *cdb,
73 int dma_dir, void *buf, unsigned int buflen, 74 int dma_dir, void *buf, unsigned int buflen,
@@ -138,6 +139,8 @@ extern int ata_scsi_add_hosts(struct ata_host *host,
138extern void ata_scsi_scan_host(struct ata_port *ap, int sync); 139extern void ata_scsi_scan_host(struct ata_port *ap, int sync);
139extern int ata_scsi_offline_dev(struct ata_device *dev); 140extern int ata_scsi_offline_dev(struct ata_device *dev);
140extern void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq); 141extern void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq);
142extern void ata_scsi_set_sense_information(struct scsi_cmnd *cmd,
143 const struct ata_taskfile *tf);
141extern void ata_scsi_media_change_notify(struct ata_device *dev); 144extern void ata_scsi_media_change_notify(struct ata_device *dev);
142extern void ata_scsi_hotplug(struct work_struct *work); 145extern void ata_scsi_hotplug(struct work_struct *work);
143extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); 146extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 4cdaffca17fc..c95a4e943fc6 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -26,6 +26,7 @@
26#include <linux/blkdev.h> 26#include <linux/blkdev.h>
27#include <linux/delay.h> 27#include <linux/delay.h>
28#include <linux/jiffies.h> 28#include <linux/jiffies.h>
29#include <asm/unaligned.h>
29 30
30#include <scsi/scsi.h> 31#include <scsi/scsi.h>
31#include <scsi/scsi_cmnd.h> 32#include <scsi/scsi_cmnd.h>
@@ -2586,3 +2587,33 @@ void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq)
2586 } 2587 }
2587} 2588}
2588EXPORT_SYMBOL(scsi_build_sense_buffer); 2589EXPORT_SYMBOL(scsi_build_sense_buffer);
2590
2591/**
2592 * scsi_set_sense_information - set the information field in a
2593 * formatted sense data buffer
2594 * @buf: Where to build sense data
2595 * @info: 64-bit information value to be set
2596 *
2597 **/
2598void scsi_set_sense_information(u8 *buf, u64 info)
2599{
2600 if ((buf[0] & 0x7f) == 0x72) {
2601 u8 *ucp, len;
2602
2603 len = buf[7];
2604 ucp = (char *)scsi_sense_desc_find(buf, len + 8, 0);
2605 if (!ucp) {
2606 buf[7] = len + 0xa;
2607 ucp = buf + 8 + len;
2608 }
2609 ucp[0] = 0;
2610 ucp[1] = 0xa;
2611 ucp[2] = 0x80; /* Valid bit */
2612 ucp[3] = 0;
2613 put_unaligned_be64(info, &ucp[4]);
2614 } else if ((buf[0] & 0x7f) == 0x70) {
2615 buf[0] |= 0x80;
2616 put_unaligned_be64(info, &buf[3]);
2617 }
2618}
2619EXPORT_SYMBOL(scsi_set_sense_information);
diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h
index 1e1421b06565..5a4bb5bb66b3 100644
--- a/include/scsi/scsi_eh.h
+++ b/include/scsi/scsi_eh.h
@@ -59,6 +59,7 @@ extern int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len,
59 u64 * info_out); 59 u64 * info_out);
60 60
61extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq); 61extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq);
62extern void scsi_set_sense_information(u8 *buf, u64 info);
62 63
63extern int scsi_ioctl_reset(struct scsi_device *, int __user *); 64extern int scsi_ioctl_reset(struct scsi_device *, int __user *);
64 65