diff options
Diffstat (limited to 'drivers/vhost/tcm_vhost.c')
-rw-r--r-- | drivers/vhost/tcm_vhost.c | 287 |
1 files changed, 161 insertions, 126 deletions
diff --git a/drivers/vhost/tcm_vhost.c b/drivers/vhost/tcm_vhost.c index 22321cf84fbe..9951297b2427 100644 --- a/drivers/vhost/tcm_vhost.c +++ b/drivers/vhost/tcm_vhost.c | |||
@@ -47,6 +47,8 @@ | |||
47 | #include <linux/vhost.h> | 47 | #include <linux/vhost.h> |
48 | #include <linux/virtio_net.h> /* TODO vhost.h currently depends on this */ | 48 | #include <linux/virtio_net.h> /* TODO vhost.h currently depends on this */ |
49 | #include <linux/virtio_scsi.h> | 49 | #include <linux/virtio_scsi.h> |
50 | #include <linux/llist.h> | ||
51 | #include <linux/bitmap.h> | ||
50 | 52 | ||
51 | #include "vhost.c" | 53 | #include "vhost.c" |
52 | #include "vhost.h" | 54 | #include "vhost.h" |
@@ -58,14 +60,20 @@ enum { | |||
58 | VHOST_SCSI_VQ_IO = 2, | 60 | VHOST_SCSI_VQ_IO = 2, |
59 | }; | 61 | }; |
60 | 62 | ||
63 | #define VHOST_SCSI_MAX_TARGET 256 | ||
64 | #define VHOST_SCSI_MAX_VQ 128 | ||
65 | |||
61 | struct vhost_scsi { | 66 | struct vhost_scsi { |
62 | struct tcm_vhost_tpg *vs_tpg; /* Protected by vhost_scsi->dev.mutex */ | 67 | /* Protected by vhost_scsi->dev.mutex */ |
68 | struct tcm_vhost_tpg *vs_tpg[VHOST_SCSI_MAX_TARGET]; | ||
69 | char vs_vhost_wwpn[TRANSPORT_IQN_LEN]; | ||
70 | bool vs_endpoint; | ||
71 | |||
63 | struct vhost_dev dev; | 72 | struct vhost_dev dev; |
64 | struct vhost_virtqueue vqs[3]; | 73 | struct vhost_virtqueue vqs[VHOST_SCSI_MAX_VQ]; |
65 | 74 | ||
66 | struct vhost_work vs_completion_work; /* cmd completion work item */ | 75 | struct vhost_work vs_completion_work; /* cmd completion work item */ |
67 | struct list_head vs_completion_list; /* cmd completion queue */ | 76 | struct llist_head vs_completion_list; /* cmd completion queue */ |
68 | spinlock_t vs_completion_lock; /* protects s_completion_list */ | ||
69 | }; | 77 | }; |
70 | 78 | ||
71 | /* Local pointer to allocated TCM configfs fabric module */ | 79 | /* Local pointer to allocated TCM configfs fabric module */ |
@@ -77,6 +85,12 @@ static struct workqueue_struct *tcm_vhost_workqueue; | |||
77 | static DEFINE_MUTEX(tcm_vhost_mutex); | 85 | static DEFINE_MUTEX(tcm_vhost_mutex); |
78 | static LIST_HEAD(tcm_vhost_list); | 86 | static LIST_HEAD(tcm_vhost_list); |
79 | 87 | ||
88 | static int iov_num_pages(struct iovec *iov) | ||
89 | { | ||
90 | return (PAGE_ALIGN((unsigned long)iov->iov_base + iov->iov_len) - | ||
91 | ((unsigned long)iov->iov_base & PAGE_MASK)) >> PAGE_SHIFT; | ||
92 | } | ||
93 | |||
80 | static int tcm_vhost_check_true(struct se_portal_group *se_tpg) | 94 | static int tcm_vhost_check_true(struct se_portal_group *se_tpg) |
81 | { | 95 | { |
82 | return 1; | 96 | return 1; |
@@ -301,9 +315,7 @@ static void vhost_scsi_complete_cmd(struct tcm_vhost_cmd *tv_cmd) | |||
301 | { | 315 | { |
302 | struct vhost_scsi *vs = tv_cmd->tvc_vhost; | 316 | struct vhost_scsi *vs = tv_cmd->tvc_vhost; |
303 | 317 | ||
304 | spin_lock_bh(&vs->vs_completion_lock); | 318 | llist_add(&tv_cmd->tvc_completion_list, &vs->vs_completion_list); |
305 | list_add_tail(&tv_cmd->tvc_completion_list, &vs->vs_completion_list); | ||
306 | spin_unlock_bh(&vs->vs_completion_lock); | ||
307 | 319 | ||
308 | vhost_work_queue(&vs->dev, &vs->vs_completion_work); | 320 | vhost_work_queue(&vs->dev, &vs->vs_completion_work); |
309 | } | 321 | } |
@@ -347,27 +359,6 @@ static void vhost_scsi_free_cmd(struct tcm_vhost_cmd *tv_cmd) | |||
347 | kfree(tv_cmd); | 359 | kfree(tv_cmd); |
348 | } | 360 | } |
349 | 361 | ||
350 | /* Dequeue a command from the completion list */ | ||
351 | static struct tcm_vhost_cmd *vhost_scsi_get_cmd_from_completion( | ||
352 | struct vhost_scsi *vs) | ||
353 | { | ||
354 | struct tcm_vhost_cmd *tv_cmd = NULL; | ||
355 | |||
356 | spin_lock_bh(&vs->vs_completion_lock); | ||
357 | if (list_empty(&vs->vs_completion_list)) { | ||
358 | spin_unlock_bh(&vs->vs_completion_lock); | ||
359 | return NULL; | ||
360 | } | ||
361 | |||
362 | list_for_each_entry(tv_cmd, &vs->vs_completion_list, | ||
363 | tvc_completion_list) { | ||
364 | list_del(&tv_cmd->tvc_completion_list); | ||
365 | break; | ||
366 | } | ||
367 | spin_unlock_bh(&vs->vs_completion_lock); | ||
368 | return tv_cmd; | ||
369 | } | ||
370 | |||
371 | /* Fill in status and signal that we are done processing this command | 362 | /* Fill in status and signal that we are done processing this command |
372 | * | 363 | * |
373 | * This is scheduled in the vhost work queue so we are called with the owner | 364 | * This is scheduled in the vhost work queue so we are called with the owner |
@@ -377,12 +368,20 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work) | |||
377 | { | 368 | { |
378 | struct vhost_scsi *vs = container_of(work, struct vhost_scsi, | 369 | struct vhost_scsi *vs = container_of(work, struct vhost_scsi, |
379 | vs_completion_work); | 370 | vs_completion_work); |
371 | DECLARE_BITMAP(signal, VHOST_SCSI_MAX_VQ); | ||
372 | struct virtio_scsi_cmd_resp v_rsp; | ||
380 | struct tcm_vhost_cmd *tv_cmd; | 373 | struct tcm_vhost_cmd *tv_cmd; |
381 | 374 | struct llist_node *llnode; | |
382 | while ((tv_cmd = vhost_scsi_get_cmd_from_completion(vs))) { | 375 | struct se_cmd *se_cmd; |
383 | struct virtio_scsi_cmd_resp v_rsp; | 376 | int ret, vq; |
384 | struct se_cmd *se_cmd = &tv_cmd->tvc_se_cmd; | 377 | |
385 | int ret; | 378 | bitmap_zero(signal, VHOST_SCSI_MAX_VQ); |
379 | llnode = llist_del_all(&vs->vs_completion_list); | ||
380 | while (llnode) { | ||
381 | tv_cmd = llist_entry(llnode, struct tcm_vhost_cmd, | ||
382 | tvc_completion_list); | ||
383 | llnode = llist_next(llnode); | ||
384 | se_cmd = &tv_cmd->tvc_se_cmd; | ||
386 | 385 | ||
387 | pr_debug("%s tv_cmd %p resid %u status %#02x\n", __func__, | 386 | pr_debug("%s tv_cmd %p resid %u status %#02x\n", __func__, |
388 | tv_cmd, se_cmd->residual_count, se_cmd->scsi_status); | 387 | tv_cmd, se_cmd->residual_count, se_cmd->scsi_status); |
@@ -395,15 +394,20 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work) | |||
395 | memcpy(v_rsp.sense, tv_cmd->tvc_sense_buf, | 394 | memcpy(v_rsp.sense, tv_cmd->tvc_sense_buf, |
396 | v_rsp.sense_len); | 395 | v_rsp.sense_len); |
397 | ret = copy_to_user(tv_cmd->tvc_resp, &v_rsp, sizeof(v_rsp)); | 396 | ret = copy_to_user(tv_cmd->tvc_resp, &v_rsp, sizeof(v_rsp)); |
398 | if (likely(ret == 0)) | 397 | if (likely(ret == 0)) { |
399 | vhost_add_used(&vs->vqs[2], tv_cmd->tvc_vq_desc, 0); | 398 | vhost_add_used(tv_cmd->tvc_vq, tv_cmd->tvc_vq_desc, 0); |
400 | else | 399 | vq = tv_cmd->tvc_vq - vs->vqs; |
400 | __set_bit(vq, signal); | ||
401 | } else | ||
401 | pr_err("Faulted on virtio_scsi_cmd_resp\n"); | 402 | pr_err("Faulted on virtio_scsi_cmd_resp\n"); |
402 | 403 | ||
403 | vhost_scsi_free_cmd(tv_cmd); | 404 | vhost_scsi_free_cmd(tv_cmd); |
404 | } | 405 | } |
405 | 406 | ||
406 | vhost_signal(&vs->dev, &vs->vqs[2]); | 407 | vq = -1; |
408 | while ((vq = find_next_bit(signal, VHOST_SCSI_MAX_VQ, vq + 1)) | ||
409 | < VHOST_SCSI_MAX_VQ) | ||
410 | vhost_signal(&vs->dev, &vs->vqs[vq]); | ||
407 | } | 411 | } |
408 | 412 | ||
409 | static struct tcm_vhost_cmd *vhost_scsi_allocate_cmd( | 413 | static struct tcm_vhost_cmd *vhost_scsi_allocate_cmd( |
@@ -426,7 +430,6 @@ static struct tcm_vhost_cmd *vhost_scsi_allocate_cmd( | |||
426 | pr_err("Unable to allocate struct tcm_vhost_cmd\n"); | 430 | pr_err("Unable to allocate struct tcm_vhost_cmd\n"); |
427 | return ERR_PTR(-ENOMEM); | 431 | return ERR_PTR(-ENOMEM); |
428 | } | 432 | } |
429 | INIT_LIST_HEAD(&tv_cmd->tvc_completion_list); | ||
430 | tv_cmd->tvc_tag = v_req->tag; | 433 | tv_cmd->tvc_tag = v_req->tag; |
431 | tv_cmd->tvc_task_attr = v_req->task_attr; | 434 | tv_cmd->tvc_task_attr = v_req->task_attr; |
432 | tv_cmd->tvc_exp_data_len = exp_data_len; | 435 | tv_cmd->tvc_exp_data_len = exp_data_len; |
@@ -442,40 +445,47 @@ static struct tcm_vhost_cmd *vhost_scsi_allocate_cmd( | |||
442 | * Returns the number of scatterlist entries used or -errno on error. | 445 | * Returns the number of scatterlist entries used or -errno on error. |
443 | */ | 446 | */ |
444 | static int vhost_scsi_map_to_sgl(struct scatterlist *sgl, | 447 | static int vhost_scsi_map_to_sgl(struct scatterlist *sgl, |
445 | unsigned int sgl_count, void __user *ptr, size_t len, int write) | 448 | unsigned int sgl_count, struct iovec *iov, int write) |
446 | { | 449 | { |
450 | unsigned int npages = 0, pages_nr, offset, nbytes; | ||
447 | struct scatterlist *sg = sgl; | 451 | struct scatterlist *sg = sgl; |
448 | unsigned int npages = 0; | 452 | void __user *ptr = iov->iov_base; |
449 | int ret; | 453 | size_t len = iov->iov_len; |
454 | struct page **pages; | ||
455 | int ret, i; | ||
450 | 456 | ||
451 | while (len > 0) { | 457 | pages_nr = iov_num_pages(iov); |
452 | struct page *page; | 458 | if (pages_nr > sgl_count) |
453 | unsigned int offset = (uintptr_t)ptr & ~PAGE_MASK; | 459 | return -ENOBUFS; |
454 | unsigned int nbytes = min_t(unsigned int, | ||
455 | PAGE_SIZE - offset, len); | ||
456 | 460 | ||
457 | if (npages == sgl_count) { | 461 | pages = kmalloc(pages_nr * sizeof(struct page *), GFP_KERNEL); |
458 | ret = -ENOBUFS; | 462 | if (!pages) |
459 | goto err; | 463 | return -ENOMEM; |
460 | } | ||
461 | 464 | ||
462 | ret = get_user_pages_fast((unsigned long)ptr, 1, write, &page); | 465 | ret = get_user_pages_fast((unsigned long)ptr, pages_nr, write, pages); |
463 | BUG_ON(ret == 0); /* we should either get our page or fail */ | 466 | /* No pages were pinned */ |
464 | if (ret < 0) | 467 | if (ret < 0) |
465 | goto err; | 468 | goto out; |
469 | /* Less pages pinned than wanted */ | ||
470 | if (ret != pages_nr) { | ||
471 | for (i = 0; i < ret; i++) | ||
472 | put_page(pages[i]); | ||
473 | ret = -EFAULT; | ||
474 | goto out; | ||
475 | } | ||
466 | 476 | ||
467 | sg_set_page(sg, page, nbytes, offset); | 477 | while (len > 0) { |
478 | offset = (uintptr_t)ptr & ~PAGE_MASK; | ||
479 | nbytes = min_t(unsigned int, PAGE_SIZE - offset, len); | ||
480 | sg_set_page(sg, pages[npages], nbytes, offset); | ||
468 | ptr += nbytes; | 481 | ptr += nbytes; |
469 | len -= nbytes; | 482 | len -= nbytes; |
470 | sg++; | 483 | sg++; |
471 | npages++; | 484 | npages++; |
472 | } | 485 | } |
473 | return npages; | ||
474 | 486 | ||
475 | err: | 487 | out: |
476 | /* Put pages that we hold */ | 488 | kfree(pages); |
477 | for (sg = sgl; sg != &sgl[npages]; sg++) | ||
478 | put_page(sg_page(sg)); | ||
479 | return ret; | 489 | return ret; |
480 | } | 490 | } |
481 | 491 | ||
@@ -491,11 +501,9 @@ static int vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *tv_cmd, | |||
491 | * Find out how long sglist needs to be | 501 | * Find out how long sglist needs to be |
492 | */ | 502 | */ |
493 | sgl_count = 0; | 503 | sgl_count = 0; |
494 | for (i = 0; i < niov; i++) { | 504 | for (i = 0; i < niov; i++) |
495 | sgl_count += (((uintptr_t)iov[i].iov_base + iov[i].iov_len + | 505 | sgl_count += iov_num_pages(&iov[i]); |
496 | PAGE_SIZE - 1) >> PAGE_SHIFT) - | 506 | |
497 | ((uintptr_t)iov[i].iov_base >> PAGE_SHIFT); | ||
498 | } | ||
499 | /* TODO overflow checking */ | 507 | /* TODO overflow checking */ |
500 | 508 | ||
501 | sg = kmalloc(sizeof(tv_cmd->tvc_sgl[0]) * sgl_count, GFP_ATOMIC); | 509 | sg = kmalloc(sizeof(tv_cmd->tvc_sgl[0]) * sgl_count, GFP_ATOMIC); |
@@ -510,8 +518,7 @@ static int vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *tv_cmd, | |||
510 | 518 | ||
511 | pr_debug("Mapping %u iovecs for %u pages\n", niov, sgl_count); | 519 | pr_debug("Mapping %u iovecs for %u pages\n", niov, sgl_count); |
512 | for (i = 0; i < niov; i++) { | 520 | for (i = 0; i < niov; i++) { |
513 | ret = vhost_scsi_map_to_sgl(sg, sgl_count, iov[i].iov_base, | 521 | ret = vhost_scsi_map_to_sgl(sg, sgl_count, &iov[i], write); |
514 | iov[i].iov_len, write); | ||
515 | if (ret < 0) { | 522 | if (ret < 0) { |
516 | for (i = 0; i < tv_cmd->tvc_sgl_count; i++) | 523 | for (i = 0; i < tv_cmd->tvc_sgl_count; i++) |
517 | put_page(sg_page(&tv_cmd->tvc_sgl[i])); | 524 | put_page(sg_page(&tv_cmd->tvc_sgl[i])); |
@@ -563,19 +570,19 @@ static void tcm_vhost_submission_work(struct work_struct *work) | |||
563 | } | 570 | } |
564 | } | 571 | } |
565 | 572 | ||
566 | static void vhost_scsi_handle_vq(struct vhost_scsi *vs) | 573 | static void vhost_scsi_handle_vq(struct vhost_scsi *vs, |
574 | struct vhost_virtqueue *vq) | ||
567 | { | 575 | { |
568 | struct vhost_virtqueue *vq = &vs->vqs[2]; | ||
569 | struct virtio_scsi_cmd_req v_req; | 576 | struct virtio_scsi_cmd_req v_req; |
570 | struct tcm_vhost_tpg *tv_tpg; | 577 | struct tcm_vhost_tpg *tv_tpg; |
571 | struct tcm_vhost_cmd *tv_cmd; | 578 | struct tcm_vhost_cmd *tv_cmd; |
572 | u32 exp_data_len, data_first, data_num, data_direction; | 579 | u32 exp_data_len, data_first, data_num, data_direction; |
573 | unsigned out, in, i; | 580 | unsigned out, in, i; |
574 | int head, ret; | 581 | int head, ret; |
582 | u8 target; | ||
575 | 583 | ||
576 | /* Must use ioctl VHOST_SCSI_SET_ENDPOINT */ | 584 | /* Must use ioctl VHOST_SCSI_SET_ENDPOINT */ |
577 | tv_tpg = vs->vs_tpg; | 585 | if (unlikely(!vs->vs_endpoint)) |
578 | if (unlikely(!tv_tpg)) | ||
579 | return; | 586 | return; |
580 | 587 | ||
581 | mutex_lock(&vq->mutex); | 588 | mutex_lock(&vq->mutex); |
@@ -643,6 +650,28 @@ static void vhost_scsi_handle_vq(struct vhost_scsi *vs) | |||
643 | break; | 650 | break; |
644 | } | 651 | } |
645 | 652 | ||
653 | /* Extract the tpgt */ | ||
654 | target = v_req.lun[1]; | ||
655 | tv_tpg = vs->vs_tpg[target]; | ||
656 | |||
657 | /* Target does not exist, fail the request */ | ||
658 | if (unlikely(!tv_tpg)) { | ||
659 | struct virtio_scsi_cmd_resp __user *resp; | ||
660 | struct virtio_scsi_cmd_resp rsp; | ||
661 | |||
662 | memset(&rsp, 0, sizeof(rsp)); | ||
663 | rsp.response = VIRTIO_SCSI_S_BAD_TARGET; | ||
664 | resp = vq->iov[out].iov_base; | ||
665 | ret = __copy_to_user(resp, &rsp, sizeof(rsp)); | ||
666 | if (!ret) | ||
667 | vhost_add_used_and_signal(&vs->dev, | ||
668 | vq, head, 0); | ||
669 | else | ||
670 | pr_err("Faulted on virtio_scsi_cmd_resp\n"); | ||
671 | |||
672 | continue; | ||
673 | } | ||
674 | |||
646 | exp_data_len = 0; | 675 | exp_data_len = 0; |
647 | for (i = 0; i < data_num; i++) | 676 | for (i = 0; i < data_num; i++) |
648 | exp_data_len += vq->iov[data_first + i].iov_len; | 677 | exp_data_len += vq->iov[data_first + i].iov_len; |
@@ -658,6 +687,7 @@ static void vhost_scsi_handle_vq(struct vhost_scsi *vs) | |||
658 | ": %d\n", tv_cmd, exp_data_len, data_direction); | 687 | ": %d\n", tv_cmd, exp_data_len, data_direction); |
659 | 688 | ||
660 | tv_cmd->tvc_vhost = vs; | 689 | tv_cmd->tvc_vhost = vs; |
690 | tv_cmd->tvc_vq = vq; | ||
661 | 691 | ||
662 | if (unlikely(vq->iov[out].iov_len != | 692 | if (unlikely(vq->iov[out].iov_len != |
663 | sizeof(struct virtio_scsi_cmd_resp))) { | 693 | sizeof(struct virtio_scsi_cmd_resp))) { |
@@ -738,7 +768,7 @@ static void vhost_scsi_handle_kick(struct vhost_work *work) | |||
738 | poll.work); | 768 | poll.work); |
739 | struct vhost_scsi *vs = container_of(vq->dev, struct vhost_scsi, dev); | 769 | struct vhost_scsi *vs = container_of(vq->dev, struct vhost_scsi, dev); |
740 | 770 | ||
741 | vhost_scsi_handle_vq(vs); | 771 | vhost_scsi_handle_vq(vs, vq); |
742 | } | 772 | } |
743 | 773 | ||
744 | /* | 774 | /* |
@@ -751,7 +781,8 @@ static int vhost_scsi_set_endpoint( | |||
751 | { | 781 | { |
752 | struct tcm_vhost_tport *tv_tport; | 782 | struct tcm_vhost_tport *tv_tport; |
753 | struct tcm_vhost_tpg *tv_tpg; | 783 | struct tcm_vhost_tpg *tv_tpg; |
754 | int index; | 784 | bool match = false; |
785 | int index, ret; | ||
755 | 786 | ||
756 | mutex_lock(&vs->dev.mutex); | 787 | mutex_lock(&vs->dev.mutex); |
757 | /* Verify that ring has been setup correctly. */ | 788 | /* Verify that ring has been setup correctly. */ |
@@ -762,7 +793,6 @@ static int vhost_scsi_set_endpoint( | |||
762 | return -EFAULT; | 793 | return -EFAULT; |
763 | } | 794 | } |
764 | } | 795 | } |
765 | mutex_unlock(&vs->dev.mutex); | ||
766 | 796 | ||
767 | mutex_lock(&tcm_vhost_mutex); | 797 | mutex_lock(&tcm_vhost_mutex); |
768 | list_for_each_entry(tv_tpg, &tcm_vhost_list, tv_tpg_list) { | 798 | list_for_each_entry(tv_tpg, &tcm_vhost_list, tv_tpg_list) { |
@@ -777,30 +807,33 @@ static int vhost_scsi_set_endpoint( | |||
777 | } | 807 | } |
778 | tv_tport = tv_tpg->tport; | 808 | tv_tport = tv_tpg->tport; |
779 | 809 | ||
780 | if (!strcmp(tv_tport->tport_name, t->vhost_wwpn) && | 810 | if (!strcmp(tv_tport->tport_name, t->vhost_wwpn)) { |
781 | (tv_tpg->tport_tpgt == t->vhost_tpgt)) { | 811 | if (vs->vs_tpg[tv_tpg->tport_tpgt]) { |
782 | tv_tpg->tv_tpg_vhost_count++; | ||
783 | mutex_unlock(&tv_tpg->tv_tpg_mutex); | ||
784 | mutex_unlock(&tcm_vhost_mutex); | ||
785 | |||
786 | mutex_lock(&vs->dev.mutex); | ||
787 | if (vs->vs_tpg) { | ||
788 | mutex_unlock(&vs->dev.mutex); | ||
789 | mutex_lock(&tv_tpg->tv_tpg_mutex); | ||
790 | tv_tpg->tv_tpg_vhost_count--; | ||
791 | mutex_unlock(&tv_tpg->tv_tpg_mutex); | 812 | mutex_unlock(&tv_tpg->tv_tpg_mutex); |
813 | mutex_unlock(&tcm_vhost_mutex); | ||
814 | mutex_unlock(&vs->dev.mutex); | ||
792 | return -EEXIST; | 815 | return -EEXIST; |
793 | } | 816 | } |
794 | 817 | tv_tpg->tv_tpg_vhost_count++; | |
795 | vs->vs_tpg = tv_tpg; | 818 | vs->vs_tpg[tv_tpg->tport_tpgt] = tv_tpg; |
796 | smp_mb__after_atomic_inc(); | 819 | smp_mb__after_atomic_inc(); |
797 | mutex_unlock(&vs->dev.mutex); | 820 | match = true; |
798 | return 0; | ||
799 | } | 821 | } |
800 | mutex_unlock(&tv_tpg->tv_tpg_mutex); | 822 | mutex_unlock(&tv_tpg->tv_tpg_mutex); |
801 | } | 823 | } |
802 | mutex_unlock(&tcm_vhost_mutex); | 824 | mutex_unlock(&tcm_vhost_mutex); |
803 | return -EINVAL; | 825 | |
826 | if (match) { | ||
827 | memcpy(vs->vs_vhost_wwpn, t->vhost_wwpn, | ||
828 | sizeof(vs->vs_vhost_wwpn)); | ||
829 | vs->vs_endpoint = true; | ||
830 | ret = 0; | ||
831 | } else { | ||
832 | ret = -EEXIST; | ||
833 | } | ||
834 | |||
835 | mutex_unlock(&vs->dev.mutex); | ||
836 | return ret; | ||
804 | } | 837 | } |
805 | 838 | ||
806 | static int vhost_scsi_clear_endpoint( | 839 | static int vhost_scsi_clear_endpoint( |
@@ -809,7 +842,8 @@ static int vhost_scsi_clear_endpoint( | |||
809 | { | 842 | { |
810 | struct tcm_vhost_tport *tv_tport; | 843 | struct tcm_vhost_tport *tv_tport; |
811 | struct tcm_vhost_tpg *tv_tpg; | 844 | struct tcm_vhost_tpg *tv_tpg; |
812 | int index, ret; | 845 | int index, ret, i; |
846 | u8 target; | ||
813 | 847 | ||
814 | mutex_lock(&vs->dev.mutex); | 848 | mutex_lock(&vs->dev.mutex); |
815 | /* Verify that ring has been setup correctly. */ | 849 | /* Verify that ring has been setup correctly. */ |
@@ -819,27 +853,32 @@ static int vhost_scsi_clear_endpoint( | |||
819 | goto err; | 853 | goto err; |
820 | } | 854 | } |
821 | } | 855 | } |
856 | for (i = 0; i < VHOST_SCSI_MAX_TARGET; i++) { | ||
857 | target = i; | ||
822 | 858 | ||
823 | if (!vs->vs_tpg) { | 859 | tv_tpg = vs->vs_tpg[target]; |
824 | ret = -ENODEV; | 860 | if (!tv_tpg) |
825 | goto err; | 861 | continue; |
826 | } | 862 | |
827 | tv_tpg = vs->vs_tpg; | 863 | tv_tport = tv_tpg->tport; |
828 | tv_tport = tv_tpg->tport; | 864 | if (!tv_tport) { |
829 | 865 | ret = -ENODEV; | |
830 | if (strcmp(tv_tport->tport_name, t->vhost_wwpn) || | 866 | goto err; |
831 | (tv_tpg->tport_tpgt != t->vhost_tpgt)) { | 867 | } |
832 | pr_warn("tv_tport->tport_name: %s, tv_tpg->tport_tpgt: %hu" | 868 | |
833 | " does not match t->vhost_wwpn: %s, t->vhost_tpgt: %hu\n", | 869 | if (strcmp(tv_tport->tport_name, t->vhost_wwpn)) { |
834 | tv_tport->tport_name, tv_tpg->tport_tpgt, | 870 | pr_warn("tv_tport->tport_name: %s, tv_tpg->tport_tpgt: %hu" |
835 | t->vhost_wwpn, t->vhost_tpgt); | 871 | " does not match t->vhost_wwpn: %s, t->vhost_tpgt: %hu\n", |
836 | ret = -EINVAL; | 872 | tv_tport->tport_name, tv_tpg->tport_tpgt, |
837 | goto err; | 873 | t->vhost_wwpn, t->vhost_tpgt); |
874 | ret = -EINVAL; | ||
875 | goto err; | ||
876 | } | ||
877 | tv_tpg->tv_tpg_vhost_count--; | ||
878 | vs->vs_tpg[target] = NULL; | ||
879 | vs->vs_endpoint = false; | ||
838 | } | 880 | } |
839 | tv_tpg->tv_tpg_vhost_count--; | ||
840 | vs->vs_tpg = NULL; | ||
841 | mutex_unlock(&vs->dev.mutex); | 881 | mutex_unlock(&vs->dev.mutex); |
842 | |||
843 | return 0; | 882 | return 0; |
844 | 883 | ||
845 | err: | 884 | err: |
@@ -850,20 +889,19 @@ err: | |||
850 | static int vhost_scsi_open(struct inode *inode, struct file *f) | 889 | static int vhost_scsi_open(struct inode *inode, struct file *f) |
851 | { | 890 | { |
852 | struct vhost_scsi *s; | 891 | struct vhost_scsi *s; |
853 | int r; | 892 | int r, i; |
854 | 893 | ||
855 | s = kzalloc(sizeof(*s), GFP_KERNEL); | 894 | s = kzalloc(sizeof(*s), GFP_KERNEL); |
856 | if (!s) | 895 | if (!s) |
857 | return -ENOMEM; | 896 | return -ENOMEM; |
858 | 897 | ||
859 | vhost_work_init(&s->vs_completion_work, vhost_scsi_complete_cmd_work); | 898 | vhost_work_init(&s->vs_completion_work, vhost_scsi_complete_cmd_work); |
860 | INIT_LIST_HEAD(&s->vs_completion_list); | ||
861 | spin_lock_init(&s->vs_completion_lock); | ||
862 | 899 | ||
863 | s->vqs[VHOST_SCSI_VQ_CTL].handle_kick = vhost_scsi_ctl_handle_kick; | 900 | s->vqs[VHOST_SCSI_VQ_CTL].handle_kick = vhost_scsi_ctl_handle_kick; |
864 | s->vqs[VHOST_SCSI_VQ_EVT].handle_kick = vhost_scsi_evt_handle_kick; | 901 | s->vqs[VHOST_SCSI_VQ_EVT].handle_kick = vhost_scsi_evt_handle_kick; |
865 | s->vqs[VHOST_SCSI_VQ_IO].handle_kick = vhost_scsi_handle_kick; | 902 | for (i = VHOST_SCSI_VQ_IO; i < VHOST_SCSI_MAX_VQ; i++) |
866 | r = vhost_dev_init(&s->dev, s->vqs, 3); | 903 | s->vqs[i].handle_kick = vhost_scsi_handle_kick; |
904 | r = vhost_dev_init(&s->dev, s->vqs, VHOST_SCSI_MAX_VQ); | ||
867 | if (r < 0) { | 905 | if (r < 0) { |
868 | kfree(s); | 906 | kfree(s); |
869 | return r; | 907 | return r; |
@@ -876,16 +914,12 @@ static int vhost_scsi_open(struct inode *inode, struct file *f) | |||
876 | static int vhost_scsi_release(struct inode *inode, struct file *f) | 914 | static int vhost_scsi_release(struct inode *inode, struct file *f) |
877 | { | 915 | { |
878 | struct vhost_scsi *s = f->private_data; | 916 | struct vhost_scsi *s = f->private_data; |
917 | struct vhost_scsi_target t; | ||
879 | 918 | ||
880 | if (s->vs_tpg && s->vs_tpg->tport) { | 919 | mutex_lock(&s->dev.mutex); |
881 | struct vhost_scsi_target backend; | 920 | memcpy(t.vhost_wwpn, s->vs_vhost_wwpn, sizeof(t.vhost_wwpn)); |
882 | 921 | mutex_unlock(&s->dev.mutex); | |
883 | memcpy(backend.vhost_wwpn, s->vs_tpg->tport->tport_name, | 922 | vhost_scsi_clear_endpoint(s, &t); |
884 | sizeof(backend.vhost_wwpn)); | ||
885 | backend.vhost_tpgt = s->vs_tpg->tport_tpgt; | ||
886 | vhost_scsi_clear_endpoint(s, &backend); | ||
887 | } | ||
888 | |||
889 | vhost_dev_stop(&s->dev); | 923 | vhost_dev_stop(&s->dev); |
890 | vhost_dev_cleanup(&s->dev, false); | 924 | vhost_dev_cleanup(&s->dev, false); |
891 | kfree(s); | 925 | kfree(s); |
@@ -899,9 +933,10 @@ static void vhost_scsi_flush_vq(struct vhost_scsi *vs, int index) | |||
899 | 933 | ||
900 | static void vhost_scsi_flush(struct vhost_scsi *vs) | 934 | static void vhost_scsi_flush(struct vhost_scsi *vs) |
901 | { | 935 | { |
902 | vhost_scsi_flush_vq(vs, VHOST_SCSI_VQ_CTL); | 936 | int i; |
903 | vhost_scsi_flush_vq(vs, VHOST_SCSI_VQ_EVT); | 937 | |
904 | vhost_scsi_flush_vq(vs, VHOST_SCSI_VQ_IO); | 938 | for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) |
939 | vhost_scsi_flush_vq(vs, i); | ||
905 | } | 940 | } |
906 | 941 | ||
907 | static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features) | 942 | static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features) |