aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2013-11-12 07:44:20 -0500
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2014-03-04 18:38:22 -0500
commit61c09ce510a1eba8595beda6aac194f42571d768 (patch)
treedc99ca6f8b01509ab4b09738a362fc49a7a57344
parentc6d4579d4ba24c494d03daf656cd2ff2a9e683c6 (diff)
uas: Properly complete inflight commands on bus-reset or disconnect
Before this commit the uas driver would keep track of scsi commands which still need to have some urbs submitted to the device, and complete this with an ABORT result code on bus-reset or disconnect, but in flight scsi commands which have all their urbs submitted, and thus are not part of the work list, would never get their done callback called. The problem is killed sense urbs don't have any tag info, so it is impossible to tell which scsi cmd they belong to, so merely making sure all the urbs have completed one way or the other is not enough. This commit fixes this by changing the work list to an inflight list, which keeps tracks of all inflight scsi cmnds, using the IS_IN_WORK_LIST flag to determine if actual work needs to be done in uas_do_work(), and by moving marking all inflight scsi commands as aborted and moving them to the dead list on bus-reset or disconnect. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
-rw-r--r--drivers/usb/storage/uas.c41
1 files changed, 21 insertions, 20 deletions
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index e06505c8f6f0..1a188399e090 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -58,7 +58,7 @@ struct uas_dev_info {
58 struct scsi_cmnd *cmnd; 58 struct scsi_cmnd *cmnd;
59 spinlock_t lock; 59 spinlock_t lock;
60 struct work_struct work; 60 struct work_struct work;
61 struct list_head work_list; 61 struct list_head inflight_list;
62 struct list_head dead_list; 62 struct list_head dead_list;
63}; 63};
64 64
@@ -86,7 +86,7 @@ struct uas_cmd_info {
86 struct urb *cmd_urb; 86 struct urb *cmd_urb;
87 struct urb *data_in_urb; 87 struct urb *data_in_urb;
88 struct urb *data_out_urb; 88 struct urb *data_out_urb;
89 struct list_head work; 89 struct list_head inflight;
90 struct list_head dead; 90 struct list_head dead;
91}; 91};
92 92
@@ -125,34 +125,36 @@ static void uas_do_work(struct work_struct *work)
125 struct uas_dev_info *devinfo = 125 struct uas_dev_info *devinfo =
126 container_of(work, struct uas_dev_info, work); 126 container_of(work, struct uas_dev_info, work);
127 struct uas_cmd_info *cmdinfo; 127 struct uas_cmd_info *cmdinfo;
128 struct uas_cmd_info *temp;
129 unsigned long flags; 128 unsigned long flags;
130 int err; 129 int err;
131 130
132 spin_lock_irqsave(&devinfo->lock, flags); 131 spin_lock_irqsave(&devinfo->lock, flags);
133 list_for_each_entry_safe(cmdinfo, temp, &devinfo->work_list, work) { 132 list_for_each_entry(cmdinfo, &devinfo->inflight_list, inflight) {
134 struct scsi_pointer *scp = (void *)cmdinfo; 133 struct scsi_pointer *scp = (void *)cmdinfo;
135 struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, 134 struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
136 SCp); 135 SCp);
136
137 if (!(cmdinfo->state & IS_IN_WORK_LIST))
138 continue;
139
137 err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO); 140 err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO);
138 if (!err) { 141 if (!err)
139 cmdinfo->state &= ~IS_IN_WORK_LIST; 142 cmdinfo->state &= ~IS_IN_WORK_LIST;
140 list_del(&cmdinfo->work); 143 else
141 } else {
142 schedule_work(&devinfo->work); 144 schedule_work(&devinfo->work);
143 }
144 } 145 }
145 spin_unlock_irqrestore(&devinfo->lock, flags); 146 spin_unlock_irqrestore(&devinfo->lock, flags);
146} 147}
147 148
148static void uas_abort_work(struct uas_dev_info *devinfo) 149static void uas_abort_inflight(struct uas_dev_info *devinfo)
149{ 150{
150 struct uas_cmd_info *cmdinfo; 151 struct uas_cmd_info *cmdinfo;
151 struct uas_cmd_info *temp; 152 struct uas_cmd_info *temp;
152 unsigned long flags; 153 unsigned long flags;
153 154
154 spin_lock_irqsave(&devinfo->lock, flags); 155 spin_lock_irqsave(&devinfo->lock, flags);
155 list_for_each_entry_safe(cmdinfo, temp, &devinfo->work_list, work) { 156 list_for_each_entry_safe(cmdinfo, temp, &devinfo->inflight_list,
157 inflight) {
156 struct scsi_pointer *scp = (void *)cmdinfo; 158 struct scsi_pointer *scp = (void *)cmdinfo;
157 struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, 159 struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
158 SCp); 160 SCp);
@@ -160,7 +162,7 @@ static void uas_abort_work(struct uas_dev_info *devinfo)
160 WARN_ON_ONCE(cmdinfo->state & COMMAND_ABORTED); 162 WARN_ON_ONCE(cmdinfo->state & COMMAND_ABORTED);
161 cmdinfo->state |= COMMAND_ABORTED; 163 cmdinfo->state |= COMMAND_ABORTED;
162 cmdinfo->state &= ~IS_IN_WORK_LIST; 164 cmdinfo->state &= ~IS_IN_WORK_LIST;
163 list_del(&cmdinfo->work); 165 list_del(&cmdinfo->inflight);
164 list_add_tail(&cmdinfo->dead, &devinfo->dead_list); 166 list_add_tail(&cmdinfo->dead, &devinfo->dead_list);
165 } 167 }
166 spin_unlock_irqrestore(&devinfo->lock, flags); 168 spin_unlock_irqrestore(&devinfo->lock, flags);
@@ -173,7 +175,6 @@ static void uas_add_work(struct uas_cmd_info *cmdinfo)
173 struct uas_dev_info *devinfo = cmnd->device->hostdata; 175 struct uas_dev_info *devinfo = cmnd->device->hostdata;
174 176
175 WARN_ON_ONCE(!spin_is_locked(&devinfo->lock)); 177 WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
176 list_add_tail(&cmdinfo->work, &devinfo->work_list);
177 cmdinfo->state |= IS_IN_WORK_LIST; 178 cmdinfo->state |= IS_IN_WORK_LIST;
178 schedule_work(&devinfo->work); 179 schedule_work(&devinfo->work);
179} 180}
@@ -289,7 +290,8 @@ static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
289 scmd_printk(KERN_INFO, cmnd, "abort completed\n"); 290 scmd_printk(KERN_INFO, cmnd, "abort completed\n");
290 cmnd->result = DID_ABORT << 16; 291 cmnd->result = DID_ABORT << 16;
291 list_del(&cmdinfo->dead); 292 list_del(&cmdinfo->dead);
292 } 293 } else
294 list_del(&cmdinfo->inflight);
293 cmnd->scsi_done(cmnd); 295 cmnd->scsi_done(cmnd);
294 return 0; 296 return 0;
295} 297}
@@ -717,6 +719,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
717 uas_add_work(cmdinfo); 719 uas_add_work(cmdinfo);
718 } 720 }
719 721
722 list_add_tail(&cmdinfo->inflight, &devinfo->inflight_list);
720 spin_unlock_irqrestore(&devinfo->lock, flags); 723 spin_unlock_irqrestore(&devinfo->lock, flags);
721 return 0; 724 return 0;
722} 725}
@@ -807,11 +810,9 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
807 spin_lock_irqsave(&devinfo->lock, flags); 810 spin_lock_irqsave(&devinfo->lock, flags);
808 WARN_ON_ONCE(cmdinfo->state & COMMAND_ABORTED); 811 WARN_ON_ONCE(cmdinfo->state & COMMAND_ABORTED);
809 cmdinfo->state |= COMMAND_ABORTED; 812 cmdinfo->state |= COMMAND_ABORTED;
813 cmdinfo->state &= ~IS_IN_WORK_LIST;
814 list_del(&cmdinfo->inflight);
810 list_add_tail(&cmdinfo->dead, &devinfo->dead_list); 815 list_add_tail(&cmdinfo->dead, &devinfo->dead_list);
811 if (cmdinfo->state & IS_IN_WORK_LIST) {
812 list_del(&cmdinfo->work);
813 cmdinfo->state &= ~IS_IN_WORK_LIST;
814 }
815 if (cmdinfo->state & COMMAND_INFLIGHT) { 816 if (cmdinfo->state & COMMAND_INFLIGHT) {
816 spin_unlock_irqrestore(&devinfo->lock, flags); 817 spin_unlock_irqrestore(&devinfo->lock, flags);
817 ret = uas_eh_task_mgmt(cmnd, "ABORT TASK", TMF_ABORT_TASK); 818 ret = uas_eh_task_mgmt(cmnd, "ABORT TASK", TMF_ABORT_TASK);
@@ -847,7 +848,7 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
847 848
848 shost_printk(KERN_INFO, sdev->host, "%s start\n", __func__); 849 shost_printk(KERN_INFO, sdev->host, "%s start\n", __func__);
849 devinfo->resetting = 1; 850 devinfo->resetting = 1;
850 uas_abort_work(devinfo); 851 uas_abort_inflight(devinfo);
851 usb_kill_anchored_urbs(&devinfo->cmd_urbs); 852 usb_kill_anchored_urbs(&devinfo->cmd_urbs);
852 usb_kill_anchored_urbs(&devinfo->sense_urbs); 853 usb_kill_anchored_urbs(&devinfo->sense_urbs);
853 usb_kill_anchored_urbs(&devinfo->data_urbs); 854 usb_kill_anchored_urbs(&devinfo->data_urbs);
@@ -1018,7 +1019,7 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
1018 init_usb_anchor(&devinfo->data_urbs); 1019 init_usb_anchor(&devinfo->data_urbs);
1019 spin_lock_init(&devinfo->lock); 1020 spin_lock_init(&devinfo->lock);
1020 INIT_WORK(&devinfo->work, uas_do_work); 1021 INIT_WORK(&devinfo->work, uas_do_work);
1021 INIT_LIST_HEAD(&devinfo->work_list); 1022 INIT_LIST_HEAD(&devinfo->inflight_list);
1022 INIT_LIST_HEAD(&devinfo->dead_list); 1023 INIT_LIST_HEAD(&devinfo->dead_list);
1023 1024
1024 result = uas_configure_endpoints(devinfo); 1025 result = uas_configure_endpoints(devinfo);
@@ -1145,7 +1146,7 @@ static void uas_disconnect(struct usb_interface *intf)
1145 1146
1146 devinfo->resetting = 1; 1147 devinfo->resetting = 1;
1147 cancel_work_sync(&devinfo->work); 1148 cancel_work_sync(&devinfo->work);
1148 uas_abort_work(devinfo); 1149 uas_abort_inflight(devinfo);
1149 usb_kill_anchored_urbs(&devinfo->cmd_urbs); 1150 usb_kill_anchored_urbs(&devinfo->cmd_urbs);
1150 usb_kill_anchored_urbs(&devinfo->sense_urbs); 1151 usb_kill_anchored_urbs(&devinfo->sense_urbs);
1151 usb_kill_anchored_urbs(&devinfo->data_urbs); 1152 usb_kill_anchored_urbs(&devinfo->data_urbs);