Commit 9e5470fe authored by Paolo Bonzini's avatar Paolo Bonzini Committed by Martin K. Petersen

scsi: virtio_scsi: implement request batching

Adding the command and kicking the virtqueue so far was done one after
another.  Make the kick optional, so that we can take into account
SCMD_LAST.  We also need a commit_rqs callback to kick the device if
blk-mq aborts the submission before the last request is reached.
Suggested-by: default avatarStefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
Reviewed-by: default avatarMing Lei <ming.lei@redhat.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 8930a6c2
...@@ -369,14 +369,7 @@ static void virtscsi_event_done(struct virtqueue *vq) ...@@ -369,14 +369,7 @@ static void virtscsi_event_done(struct virtqueue *vq)
virtscsi_vq_done(vscsi, &vscsi->event_vq, virtscsi_complete_event); virtscsi_vq_done(vscsi, &vscsi->event_vq, virtscsi_complete_event);
}; };
/** static int __virtscsi_add_cmd(struct virtqueue *vq,
* virtscsi_add_cmd - add a virtio_scsi_cmd to a virtqueue
* @vq : the struct virtqueue we're talking about
* @cmd : command structure
* @req_size : size of the request buffer
* @resp_size : size of the response buffer
*/
static int virtscsi_add_cmd(struct virtqueue *vq,
struct virtio_scsi_cmd *cmd, struct virtio_scsi_cmd *cmd,
size_t req_size, size_t resp_size) size_t req_size, size_t resp_size)
{ {
...@@ -421,17 +414,39 @@ static int virtscsi_add_cmd(struct virtqueue *vq, ...@@ -421,17 +414,39 @@ static int virtscsi_add_cmd(struct virtqueue *vq,
return virtqueue_add_sgs(vq, sgs, out_num, in_num, cmd, GFP_ATOMIC); return virtqueue_add_sgs(vq, sgs, out_num, in_num, cmd, GFP_ATOMIC);
} }
static int virtscsi_kick_cmd(struct virtio_scsi_vq *vq, static void virtscsi_kick_vq(struct virtio_scsi_vq *vq)
{
bool needs_kick;
unsigned long flags;
spin_lock_irqsave(&vq->vq_lock, flags);
needs_kick = virtqueue_kick_prepare(vq->vq);
spin_unlock_irqrestore(&vq->vq_lock, flags);
if (needs_kick)
virtqueue_notify(vq->vq);
}
/**
* virtscsi_add_cmd - add a virtio_scsi_cmd to a virtqueue, optionally kick it
* @vq : the struct virtqueue we're talking about
* @cmd : command structure
* @req_size : size of the request buffer
* @resp_size : size of the response buffer
* @kick : whether to kick the virtqueue immediately
*/
static int virtscsi_add_cmd(struct virtio_scsi_vq *vq,
struct virtio_scsi_cmd *cmd, struct virtio_scsi_cmd *cmd,
size_t req_size, size_t resp_size) size_t req_size, size_t resp_size,
bool kick)
{ {
unsigned long flags; unsigned long flags;
int err; int err;
bool needs_kick = false; bool needs_kick = false;
spin_lock_irqsave(&vq->vq_lock, flags); spin_lock_irqsave(&vq->vq_lock, flags);
err = virtscsi_add_cmd(vq->vq, cmd, req_size, resp_size); err = __virtscsi_add_cmd(vq->vq, cmd, req_size, resp_size);
if (!err) if (!err && kick)
needs_kick = virtqueue_kick_prepare(vq->vq); needs_kick = virtqueue_kick_prepare(vq->vq);
spin_unlock_irqrestore(&vq->vq_lock, flags); spin_unlock_irqrestore(&vq->vq_lock, flags);
...@@ -496,6 +511,7 @@ static int virtscsi_queuecommand(struct Scsi_Host *shost, ...@@ -496,6 +511,7 @@ static int virtscsi_queuecommand(struct Scsi_Host *shost,
struct virtio_scsi *vscsi = shost_priv(shost); struct virtio_scsi *vscsi = shost_priv(shost);
struct virtio_scsi_vq *req_vq = virtscsi_pick_vq_mq(vscsi, sc); struct virtio_scsi_vq *req_vq = virtscsi_pick_vq_mq(vscsi, sc);
struct virtio_scsi_cmd *cmd = scsi_cmd_priv(sc); struct virtio_scsi_cmd *cmd = scsi_cmd_priv(sc);
bool kick;
unsigned long flags; unsigned long flags;
int req_size; int req_size;
int ret; int ret;
...@@ -525,7 +541,8 @@ static int virtscsi_queuecommand(struct Scsi_Host *shost, ...@@ -525,7 +541,8 @@ static int virtscsi_queuecommand(struct Scsi_Host *shost,
req_size = sizeof(cmd->req.cmd); req_size = sizeof(cmd->req.cmd);
} }
ret = virtscsi_kick_cmd(req_vq, cmd, req_size, sizeof(cmd->resp.cmd)); kick = (sc->flags & SCMD_LAST) != 0;
ret = virtscsi_add_cmd(req_vq, cmd, req_size, sizeof(cmd->resp.cmd), kick);
if (ret == -EIO) { if (ret == -EIO) {
cmd->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET; cmd->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET;
spin_lock_irqsave(&req_vq->vq_lock, flags); spin_lock_irqsave(&req_vq->vq_lock, flags);
...@@ -543,8 +560,8 @@ static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd) ...@@ -543,8 +560,8 @@ static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd)
int ret = FAILED; int ret = FAILED;
cmd->comp = &comp; cmd->comp = &comp;
if (virtscsi_kick_cmd(&vscsi->ctrl_vq, cmd, if (virtscsi_add_cmd(&vscsi->ctrl_vq, cmd,
sizeof cmd->req.tmf, sizeof cmd->resp.tmf) < 0) sizeof cmd->req.tmf, sizeof cmd->resp.tmf, true) < 0)
goto out; goto out;
wait_for_completion(&comp); wait_for_completion(&comp);
...@@ -658,6 +675,13 @@ static int virtscsi_map_queues(struct Scsi_Host *shost) ...@@ -658,6 +675,13 @@ static int virtscsi_map_queues(struct Scsi_Host *shost)
return blk_mq_virtio_map_queues(qmap, vscsi->vdev, 2); return blk_mq_virtio_map_queues(qmap, vscsi->vdev, 2);
} }
static void virtscsi_commit_rqs(struct Scsi_Host *shost, u16 hwq)
{
struct virtio_scsi *vscsi = shost_priv(shost);
virtscsi_kick_vq(&vscsi->req_vqs[hwq]);
}
/* /*
* The host guarantees to respond to each command, although I/O * The host guarantees to respond to each command, although I/O
* latencies might be higher than on bare metal. Reset the timer * latencies might be higher than on bare metal. Reset the timer
...@@ -675,6 +699,7 @@ static struct scsi_host_template virtscsi_host_template = { ...@@ -675,6 +699,7 @@ static struct scsi_host_template virtscsi_host_template = {
.this_id = -1, .this_id = -1,
.cmd_size = sizeof(struct virtio_scsi_cmd), .cmd_size = sizeof(struct virtio_scsi_cmd),
.queuecommand = virtscsi_queuecommand, .queuecommand = virtscsi_queuecommand,
.commit_rqs = virtscsi_commit_rqs,
.change_queue_depth = virtscsi_change_queue_depth, .change_queue_depth = virtscsi_change_queue_depth,
.eh_abort_handler = virtscsi_abort, .eh_abort_handler = virtscsi_abort,
.eh_device_reset_handler = virtscsi_device_reset, .eh_device_reset_handler = virtscsi_device_reset,
......
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