Commit e28e2f2f authored by Hans de Goede's avatar Hans de Goede Committed by Greg Kroah-Hartman

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: default avatarDouglas Gilbert <dgilbert@interlog.com>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Reviewed-by: default avatarChristoph 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: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 1cc373c6
...@@ -66,7 +66,7 @@ enum { ...@@ -66,7 +66,7 @@ enum {
/* Overrides scsi_pointer */ /* Overrides scsi_pointer */
struct uas_cmd_info { struct uas_cmd_info {
unsigned int state; unsigned int state;
unsigned int stream; unsigned int uas_tag;
struct urb *cmd_urb; struct urb *cmd_urb;
struct urb *data_in_urb; struct urb *data_in_urb;
struct urb *data_out_urb; struct urb *data_out_urb;
...@@ -173,30 +173,15 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd) ...@@ -173,30 +173,15 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
cmnd->result = sense_iu->status; cmnd->result = sense_iu->status;
} }
/*
* scsi-tags go from 0 - (nr_tags - 1), uas tags need to match stream-ids,
* which go from 1 - nr_streams. And we use 1 for untagged commands.
*/
static int uas_get_tag(struct scsi_cmnd *cmnd)
{
int tag;
if (blk_rq_tagged(cmnd->request))
tag = cmnd->request->tag + 2;
else
tag = 1;
return tag;
}
static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *prefix, static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *prefix,
int status) int status)
{ {
struct uas_cmd_info *ci = (void *)&cmnd->SCp; struct uas_cmd_info *ci = (void *)&cmnd->SCp;
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
scmd_printk(KERN_INFO, cmnd, scmd_printk(KERN_INFO, cmnd,
"%s %d tag %d inflight:%s%s%s%s%s%s%s%s%s%s%s%s ", "%s %d uas-tag %d inflight:%s%s%s%s%s%s%s%s%s%s%s%s ",
prefix, status, uas_get_tag(cmnd), prefix, status, cmdinfo->uas_tag,
(ci->state & SUBMIT_STATUS_URB) ? " s-st" : "", (ci->state & SUBMIT_STATUS_URB) ? " s-st" : "",
(ci->state & ALLOC_DATA_IN_URB) ? " a-in" : "", (ci->state & ALLOC_DATA_IN_URB) ? " a-in" : "",
(ci->state & SUBMIT_DATA_IN_URB) ? " s-in" : "", (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,7 +227,7 @@ static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
DATA_OUT_URB_INFLIGHT | DATA_OUT_URB_INFLIGHT |
COMMAND_ABORTED)) COMMAND_ABORTED))
return -EBUSY; return -EBUSY;
devinfo->cmnd[uas_get_tag(cmnd) - 1] = NULL; devinfo->cmnd[cmdinfo->uas_tag - 1] = NULL;
uas_free_unsubmitted_urbs(cmnd); uas_free_unsubmitted_urbs(cmnd);
cmnd->scsi_done(cmnd); cmnd->scsi_done(cmnd);
return 0; return 0;
...@@ -289,7 +274,7 @@ static void uas_stat_cmplt(struct urb *urb) ...@@ -289,7 +274,7 @@ static void uas_stat_cmplt(struct urb *urb)
idx = be16_to_cpup(&iu->tag) - 1; idx = be16_to_cpup(&iu->tag) - 1;
if (idx >= MAX_CMNDS || !devinfo->cmnd[idx]) { if (idx >= MAX_CMNDS || !devinfo->cmnd[idx]) {
dev_err(&urb->dev->dev, dev_err(&urb->dev->dev,
"stat urb: no pending cmd for tag %d\n", idx + 1); "stat urb: no pending cmd for uas-tag %d\n", idx + 1);
goto out; goto out;
} }
...@@ -427,7 +412,8 @@ static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp, ...@@ -427,7 +412,8 @@ static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
goto out; goto out;
usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length, usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length,
uas_data_cmplt, cmnd); uas_data_cmplt, cmnd);
urb->stream_id = cmdinfo->stream; if (devinfo->use_streams)
urb->stream_id = cmdinfo->uas_tag;
urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0; urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0;
urb->sg = sdb->table.sgl; urb->sg = sdb->table.sgl;
out: out:
...@@ -451,7 +437,8 @@ static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp, ...@@ -451,7 +437,8 @@ static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu), usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu),
uas_stat_cmplt, cmnd->device->host); uas_stat_cmplt, cmnd->device->host);
urb->stream_id = cmdinfo->stream; if (devinfo->use_streams)
urb->stream_id = cmdinfo->uas_tag;
urb->transfer_flags |= URB_FREE_BUFFER; urb->transfer_flags |= URB_FREE_BUFFER;
out: out:
return urb; return urb;
...@@ -465,6 +452,7 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp, ...@@ -465,6 +452,7 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
{ {
struct usb_device *udev = devinfo->udev; struct usb_device *udev = devinfo->udev;
struct scsi_device *sdev = cmnd->device; struct scsi_device *sdev = cmnd->device;
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
struct urb *urb = usb_alloc_urb(0, gfp); struct urb *urb = usb_alloc_urb(0, gfp);
struct command_iu *iu; struct command_iu *iu;
int len; int len;
...@@ -481,7 +469,7 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp, ...@@ -481,7 +469,7 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
goto free; goto free;
iu->iu_id = IU_ID_COMMAND; iu->iu_id = IU_ID_COMMAND;
iu->tag = cpu_to_be16(uas_get_tag(cmnd)); iu->tag = cpu_to_be16(cmdinfo->uas_tag);
iu->prio_attr = UAS_SIMPLE_TAG; iu->prio_attr = UAS_SIMPLE_TAG;
iu->len = len; iu->len = len;
int_to_scsilun(sdev->lun, &iu->lun); int_to_scsilun(sdev->lun, &iu->lun);
...@@ -608,8 +596,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, ...@@ -608,8 +596,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
struct uas_dev_info *devinfo = sdev->hostdata; struct uas_dev_info *devinfo = sdev->hostdata;
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
unsigned long flags; unsigned long flags;
unsigned int stream; int idx, err;
int err;
BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer)); BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer));
...@@ -635,8 +622,12 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, ...@@ -635,8 +622,12 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
return 0; return 0;
} }
stream = uas_get_tag(cmnd); /* Find a free uas-tag */
if (devinfo->cmnd[stream - 1]) { for (idx = 0; idx < devinfo->qdepth; idx++) {
if (!devinfo->cmnd[idx])
break;
}
if (idx == devinfo->qdepth) {
spin_unlock_irqrestore(&devinfo->lock, flags); spin_unlock_irqrestore(&devinfo->lock, flags);
return SCSI_MLQUEUE_DEVICE_BUSY; return SCSI_MLQUEUE_DEVICE_BUSY;
} }
...@@ -644,7 +635,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, ...@@ -644,7 +635,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
cmnd->scsi_done = done; cmnd->scsi_done = done;
memset(cmdinfo, 0, sizeof(*cmdinfo)); memset(cmdinfo, 0, sizeof(*cmdinfo));
cmdinfo->stream = stream; cmdinfo->uas_tag = idx + 1; /* uas-tag == usb-stream-id, so 1 based */
cmdinfo->state = SUBMIT_STATUS_URB | ALLOC_CMD_URB | SUBMIT_CMD_URB; cmdinfo->state = SUBMIT_STATUS_URB | ALLOC_CMD_URB | SUBMIT_CMD_URB;
switch (cmnd->sc_data_direction) { switch (cmnd->sc_data_direction) {
...@@ -659,10 +650,8 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, ...@@ -659,10 +650,8 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
break; break;
} }
if (!devinfo->use_streams) { if (!devinfo->use_streams)
cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB); cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB);
cmdinfo->stream = 0;
}
err = uas_submit_urbs(cmnd, devinfo, GFP_ATOMIC); err = uas_submit_urbs(cmnd, devinfo, GFP_ATOMIC);
if (err) { if (err) {
...@@ -674,7 +663,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, ...@@ -674,7 +663,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
uas_add_work(cmdinfo); uas_add_work(cmdinfo);
} }
devinfo->cmnd[stream - 1] = cmnd; devinfo->cmnd[idx] = cmnd;
spin_unlock_irqrestore(&devinfo->lock, flags); spin_unlock_irqrestore(&devinfo->lock, flags);
return 0; return 0;
} }
...@@ -702,7 +691,7 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd) ...@@ -702,7 +691,7 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
cmdinfo->state |= COMMAND_ABORTED; cmdinfo->state |= COMMAND_ABORTED;
/* Drop all refs to this cmnd, kill data urbs to break their ref */ /* Drop all refs to this cmnd, kill data urbs to break their ref */
devinfo->cmnd[uas_get_tag(cmnd) - 1] = NULL; devinfo->cmnd[cmdinfo->uas_tag - 1] = NULL;
if (cmdinfo->state & DATA_IN_URB_INFLIGHT) if (cmdinfo->state & DATA_IN_URB_INFLIGHT)
data_in_urb = usb_get_urb(cmdinfo->data_in_urb); data_in_urb = usb_get_urb(cmdinfo->data_in_urb);
if (cmdinfo->state & DATA_OUT_URB_INFLIGHT) if (cmdinfo->state & DATA_OUT_URB_INFLIGHT)
...@@ -818,13 +807,6 @@ static struct scsi_host_template uas_host_template = { ...@@ -818,13 +807,6 @@ static struct scsi_host_template uas_host_template = {
.cmd_per_lun = 1, /* until we override it */ .cmd_per_lun = 1, /* until we override it */
.skip_settle_delay = 1, .skip_settle_delay = 1,
.ordered_tag = 1, .ordered_tag = 1,
/*
* The uas drivers expects tags not to be bigger than the maximum
* per-device queue depth, which is not true with the blk-mq tag
* allocator.
*/
.disable_blk_mq = true,
}; };
#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment