summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@HansenPartnership.com>2007-12-29 11:49:53 -0600
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-01-11 18:29:12 -0600
commit2d4b63e1505b317d4253cee3f2970792ec6d41cb (patch)
treea0b0ec862dfd20ecc33393e014396c7427074a52 /drivers
parentb98e66fa0b687149dc3b26179096dc542c7d5001 (diff)
downloadlinux-2d4b63e1505b317d4253cee3f2970792ec6d41cb.tar.bz2
[SCSI] libsas: don't treat underrun as an error on SMP tasks
All SMP tasks sent through bsg generate messages like: sas: smp_execute_task: task to dev 500605b000001450 response: 0x0 status 0x81 Three times (because the task gets retried). Firstly, don't retry either overrun or underrun (the data buffer isn't going to change size) and secondly, just report the underrun but don't set an error for it. This is necessary so bsg can report back the residual. Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/libsas/sas_expander.c19
1 files changed, 19 insertions, 0 deletions
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 76555b1ddfd5..8aeaad95242c 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -109,6 +109,16 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
task->task_status.stat == SAM_GOOD) {
res = 0;
break;
+ } if (task->task_status.resp == SAS_TASK_COMPLETE &&
+ task->task_status.stat == SAS_DATA_UNDERRUN) {
+ /* no error, but return the number of bytes of
+ * underrun */
+ res = task->task_status.residual;
+ break;
+ } if (task->task_status.resp == SAS_TASK_COMPLETE &&
+ task->task_status.stat == SAS_DATA_OVERRUN) {
+ res = -EMSGSIZE;
+ break;
} else {
SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
"status 0x%x\n", __FUNCTION__,
@@ -1924,6 +1934,15 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
ret = smp_execute_task(dev, bio_data(req->bio), req->data_len,
bio_data(rsp->bio), rsp->data_len);
+ if (ret > 0) {
+ /* positive number is the untransferred residual */
+ rsp->data_len = ret;
+ req->data_len = 0;
+ ret = 0;
+ } else if (ret == 0) {
+ rsp->data_len = 0;
+ req->data_len = 0;
+ }
return ret;
}