|
@@ -30,6 +30,8 @@
|
|
#include "uas-detect.h"
|
|
#include "uas-detect.h"
|
|
#include "scsiglue.h"
|
|
#include "scsiglue.h"
|
|
|
|
|
|
|
|
+#define MAX_CMNDS 256
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* The r00-r01c specs define this version of the SENSE IU data structure.
|
|
* The r00-r01c specs define this version of the SENSE IU data structure.
|
|
* It's still in use by several different firmware releases.
|
|
* It's still in use by several different firmware releases.
|
|
@@ -56,7 +58,7 @@ struct uas_dev_info {
|
|
unsigned use_streams:1;
|
|
unsigned use_streams:1;
|
|
unsigned uas_sense_old:1;
|
|
unsigned uas_sense_old:1;
|
|
unsigned shutdown:1;
|
|
unsigned shutdown:1;
|
|
- struct scsi_cmnd *cmnd;
|
|
|
|
|
|
+ struct scsi_cmnd *cmnd[MAX_CMNDS];
|
|
spinlock_t lock;
|
|
spinlock_t lock;
|
|
struct work_struct work;
|
|
struct work_struct work;
|
|
struct list_head inflight_list;
|
|
struct list_head inflight_list;
|
|
@@ -316,6 +318,7 @@ static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
|
|
if (cmdinfo->state & COMMAND_ABORTED)
|
|
if (cmdinfo->state & COMMAND_ABORTED)
|
|
scmd_printk(KERN_INFO, cmnd, "abort completed\n");
|
|
scmd_printk(KERN_INFO, cmnd, "abort completed\n");
|
|
list_del(&cmdinfo->list);
|
|
list_del(&cmdinfo->list);
|
|
|
|
+ devinfo->cmnd[uas_get_tag(cmnd) - 1] = NULL;
|
|
cmnd->scsi_done(cmnd);
|
|
cmnd->scsi_done(cmnd);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -341,7 +344,7 @@ static void uas_stat_cmplt(struct urb *urb)
|
|
struct scsi_cmnd *cmnd;
|
|
struct scsi_cmnd *cmnd;
|
|
struct uas_cmd_info *cmdinfo;
|
|
struct uas_cmd_info *cmdinfo;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
- u16 tag;
|
|
|
|
|
|
+ unsigned int idx;
|
|
|
|
|
|
spin_lock_irqsave(&devinfo->lock, flags);
|
|
spin_lock_irqsave(&devinfo->lock, flags);
|
|
|
|
|
|
@@ -359,21 +362,17 @@ static void uas_stat_cmplt(struct urb *urb)
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
- tag = be16_to_cpup(&iu->tag) - 1;
|
|
|
|
- if (tag == 0)
|
|
|
|
- cmnd = devinfo->cmnd;
|
|
|
|
- else
|
|
|
|
- cmnd = scsi_host_find_tag(shost, tag - 1);
|
|
|
|
-
|
|
|
|
- if (!cmnd)
|
|
|
|
|
|
+ idx = be16_to_cpup(&iu->tag) - 1;
|
|
|
|
+ if (idx >= MAX_CMNDS || !devinfo->cmnd[idx]) {
|
|
|
|
+ dev_err(&urb->dev->dev,
|
|
|
|
+ "stat urb: no pending cmd for tag %d\n", idx + 1);
|
|
goto out;
|
|
goto out;
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ cmnd = devinfo->cmnd[idx];
|
|
cmdinfo = (void *)&cmnd->SCp;
|
|
cmdinfo = (void *)&cmnd->SCp;
|
|
switch (iu->iu_id) {
|
|
switch (iu->iu_id) {
|
|
case IU_ID_STATUS:
|
|
case IU_ID_STATUS:
|
|
- if (devinfo->cmnd == cmnd)
|
|
|
|
- devinfo->cmnd = NULL;
|
|
|
|
-
|
|
|
|
if (urb->actual_length < 16)
|
|
if (urb->actual_length < 16)
|
|
devinfo->uas_sense_old = 1;
|
|
devinfo->uas_sense_old = 1;
|
|
if (devinfo->uas_sense_old)
|
|
if (devinfo->uas_sense_old)
|
|
@@ -674,6 +673,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 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));
|
|
@@ -696,19 +696,16 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
- if (devinfo->cmnd) {
|
|
|
|
|
|
+ stream = uas_get_tag(cmnd);
|
|
|
|
+ if (devinfo->cmnd[stream - 1]) {
|
|
spin_unlock_irqrestore(&devinfo->lock, flags);
|
|
spin_unlock_irqrestore(&devinfo->lock, flags);
|
|
return SCSI_MLQUEUE_DEVICE_BUSY;
|
|
return SCSI_MLQUEUE_DEVICE_BUSY;
|
|
}
|
|
}
|
|
|
|
|
|
- memset(cmdinfo, 0, sizeof(*cmdinfo));
|
|
|
|
-
|
|
|
|
- if (!blk_rq_tagged(cmnd->request))
|
|
|
|
- devinfo->cmnd = cmnd;
|
|
|
|
-
|
|
|
|
cmnd->scsi_done = done;
|
|
cmnd->scsi_done = done;
|
|
|
|
|
|
- cmdinfo->stream = uas_get_tag(cmnd);
|
|
|
|
|
|
+ memset(cmdinfo, 0, sizeof(*cmdinfo));
|
|
|
|
+ cmdinfo->stream = stream;
|
|
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) {
|
|
@@ -738,6 +735,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
|
|
uas_add_work(cmdinfo);
|
|
uas_add_work(cmdinfo);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ devinfo->cmnd[stream - 1] = cmnd;
|
|
list_add_tail(&cmdinfo->list, &devinfo->inflight_list);
|
|
list_add_tail(&cmdinfo->list, &devinfo->inflight_list);
|
|
spin_unlock_irqrestore(&devinfo->lock, flags);
|
|
spin_unlock_irqrestore(&devinfo->lock, flags);
|
|
return 0;
|
|
return 0;
|
|
@@ -877,7 +875,6 @@ static int uas_configure_endpoints(struct uas_dev_info *devinfo)
|
|
int r;
|
|
int r;
|
|
|
|
|
|
devinfo->uas_sense_old = 0;
|
|
devinfo->uas_sense_old = 0;
|
|
- devinfo->cmnd = NULL;
|
|
|
|
|
|
|
|
r = uas_find_endpoints(devinfo->intf->cur_altsetting, eps);
|
|
r = uas_find_endpoints(devinfo->intf->cur_altsetting, eps);
|
|
if (r)
|
|
if (r)
|
|
@@ -897,7 +894,7 @@ static int uas_configure_endpoints(struct uas_dev_info *devinfo)
|
|
devinfo->use_streams = 0;
|
|
devinfo->use_streams = 0;
|
|
} else {
|
|
} else {
|
|
devinfo->qdepth = usb_alloc_streams(devinfo->intf, eps + 1,
|
|
devinfo->qdepth = usb_alloc_streams(devinfo->intf, eps + 1,
|
|
- 3, 256, GFP_NOIO);
|
|
|
|
|
|
+ 3, MAX_CMNDS, GFP_NOIO);
|
|
if (devinfo->qdepth < 0)
|
|
if (devinfo->qdepth < 0)
|
|
return devinfo->qdepth;
|
|
return devinfo->qdepth;
|
|
devinfo->use_streams = 1;
|
|
devinfo->use_streams = 1;
|