aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/storage
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2012-06-19 03:54:48 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-06-25 14:50:58 -0400
commitc621a81edecdee85da32c566c21836332c764fda (patch)
tree78bb018ee771516a8892b6f9b96103c37520aef8 /drivers/usb/storage
parent889e5528cbe7dff2e91caf48f4bb23c17748b984 (diff)
Revert "usb/uas: make sure data urb is gone if we receive status before that"
This reverts commit e4d8318a85779b25b880187b1b1c44e797bd7d4b. This patch makes uas.c call usb_unlink_urb on data urbs. The data urbs get freed in the completion callback. This is illegal according to the usb_unlink_urb documentation. This patch also makes the code expect the data completion callback being called before the status completion callback. This isn't guaranteed to be the case, even though the actual data transfer should be finished by the time the status is received. Background: The ehci irq handler for example only know that there are finished transfers, it then has go check the QHs & TDs to see which transfers did actually finish. It has no way to figure in which order the transfers did complete. The xhci driver can call the callbacks in completion order thanks to the event queue. This does nicely explain why the driver is solid on a (usb2) xhci port whereas it goes crazy on ehci in my testing. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/storage')
-rw-r--r--drivers/usb/storage/uas.c90
1 files changed, 15 insertions, 75 deletions
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 8ec8a6e66f50..f98ba40352c1 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -58,9 +58,6 @@ enum {
58 SUBMIT_DATA_OUT_URB = (1 << 5), 58 SUBMIT_DATA_OUT_URB = (1 << 5),
59 ALLOC_CMD_URB = (1 << 6), 59 ALLOC_CMD_URB = (1 << 6),
60 SUBMIT_CMD_URB = (1 << 7), 60 SUBMIT_CMD_URB = (1 << 7),
61 COMPLETED_DATA_IN = (1 << 8),
62 COMPLETED_DATA_OUT = (1 << 9),
63 DATA_COMPLETES_CMD = (1 << 10),
64}; 61};
65 62
66/* Overrides scsi_pointer */ 63/* Overrides scsi_pointer */
@@ -114,7 +111,6 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
114{ 111{
115 struct sense_iu *sense_iu = urb->transfer_buffer; 112 struct sense_iu *sense_iu = urb->transfer_buffer;
116 struct scsi_device *sdev = cmnd->device; 113 struct scsi_device *sdev = cmnd->device;
117 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
118 114
119 if (urb->actual_length > 16) { 115 if (urb->actual_length > 16) {
120 unsigned len = be16_to_cpup(&sense_iu->len); 116 unsigned len = be16_to_cpup(&sense_iu->len);
@@ -132,15 +128,13 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
132 } 128 }
133 129
134 cmnd->result = sense_iu->status; 130 cmnd->result = sense_iu->status;
135 if (!(cmdinfo->state & DATA_COMPLETES_CMD)) 131 cmnd->scsi_done(cmnd);
136 cmnd->scsi_done(cmnd);
137} 132}
138 133
139static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd) 134static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)
140{ 135{
141 struct sense_iu_old *sense_iu = urb->transfer_buffer; 136 struct sense_iu_old *sense_iu = urb->transfer_buffer;
142 struct scsi_device *sdev = cmnd->device; 137 struct scsi_device *sdev = cmnd->device;
143 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
144 138
145 if (urb->actual_length > 8) { 139 if (urb->actual_length > 8) {
146 unsigned len = be16_to_cpup(&sense_iu->len) - 2; 140 unsigned len = be16_to_cpup(&sense_iu->len) - 2;
@@ -158,8 +152,7 @@ static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)
158 } 152 }
159 153
160 cmnd->result = sense_iu->status; 154 cmnd->result = sense_iu->status;
161 if (!(cmdinfo->state & DATA_COMPLETES_CMD)) 155 cmnd->scsi_done(cmnd);
162 cmnd->scsi_done(cmnd);
163} 156}
164 157
165static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd, 158static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
@@ -184,7 +177,6 @@ static void uas_stat_cmplt(struct urb *urb)
184 struct Scsi_Host *shost = urb->context; 177 struct Scsi_Host *shost = urb->context;
185 struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; 178 struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
186 struct scsi_cmnd *cmnd; 179 struct scsi_cmnd *cmnd;
187 struct uas_cmd_info *cmdinfo;
188 u16 tag; 180 u16 tag;
189 int ret; 181 int ret;
190 182
@@ -210,32 +202,12 @@ static void uas_stat_cmplt(struct urb *urb)
210 dev_err(&urb->dev->dev, "failed submit status urb\n"); 202 dev_err(&urb->dev->dev, "failed submit status urb\n");
211 return; 203 return;
212 } 204 }
213 cmdinfo = (void *)&cmnd->SCp;
214 205
215 switch (iu->iu_id) { 206 switch (iu->iu_id) {
216 case IU_ID_STATUS: 207 case IU_ID_STATUS:
217 if (devinfo->cmnd == cmnd) 208 if (devinfo->cmnd == cmnd)
218 devinfo->cmnd = NULL; 209 devinfo->cmnd = NULL;
219 210
220 if (!(cmdinfo->state & COMPLETED_DATA_IN) &&
221 cmdinfo->data_in_urb) {
222 if (devinfo->use_streams) {
223 cmdinfo->state |= DATA_COMPLETES_CMD;
224 usb_unlink_urb(cmdinfo->data_in_urb);
225 } else {
226 usb_free_urb(cmdinfo->data_in_urb);
227 }
228 }
229 if (!(cmdinfo->state & COMPLETED_DATA_OUT) &&
230 cmdinfo->data_out_urb) {
231 if (devinfo->use_streams) {
232 cmdinfo->state |= DATA_COMPLETES_CMD;
233 usb_unlink_urb(cmdinfo->data_in_urb);
234 } else {
235 usb_free_urb(cmdinfo->data_out_urb);
236 }
237 }
238
239 if (urb->actual_length < 16) 211 if (urb->actual_length < 16)
240 devinfo->uas_sense_old = 1; 212 devinfo->uas_sense_old = 1;
241 if (devinfo->uas_sense_old) 213 if (devinfo->uas_sense_old)
@@ -264,59 +236,27 @@ static void uas_stat_cmplt(struct urb *urb)
264 dev_err(&urb->dev->dev, "failed submit status urb\n"); 236 dev_err(&urb->dev->dev, "failed submit status urb\n");
265} 237}
266 238
267static void uas_data_out_cmplt(struct urb *urb) 239static void uas_data_cmplt(struct urb *urb)
268{
269 struct scsi_cmnd *cmnd = urb->context;
270 struct scsi_data_buffer *sdb = scsi_out(cmnd);
271 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
272
273 cmdinfo->state |= COMPLETED_DATA_OUT;
274
275 sdb->resid = sdb->length - urb->actual_length;
276 usb_free_urb(urb);
277
278 if (cmdinfo->state & DATA_COMPLETES_CMD)
279 cmnd->scsi_done(cmnd);
280}
281
282static void uas_data_in_cmplt(struct urb *urb)
283{ 240{
284 struct scsi_cmnd *cmnd = urb->context; 241 struct scsi_data_buffer *sdb = urb->context;
285 struct scsi_data_buffer *sdb = scsi_in(cmnd);
286 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
287
288 cmdinfo->state |= COMPLETED_DATA_IN;
289
290 sdb->resid = sdb->length - urb->actual_length; 242 sdb->resid = sdb->length - urb->actual_length;
291 usb_free_urb(urb); 243 usb_free_urb(urb);
292
293 if (cmdinfo->state & DATA_COMPLETES_CMD)
294 cmnd->scsi_done(cmnd);
295} 244}
296 245
297static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp, 246static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
298 unsigned int pipe, struct scsi_cmnd *cmnd, 247 unsigned int pipe, u16 stream_id,
299 enum dma_data_direction dir) 248 struct scsi_data_buffer *sdb,
249 enum dma_data_direction dir)
300{ 250{
301 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
302 struct usb_device *udev = devinfo->udev; 251 struct usb_device *udev = devinfo->udev;
303 struct urb *urb = usb_alloc_urb(0, gfp); 252 struct urb *urb = usb_alloc_urb(0, gfp);
304 struct scsi_data_buffer *sdb;
305 usb_complete_t complete_fn;
306 u16 stream_id = cmdinfo->stream;
307 253
308 if (!urb) 254 if (!urb)
309 goto out; 255 goto out;
310 if (dir == DMA_FROM_DEVICE) { 256 usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length, uas_data_cmplt,
311 sdb = scsi_in(cmnd); 257 sdb);
312 complete_fn = uas_data_in_cmplt; 258 if (devinfo->use_streams)
313 } else { 259 urb->stream_id = stream_id;
314 sdb = scsi_out(cmnd);
315 complete_fn = uas_data_out_cmplt;
316 }
317 usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length,
318 complete_fn, cmnd);
319 urb->stream_id = stream_id;
320 urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0; 260 urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0;
321 urb->sg = sdb->table.sgl; 261 urb->sg = sdb->table.sgl;
322 out: 262 out:
@@ -418,8 +358,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
418 358
419 if (cmdinfo->state & ALLOC_DATA_IN_URB) { 359 if (cmdinfo->state & ALLOC_DATA_IN_URB) {
420 cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp, 360 cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp,
421 devinfo->data_in_pipe, cmnd, 361 devinfo->data_in_pipe, cmdinfo->stream,
422 DMA_FROM_DEVICE); 362 scsi_in(cmnd), DMA_FROM_DEVICE);
423 if (!cmdinfo->data_in_urb) 363 if (!cmdinfo->data_in_urb)
424 return SCSI_MLQUEUE_DEVICE_BUSY; 364 return SCSI_MLQUEUE_DEVICE_BUSY;
425 cmdinfo->state &= ~ALLOC_DATA_IN_URB; 365 cmdinfo->state &= ~ALLOC_DATA_IN_URB;
@@ -436,8 +376,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
436 376
437 if (cmdinfo->state & ALLOC_DATA_OUT_URB) { 377 if (cmdinfo->state & ALLOC_DATA_OUT_URB) {
438 cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp, 378 cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp,
439 devinfo->data_out_pipe, cmnd, 379 devinfo->data_out_pipe, cmdinfo->stream,
440 DMA_TO_DEVICE); 380 scsi_out(cmnd), DMA_TO_DEVICE);
441 if (!cmdinfo->data_out_urb) 381 if (!cmdinfo->data_out_urb)
442 return SCSI_MLQUEUE_DEVICE_BUSY; 382 return SCSI_MLQUEUE_DEVICE_BUSY;
443 cmdinfo->state &= ~ALLOC_DATA_OUT_URB; 383 cmdinfo->state &= ~ALLOC_DATA_OUT_URB;