diff options
author | Hans de Goede <hdegoede@redhat.com> | 2014-10-12 06:19:40 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-11-03 18:34:00 -0500 |
commit | e28e2f2f7c42e5b9dd4c965a0245267e44a8a7ae (patch) | |
tree | d03d3f98fe2a92f51a5a9a55606a84306251b6e9 /drivers/usb/storage | |
parent | 1cc373c654acde47d78da9cccb5732dab2cc584f (diff) |
uas: Make uas work with blk-mq
With uas over usb-3 the tags inside the uas iu-s must match the usb-3 stream
ids, and those go from 1 - qdepth.
Before blk-mq calling scsi_activate_tcq(sdev, qdepth) guaranteed that we would
only get cmnd->request->tag from 0 - (qdepth - 1), and we used those as
uas-tags / stream-ids.
With blk-mq however we are guaranteed to never get more then qdepth commands
queued at the same time, but the cmnd->request->tag values may be much larger,
which breaks uas.
This commit fixes this by generating uas tags in the 1 - qdepth range ourselves
instead of using cmnd->request->tag.
While touching all involved code anyways also rename the uas_cmd_info stream
field to uas_tag, because when using uas over usb-2 streams are not used.
Cc: Christoph Hellwig <hch@infradead.org>
Reported-by: Douglas Gilbert <dgilbert@interlog.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
--
Changes in v2:
-Remove ".disable_blk_mq = true" from uas_host_template
Changes in v3:
-Rebased on top of Linus' current master branch
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/storage')
-rw-r--r-- | drivers/usb/storage/uas.c | 64 |
1 files changed, 23 insertions, 41 deletions
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 89b24349269e..004ebc12bc21 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c | |||
@@ -66,7 +66,7 @@ enum { | |||
66 | /* Overrides scsi_pointer */ | 66 | /* Overrides scsi_pointer */ |
67 | struct uas_cmd_info { | 67 | struct uas_cmd_info { |
68 | unsigned int state; | 68 | unsigned int state; |
69 | unsigned int stream; | 69 | unsigned int uas_tag; |
70 | struct urb *cmd_urb; | 70 | struct urb *cmd_urb; |
71 | struct urb *data_in_urb; | 71 | struct urb *data_in_urb; |
72 | struct urb *data_out_urb; | 72 | struct urb *data_out_urb; |
@@ -173,30 +173,15 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd) | |||
173 | cmnd->result = sense_iu->status; | 173 | cmnd->result = sense_iu->status; |
174 | } | 174 | } |
175 | 175 | ||
176 | /* | ||
177 | * scsi-tags go from 0 - (nr_tags - 1), uas tags need to match stream-ids, | ||
178 | * which go from 1 - nr_streams. And we use 1 for untagged commands. | ||
179 | */ | ||
180 | static int uas_get_tag(struct scsi_cmnd *cmnd) | ||
181 | { | ||
182 | int tag; | ||
183 | |||
184 | if (blk_rq_tagged(cmnd->request)) | ||
185 | tag = cmnd->request->tag + 2; | ||
186 | else | ||
187 | tag = 1; | ||
188 | |||
189 | return tag; | ||
190 | } | ||
191 | |||
192 | static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *prefix, | 176 | static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *prefix, |
193 | int status) | 177 | int status) |
194 | { | 178 | { |
195 | struct uas_cmd_info *ci = (void *)&cmnd->SCp; | 179 | struct uas_cmd_info *ci = (void *)&cmnd->SCp; |
180 | struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; | ||
196 | 181 | ||
197 | scmd_printk(KERN_INFO, cmnd, | 182 | scmd_printk(KERN_INFO, cmnd, |
198 | "%s %d tag %d inflight:%s%s%s%s%s%s%s%s%s%s%s%s ", | 183 | "%s %d uas-tag %d inflight:%s%s%s%s%s%s%s%s%s%s%s%s ", |
199 | prefix, status, uas_get_tag(cmnd), | 184 | prefix, status, cmdinfo->uas_tag, |
200 | (ci->state & SUBMIT_STATUS_URB) ? " s-st" : "", | 185 | (ci->state & SUBMIT_STATUS_URB) ? " s-st" : "", |
201 | (ci->state & ALLOC_DATA_IN_URB) ? " a-in" : "", | 186 | (ci->state & ALLOC_DATA_IN_URB) ? " a-in" : "", |
202 | (ci->state & SUBMIT_DATA_IN_URB) ? " s-in" : "", | 187 | (ci->state & SUBMIT_DATA_IN_URB) ? " s-in" : "", |
@@ -242,7 +227,7 @@ static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller) | |||
242 | DATA_OUT_URB_INFLIGHT | | 227 | DATA_OUT_URB_INFLIGHT | |
243 | COMMAND_ABORTED)) | 228 | COMMAND_ABORTED)) |
244 | return -EBUSY; | 229 | return -EBUSY; |
245 | devinfo->cmnd[uas_get_tag(cmnd) - 1] = NULL; | 230 | devinfo->cmnd[cmdinfo->uas_tag - 1] = NULL; |
246 | uas_free_unsubmitted_urbs(cmnd); | 231 | uas_free_unsubmitted_urbs(cmnd); |
247 | cmnd->scsi_done(cmnd); | 232 | cmnd->scsi_done(cmnd); |
248 | return 0; | 233 | return 0; |
@@ -289,7 +274,7 @@ static void uas_stat_cmplt(struct urb *urb) | |||
289 | idx = be16_to_cpup(&iu->tag) - 1; | 274 | idx = be16_to_cpup(&iu->tag) - 1; |
290 | if (idx >= MAX_CMNDS || !devinfo->cmnd[idx]) { | 275 | if (idx >= MAX_CMNDS || !devinfo->cmnd[idx]) { |
291 | dev_err(&urb->dev->dev, | 276 | dev_err(&urb->dev->dev, |
292 | "stat urb: no pending cmd for tag %d\n", idx + 1); | 277 | "stat urb: no pending cmd for uas-tag %d\n", idx + 1); |
293 | goto out; | 278 | goto out; |
294 | } | 279 | } |
295 | 280 | ||
@@ -427,7 +412,8 @@ static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp, | |||
427 | goto out; | 412 | goto out; |
428 | usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length, | 413 | usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length, |
429 | uas_data_cmplt, cmnd); | 414 | uas_data_cmplt, cmnd); |
430 | urb->stream_id = cmdinfo->stream; | 415 | if (devinfo->use_streams) |
416 | urb->stream_id = cmdinfo->uas_tag; | ||
431 | urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0; | 417 | urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0; |
432 | urb->sg = sdb->table.sgl; | 418 | urb->sg = sdb->table.sgl; |
433 | out: | 419 | out: |
@@ -451,7 +437,8 @@ static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp, | |||
451 | 437 | ||
452 | usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu), | 438 | usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu), |
453 | uas_stat_cmplt, cmnd->device->host); | 439 | uas_stat_cmplt, cmnd->device->host); |
454 | urb->stream_id = cmdinfo->stream; | 440 | if (devinfo->use_streams) |
441 | urb->stream_id = cmdinfo->uas_tag; | ||
455 | urb->transfer_flags |= URB_FREE_BUFFER; | 442 | urb->transfer_flags |= URB_FREE_BUFFER; |
456 | out: | 443 | out: |
457 | return urb; | 444 | return urb; |
@@ -465,6 +452,7 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp, | |||
465 | { | 452 | { |
466 | struct usb_device *udev = devinfo->udev; | 453 | struct usb_device *udev = devinfo->udev; |
467 | struct scsi_device *sdev = cmnd->device; | 454 | struct scsi_device *sdev = cmnd->device; |
455 | struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; | ||
468 | struct urb *urb = usb_alloc_urb(0, gfp); | 456 | struct urb *urb = usb_alloc_urb(0, gfp); |
469 | struct command_iu *iu; | 457 | struct command_iu *iu; |
470 | int len; | 458 | int len; |
@@ -481,7 +469,7 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp, | |||
481 | goto free; | 469 | goto free; |
482 | 470 | ||
483 | iu->iu_id = IU_ID_COMMAND; | 471 | iu->iu_id = IU_ID_COMMAND; |
484 | iu->tag = cpu_to_be16(uas_get_tag(cmnd)); | 472 | iu->tag = cpu_to_be16(cmdinfo->uas_tag); |
485 | iu->prio_attr = UAS_SIMPLE_TAG; | 473 | iu->prio_attr = UAS_SIMPLE_TAG; |
486 | iu->len = len; | 474 | iu->len = len; |
487 | int_to_scsilun(sdev->lun, &iu->lun); | 475 | int_to_scsilun(sdev->lun, &iu->lun); |
@@ -608,8 +596,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, | |||
608 | struct uas_dev_info *devinfo = sdev->hostdata; | 596 | struct uas_dev_info *devinfo = sdev->hostdata; |
609 | struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; | 597 | struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; |
610 | unsigned long flags; | 598 | unsigned long flags; |
611 | unsigned int stream; | 599 | int idx, err; |
612 | int err; | ||
613 | 600 | ||
614 | BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer)); | 601 | BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer)); |
615 | 602 | ||
@@ -635,8 +622,12 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, | |||
635 | return 0; | 622 | return 0; |
636 | } | 623 | } |
637 | 624 | ||
638 | stream = uas_get_tag(cmnd); | 625 | /* Find a free uas-tag */ |
639 | if (devinfo->cmnd[stream - 1]) { | 626 | for (idx = 0; idx < devinfo->qdepth; idx++) { |
627 | if (!devinfo->cmnd[idx]) | ||
628 | break; | ||
629 | } | ||
630 | if (idx == devinfo->qdepth) { | ||
640 | spin_unlock_irqrestore(&devinfo->lock, flags); | 631 | spin_unlock_irqrestore(&devinfo->lock, flags); |
641 | return SCSI_MLQUEUE_DEVICE_BUSY; | 632 | return SCSI_MLQUEUE_DEVICE_BUSY; |
642 | } | 633 | } |
@@ -644,7 +635,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, | |||
644 | cmnd->scsi_done = done; | 635 | cmnd->scsi_done = done; |
645 | 636 | ||
646 | memset(cmdinfo, 0, sizeof(*cmdinfo)); | 637 | memset(cmdinfo, 0, sizeof(*cmdinfo)); |
647 | cmdinfo->stream = stream; | 638 | cmdinfo->uas_tag = idx + 1; /* uas-tag == usb-stream-id, so 1 based */ |
648 | cmdinfo->state = SUBMIT_STATUS_URB | ALLOC_CMD_URB | SUBMIT_CMD_URB; | 639 | cmdinfo->state = SUBMIT_STATUS_URB | ALLOC_CMD_URB | SUBMIT_CMD_URB; |
649 | 640 | ||
650 | switch (cmnd->sc_data_direction) { | 641 | switch (cmnd->sc_data_direction) { |
@@ -659,10 +650,8 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, | |||
659 | break; | 650 | break; |
660 | } | 651 | } |
661 | 652 | ||
662 | if (!devinfo->use_streams) { | 653 | if (!devinfo->use_streams) |
663 | cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB); | 654 | cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB); |
664 | cmdinfo->stream = 0; | ||
665 | } | ||
666 | 655 | ||
667 | err = uas_submit_urbs(cmnd, devinfo, GFP_ATOMIC); | 656 | err = uas_submit_urbs(cmnd, devinfo, GFP_ATOMIC); |
668 | if (err) { | 657 | if (err) { |
@@ -674,7 +663,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, | |||
674 | uas_add_work(cmdinfo); | 663 | uas_add_work(cmdinfo); |
675 | } | 664 | } |
676 | 665 | ||
677 | devinfo->cmnd[stream - 1] = cmnd; | 666 | devinfo->cmnd[idx] = cmnd; |
678 | spin_unlock_irqrestore(&devinfo->lock, flags); | 667 | spin_unlock_irqrestore(&devinfo->lock, flags); |
679 | return 0; | 668 | return 0; |
680 | } | 669 | } |
@@ -702,7 +691,7 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd) | |||
702 | cmdinfo->state |= COMMAND_ABORTED; | 691 | cmdinfo->state |= COMMAND_ABORTED; |
703 | 692 | ||
704 | /* Drop all refs to this cmnd, kill data urbs to break their ref */ | 693 | /* Drop all refs to this cmnd, kill data urbs to break their ref */ |
705 | devinfo->cmnd[uas_get_tag(cmnd) - 1] = NULL; | 694 | devinfo->cmnd[cmdinfo->uas_tag - 1] = NULL; |
706 | if (cmdinfo->state & DATA_IN_URB_INFLIGHT) | 695 | if (cmdinfo->state & DATA_IN_URB_INFLIGHT) |
707 | data_in_urb = usb_get_urb(cmdinfo->data_in_urb); | 696 | data_in_urb = usb_get_urb(cmdinfo->data_in_urb); |
708 | if (cmdinfo->state & DATA_OUT_URB_INFLIGHT) | 697 | if (cmdinfo->state & DATA_OUT_URB_INFLIGHT) |
@@ -818,13 +807,6 @@ static struct scsi_host_template uas_host_template = { | |||
818 | .cmd_per_lun = 1, /* until we override it */ | 807 | .cmd_per_lun = 1, /* until we override it */ |
819 | .skip_settle_delay = 1, | 808 | .skip_settle_delay = 1, |
820 | .ordered_tag = 1, | 809 | .ordered_tag = 1, |
821 | |||
822 | /* | ||
823 | * The uas drivers expects tags not to be bigger than the maximum | ||
824 | * per-device queue depth, which is not true with the blk-mq tag | ||
825 | * allocator. | ||
826 | */ | ||
827 | .disable_blk_mq = true, | ||
828 | }; | 810 | }; |
829 | 811 | ||
830 | #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ | 812 | #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ |