Skip to content

Commit ceb3f91

Browse files
author
Sebastian Andrzej Siewior
committed
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 <[email protected]>
1 parent 22188f4 commit ceb3f91

File tree

1 file changed

+60
-10
lines changed

1 file changed

+60
-10
lines changed

drivers/usb/storage/uas.c

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ struct uas_dev_info {
9999
unsigned use_streams:1;
100100
unsigned uas_sense_old:1;
101101
struct scsi_cmnd *cmnd;
102+
struct urb *status_urb; /* used only if stream support is available */
102103
};
103104

104105
enum {
@@ -117,6 +118,7 @@ struct uas_cmd_info {
117118
unsigned int state;
118119
unsigned int stream;
119120
struct urb *cmd_urb;
121+
/* status_urb is used only if stream support isn't available */
120122
struct urb *status_urb;
121123
struct urb *data_in_urb;
122124
struct urb *data_out_urb;
@@ -180,7 +182,6 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
180182

181183
cmnd->result = sense_iu->status;
182184
cmnd->scsi_done(cmnd);
183-
usb_free_urb(urb);
184185
}
185186

186187
static 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)
205206

206207
cmnd->result = sense_iu->status;
207208
cmnd->scsi_done(cmnd);
208-
usb_free_urb(urb);
209209
}
210210

211211
static 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,
214214
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
215215
int err;
216216

217-
cmdinfo->state = direction | SUBMIT_STATUS_URB;
217+
cmdinfo->state = direction;
218218
err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
219219
if (err) {
220220
spin_lock(&uas_work_lock);
@@ -231,10 +231,12 @@ static void uas_stat_cmplt(struct urb *urb)
231231
struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
232232
struct scsi_cmnd *cmnd;
233233
u16 tag;
234+
int ret;
234235

235236
if (urb->status) {
236237
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);
238240
return;
239241
}
240242

@@ -244,7 +246,13 @@ static void uas_stat_cmplt(struct urb *urb)
244246
else
245247
cmnd = scsi_host_find_tag(shost, tag - 1);
246248
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");
248256
return;
249257
}
250258

@@ -270,6 +278,15 @@ static void uas_stat_cmplt(struct urb *urb)
270278
scmd_printk(KERN_ERR, cmnd,
271279
"Bogus IU (%d) received on status pipe\n", iu->iu_id);
272280
}
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");
273290
}
274291

275292
static 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,
300317
}
301318

302319
static 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)
304321
{
305322
struct usb_device *udev = devinfo->udev;
306323
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,
314331
goto free;
315332

316333
usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu),
317-
uas_stat_cmplt, cmnd->device->host);
334+
uas_stat_cmplt, shost);
318335
urb->stream_id = stream_id;
319336
urb->transfer_flags |= URB_FREE_BUFFER;
320337
out:
@@ -376,8 +393,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
376393
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
377394

378395
if (cmdinfo->state & ALLOC_STATUS_URB) {
379-
cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp, cmnd,
380-
cmdinfo->stream);
396+
cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp,
397+
cmnd->device->host, cmdinfo->stream);
381398
if (!cmdinfo->status_urb)
382399
return SCSI_MLQUEUE_DEVICE_BUSY;
383400
cmdinfo->state &= ~ALLOC_STATUS_URB;
@@ -486,7 +503,8 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
486503
}
487504

488505
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);
490508
cmdinfo->stream = 0;
491509
}
492510

@@ -685,6 +703,29 @@ static void uas_configure_endpoints(struct uas_dev_info *devinfo)
685703
}
686704
}
687705

706+
static 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;
723+
err_submit_urb:
724+
usb_free_urb(devinfo->status_urb);
725+
err_s_urb:
726+
return -ENOMEM;
727+
}
728+
688729
static void uas_free_streams(struct uas_dev_info *devinfo)
689730
{
690731
struct usb_device *udev = devinfo->udev;
@@ -739,10 +780,17 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
739780

740781
shost->hostdata[0] = (unsigned long)devinfo;
741782

783+
result = uas_alloc_status_urb(devinfo, shost);
784+
if (result)
785+
goto err_alloc_status;
786+
742787
scsi_scan_host(shost);
743788
usb_set_intfdata(intf, shost);
744789
return result;
745790

791+
err_alloc_status:
792+
scsi_remove_host(shost);
793+
shost = NULL;
746794
deconfig_eps:
747795
uas_free_streams(devinfo);
748796
free:
@@ -770,6 +818,8 @@ static void uas_disconnect(struct usb_interface *intf)
770818
struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
771819

772820
scsi_remove_host(shost);
821+
usb_kill_urb(devinfo->status_urb);
822+
usb_free_urb(devinfo->status_urb);
773823
uas_free_streams(devinfo);
774824
kfree(devinfo);
775825
}

0 commit comments

Comments
 (0)