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, \ |
