提交 b83b86a3 编写于 作者: H Hans de Goede 提交者: Sarah Sharp

uas: Don't allow more then one task to run at the same time

Since we use a fixed tag / stream for tasks we cannot allow more then one
to run at the same time. This could happen before this time if a task timed
out.
Signed-off-by: NHans de Goede <hdegoede@redhat.com>
Signed-off-by: NSarah Sharp <sarah.a.sharp@linux.intel.com>
上级 70cf0fba
...@@ -53,6 +53,7 @@ struct uas_dev_info { ...@@ -53,6 +53,7 @@ struct uas_dev_info {
unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe; unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;
unsigned use_streams:1; unsigned use_streams:1;
unsigned uas_sense_old:1; unsigned uas_sense_old:1;
unsigned running_task:1;
struct scsi_cmnd *cmnd; struct scsi_cmnd *cmnd;
spinlock_t lock; spinlock_t lock;
struct work_struct work; struct work_struct work;
...@@ -195,6 +196,7 @@ static void uas_zap_dead(struct uas_dev_info *devinfo) ...@@ -195,6 +196,7 @@ static void uas_zap_dead(struct uas_dev_info *devinfo)
DATA_OUT_URB_INFLIGHT); DATA_OUT_URB_INFLIGHT);
uas_try_complete(cmnd, __func__); uas_try_complete(cmnd, __func__);
} }
devinfo->running_task = 0;
spin_unlock_irqrestore(&devinfo->lock, flags); spin_unlock_irqrestore(&devinfo->lock, flags);
} }
...@@ -340,6 +342,9 @@ static void uas_stat_cmplt(struct urb *urb) ...@@ -340,6 +342,9 @@ static void uas_stat_cmplt(struct urb *urb)
if (!cmnd) { if (!cmnd) {
if (iu->iu_id == IU_ID_RESPONSE) { if (iu->iu_id == IU_ID_RESPONSE) {
if (!devinfo->running_task)
dev_warn(&urb->dev->dev,
"stat urb: recv unexpected response iu\n");
/* store results for uas_eh_task_mgmt() */ /* store results for uas_eh_task_mgmt() */
memcpy(&devinfo->response, iu, sizeof(devinfo->response)); memcpy(&devinfo->response, iu, sizeof(devinfo->response));
} }
...@@ -726,14 +731,26 @@ static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd, ...@@ -726,14 +731,26 @@ static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd,
u16 tag = devinfo->qdepth; u16 tag = devinfo->qdepth;
unsigned long flags; unsigned long flags;
struct urb *sense_urb; struct urb *sense_urb;
int result = SUCCESS;
spin_lock_irqsave(&devinfo->lock, flags); spin_lock_irqsave(&devinfo->lock, flags);
if (devinfo->running_task) {
shost_printk(KERN_INFO, shost,
"%s: %s: error already running a task\n",
__func__, fname);
spin_unlock_irqrestore(&devinfo->lock, flags);
return FAILED;
}
devinfo->running_task = 1;
memset(&devinfo->response, 0, sizeof(devinfo->response)); memset(&devinfo->response, 0, sizeof(devinfo->response));
sense_urb = uas_submit_sense_urb(shost, GFP_ATOMIC, tag); sense_urb = uas_submit_sense_urb(shost, GFP_ATOMIC, tag);
if (!sense_urb) { if (!sense_urb) {
shost_printk(KERN_INFO, shost, shost_printk(KERN_INFO, shost,
"%s: %s: submit sense urb failed\n", "%s: %s: submit sense urb failed\n",
__func__, fname); __func__, fname);
devinfo->running_task = 0;
spin_unlock_irqrestore(&devinfo->lock, flags); spin_unlock_irqrestore(&devinfo->lock, flags);
return FAILED; return FAILED;
} }
...@@ -741,6 +758,7 @@ static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd, ...@@ -741,6 +758,7 @@ static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd,
shost_printk(KERN_INFO, shost, shost_printk(KERN_INFO, shost,
"%s: %s: submit task mgmt urb failed\n", "%s: %s: submit task mgmt urb failed\n",
__func__, fname); __func__, fname);
devinfo->running_task = 0;
spin_unlock_irqrestore(&devinfo->lock, flags); spin_unlock_irqrestore(&devinfo->lock, flags);
usb_kill_urb(sense_urb); usb_kill_urb(sense_urb);
return FAILED; return FAILED;
...@@ -748,23 +766,33 @@ static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd, ...@@ -748,23 +766,33 @@ static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd,
spin_unlock_irqrestore(&devinfo->lock, flags); spin_unlock_irqrestore(&devinfo->lock, flags);
if (usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 3000) == 0) { if (usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 3000) == 0) {
/*
* Note we deliberately do not clear running_task here. If we
* allow new tasks to be submitted, there is no way to figure
* out if a received response_iu is for the failed task or for
* the new one. A bus-reset will eventually clear running_task.
*/
shost_printk(KERN_INFO, shost, shost_printk(KERN_INFO, shost,
"%s: %s timed out\n", __func__, fname); "%s: %s timed out\n", __func__, fname);
return FAILED; return FAILED;
} }
spin_lock_irqsave(&devinfo->lock, flags);
devinfo->running_task = 0;
if (be16_to_cpu(devinfo->response.tag) != tag) { if (be16_to_cpu(devinfo->response.tag) != tag) {
shost_printk(KERN_INFO, shost, shost_printk(KERN_INFO, shost,
"%s: %s failed (wrong tag %d/%d)\n", __func__, "%s: %s failed (wrong tag %d/%d)\n", __func__,
fname, be16_to_cpu(devinfo->response.tag), tag); fname, be16_to_cpu(devinfo->response.tag), tag);
return FAILED; result = FAILED;
} } else if (devinfo->response.response_code != RC_TMF_COMPLETE) {
if (devinfo->response.response_code != RC_TMF_COMPLETE) {
shost_printk(KERN_INFO, shost, shost_printk(KERN_INFO, shost,
"%s: %s failed (rc 0x%x)\n", __func__, "%s: %s failed (rc 0x%x)\n", __func__,
fname, devinfo->response.response_code); fname, devinfo->response.response_code);
return FAILED; result = FAILED;
} }
return SUCCESS; spin_unlock_irqrestore(&devinfo->lock, flags);
return result;
} }
static int uas_eh_abort_handler(struct scsi_cmnd *cmnd) static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
...@@ -982,6 +1010,7 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id) ...@@ -982,6 +1010,7 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
devinfo->intf = intf; devinfo->intf = intf;
devinfo->udev = udev; devinfo->udev = udev;
devinfo->resetting = 0; devinfo->resetting = 0;
devinfo->running_task = 0;
init_usb_anchor(&devinfo->cmd_urbs); init_usb_anchor(&devinfo->cmd_urbs);
init_usb_anchor(&devinfo->sense_urbs); init_usb_anchor(&devinfo->sense_urbs);
init_usb_anchor(&devinfo->data_urbs); init_usb_anchor(&devinfo->data_urbs);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册