Skip to content

Commit b603669

Browse files
author
Sarah Sharp
committed
Merge tag 'uas_for_sarah' of git://linutronix.de/users/bigeasy/linux into for-uas-next
Merge UAS bug fixes from Sebastian Andrzej Siewior, including some patches of mine that he signed. UAS fixes for Sarah
2 parents fec67b4 + ceb3f91 commit b603669

File tree

1 file changed

+117
-40
lines changed

1 file changed

+117
-40
lines changed

drivers/usb/storage/uas.c

Lines changed: 117 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ struct uas_dev_info {
9898
unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;
9999
unsigned use_streams:1;
100100
unsigned uas_sense_old:1;
101+
struct scsi_cmnd *cmnd;
102+
struct urb *status_urb; /* used only if stream support is available */
101103
};
102104

103105
enum {
@@ -116,6 +118,7 @@ struct uas_cmd_info {
116118
unsigned int state;
117119
unsigned int stream;
118120
struct urb *cmd_urb;
121+
/* status_urb is used only if stream support isn't available */
119122
struct urb *status_urb;
120123
struct urb *data_in_urb;
121124
struct urb *data_out_urb;
@@ -125,29 +128,38 @@ struct uas_cmd_info {
125128
/* I hate forward declarations, but I actually have a loop */
126129
static int uas_submit_urbs(struct scsi_cmnd *cmnd,
127130
struct uas_dev_info *devinfo, gfp_t gfp);
131+
static void uas_do_work(struct work_struct *work);
128132

133+
static DECLARE_WORK(uas_work, uas_do_work);
129134
static DEFINE_SPINLOCK(uas_work_lock);
130135
static LIST_HEAD(uas_work_list);
131136

132137
static void uas_do_work(struct work_struct *work)
133138
{
134139
struct uas_cmd_info *cmdinfo;
140+
struct uas_cmd_info *temp;
135141
struct list_head list;
142+
int err;
136143

137144
spin_lock_irq(&uas_work_lock);
138145
list_replace_init(&uas_work_list, &list);
139146
spin_unlock_irq(&uas_work_lock);
140147

141-
list_for_each_entry(cmdinfo, &list, list) {
148+
list_for_each_entry_safe(cmdinfo, temp, &list, list) {
142149
struct scsi_pointer *scp = (void *)cmdinfo;
143150
struct scsi_cmnd *cmnd = container_of(scp,
144151
struct scsi_cmnd, SCp);
145-
uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO);
152+
err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO);
153+
if (err) {
154+
list_del(&cmdinfo->list);
155+
spin_lock_irq(&uas_work_lock);
156+
list_add_tail(&cmdinfo->list, &uas_work_list);
157+
spin_unlock_irq(&uas_work_lock);
158+
schedule_work(&uas_work);
159+
}
146160
}
147161
}
148162

149-
static DECLARE_WORK(uas_work, uas_do_work);
150-
151163
static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
152164
{
153165
struct sense_iu *sense_iu = urb->transfer_buffer;
@@ -169,10 +181,7 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
169181
}
170182

171183
cmnd->result = sense_iu->status;
172-
if (sdev->current_cmnd)
173-
sdev->current_cmnd = NULL;
174184
cmnd->scsi_done(cmnd);
175-
usb_free_urb(urb);
176185
}
177186

178187
static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)
@@ -196,10 +205,7 @@ static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)
196205
}
197206

198207
cmnd->result = sense_iu->status;
199-
if (sdev->current_cmnd)
200-
sdev->current_cmnd = NULL;
201208
cmnd->scsi_done(cmnd);
202-
usb_free_urb(urb);
203209
}
204210

205211
static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
@@ -208,7 +214,7 @@ static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
208214
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
209215
int err;
210216

