mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-24 04:34:08 +08:00
[SCSI] libsas: fix taskfile corruption in sas_ata_qc_fill_rtf
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. Cc: <stable@vger.kernel.org> Reported-by: Praveen Murali <pmurali@logicube.com> Tested-by: Praveen Murali <pmurali@logicube.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
parent
222a806af8
commit
6ef1b512f4
@ -201,7 +201,7 @@ static void asd_get_response_tasklet(struct asd_ascb *ascb,
|
||||
|
||||
if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -139,12 +139,12 @@ static void sas_ata_task_done(struct sas_task *task)
|
||||
if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD ||
|
||||
((stat->stat == SAM_STAT_CHECK_CONDITION &&
|
||||
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) {
|
||||
qc->err_mask |= ac_err_mask(dev->sata_dev.tf.command);
|
||||
qc->err_mask |= ac_err_mask(dev->sata_dev.fis[2]);
|
||||
} 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))
|
||||
qc->flags |= ATA_QCFLAG_FAILED;
|
||||
}
|
||||
@ -161,8 +161,8 @@ static void sas_ata_task_done(struct sas_task *task)
|
||||
qc->flags |= ATA_QCFLAG_FAILED;
|
||||
}
|
||||
|
||||
dev->sata_dev.tf.feature = 0x04; /* status err */
|
||||
dev->sata_dev.tf.command = ATA_ERR;
|
||||
dev->sata_dev.fis[3] = 0x04; /* status err */
|
||||
dev->sata_dev.fis[2] = ATA_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
@ -269,7 +269,7 @@ static bool sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -163,6 +163,8 @@ enum ata_command_set {
|
||||
ATAPI_COMMAND_SET = 1,
|
||||
};
|
||||
|
||||
#define ATA_RESP_FIS_SIZE 24
|
||||
|
||||
struct sata_device {
|
||||
enum ata_command_set command_set;
|
||||
struct smp_resp rps_resp; /* report_phy_sata_resp */
|
||||
@ -171,7 +173,7 @@ struct sata_device {
|
||||
|
||||
struct ata_port *ap;
|
||||
struct ata_host ata_host;
|
||||
struct ata_taskfile tf;
|
||||
u8 fis[ATA_RESP_FIS_SIZE];
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -537,7 +539,7 @@ enum exec_status {
|
||||
*/
|
||||
struct ata_task_resp {
|
||||
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 */
|
||||
};
|
||||
|
||||
#define SAS_STATUS_BUF_SIZE 96
|
||||
|
Loading…
Reference in New Issue
Block a user