unsigned char key, asc, ascq; /* May be valid if error==-EIO */
int stat_count; /* Retries getting status. */
+ unsigned int timeo; /* jiffies until rq->timeout changes */
unsigned int len; /* Requested length */
unsigned int current_sg;
int openc; /* protected by ub_lock! */
/* kref is too implicit for our taste */
int reset; /* Reset is running */
+ int bad_resid;
unsigned int tagcnt;
char name[12];
struct usb_device *dev;
cmd->cdb_len = rq->cmd_len;
cmd->len = rq->data_len;
+
+ /*
+ * To reapply this to every URB is not as incorrect as it looks.
+ * In return, we avoid any complicated tracking calculations.
+ */
+ cmd->timeo = rq->timeout;
}
static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
scsi_status = 0;
} else {
if (cmd->act_len != cmd->len) {
- if ((cmd->key == MEDIUM_ERROR ||
- cmd->key == UNIT_ATTENTION) &&
- ub_rw_cmd_retry(sc, lun, urq, cmd) == 0)
- return;
scsi_status = SAM_STAT_CHECK_CONDITION;
} else {
scsi_status = 0;
else
scsi_status = DID_ERROR << 16;
} else {
- if (cmd->error == -EIO) {
+ if (cmd->error == -EIO &&
+ (cmd->key == 0 ||
+ cmd->key == MEDIUM_ERROR ||
+ cmd->key == UNIT_ATTENTION)) {
if (ub_rw_cmd_retry(sc, lun, urq, cmd) == 0)
return;
}
return;
}
- len = le32_to_cpu(bcs->Residue);
- if (len != cmd->len - cmd->act_len) {
- /*
- * It is all right to transfer less, the caller has
- * to check. But it's not all right if the device
- * counts disagree with our counts.
- */
- goto Bad_End;
+ if (!sc->bad_resid) {
+ len = le32_to_cpu(bcs->Residue);
+ if (len != cmd->len - cmd->act_len) {
+ /*
+ * Only start ignoring if this cmd ended well.
+ */
+ if (cmd->len == cmd->act_len) {
+ printk(KERN_NOTICE "%s: "
+ "bad residual %d of %d, ignoring\n",
+ sc->name, len, cmd->len);
+ sc->bad_resid = 1;
+ }
+ }
}
switch (bcs->Status) {
return;
}
- sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
+ if (cmd->timeo)
+ sc->work_timer.expires = jiffies + cmd->timeo;
+ else
+ sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
add_timer(&sc->work_timer);
cmd->state = UB_CMDST_DATA;
return -1;
}
- sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT;
+ if (cmd->timeo)
+ sc->work_timer.expires = jiffies + cmd->timeo;
+ else
+ sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT;
add_timer(&sc->work_timer);
return 0;
}
del_gendisk(lun->disk);
/*
* I wish I could do:
- * set_bit(QUEUE_FLAG_DEAD, &q->queue_flags);
+ * queue_flag_set(QUEUE_FLAG_DEAD, q);
* As it is, we rely on our internal poisoning and let
* the upper levels to spin furiously failing all the I/O.
*/