211-
cmdinfo->state = direction | SUBMIT_STATUS_URB;
217+
cmdinfo->state = direction;
212218
err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
213219
if (err) {
214220
spin_lock(&uas_work_lock);
@@ -221,27 +227,40 @@ static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
221227
static void uas_stat_cmplt(struct urb *urb)
222228
{
223229
struct iu *iu = urb->transfer_buffer;
224-
struct scsi_device *sdev = urb->context;
225-
struct uas_dev_info *devinfo = sdev->hostdata;
230+
struct Scsi_Host *shost = urb->context;
231+
struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
226232
struct scsi_cmnd *cmnd;
227233
u16 tag;
234+
int ret;
228235

229236
if (urb->status) {
230237
dev_err(&urb->dev->dev, "URB BAD STATUS %d\n", urb->status);
231-
usb_free_urb(urb);
238+
if (devinfo->use_streams)
239+
usb_free_urb(urb);
232240
return;
233241
}
234242

235243
tag = be16_to_cpup(&iu->tag) - 1;
236-
if (sdev->current_cmnd)
237-
cmnd = sdev->current_cmnd;
244+
if (tag == 0)
245+
cmnd = devinfo->cmnd;
238246
else
239-
cmnd = scsi_find_tag(sdev, tag);
240-
if (!cmnd)
247+
cmnd = scsi_host_find_tag(shost, tag - 1);
248+
if (!cmnd) {
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");
241256
return;
257+
}
242258

243259
switch (iu->iu_id) {
244260
case IU_ID_STATUS:
261+
if (devinfo->cmnd == cmnd)
262+
devinfo->cmnd = NULL;
263+
245264
if (urb->actual_length < 16)
246265
devinfo->uas_sense_old = 1;
247266
if (devinfo->uas_sense_old)
@@ -259,6 +278,15 @@ static void uas_stat_cmplt(struct urb *urb)
259278
scmd_printk(KERN_ERR, cmnd,
260279
"Bogus IU (%d) received on status pipe\n", iu->iu_id);
261280
}
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");
262290
}
263291

264292
static void uas_data_cmplt(struct urb *urb)
@@ -289,7 +317,7 @@ static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
289317
}
290318

291319
static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
292-
struct scsi_cmnd *cmnd, u16 stream_id)
320+
struct Scsi_Host *shost, u16 stream_id)
293321
{
294322
struct usb_device *udev = devinfo->udev;
295323
struct urb *urb = usb_alloc_urb(0, gfp);
@@ -303,7 +331,7 @@ static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
303331
goto free;
304332

305333
usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu),
306-
uas_stat_cmplt, cmnd->device);
334+
uas_stat_cmplt, shost);
307335
urb->stream_id = stream_id;
308336
urb->transfer_flags |= URB_FREE_BUFFER;
309337
out:
@@ -334,7 +362,10 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
334362
goto free;
335363

336364
iu->iu_id = IU_ID_COMMAND;
337-
iu->tag = cpu_to_be16(stream_id);
365+
if (blk_rq_tagged(cmnd->request))
366+
iu->tag = cpu_to_be16(cmnd->request->tag + 2);
367+
else
368+
iu->tag = cpu_to_be16(1);
338369
iu->prio_attr = UAS_SIMPLE_TAG;
339370
iu->len = len;
340371
int_to_scsilun(sdev->lun, &iu->lun);
@@ -362,8 +393,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
362393
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
363394

364395
if (cmdinfo->state & ALLOC_STATUS_URB) {
365-
cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp, cmnd,
366-
cmdinfo->stream);
396+
cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp,
397+
cmnd->device->host, cmdinfo->stream);
367398
if (!cmdinfo->status_urb)
368399
return SCSI_MLQUEUE_DEVICE_BUSY;
369400
cmdinfo->state &= ~ALLOC_STATUS_URB;
@@ -444,13 +475,13 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
444475

445476
BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer));
446477

447-
if (!cmdinfo->status_urb && sdev->current_cmnd)
478+
if (devinfo->cmnd)
448479
return SCSI_MLQUEUE_DEVICE_BUSY;
449480

450481
if (blk_rq_tagged(cmnd->request)) {
451-
cmdinfo->stream = cmnd->request->tag + 1;
482+
cmdinfo->stream = cmnd->request->tag + 2;
452483
} else {
453-
sdev->current_cmnd = cmnd;
484+
devinfo->cmnd = cmnd;
454485
cmdinfo->stream = 1;
455486
}
456487

