aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2012-06-22 13:52:34 -0400
committerJames Bottomley <JBottomley@Parallels.com>2012-07-08 04:49:14 -0400
commit6ef1b512f4e6f936d89aa20be3d97a7ec7c290ac (patch)
treede2a0d0a74d2f0cdab456766fa77c5ec60487771
parent222a806af830fda34ad1f6bc991cd226916de060 (diff)
[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>
-rw-r--r--drivers/scsi/aic94xx/aic94xx_task.c2
-rw-r--r--drivers/scsi/libsas/sas_ata.c12
-rw-r--r--include/scsi/libsas.h6
3 files changed, 11 insertions, 9 deletions
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c
index 532d212b6b2c..393e7ce8e95a 100644
--- a/drivers/scsi/aic94xx/aic94xx_task.c
+++ b/drivers/scsi/aic94xx/aic94xx_task.c
@@ -201,7 +201,7 @@ static void asd_get_response_tasklet(struct asd_ascb *ascb,
201 201
202 if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) { 202 if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) {
203 resp->frame_len = le16_to_cpu(*(__le16 *)(r+6)); 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 ts->buf_valid_size = sizeof(*resp); 205 ts->buf_valid_size = sizeof(*resp);
206 } 206 }
207 } 207 }
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 441d88ad99a7..d109cc3a17b6 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -139,12 +139,12 @@ static void sas_ata_task_done(struct sas_task *task)
139 if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD || 139 if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD ||
140 ((stat->stat == SAM_STAT_CHECK_CONDITION && 140 ((stat->stat == SAM_STAT_CHECK_CONDITION &&
141 dev->sata_dev.command_set == ATAPI_COMMAND_SET))) { 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 if (!link->sactive) { 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 } else { 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 if (unlikely(link->eh_info.err_mask)) 148 if (unlikely(link->eh_info.err_mask))
149 qc->flags |= ATA_QCFLAG_FAILED; 149 qc->flags |= ATA_QCFLAG_FAILED;
150 } 150 }
@@ -161,8 +161,8 @@ static void sas_ata_task_done(struct sas_task *task)
161 qc->flags |= ATA_QCFLAG_FAILED; 161 qc->flags |= ATA_QCFLAG_FAILED;
162 } 162 }
163 163
164 dev->sata_dev.tf.feature = 0x04; /* status err */ 164 dev->sata_dev.fis[3] = 0x04; /* status err */
165 dev->sata_dev.tf.command = ATA_ERR; 165 dev->sata_dev.fis[2] = ATA_ERR;
166 } 166 }
167 } 167 }
168 168
@@ -269,7 +269,7 @@ static bool sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc)
269{ 269{
270 struct domain_device *dev = qc->ap->private_data; 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 return true; 273 return true;
274} 274}
275 275
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index f4f1c96dca72..10ce74f589c5 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -163,6 +163,8 @@ enum ata_command_set {
163 ATAPI_COMMAND_SET = 1, 163 ATAPI_COMMAND_SET = 1,
164}; 164};
165 165
166#define ATA_RESP_FIS_SIZE 24
167
166struct sata_device { 168struct sata_device {
167 enum ata_command_set command_set; 169 enum ata_command_set command_set;
168 struct smp_resp rps_resp; /* report_phy_sata_resp */ 170 struct smp_resp rps_resp; /* report_phy_sata_resp */
@@ -171,7 +173,7 @@ struct sata_device {
171 173
172 struct ata_port *ap; 174 struct ata_port *ap;
173 struct ata_host ata_host; 175 struct ata_host ata_host;
174 struct ata_taskfile tf; 176 u8 fis[ATA_RESP_FIS_SIZE];
175}; 177};
176 178
177enum { 179enum {
@@ -537,7 +539,7 @@ enum exec_status {
537 */ 539 */
538struct ata_task_resp { 540struct ata_task_resp {
539 u16 frame_len; 541 u16 frame_len;
540 u8 ending_fis[24]; /* dev to host or data-in */ 542 u8 ending_fis[ATA_RESP_FIS_SIZE]; /* dev to host or data-in */
541}; 543};
542 544
543#define SAS_STATUS_BUF_SIZE 96 545#define SAS_STATUS_BUF_SIZE 96