diff options
Diffstat (limited to 'drivers/scsi/virtio_scsi.c')
-rw-r--r-- | drivers/scsi/virtio_scsi.c | 71 |
1 files changed, 25 insertions, 46 deletions
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index b53ba9e18f47..ffa03e8cb19c 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c | |||
@@ -75,8 +75,6 @@ struct virtio_scsi { | |||
75 | 75 | ||
76 | /* Get some buffers ready for event vq */ | 76 | /* Get some buffers ready for event vq */ |
77 | struct virtio_scsi_event_node event_list[VIRTIO_SCSI_EVENT_LEN]; | 77 | struct virtio_scsi_event_node event_list[VIRTIO_SCSI_EVENT_LEN]; |
78 | |||
79 | struct virtio_scsi_target_state *tgt[]; | ||
80 | }; | 78 | }; |
81 | 79 | ||
82 | static struct kmem_cache *virtscsi_cmd_cache; | 80 | static struct kmem_cache *virtscsi_cmd_cache; |
@@ -530,6 +528,25 @@ static int virtscsi_abort(struct scsi_cmnd *sc) | |||
530 | return virtscsi_tmf(vscsi, cmd); | 528 | return virtscsi_tmf(vscsi, cmd); |
531 | } | 529 | } |
532 | 530 | ||
531 | static int virtscsi_target_alloc(struct scsi_target *starget) | ||
532 | { | ||
533 | struct virtio_scsi_target_state *tgt = | ||
534 | kmalloc(sizeof(*tgt), GFP_KERNEL); | ||
535 | if (!tgt) | ||
536 | return -ENOMEM; | ||
537 | |||
538 | spin_lock_init(&tgt->tgt_lock); | ||
539 | |||
540 | starget->hostdata = tgt; | ||
541 | return 0; | ||
542 | } | ||
543 | |||
544 | static void virtscsi_target_destroy(struct scsi_target *starget) | ||
545 | { | ||
546 | struct virtio_scsi_target_state *tgt = starget->hostdata; | ||
547 | kfree(tgt); | ||
548 | } | ||
549 | |||
533 | static struct scsi_host_template virtscsi_host_template = { | 550 | static struct scsi_host_template virtscsi_host_template = { |
534 | .module = THIS_MODULE, | 551 | .module = THIS_MODULE, |
535 | .name = "Virtio SCSI HBA", | 552 | .name = "Virtio SCSI HBA", |
@@ -542,6 +559,8 @@ static struct scsi_host_template virtscsi_host_template = { | |||
542 | .can_queue = 1024, | 559 | .can_queue = 1024, |
543 | .dma_boundary = UINT_MAX, | 560 | .dma_boundary = UINT_MAX, |
544 | .use_clustering = ENABLE_CLUSTERING, | 561 | .use_clustering = ENABLE_CLUSTERING, |
562 | .target_alloc = virtscsi_target_alloc, | ||
563 | .target_destroy = virtscsi_target_destroy, | ||
545 | }; | 564 | }; |
546 | 565 | ||
547 | #define virtscsi_config_get(vdev, fld) \ | 566 | #define virtscsi_config_get(vdev, fld) \ |
@@ -568,20 +587,6 @@ static void virtscsi_init_vq(struct virtio_scsi_vq *virtscsi_vq, | |||
568 | virtscsi_vq->vq = vq; | 587 | virtscsi_vq->vq = vq; |
569 | } | 588 | } |
570 | 589 | ||
571 | static struct virtio_scsi_target_state *virtscsi_alloc_tgt( | ||
572 | struct virtio_device *vdev) | ||
573 | { | ||
574 | struct virtio_scsi_target_state *tgt; | ||
575 | gfp_t gfp_mask = GFP_KERNEL; | ||
576 | |||
577 | tgt = kmalloc(sizeof(*tgt), gfp_mask); | ||
578 | if (!tgt) | ||
579 | return NULL; | ||
580 | |||
581 | spin_lock_init(&tgt->tgt_lock); | ||
582 | return tgt; | ||
583 | } | ||
584 | |||
585 | static void virtscsi_scan(struct virtio_device *vdev) | 590 | static void virtscsi_scan(struct virtio_device *vdev) |
586 | { | 591 | { |
587 | struct Scsi_Host *shost = (struct Scsi_Host *)vdev->priv; | 592 | struct Scsi_Host *shost = (struct Scsi_Host *)vdev->priv; |
@@ -591,28 +596,17 @@ static void virtscsi_scan(struct virtio_device *vdev) | |||
591 | 596 | ||
592 | static void virtscsi_remove_vqs(struct virtio_device *vdev) | 597 | static void virtscsi_remove_vqs(struct virtio_device *vdev) |
593 | { | 598 | { |
594 | struct Scsi_Host *sh = virtio_scsi_host(vdev); | ||
595 | struct virtio_scsi *vscsi = shost_priv(sh); | ||
596 | u32 i, num_targets; | ||
597 | |||
598 | /* Stop all the virtqueues. */ | 599 | /* Stop all the virtqueues. */ |
599 | vdev->config->reset(vdev); | 600 | vdev->config->reset(vdev); |
600 | 601 | ||
601 | num_targets = sh->max_id; | ||
602 | for (i = 0; i < num_targets; i++) { | ||
603 | kfree(vscsi->tgt[i]); | ||
604 | vscsi->tgt[i] = NULL; | ||
605 | } | ||
606 | |||
607 | vdev->config->del_vqs(vdev); | 602 | vdev->config->del_vqs(vdev); |
608 | } | 603 | } |
609 | 604 | ||
610 | static int virtscsi_init(struct virtio_device *vdev, | 605 | static int virtscsi_init(struct virtio_device *vdev, |
611 | struct virtio_scsi *vscsi, int num_targets) | 606 | struct virtio_scsi *vscsi) |
612 | { | 607 | { |
613 | int err; | 608 | int err; |
614 | struct virtqueue *vqs[3]; | 609 | struct virtqueue *vqs[3]; |
615 | u32 i; | ||
616 | 610 | ||
617 | vq_callback_t *callbacks[] = { | 611 | vq_callback_t *callbacks[] = { |
618 | virtscsi_ctrl_done, | 612 | virtscsi_ctrl_done, |
@@ -640,18 +634,6 @@ static int virtscsi_init(struct virtio_device *vdev, | |||
640 | if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) | 634 | if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) |
641 | virtscsi_kick_event_all(vscsi); | 635 | virtscsi_kick_event_all(vscsi); |
642 | 636 | ||
643 | for (i = 0; i < num_targets; i++) { | ||
644 | vscsi->tgt[i] = virtscsi_alloc_tgt(vdev); | ||
645 | if (!vscsi->tgt[i]) { | ||
646 | err = -ENOMEM; | ||
647 | goto out; | ||
648 | } | ||
649 | } | ||
650 | err = 0; | ||
651 | |||
652 | out: | ||
653 | if (err) | ||
654 | virtscsi_remove_vqs(vdev); | ||
655 | return err; | 637 | return err; |
656 | } | 638 | } |
657 | 639 | ||
@@ -663,12 +645,9 @@ static int virtscsi_probe(struct virtio_device *vdev) | |||
663 | u32 sg_elems, num_targets; | 645 | u32 sg_elems, num_targets; |
664 | u32 cmd_per_lun; | 646 | u32 cmd_per_lun; |
665 | 647 | ||
666 | /* Allocate memory and link the structs together. */ | ||
667 | num_targets = virtscsi_config_get(vdev, max_target) + 1; | 648 | num_targets = virtscsi_config_get(vdev, max_target) + 1; |
668 | shost = scsi_host_alloc(&virtscsi_host_template, | ||
669 | sizeof(*vscsi) | ||
670 | + num_targets * sizeof(struct virtio_scsi_target_state)); | ||
671 | 649 | ||
650 | shost = scsi_host_alloc(&virtscsi_host_template, sizeof(*vscsi)); | ||
672 | if (!shost) | 651 | if (!shost) |
673 | return -ENOMEM; | 652 | return -ENOMEM; |
674 | 653 | ||
@@ -678,7 +657,7 @@ static int virtscsi_probe(struct virtio_device *vdev) | |||
678 | vscsi->vdev = vdev; | 657 | vscsi->vdev = vdev; |
679 | vdev->priv = shost; | 658 | vdev->priv = shost; |
680 | 659 | ||
681 | err = virtscsi_init(vdev, vscsi, num_targets); | 660 | err = virtscsi_init(vdev, vscsi); |
682 | if (err) | 661 | if (err) |
683 | goto virtscsi_init_failed; | 662 | goto virtscsi_init_failed; |
684 | 663 | ||
@@ -735,7 +714,7 @@ static int virtscsi_restore(struct virtio_device *vdev) | |||
735 | struct Scsi_Host *sh = virtio_scsi_host(vdev); | 714 | struct Scsi_Host *sh = virtio_scsi_host(vdev); |
736 | struct virtio_scsi *vscsi = shost_priv(sh); | 715 | struct virtio_scsi *vscsi = shost_priv(sh); |
737 | 716 | ||
738 | return virtscsi_init(vdev, vscsi, sh->max_id); | 717 | return virtscsi_init(vdev, vscsi); |
739 | } | 718 | } |
740 | #endif | 719 | #endif |
741 | 720 | ||