aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/storage
diff options
context:
space:
mode:
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>2011-12-20 08:50:26 -0500
committerSebastian Andrzej Siewior <bigeasy@linutronix.de>2011-12-22 05:28:19 -0500
commitceb3f91fd53c9fbd7b292fc2754ba4efffeeeedb (patch)
tree84d7287caec1f614495d176dd146aae301d21f07 /drivers/usb/storage
parent22188f4a933c6e86ac67f52028895c795896492e (diff)
usb/uas: one only one status URB/host on stream-less connection
The status/sense URB is allocated on per-command basis. A read/write looks the following way on a stream-less connection: - send cmd tag X, queue status - receive status, oh it is a read for tag X. queue status & read - receive read - receive status, oh I'm done for tag X. Cool call complete and free status urb. This block repeats itself 1:1 for further commands and looks great so far. Lets take a look now what happens if we do allow multiple commands: - send cmd tag X, queue statusX (belongs to the command with the X tag) - send cmd tag Y, queue statusY (belongs to the command with the Y tag) - receive statusX, oh it is a read for tag X. queue statusX & a read - receive read - receive statusY, oh I'm done for tag X. Cool call complete and free statusY. - receive statusX, oh it is a read for tag Y. queue statusY & before we queue the read the the following message can be observed: |sd 0:0:0:0: [sda] sense urb submission failure followed by a second attempt with the same result. In order to address this problem we will use only one status URB for each scsi host in case we don't have stream support (as suggested by Matthew). This URB is requeued until the device removed. Nothing changes on stream based endpoints. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Diffstat (limited to 'drivers/usb/storage')
-rw-r--r--drivers/usb/storage/uas.c70
1 files changed, 60 insertions, 10 deletions
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index e2386e8c7678..036e96900956 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -99,6 +99,7 @@ struct uas_dev_info {
99 unsigned use_streams:1; 99 unsigned use_streams:1;
100 unsigned uas_sense_old:1; 100 unsigned uas_sense_old:1;
101 struct scsi_cmnd *cmnd; 101 struct scsi_cmnd *cmnd;
102 struct urb *status_urb; /* used only if stream support is available */
102}; 103};
103 104
104enum { 105enum {
@@ -117,6 +118,7 @@ struct uas_cmd_info {
117 unsigned int state; 118 unsigned int state;
118 unsigned int stream; 119 unsigned int stream;
119 struct urb *cmd_urb; 120 struct urb *cmd_urb;
121 /* status_urb is used only if stream support isn't available */
120 struct urb *status_urb; 122 struct urb *status_urb;
121 struct urb *data_in_urb; 123 struct urb *data_in_urb;
122 struct urb *data_out_urb; 124 struct urb *data_out_urb;
@@ -180,7 +182,6 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
180 182
181 cmnd->result = sense_iu->status; 183 cmnd->result = sense_iu->status;
182 cmnd->scsi_done(cmnd); 184 cmnd->scsi_done(cmnd);
183 usb_free_urb(urb);
184} 185}
185 186
186static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd) 187static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)
@@ -205,7 +206,6 @@ static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)
205 206
206 cmnd->result = sense_iu->status; 207 cmnd->result = sense_iu->status;
207 cmnd->scsi_done(cmnd); 208 cmnd->scsi_done(cmnd);
208 usb_free_urb(urb);
209} 209}
210 210
211static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd, 211static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
@@ -214,7 +214,7 @@ static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
214 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; 214 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
215 int err; 215 int err;
216 216
217 cmdinfo->state = direction | SUBMIT_STATUS_URB; 217 cmdinfo->state = direction;
218 err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC); 218 err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
219 if (err) { 219 if (err) {
220 spin_lock(&uas_work_lock); 220 spin_lock(&uas_work_lock);
@@ -231,10 +231,12 @@ static void uas_stat_cmplt(struct urb *urb)
231 struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; 231 struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
232 struct scsi_cmnd *cmnd; 232 struct scsi_cmnd *cmnd;
233 u16 tag; 233 u16 tag;
234 int ret;
234 235
235 if (urb->status) { 236 if (urb->status) {
236 dev_err(&urb->dev->dev, "URB BAD STATUS %d\n", urb->status); 237 dev_err(&urb->dev->dev, "URB BAD STATUS %d\n", urb->status);
237 usb_free_urb(urb); 238 if (devinfo->use_streams)
239 usb_free_urb(urb);
238 return; 240 return;
239 } 241 }
240 242
@@ -244,7 +246,13 @@ static void uas_stat_cmplt(struct urb *urb)
244 else 246 else
245 cmnd = scsi_host_find_tag(shost, tag - 1); 247 cmnd = scsi_host_find_tag(shost, tag - 1);
246 if (!cmnd) { 248 if (!cmnd) {
247 usb_free_urb(urb); 249 if (devinfo->use_streams) {
250 usb_free_urb(urb);
251 return;
252 }
253 ret = usb_submit_urb(urb, GFP_ATOMIC);
254 if (ret)
255 dev_err(&urb->dev->dev, "failed submit status urb\n");
248 return; 256 return;
249 } 257 }
250 258
@@ -270,6 +278,15 @@ static void uas_stat_cmplt(struct urb *urb)
270 scmd_printk(KERN_ERR, cmnd, 278 scmd_printk(KERN_ERR, cmnd,
271 "Bogus IU (%d) received on status pipe\n", iu->iu_id); 279 "Bogus IU (%d) received on status pipe\n", iu->iu_id);
272 } 280 }
281
282 if (devinfo->use_streams) {
283 usb_free_urb(urb);
284 return;
285 }
286
287 ret = usb_submit_urb(urb, GFP_ATOMIC);
288 if (ret)
289 dev_err(&urb->dev->dev, "failed submit status urb\n");
273} 290}
274 291
275static void uas_data_cmplt(struct urb *urb) 292static void uas_data_cmplt(struct urb *urb)
@@ -300,7 +317,7 @@ static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
300} 317}
301 318
302static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp, 319static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
303 struct scsi_cmnd *cmnd, u16 stream_id) 320 struct Scsi_Host *shost, u16 stream_id)
304{ 321{
305 struct usb_device *udev = devinfo->udev; 322 struct usb_device *udev = devinfo->udev;
306 struct urb *urb = usb_alloc_urb(0, gfp); 323 struct urb *urb = usb_alloc_urb(0, gfp);
@@ -314,7 +331,7 @@ static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
314 goto free; 331 goto free;
315 332
316 usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu), 333 usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu),
317 uas_stat_cmplt, cmnd->device->host); 334 uas_stat_cmplt, shost);
318 urb->stream_id = stream_id; 335 urb->stream_id = stream_id;
319 urb->transfer_flags |= URB_FREE_BUFFER; 336 urb->transfer_flags |= URB_FREE_BUFFER;
320 out: 337 out:
@@ -376,8 +393,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
376 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; 393 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
377 394
378 if (cmdinfo->state & ALLOC_STATUS_URB) { 395 if (cmdinfo->state & ALLOC_STATUS_URB) {
379 cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp, cmnd, 396 cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp,
380 cmdinfo->stream); 397 cmnd->device->host, cmdinfo->stream);
381 if (!cmdinfo->status_urb) 398 if (!cmdinfo->status_urb)
382 return SCSI_MLQUEUE_DEVICE_BUSY; 399 return SCSI_MLQUEUE_DEVICE_BUSY;
383 cmdinfo->state &= ~ALLOC_STATUS_URB; 400 cmdinfo->state &= ~ALLOC_STATUS_URB;
@@ -486,7 +503,8 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
486 } 503 }
487 504
488 if (!devinfo->use_streams) { 505 if (!devinfo->use_streams) {
489 cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB); 506 cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB |
507 ALLOC_STATUS_URB | SUBMIT_STATUS_URB);
490 cmdinfo->stream = 0; 508 cmdinfo->stream = 0;
491 } 509 }
492 510
@@ -685,6 +703,29 @@ static void uas_configure_endpoints(struct uas_dev_info *devinfo)
685 } 703 }
686} 704}
687 705
706static int uas_alloc_status_urb(struct uas_dev_info *devinfo,
707 struct Scsi_Host *shost)
708{
709 if (devinfo->use_streams) {
710 devinfo->status_urb = NULL;
711 return 0;
712 }
713
714 devinfo->status_urb = uas_alloc_sense_urb(devinfo, GFP_KERNEL,
715 shost, 0);
716 if (!devinfo->status_urb)
717 goto err_s_urb;
718
719 if (usb_submit_urb(devinfo->status_urb, GFP_KERNEL))
720 goto err_submit_urb;
721
722 return 0;
723err_submit_urb:
724 usb_free_urb(devinfo->status_urb);
725err_s_urb:
726 return -ENOMEM;
727}
728
688static void uas_free_streams(struct uas_dev_info *devinfo) 729static void uas_free_streams(struct uas_dev_info *devinfo)
689{ 730{
690 struct usb_device *udev = devinfo->udev; 731 struct usb_device *udev = devinfo->udev;
@@ -739,10 +780,17 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
739 780
740 shost->hostdata[0] = (unsigned long)devinfo; 781 shost->hostdata[0] = (unsigned long)devinfo;
741 782
783 result = uas_alloc_status_urb(devinfo, shost);
784 if (result)
785 goto err_alloc_status;
786
742 scsi_scan_host(shost); 787 scsi_scan_host(shost);
743 usb_set_intfdata(intf, shost); 788 usb_set_intfdata(intf, shost);
744 return result; 789 return result;
745 790
791err_alloc_status:
792 scsi_remove_host(shost);
793 shost = NULL;
746deconfig_eps: 794deconfig_eps:
747 uas_free_streams(devinfo); 795 uas_free_streams(devinfo);
748 free: 796 free:
@@ -770,6 +818,8 @@ static void uas_disconnect(struct usb_interface *intf)
770 struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; 818 struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
771 819
772 scsi_remove_host(shost); 820 scsi_remove_host(shost);
821 usb_kill_urb(devinfo->status_urb);
822 usb_free_urb(devinfo->status_urb);
773 uas_free_streams(devinfo); 823 uas_free_streams(devinfo);
774 kfree(devinfo); 824 kfree(devinfo);
775} 825}