@@ -640,9 +640,10 @@ EXPORT_SYMBOL(scsi_cmd_get_serial);
* Return: nonzero return request was rejected and device's queue needs to be
* plugged.
*/
-int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
+int scsi_dispatch_cmd(struct blk_mq_hw_ctx *hctx, struct scsi_cmnd *cmd)
{
struct Scsi_Host *host = cmd->device->host;
+ struct scsi_host_template *hostt = host->hostt;
int rtn = 0;
atomic_inc(&cmd->device->iorequest_cnt);
@@ -701,7 +702,9 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
}
trace_scsi_dispatch_cmd_start(cmd);
- rtn = host->hostt->queuecommand(host, cmd);
+ rtn = hctx && hostt->mq_queuecommand ?
+ hostt->mq_queuecommand(hctx, cmd) :
+ hostt->queuecommand(host, cmd);
if (rtn) {
trace_scsi_dispatch_cmd_error(cmd, rtn);
if (rtn != SCSI_MLQUEUE_DEVICE_BUSY &&
@@ -1747,7 +1747,7 @@ static void scsi_request_fn(struct request_queue *q)
* Dispatch the command to the low-level driver.
*/
cmd->scsi_done = scsi_done;
- rtn = scsi_dispatch_cmd(cmd);
+ rtn = scsi_dispatch_cmd(NULL, cmd);
if (rtn) {
scsi_queue_insert(cmd, rtn);
spin_lock_irq(q->queue_lock);
@@ -1889,7 +1889,7 @@ static int scsi_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req)
scsi_init_cmd_errh(cmd);
cmd->scsi_done = scsi_mq_done;
- reason = scsi_dispatch_cmd(cmd);
+ reason = scsi_dispatch_cmd(hctx, cmd);
if (reason) {
scsi_set_blocked(cmd, reason);
ret = BLK_MQ_RQ_QUEUE_BUSY;
@@ -29,7 +29,7 @@ extern int scsi_init_hosts(void);
extern void scsi_exit_hosts(void);
/* scsi.c */
-extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd);
+extern int scsi_dispatch_cmd(struct blk_mq_hw_ctx *hctx, struct scsi_cmnd *cmd);
extern int scsi_setup_command_freelist(struct Scsi_Host *shost);
extern void scsi_destroy_command_freelist(struct Scsi_Host *shost);
#ifdef CONFIG_SCSI_LOGGING
@@ -133,6 +133,20 @@ struct scsi_host_template {
int (* queuecommand)(struct Scsi_Host *, struct scsi_cmnd *);
/*
+ * scsi-mq version of queuecommand(). Must be provided by LLDDs that
+ * provide multiple hardware queues and that need to know on which
+ * hardware context a command has been queued by the block layer.
+ *
+ * Note: even if an LLDD provides an mq_queuecommand callback function
+ * it still has to provide a queuecommand callback function. The SCSI
+ * error handler namely can invoke the queuecommand callback function
+ * even if scsi-mq is enabled.
+ *
+ * STATUS: OPTIONAL
+ */
+ int (* mq_queuecommand)(struct blk_mq_hw_ctx *hctx, struct scsi_cmnd *);
+
+ /*
* This is an error handling strategy routine. You don't need to
* define one of these if you don't want to - there is a default
* routine that is present that should work in most cases. For those
Low-level drivers (LLDs) need to know which hardware context has been selected by the block layer. Hence pass this information to SCSI LLDs. Signed-off-by: Bart Van Assche <bvanassche@acm.org> Cc: Christoph Hellwig <hch@lst.de> --- drivers/scsi/scsi.c | 7 +++++-- drivers/scsi/scsi_lib.c | 4 ++-- drivers/scsi/scsi_priv.h | 2 +- include/scsi/scsi_host.h | 14 ++++++++++++++ 4 files changed, 22 insertions(+), 5 deletions(-)