diff options
Diffstat (limited to 'drivers/scsi/virtio_scsi.c')
-rw-r--r-- | drivers/scsi/virtio_scsi.c | 26 |
1 files changed, 25 insertions, 1 deletions
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 89ee5929eb6d..308256b5e4cb 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c | |||
@@ -237,6 +237,16 @@ static void virtscsi_req_done(struct virtqueue *vq) | |||
237 | virtscsi_vq_done(vscsi, req_vq, virtscsi_complete_cmd); | 237 | virtscsi_vq_done(vscsi, req_vq, virtscsi_complete_cmd); |
238 | }; | 238 | }; |
239 | 239 | ||
240 | static void virtscsi_poll_requests(struct virtio_scsi *vscsi) | ||
241 | { | ||
242 | int i, num_vqs; | ||
243 | |||
244 | num_vqs = vscsi->num_queues; | ||
245 | for (i = 0; i < num_vqs; i++) | ||
246 | virtscsi_vq_done(vscsi, &vscsi->req_vqs[i], | ||
247 | virtscsi_complete_cmd); | ||
248 | } | ||
249 | |||
240 | static void virtscsi_complete_free(struct virtio_scsi *vscsi, void *buf) | 250 | static void virtscsi_complete_free(struct virtio_scsi *vscsi, void *buf) |
241 | { | 251 | { |
242 | struct virtio_scsi_cmd *cmd = buf; | 252 | struct virtio_scsi_cmd *cmd = buf; |
@@ -253,6 +263,8 @@ static void virtscsi_ctrl_done(struct virtqueue *vq) | |||
253 | virtscsi_vq_done(vscsi, &vscsi->ctrl_vq, virtscsi_complete_free); | 263 | virtscsi_vq_done(vscsi, &vscsi->ctrl_vq, virtscsi_complete_free); |
254 | }; | 264 | }; |
255 | 265 | ||
266 | static void virtscsi_handle_event(struct work_struct *work); | ||
267 | |||
256 | static int virtscsi_kick_event(struct virtio_scsi *vscsi, | 268 | static int virtscsi_kick_event(struct virtio_scsi *vscsi, |
257 | struct virtio_scsi_event_node *event_node) | 269 | struct virtio_scsi_event_node *event_node) |
258 | { | 270 | { |
@@ -260,6 +272,7 @@ static int virtscsi_kick_event(struct virtio_scsi *vscsi, | |||
260 | struct scatterlist sg; | 272 | struct scatterlist sg; |
261 | unsigned long flags; | 273 | unsigned long flags; |
262 | 274 | ||
275 | INIT_WORK(&event_node->work, virtscsi_handle_event); | ||
263 | sg_init_one(&sg, &event_node->event, sizeof(struct virtio_scsi_event)); | 276 | sg_init_one(&sg, &event_node->event, sizeof(struct virtio_scsi_event)); |
264 | 277 | ||
265 | spin_lock_irqsave(&vscsi->event_vq.vq_lock, flags); | 278 | spin_lock_irqsave(&vscsi->event_vq.vq_lock, flags); |
@@ -377,7 +390,6 @@ static void virtscsi_complete_event(struct virtio_scsi *vscsi, void *buf) | |||
377 | { | 390 | { |
378 | struct virtio_scsi_event_node *event_node = buf; | 391 | struct virtio_scsi_event_node *event_node = buf; |
379 | 392 | ||
380 | INIT_WORK(&event_node->work, virtscsi_handle_event); | ||
381 | schedule_work(&event_node->work); | 393 | schedule_work(&event_node->work); |
382 | } | 394 | } |
383 | 395 | ||
@@ -589,6 +601,18 @@ static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd) | |||
589 | cmd->resp.tmf.response == VIRTIO_SCSI_S_FUNCTION_SUCCEEDED) | 601 | cmd->resp.tmf.response == VIRTIO_SCSI_S_FUNCTION_SUCCEEDED) |
590 | ret = SUCCESS; | 602 | ret = SUCCESS; |
591 | 603 | ||
604 | /* | ||
605 | * The spec guarantees that all requests related to the TMF have | ||
606 | * been completed, but the callback might not have run yet if | ||
607 | * we're using independent interrupts (e.g. MSI). Poll the | ||
608 | * virtqueues once. | ||
609 | * | ||
610 | * In the abort case, sc->scsi_done will do nothing, because | ||
611 | * the block layer must have detected a timeout and as a result | ||
612 | * REQ_ATOM_COMPLETE has been set. | ||
613 | */ | ||
614 | virtscsi_poll_requests(vscsi); | ||
615 | |||
592 | out: | 616 | out: |
593 | mempool_free(cmd, virtscsi_cmd_pool); | 617 | mempool_free(cmd, virtscsi_cmd_pool); |
594 | return ret; | 618 | return ret; |