@@ -472,7 +503,8 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
472503
}
473504

474505
if (!devinfo->use_streams) {
475-
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);
476508
cmdinfo->stream = 0;
477509
}
478510

@@ -551,7 +583,7 @@ static int uas_slave_configure(struct scsi_device *sdev)
551583
{
552584
struct uas_dev_info *devinfo = sdev->hostdata;
553585
scsi_set_tag_type(sdev, MSG_ORDERED_TAG);
554-
scsi_activate_tcq(sdev, devinfo->qdepth - 1);
586+
scsi_activate_tcq(sdev, devinfo->qdepth - 2);
555587
return 0;
556588
}
557589

@@ -619,6 +651,7 @@ static void uas_configure_endpoints(struct uas_dev_info *devinfo)
619651
unsigned i, n_endpoints = intf->cur_altsetting->desc.bNumEndpoints;
620652

621653
devinfo->uas_sense_old = 0;
654+
devinfo->cmnd = NULL;
622655

623656
for (i = 0; i < n_endpoints; i++) {
624657
unsigned char *extra = endpoint[i].extra;
@@ -670,6 +703,40 @@ static void uas_configure_endpoints(struct uas_dev_info *devinfo)
670703
}
671704
}
672705

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+
729+
static void uas_free_streams(struct uas_dev_info *devinfo)
730+
{
731+
struct usb_device *udev = devinfo->udev;
732+
struct usb_host_endpoint *eps[3];
733+
734+
eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe);
735+
eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe);
736+
eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe);
737+
usb_free_streams(devinfo->intf, eps, 3, GFP_KERNEL);
738+
}
739+
673740
/*
674741
* XXX: What I'd like to do here is register a SCSI host for each USB host in
675742
* the system. Follow usb-storage's design of registering a SCSI host for
@@ -699,18 +766,33 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
699766
shost->max_id = 1;
700767
shost->sg_tablesize = udev->bus->sg_tablesize;
701768

702-
result = scsi_add_host(shost, &intf->dev);
769+
devinfo->intf = intf;
770+
devinfo->udev = udev;
771+
uas_configure_endpoints(devinfo);
772+
773+
result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 2);
703774
if (result)
704775
goto free;
776+
777+
result = scsi_add_host(shost, &intf->dev);
778+
if (result)
779+
goto deconfig_eps;
780+
705781
shost->hostdata[0] = (unsigned long)devinfo;
706782

707-
devinfo->intf = intf;
708-
devinfo->udev = udev;
709-
uas_configure_endpoints(devinfo);
783+
result = uas_alloc_status_urb(devinfo, shost);
784+
if (result)
785+
goto err_alloc_status;
710786

711787
scsi_scan_host(shost);
712788
usb_set_intfdata(intf, shost);
713789
return result;
790+
791+
err_alloc_status:
792+
scsi_remove_host(shost);
793+
shost = NULL;
794+
deconfig_eps:
795+
uas_free_streams(devinfo);
714796
free:
715797
kfree(devinfo);
716798
if (shost)
@@ -732,18 +814,13 @@ static int uas_post_reset(struct usb_interface *intf)
732814

733815
static void uas_disconnect(struct usb_interface *intf)
734816
{
735-
struct usb_device *udev = interface_to_usbdev(intf);
736-
struct usb_host_endpoint *eps[3];
737817
struct Scsi_Host *shost = usb_get_intfdata(intf);
738818
struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
739819

740820
scsi_remove_host(shost);
741-
742-
eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe);
743-
eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe);
744-
eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe);
745-
usb_free_streams(intf, eps, 3, GFP_KERNEL);
746-
821+
usb_kill_urb(devinfo->status_urb);
822+
usb_free_urb(devinfo->status_urb);
823+
uas_free_streams(devinfo);
747824
kfree(devinfo);
748825
}
749826

0 commit comments

Comments
 (0)