]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/scsi/virtio_scsi.c
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.git] / drivers / scsi / virtio_scsi.c
index 89ee5929eb6de4060536e89885aba5f13f19577c..308256b5e4cb07d1e3a839848aeb679aff5c8d6f 100644 (file)
@@ -237,6 +237,16 @@ static void virtscsi_req_done(struct virtqueue *vq)
        virtscsi_vq_done(vscsi, req_vq, virtscsi_complete_cmd);
 };
 
+static void virtscsi_poll_requests(struct virtio_scsi *vscsi)
+{
+       int i, num_vqs;
+
+       num_vqs = vscsi->num_queues;
+       for (i = 0; i < num_vqs; i++)
+               virtscsi_vq_done(vscsi, &vscsi->req_vqs[i],
+                                virtscsi_complete_cmd);
+}
+
 static void virtscsi_complete_free(struct virtio_scsi *vscsi, void *buf)
 {
        struct virtio_scsi_cmd *cmd = buf;
@@ -253,6 +263,8 @@ static void virtscsi_ctrl_done(struct virtqueue *vq)
        virtscsi_vq_done(vscsi, &vscsi->ctrl_vq, virtscsi_complete_free);
 };
 
+static void virtscsi_handle_event(struct work_struct *work);
+
 static int virtscsi_kick_event(struct virtio_scsi *vscsi,
                               struct virtio_scsi_event_node *event_node)
 {
@@ -260,6 +272,7 @@ static int virtscsi_kick_event(struct virtio_scsi *vscsi,
        struct scatterlist sg;
        unsigned long flags;
 
+       INIT_WORK(&event_node->work, virtscsi_handle_event);
        sg_init_one(&sg, &event_node->event, sizeof(struct virtio_scsi_event));
 
        spin_lock_irqsave(&vscsi->event_vq.vq_lock, flags);
@@ -377,7 +390,6 @@ static void virtscsi_complete_event(struct virtio_scsi *vscsi, void *buf)
 {
        struct virtio_scsi_event_node *event_node = buf;
 
-       INIT_WORK(&event_node->work, virtscsi_handle_event);
        schedule_work(&event_node->work);
 }
 
@@ -589,6 +601,18 @@ static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd)
            cmd->resp.tmf.response == VIRTIO_SCSI_S_FUNCTION_SUCCEEDED)
                ret = SUCCESS;
 
+       /*
+        * The spec guarantees that all requests related to the TMF have
+        * been completed, but the callback might not have run yet if
+        * we're using independent interrupts (e.g. MSI).  Poll the
+        * virtqueues once.
+        *
+        * In the abort case, sc->scsi_done will do nothing, because
+        * the block layer must have detected a timeout and as a result
+        * REQ_ATOM_COMPLETE has been set.
+        */
+       virtscsi_poll_requests(vscsi);
+
 out:
        mempool_free(cmd, virtscsi_cmd_pool);
        return ret;