Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Dan Williams and committed by
James Bottomley
6ef1b512 222a806a

+11 -9
+1 -1
drivers/scsi/aic94xx/aic94xx_task.c
··· 201 201 202 202 if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) { 203 203 resp->frame_len = le16_to_cpu(*(__le16 *)(r+6)); 204 - memcpy(&resp->ending_fis[0], r+16, 24); 204 + memcpy(&resp->ending_fis[0], r+16, ATA_RESP_FIS_SIZE); 205 205 ts->buf_valid_size = sizeof(*resp); 206 206 } 207 207 }
+6 -6
drivers/scsi/libsas/sas_ata.c
··· 139 139 if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD || 140 140 ((stat->stat == SAM_STAT_CHECK_CONDITION && 141 141 dev->sata_dev.command_set == ATAPI_COMMAND_SET))) { 142 - ata_tf_from_fis(resp->ending_fis, &dev->sata_dev.tf); 142 + memcpy(dev->sata_dev.fis, resp->ending_fis, ATA_RESP_FIS_SIZE); 143 143 144 144 if (!link->sactive) { 145 - qc->err_mask |= ac_err_mask(dev->sata_dev.tf.command); 145 + qc->err_mask |= ac_err_mask(dev->sata_dev.fis[2]); 146 146 } else { 147 - link->eh_info.err_mask |= ac_err_mask(dev->sata_dev.tf.command); 147 + link->eh_info.err_mask |= ac_err_mask(dev->sata_dev.fis[2]); 148 148 if (unlikely(link->eh_info.err_mask)) 149 149 qc->flags |= ATA_QCFLAG_FAILED; 150 150 } ··· 161 161 qc->flags |= ATA_QCFLAG_FAILED; 162 162 } 163 163 164 - dev->sata_dev.tf.feature = 0x04; /* status err */ 165 - dev->sata_dev.tf.command = ATA_ERR; 164 + dev->sata_dev.fis[3] = 0x04; /* status err */ 165 + dev->sata_dev.fis[2] = ATA_ERR; 166 166 } 167 167 } 168 168 ··· 269 269 { 270 270 struct domain_device *dev = qc->ap->private_data; 271 271 272 - memcpy(&qc->result_tf, &dev->sata_dev.tf, sizeof(qc->result_tf)); 272 + ata_tf_from_fis(dev->sata_dev.fis, &qc->result_tf); 273 273 return true; 274 274 } 275 275
+4 -2
include/scsi/libsas.h
··· 163 163 ATAPI_COMMAND_SET = 1, 164 164 }; 165 165 166 + #define ATA_RESP_FIS_SIZE 24 167 + 166 168 struct sata_device { 167 169 enum ata_command_set command_set; 168 170 struct smp_resp rps_resp; /* report_phy_sata_resp */ ··· 173 171 174 172 struct ata_port *ap; 175 173 struct ata_host ata_host; 176 - struct ata_taskfile tf; 174 + u8 fis[ATA_RESP_FIS_SIZE]; 177 175 }; 178 176 179 177 enum { ··· 539 537 */ 540 538 struct ata_task_resp { 541 539 u16 frame_len; 542 - u8 ending_fis[24]; /* dev to host or data-in */ 540 + u8 ending_fis[ATA_RESP_FIS_SIZE]; /* dev to host or data-in */ 543 541 }; 544 542 545 543 #define SAS_STATUS_BUF_SIZE 96