Commit cb480c94 authored by Dan Williams's avatar Dan Williams Committed by Ben Hutchings

libsas: fix taskfile corruption in sas_ata_qc_fill_rtf

commit 6ef1b512 upstream.

fill_result_tf() grabs the taskfile flags from the originating qc which
sas_ata_qc_fill_rtf() promptly overwrites.  The presence of an
ata_taskfile in the sata_device makes it tempting to just copy the full
contents in sas_ata_qc_fill_rtf().  However, libata really only wants
the fis contents and expects the other portions of the taskfile to not
be touched by ->qc_fill_rtf.  To that end store a fis buffer in the
sata_device and use ata_tf_from_fis() like every other ->qc_fill_rtf()
implementation.
Reported-by: default avatarPraveen Murali <pmurali@logicube.com>
Tested-by: default avatarPraveen Murali <pmurali@logicube.com>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
[bwh: Backported to 3.2: adjust context]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent 1e1cdddb
...@@ -201,7 +201,7 @@ static void asd_get_response_tasklet(struct asd_ascb *ascb, ...@@ -201,7 +201,7 @@ static void asd_get_response_tasklet(struct asd_ascb *ascb,
if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) { if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) {
resp->frame_len = le16_to_cpu(*(__le16 *)(r+6)); resp->frame_len = le16_to_cpu(*(__le16 *)(r+6));
memcpy(&resp->ending_fis[0], r+16, 24); memcpy(&resp->ending_fis[0], r+16, ATA_RESP_FIS_SIZE);
ts->buf_valid_size = sizeof(*resp); ts->buf_valid_size = sizeof(*resp);
} }
} }
......
...@@ -112,12 +112,12 @@ static void sas_ata_task_done(struct sas_task *task) ...@@ -112,12 +112,12 @@ static void sas_ata_task_done(struct sas_task *task)
if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD || if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD ||
((stat->stat == SAM_STAT_CHECK_CONDITION && ((stat->stat == SAM_STAT_CHECK_CONDITION &&
dev->sata_dev.command_set == ATAPI_COMMAND_SET))) { dev->sata_dev.command_set == ATAPI_COMMAND_SET))) {
ata_tf_from_fis(resp->ending_fis, &dev->sata_dev.tf); memcpy(dev->sata_dev.fis, resp->ending_fis, ATA_RESP_FIS_SIZE);
if (!link->sactive) { if (!link->sactive) {
qc->err_mask |= ac_err_mask(dev->sata_dev.tf.command); qc->err_mask |= ac_err_mask(dev->sata_dev.fis[2]);
} else { } else {
link->eh_info.err_mask |= ac_err_mask(dev->sata_dev.tf.command); link->eh_info.err_mask |= ac_err_mask(dev->sata_dev.fis[2]);
if (unlikely(link->eh_info.err_mask)) if (unlikely(link->eh_info.err_mask))
qc->flags |= ATA_QCFLAG_FAILED; qc->flags |= ATA_QCFLAG_FAILED;
} }
...@@ -138,8 +138,8 @@ static void sas_ata_task_done(struct sas_task *task) ...@@ -138,8 +138,8 @@ static void sas_ata_task_done(struct sas_task *task)
qc->flags |= ATA_QCFLAG_FAILED; qc->flags |= ATA_QCFLAG_FAILED;
} }
dev->sata_dev.tf.feature = 0x04; /* status err */ dev->sata_dev.fis[3] = 0x04; /* status err */
dev->sata_dev.tf.command = ATA_ERR; dev->sata_dev.fis[2] = ATA_ERR;
} }
} }
...@@ -252,7 +252,7 @@ static bool sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc) ...@@ -252,7 +252,7 @@ static bool sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc)
{ {
struct domain_device *dev = qc->ap->private_data; struct domain_device *dev = qc->ap->private_data;
memcpy(&qc->result_tf, &dev->sata_dev.tf, sizeof(qc->result_tf)); ata_tf_from_fis(dev->sata_dev.fis, &qc->result_tf);
return true; return true;
} }
......
...@@ -159,6 +159,8 @@ enum ata_command_set { ...@@ -159,6 +159,8 @@ enum ata_command_set {
ATAPI_COMMAND_SET = 1, ATAPI_COMMAND_SET = 1,
}; };
#define ATA_RESP_FIS_SIZE 24
struct sata_device { struct sata_device {
enum ata_command_set command_set; enum ata_command_set command_set;
struct smp_resp rps_resp; /* report_phy_sata_resp */ struct smp_resp rps_resp; /* report_phy_sata_resp */
...@@ -170,7 +172,7 @@ struct sata_device { ...@@ -170,7 +172,7 @@ struct sata_device {
struct ata_port *ap; struct ata_port *ap;
struct ata_host ata_host; struct ata_host ata_host;
struct ata_taskfile tf; u8 fis[ATA_RESP_FIS_SIZE];
u32 sstatus; u32 sstatus;
u32 serror; u32 serror;
u32 scontrol; u32 scontrol;
...@@ -486,7 +488,7 @@ enum exec_status { ...@@ -486,7 +488,7 @@ enum exec_status {
*/ */
struct ata_task_resp { struct ata_task_resp {
u16 frame_len; u16 frame_len;
u8 ending_fis[24]; /* dev to host or data-in */ u8 ending_fis[ATA_RESP_FIS_SIZE]; /* dev to host or data-in */
u32 sstatus; u32 sstatus;
u32 serror; u32 serror;
u32 scontrol; u32 scontrol;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment