| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * iSCSI Initiator over TCP/IP Data-Path |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 6 | 7 | * Copyright (C) 2005 - 2006 Mike Christie |
|---|
| 7 | 8 | * Copyright (C) 2006 Red Hat, Inc. All rights reserved. |
|---|
| 8 | 9 | * maintained by open-iscsi@googlegroups.com |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 11 | | - * it under the terms of the GNU General Public License as published |
|---|
| 12 | | - * by the Free Software Foundation; either version 2 of the License, or |
|---|
| 13 | | - * (at your option) any later version. |
|---|
| 14 | | - * |
|---|
| 15 | | - * This program is distributed in the hope that it will be useful, but |
|---|
| 16 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 17 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 18 | | - * General Public License for more details. |
|---|
| 19 | 10 | * |
|---|
| 20 | 11 | * See the file COPYING included with this distribution for more details. |
|---|
| 21 | 12 | * |
|---|
| .. | .. |
|---|
| 44 | 35 | #include <scsi/scsi_host.h> |
|---|
| 45 | 36 | #include <scsi/scsi.h> |
|---|
| 46 | 37 | #include <scsi/scsi_transport_iscsi.h> |
|---|
| 38 | +#include <trace/events/iscsi.h> |
|---|
| 47 | 39 | |
|---|
| 48 | 40 | #include "iscsi_tcp.h" |
|---|
| 49 | 41 | |
|---|
| .. | .. |
|---|
| 72 | 64 | iscsi_conn_printk(KERN_INFO, _conn, \ |
|---|
| 73 | 65 | "%s " dbg_fmt, \ |
|---|
| 74 | 66 | __func__, ##arg); \ |
|---|
| 67 | + iscsi_dbg_trace(trace_iscsi_dbg_sw_tcp, \ |
|---|
| 68 | + &(_conn)->cls_conn->dev, \ |
|---|
| 69 | + "%s " dbg_fmt, __func__, ##arg);\ |
|---|
| 75 | 70 | } while (0); |
|---|
| 76 | 71 | |
|---|
| 77 | 72 | |
|---|
| .. | .. |
|---|
| 522 | 517 | if (!task->sc) |
|---|
| 523 | 518 | iscsi_sw_tcp_send_linear_data_prep(conn, task->data, count); |
|---|
| 524 | 519 | else { |
|---|
| 525 | | - struct scsi_data_buffer *sdb = scsi_out(task->sc); |
|---|
| 520 | + struct scsi_data_buffer *sdb = &task->sc->sdb; |
|---|
| 526 | 521 | |
|---|
| 527 | 522 | err = iscsi_sw_tcp_send_data_prep(conn, sdb->table.sgl, |
|---|
| 528 | 523 | sdb->table.nents, offset, |
|---|
| .. | .. |
|---|
| 563 | 558 | tcp_conn = conn->dd_data; |
|---|
| 564 | 559 | tcp_sw_conn = tcp_conn->dd_data; |
|---|
| 565 | 560 | |
|---|
| 561 | + mutex_init(&tcp_sw_conn->sock_lock); |
|---|
| 562 | + |
|---|
| 566 | 563 | tfm = crypto_alloc_ahash("crc32c", 0, CRYPTO_ALG_ASYNC); |
|---|
| 567 | 564 | if (IS_ERR(tfm)) |
|---|
| 568 | 565 | goto free_conn; |
|---|
| .. | .. |
|---|
| 597 | 594 | |
|---|
| 598 | 595 | static void iscsi_sw_tcp_release_conn(struct iscsi_conn *conn) |
|---|
| 599 | 596 | { |
|---|
| 600 | | - struct iscsi_session *session = conn->session; |
|---|
| 601 | 597 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
|---|
| 602 | 598 | struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; |
|---|
| 603 | 599 | struct socket *sock = tcp_sw_conn->sock; |
|---|
| 604 | 600 | |
|---|
| 601 | + /* |
|---|
| 602 | + * The iscsi transport class will make sure we are not called in |
|---|
| 603 | + * parallel with start, stop, bind and destroys. However, this can be |
|---|
| 604 | + * called twice if userspace does a stop then a destroy. |
|---|
| 605 | + */ |
|---|
| 605 | 606 | if (!sock) |
|---|
| 606 | 607 | return; |
|---|
| 607 | 608 | |
|---|
| .. | .. |
|---|
| 609 | 610 | iscsi_sw_tcp_conn_restore_callbacks(conn); |
|---|
| 610 | 611 | sock_put(sock->sk); |
|---|
| 611 | 612 | |
|---|
| 612 | | - spin_lock_bh(&session->frwd_lock); |
|---|
| 613 | + mutex_lock(&tcp_sw_conn->sock_lock); |
|---|
| 613 | 614 | tcp_sw_conn->sock = NULL; |
|---|
| 614 | | - spin_unlock_bh(&session->frwd_lock); |
|---|
| 615 | + mutex_unlock(&tcp_sw_conn->sock_lock); |
|---|
| 615 | 616 | sockfd_put(sock); |
|---|
| 616 | 617 | } |
|---|
| 617 | 618 | |
|---|
| .. | .. |
|---|
| 663 | 664 | struct iscsi_cls_conn *cls_conn, uint64_t transport_eph, |
|---|
| 664 | 665 | int is_leading) |
|---|
| 665 | 666 | { |
|---|
| 666 | | - struct iscsi_session *session = cls_session->dd_data; |
|---|
| 667 | 667 | struct iscsi_conn *conn = cls_conn->dd_data; |
|---|
| 668 | 668 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
|---|
| 669 | 669 | struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; |
|---|
| .. | .. |
|---|
| 683 | 683 | if (err) |
|---|
| 684 | 684 | goto free_socket; |
|---|
| 685 | 685 | |
|---|
| 686 | | - spin_lock_bh(&session->frwd_lock); |
|---|
| 686 | + mutex_lock(&tcp_sw_conn->sock_lock); |
|---|
| 687 | 687 | /* bind iSCSI connection and socket */ |
|---|
| 688 | 688 | tcp_sw_conn->sock = sock; |
|---|
| 689 | | - spin_unlock_bh(&session->frwd_lock); |
|---|
| 689 | + mutex_unlock(&tcp_sw_conn->sock_lock); |
|---|
| 690 | 690 | |
|---|
| 691 | 691 | /* setup Socket parameters */ |
|---|
| 692 | 692 | sk = sock->sk; |
|---|
| .. | .. |
|---|
| 722 | 722 | break; |
|---|
| 723 | 723 | case ISCSI_PARAM_DATADGST_EN: |
|---|
| 724 | 724 | iscsi_set_param(cls_conn, param, buf, buflen); |
|---|
| 725 | + |
|---|
| 726 | + mutex_lock(&tcp_sw_conn->sock_lock); |
|---|
| 727 | + if (!tcp_sw_conn->sock) { |
|---|
| 728 | + mutex_unlock(&tcp_sw_conn->sock_lock); |
|---|
| 729 | + return -ENOTCONN; |
|---|
| 730 | + } |
|---|
| 725 | 731 | tcp_sw_conn->sendpage = conn->datadgst_en ? |
|---|
| 726 | 732 | sock_no_sendpage : tcp_sw_conn->sock->ops->sendpage; |
|---|
| 733 | + mutex_unlock(&tcp_sw_conn->sock_lock); |
|---|
| 727 | 734 | break; |
|---|
| 728 | 735 | case ISCSI_PARAM_MAX_R2T: |
|---|
| 729 | 736 | return iscsi_tcp_set_max_r2t(conn, buf); |
|---|
| .. | .. |
|---|
| 738 | 745 | enum iscsi_param param, char *buf) |
|---|
| 739 | 746 | { |
|---|
| 740 | 747 | struct iscsi_conn *conn = cls_conn->dd_data; |
|---|
| 741 | | - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
|---|
| 742 | | - struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; |
|---|
| 748 | + struct iscsi_sw_tcp_conn *tcp_sw_conn; |
|---|
| 749 | + struct iscsi_tcp_conn *tcp_conn; |
|---|
| 743 | 750 | struct sockaddr_in6 addr; |
|---|
| 751 | + struct socket *sock; |
|---|
| 744 | 752 | int rc; |
|---|
| 745 | 753 | |
|---|
| 746 | 754 | switch(param) { |
|---|
| .. | .. |
|---|
| 748 | 756 | case ISCSI_PARAM_CONN_ADDRESS: |
|---|
| 749 | 757 | case ISCSI_PARAM_LOCAL_PORT: |
|---|
| 750 | 758 | spin_lock_bh(&conn->session->frwd_lock); |
|---|
| 751 | | - if (!tcp_sw_conn || !tcp_sw_conn->sock) { |
|---|
| 759 | + if (!conn->session->leadconn) { |
|---|
| 752 | 760 | spin_unlock_bh(&conn->session->frwd_lock); |
|---|
| 753 | 761 | return -ENOTCONN; |
|---|
| 754 | 762 | } |
|---|
| 763 | + /* |
|---|
| 764 | + * The conn has been setup and bound, so just grab a ref |
|---|
| 765 | + * incase a destroy runs while we are in the net layer. |
|---|
| 766 | + */ |
|---|
| 767 | + iscsi_get_conn(conn->cls_conn); |
|---|
| 768 | + spin_unlock_bh(&conn->session->frwd_lock); |
|---|
| 769 | + |
|---|
| 770 | + tcp_conn = conn->dd_data; |
|---|
| 771 | + tcp_sw_conn = tcp_conn->dd_data; |
|---|
| 772 | + |
|---|
| 773 | + mutex_lock(&tcp_sw_conn->sock_lock); |
|---|
| 774 | + sock = tcp_sw_conn->sock; |
|---|
| 775 | + if (!sock) { |
|---|
| 776 | + rc = -ENOTCONN; |
|---|
| 777 | + goto sock_unlock; |
|---|
| 778 | + } |
|---|
| 779 | + |
|---|
| 755 | 780 | if (param == ISCSI_PARAM_LOCAL_PORT) |
|---|
| 756 | | - rc = kernel_getsockname(tcp_sw_conn->sock, |
|---|
| 781 | + rc = kernel_getsockname(sock, |
|---|
| 757 | 782 | (struct sockaddr *)&addr); |
|---|
| 758 | 783 | else |
|---|
| 759 | | - rc = kernel_getpeername(tcp_sw_conn->sock, |
|---|
| 784 | + rc = kernel_getpeername(sock, |
|---|
| 760 | 785 | (struct sockaddr *)&addr); |
|---|
| 761 | | - spin_unlock_bh(&conn->session->frwd_lock); |
|---|
| 786 | +sock_unlock: |
|---|
| 787 | + mutex_unlock(&tcp_sw_conn->sock_lock); |
|---|
| 788 | + iscsi_put_conn(conn->cls_conn); |
|---|
| 762 | 789 | if (rc < 0) |
|---|
| 763 | 790 | return rc; |
|---|
| 764 | 791 | |
|---|
| .. | .. |
|---|
| 780 | 807 | struct iscsi_tcp_conn *tcp_conn; |
|---|
| 781 | 808 | struct iscsi_sw_tcp_conn *tcp_sw_conn; |
|---|
| 782 | 809 | struct sockaddr_in6 addr; |
|---|
| 810 | + struct socket *sock; |
|---|
| 783 | 811 | int rc; |
|---|
| 784 | 812 | |
|---|
| 785 | 813 | switch (param) { |
|---|
| .. | .. |
|---|
| 794 | 822 | return -ENOTCONN; |
|---|
| 795 | 823 | } |
|---|
| 796 | 824 | tcp_conn = conn->dd_data; |
|---|
| 797 | | - |
|---|
| 798 | 825 | tcp_sw_conn = tcp_conn->dd_data; |
|---|
| 799 | | - if (!tcp_sw_conn->sock) { |
|---|
| 800 | | - spin_unlock_bh(&session->frwd_lock); |
|---|
| 801 | | - return -ENOTCONN; |
|---|
| 802 | | - } |
|---|
| 803 | | - |
|---|
| 804 | | - rc = kernel_getsockname(tcp_sw_conn->sock, |
|---|
| 805 | | - (struct sockaddr *)&addr); |
|---|
| 826 | + /* |
|---|
| 827 | + * The conn has been setup and bound, so just grab a ref |
|---|
| 828 | + * incase a destroy runs while we are in the net layer. |
|---|
| 829 | + */ |
|---|
| 830 | + iscsi_get_conn(conn->cls_conn); |
|---|
| 806 | 831 | spin_unlock_bh(&session->frwd_lock); |
|---|
| 832 | + |
|---|
| 833 | + mutex_lock(&tcp_sw_conn->sock_lock); |
|---|
| 834 | + sock = tcp_sw_conn->sock; |
|---|
| 835 | + if (!sock) |
|---|
| 836 | + rc = -ENOTCONN; |
|---|
| 837 | + else |
|---|
| 838 | + rc = kernel_getsockname(sock, (struct sockaddr *)&addr); |
|---|
| 839 | + mutex_unlock(&tcp_sw_conn->sock_lock); |
|---|
| 840 | + iscsi_put_conn(conn->cls_conn); |
|---|
| 807 | 841 | if (rc < 0) |
|---|
| 808 | 842 | return rc; |
|---|
| 809 | 843 | |
|---|
| .. | .. |
|---|
| 960 | 994 | return 0; |
|---|
| 961 | 995 | } |
|---|
| 962 | 996 | |
|---|
| 963 | | -static int iscsi_sw_tcp_slave_alloc(struct scsi_device *sdev) |
|---|
| 964 | | -{ |
|---|
| 965 | | - blk_queue_flag_set(QUEUE_FLAG_BIDI, sdev->request_queue); |
|---|
| 966 | | - return 0; |
|---|
| 967 | | -} |
|---|
| 968 | | - |
|---|
| 969 | 997 | static int iscsi_sw_tcp_slave_configure(struct scsi_device *sdev) |
|---|
| 970 | 998 | { |
|---|
| 971 | 999 | struct iscsi_sw_tcp_host *tcp_sw_host = iscsi_host_priv(sdev->host); |
|---|
| .. | .. |
|---|
| 973 | 1001 | struct iscsi_conn *conn = session->leadconn; |
|---|
| 974 | 1002 | |
|---|
| 975 | 1003 | if (conn->datadgst_en) |
|---|
| 976 | | - sdev->request_queue->backing_dev_info->capabilities |
|---|
| 977 | | - |= BDI_CAP_STABLE_WRITES; |
|---|
| 1004 | + blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, |
|---|
| 1005 | + sdev->request_queue); |
|---|
| 978 | 1006 | blk_queue_dma_alignment(sdev->request_queue, 0); |
|---|
| 979 | 1007 | return 0; |
|---|
| 980 | 1008 | } |
|---|
| .. | .. |
|---|
| 992 | 1020 | .eh_abort_handler = iscsi_eh_abort, |
|---|
| 993 | 1021 | .eh_device_reset_handler= iscsi_eh_device_reset, |
|---|
| 994 | 1022 | .eh_target_reset_handler = iscsi_eh_recover_target, |
|---|
| 995 | | - .use_clustering = DISABLE_CLUSTERING, |
|---|
| 996 | | - .slave_alloc = iscsi_sw_tcp_slave_alloc, |
|---|
| 1023 | + .dma_boundary = PAGE_SIZE - 1, |
|---|
| 997 | 1024 | .slave_configure = iscsi_sw_tcp_slave_configure, |
|---|
| 998 | 1025 | .target_alloc = iscsi_target_alloc, |
|---|
| 999 | 1026 | .proc_name = "iscsi_tcp", |
|---|