dm raid: fix round up of default region size
[firefly-linux-kernel-4.4.55.git] / drivers / scsi / virtio_scsi.c
index 2168258fb2c3a2cf5374a3592a302062d75bb305..11f5326f449f6871e56afdf82f5741c03a2bc730 100644 (file)
@@ -270,6 +270,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;
@@ -288,6 +298,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)
 {
@@ -295,6 +307,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);
@@ -412,7 +425,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);
 }
 
@@ -602,6 +614,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;
@@ -751,8 +775,12 @@ static void __virtscsi_set_affinity(struct virtio_scsi *vscsi, bool affinity)
 
                vscsi->affinity_hint_set = true;
        } else {
-               for (i = 0; i < vscsi->num_queues - VIRTIO_SCSI_VQ_BASE; i++)
+               for (i = 0; i < vscsi->num_queues; i++) {
+                       if (!vscsi->req_vqs[i].vq)
+                               continue;
+
                        virtqueue_set_affinity(vscsi->req_vqs[i].vq, -1);
+               }
 
                vscsi->affinity_hint_set = false;
        }
@@ -957,6 +985,10 @@ static void virtscsi_remove(struct virtio_device *vdev)
 #ifdef CONFIG_PM
 static int virtscsi_freeze(struct virtio_device *vdev)
 {
+       struct Scsi_Host *sh = virtio_scsi_host(vdev);
+       struct virtio_scsi *vscsi = shost_priv(sh);
+
+       unregister_hotcpu_notifier(&vscsi->nb);
        virtscsi_remove_vqs(vdev);
        return 0;
 }
@@ -965,8 +997,17 @@ static int virtscsi_restore(struct virtio_device *vdev)
 {
        struct Scsi_Host *sh = virtio_scsi_host(vdev);
        struct virtio_scsi *vscsi = shost_priv(sh);
+       int err;
+
+       err = virtscsi_init(vdev, vscsi);
+       if (err)
+               return err;
+
+       err = register_hotcpu_notifier(&vscsi->nb);
+       if (err)
+               vdev->config->del_vqs(vdev);
 
-       return virtscsi_init(vdev, vscsi);
+       return err;
 }
 #endif