diff options
Diffstat (limited to 'drivers/scsi/virtio_scsi.c')
-rw-r--r-- | drivers/scsi/virtio_scsi.c | 42 |
1 files changed, 25 insertions, 17 deletions
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index eee1bc0b506e..b83846fc7859 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c | |||
@@ -110,6 +110,9 @@ struct virtio_scsi { | |||
110 | /* CPU hotplug notifier */ | 110 | /* CPU hotplug notifier */ |
111 | struct notifier_block nb; | 111 | struct notifier_block nb; |
112 | 112 | ||
113 | /* Protected by event_vq lock */ | ||
114 | bool stop_events; | ||
115 | |||
113 | struct virtio_scsi_vq ctrl_vq; | 116 | struct virtio_scsi_vq ctrl_vq; |
114 | struct virtio_scsi_vq event_vq; | 117 | struct virtio_scsi_vq event_vq; |
115 | struct virtio_scsi_vq req_vqs[]; | 118 | struct virtio_scsi_vq req_vqs[]; |
@@ -303,6 +306,11 @@ static void virtscsi_cancel_event_work(struct virtio_scsi *vscsi) | |||
303 | { | 306 | { |
304 | int i; | 307 | int i; |
305 | 308 | ||
309 | /* Stop scheduling work before calling cancel_work_sync. */ | ||
310 | spin_lock_irq(&vscsi->event_vq.vq_lock); | ||
311 | vscsi->stop_events = true; | ||
312 | spin_unlock_irq(&vscsi->event_vq.vq_lock); | ||
313 | |||
306 | for (i = 0; i < VIRTIO_SCSI_EVENT_LEN; i++) | 314 | for (i = 0; i < VIRTIO_SCSI_EVENT_LEN; i++) |
307 | cancel_work_sync(&vscsi->event_list[i].work); | 315 | cancel_work_sync(&vscsi->event_list[i].work); |
308 | } | 316 | } |
@@ -390,7 +398,8 @@ static void virtscsi_complete_event(struct virtio_scsi *vscsi, void *buf) | |||
390 | { | 398 | { |
391 | struct virtio_scsi_event_node *event_node = buf; | 399 | struct virtio_scsi_event_node *event_node = buf; |
392 | 400 | ||
393 | schedule_work(&event_node->work); | 401 | if (!vscsi->stop_events) |
402 | queue_work(system_freezable_wq, &event_node->work); | ||
394 | } | 403 | } |
395 | 404 | ||
396 | static void virtscsi_event_done(struct virtqueue *vq) | 405 | static void virtscsi_event_done(struct virtqueue *vq) |
@@ -851,13 +860,6 @@ static void virtscsi_init_vq(struct virtio_scsi_vq *virtscsi_vq, | |||
851 | virtscsi_vq->vq = vq; | 860 | virtscsi_vq->vq = vq; |
852 | } | 861 | } |
853 | 862 | ||
854 | static void virtscsi_scan(struct virtio_device *vdev) | ||
855 | { | ||
856 | struct Scsi_Host *shost = (struct Scsi_Host *)vdev->priv; | ||
857 | |||
858 | scsi_scan_host(shost); | ||
859 | } | ||
860 | |||
861 | static void virtscsi_remove_vqs(struct virtio_device *vdev) | 863 | static void virtscsi_remove_vqs(struct virtio_device *vdev) |
862 | { | 864 | { |
863 | struct Scsi_Host *sh = virtio_scsi_host(vdev); | 865 | struct Scsi_Host *sh = virtio_scsi_host(vdev); |
@@ -916,9 +918,6 @@ static int virtscsi_init(struct virtio_device *vdev, | |||
916 | virtscsi_config_set(vdev, cdb_size, VIRTIO_SCSI_CDB_SIZE); | 918 | virtscsi_config_set(vdev, cdb_size, VIRTIO_SCSI_CDB_SIZE); |
917 | virtscsi_config_set(vdev, sense_size, VIRTIO_SCSI_SENSE_SIZE); | 919 | virtscsi_config_set(vdev, sense_size, VIRTIO_SCSI_SENSE_SIZE); |
918 | 920 | ||
919 | if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) | ||
920 | virtscsi_kick_event_all(vscsi); | ||
921 | |||
922 | err = 0; | 921 | err = 0; |
923 | 922 | ||
924 | out: | 923 | out: |
@@ -997,10 +996,13 @@ static int virtscsi_probe(struct virtio_device *vdev) | |||
997 | err = scsi_add_host(shost, &vdev->dev); | 996 | err = scsi_add_host(shost, &vdev->dev); |
998 | if (err) | 997 | if (err) |
999 | goto scsi_add_host_failed; | 998 | goto scsi_add_host_failed; |
1000 | /* | 999 | |
1001 | * scsi_scan_host() happens in virtscsi_scan() via virtio_driver->scan() | 1000 | virtio_device_ready(vdev); |
1002 | * after VIRTIO_CONFIG_S_DRIVER_OK has been set.. | 1001 | |
1003 | */ | 1002 | if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) |
1003 | virtscsi_kick_event_all(vscsi); | ||
1004 | |||
1005 | scsi_scan_host(shost); | ||
1004 | return 0; | 1006 | return 0; |
1005 | 1007 | ||
1006 | scsi_add_host_failed: | 1008 | scsi_add_host_failed: |
@@ -1048,8 +1050,15 @@ static int virtscsi_restore(struct virtio_device *vdev) | |||
1048 | return err; | 1050 | return err; |
1049 | 1051 | ||
1050 | err = register_hotcpu_notifier(&vscsi->nb); | 1052 | err = register_hotcpu_notifier(&vscsi->nb); |
1051 | if (err) | 1053 | if (err) { |
1052 | vdev->config->del_vqs(vdev); | 1054 | vdev->config->del_vqs(vdev); |
1055 | return err; | ||
1056 | } | ||
1057 | |||
1058 | virtio_device_ready(vdev); | ||
1059 | |||
1060 | if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) | ||
1061 | virtscsi_kick_event_all(vscsi); | ||
1053 | 1062 | ||
1054 | return err; | 1063 | return err; |
1055 | } | 1064 | } |
@@ -1073,7 +1082,6 @@ static struct virtio_driver virtio_scsi_driver = { | |||
1073 | .driver.owner = THIS_MODULE, | 1082 | .driver.owner = THIS_MODULE, |
1074 | .id_table = id_table, | 1083 | .id_table = id_table, |
1075 | .probe = virtscsi_probe, | 1084 | .probe = virtscsi_probe, |
1076 | .scan = virtscsi_scan, | ||
1077 | #ifdef CONFIG_PM_SLEEP | 1085 | #ifdef CONFIG_PM_SLEEP |
1078 | .freeze = virtscsi_freeze, | 1086 | .freeze = virtscsi_freeze, |
1079 | .restore = virtscsi_restore, | 1087 | .restore = virtscsi_restore, |