.. | .. |
---|
| 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; |
---|
.. | .. |
---|
721 | 721 | iscsi_set_param(cls_conn, param, buf, buflen); |
---|
722 | 722 | break; |
---|
723 | 723 | case ISCSI_PARAM_DATADGST_EN: |
---|
| 724 | + mutex_lock(&tcp_sw_conn->sock_lock); |
---|
| 725 | + if (!tcp_sw_conn->sock) { |
---|
| 726 | + mutex_unlock(&tcp_sw_conn->sock_lock); |
---|
| 727 | + return -ENOTCONN; |
---|
| 728 | + } |
---|
724 | 729 | iscsi_set_param(cls_conn, param, buf, buflen); |
---|
725 | 730 | tcp_sw_conn->sendpage = conn->datadgst_en ? |
---|
726 | 731 | sock_no_sendpage : tcp_sw_conn->sock->ops->sendpage; |
---|
| 732 | + mutex_unlock(&tcp_sw_conn->sock_lock); |
---|
727 | 733 | break; |
---|
728 | 734 | case ISCSI_PARAM_MAX_R2T: |
---|
729 | 735 | return iscsi_tcp_set_max_r2t(conn, buf); |
---|
.. | .. |
---|
738 | 744 | enum iscsi_param param, char *buf) |
---|
739 | 745 | { |
---|
740 | 746 | 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; |
---|
| 747 | + struct iscsi_sw_tcp_conn *tcp_sw_conn; |
---|
| 748 | + struct iscsi_tcp_conn *tcp_conn; |
---|
743 | 749 | struct sockaddr_in6 addr; |
---|
| 750 | + struct socket *sock; |
---|
744 | 751 | int rc; |
---|
745 | 752 | |
---|
746 | 753 | switch(param) { |
---|
.. | .. |
---|
748 | 755 | case ISCSI_PARAM_CONN_ADDRESS: |
---|
749 | 756 | case ISCSI_PARAM_LOCAL_PORT: |
---|
750 | 757 | spin_lock_bh(&conn->session->frwd_lock); |
---|
751 | | - if (!tcp_sw_conn || !tcp_sw_conn->sock) { |
---|
| 758 | + if (!conn->session->leadconn) { |
---|
752 | 759 | spin_unlock_bh(&conn->session->frwd_lock); |
---|
753 | 760 | return -ENOTCONN; |
---|
754 | 761 | } |
---|
| 762 | + /* |
---|
| 763 | + * The conn has been setup and bound, so just grab a ref |
---|
| 764 | + * incase a destroy runs while we are in the net layer. |
---|
| 765 | + */ |
---|
| 766 | + iscsi_get_conn(conn->cls_conn); |
---|
| 767 | + spin_unlock_bh(&conn->session->frwd_lock); |
---|
| 768 | + |
---|
| 769 | + tcp_conn = conn->dd_data; |
---|
| 770 | + tcp_sw_conn = tcp_conn->dd_data; |
---|
| 771 | + |
---|
| 772 | + mutex_lock(&tcp_sw_conn->sock_lock); |
---|
| 773 | + sock = tcp_sw_conn->sock; |
---|
| 774 | + if (!sock) { |
---|
| 775 | + rc = -ENOTCONN; |
---|
| 776 | + goto sock_unlock; |
---|
| 777 | + } |
---|
| 778 | + |
---|
755 | 779 | if (param == ISCSI_PARAM_LOCAL_PORT) |
---|
756 | | - rc = kernel_getsockname(tcp_sw_conn->sock, |
---|
| 780 | + rc = kernel_getsockname(sock, |
---|
757 | 781 | (struct sockaddr *)&addr); |
---|
758 | 782 | else |
---|
759 | | - rc = kernel_getpeername(tcp_sw_conn->sock, |
---|
| 783 | + rc = kernel_getpeername(sock, |
---|
760 | 784 | (struct sockaddr *)&addr); |
---|
761 | | - spin_unlock_bh(&conn->session->frwd_lock); |
---|
| 785 | +sock_unlock: |
---|
| 786 | + mutex_unlock(&tcp_sw_conn->sock_lock); |
---|
| 787 | + iscsi_put_conn(conn->cls_conn); |
---|
762 | 788 | if (rc < 0) |
---|
763 | 789 | return rc; |
---|
764 | 790 | |
---|
.. | .. |
---|
775 | 801 | enum iscsi_host_param param, char *buf) |
---|
776 | 802 | { |
---|
777 | 803 | struct iscsi_sw_tcp_host *tcp_sw_host = iscsi_host_priv(shost); |
---|
778 | | - struct iscsi_session *session = tcp_sw_host->session; |
---|
| 804 | + struct iscsi_session *session; |
---|
779 | 805 | struct iscsi_conn *conn; |
---|
780 | 806 | struct iscsi_tcp_conn *tcp_conn; |
---|
781 | 807 | struct iscsi_sw_tcp_conn *tcp_sw_conn; |
---|
782 | 808 | struct sockaddr_in6 addr; |
---|
| 809 | + struct socket *sock; |
---|
783 | 810 | int rc; |
---|
784 | 811 | |
---|
785 | 812 | switch (param) { |
---|
786 | 813 | case ISCSI_HOST_PARAM_IPADDRESS: |
---|
| 814 | + session = tcp_sw_host->session; |
---|
787 | 815 | if (!session) |
---|
788 | 816 | return -ENOTCONN; |
---|
789 | 817 | |
---|
.. | .. |
---|
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 | |
---|
.. | .. |
---|
872 | 906 | if (!cls_session) |
---|
873 | 907 | goto remove_host; |
---|
874 | 908 | session = cls_session->dd_data; |
---|
875 | | - tcp_sw_host = iscsi_host_priv(shost); |
---|
876 | | - tcp_sw_host->session = session; |
---|
877 | 909 | |
---|
878 | 910 | shost->can_queue = session->scsi_cmds_max; |
---|
879 | 911 | if (iscsi_tcp_r2tpool_alloc(session)) |
---|
880 | 912 | goto remove_session; |
---|
| 913 | + |
---|
| 914 | + /* We are now fully setup so expose the session to sysfs. */ |
---|
| 915 | + tcp_sw_host = iscsi_host_priv(shost); |
---|
| 916 | + tcp_sw_host->session = session; |
---|
881 | 917 | return cls_session; |
---|
882 | 918 | |
---|
883 | 919 | remove_session: |
---|
.. | .. |
---|
960 | 996 | return 0; |
---|
961 | 997 | } |
---|
962 | 998 | |
---|
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 | 999 | static int iscsi_sw_tcp_slave_configure(struct scsi_device *sdev) |
---|
970 | 1000 | { |
---|
971 | 1001 | struct iscsi_sw_tcp_host *tcp_sw_host = iscsi_host_priv(sdev->host); |
---|
.. | .. |
---|
973 | 1003 | struct iscsi_conn *conn = session->leadconn; |
---|
974 | 1004 | |
---|
975 | 1005 | if (conn->datadgst_en) |
---|
976 | | - sdev->request_queue->backing_dev_info->capabilities |
---|
977 | | - |= BDI_CAP_STABLE_WRITES; |
---|
| 1006 | + blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, |
---|
| 1007 | + sdev->request_queue); |
---|
978 | 1008 | blk_queue_dma_alignment(sdev->request_queue, 0); |
---|
979 | 1009 | return 0; |
---|
980 | 1010 | } |
---|
.. | .. |
---|
992 | 1022 | .eh_abort_handler = iscsi_eh_abort, |
---|
993 | 1023 | .eh_device_reset_handler= iscsi_eh_device_reset, |
---|
994 | 1024 | .eh_target_reset_handler = iscsi_eh_recover_target, |
---|
995 | | - .use_clustering = DISABLE_CLUSTERING, |
---|
996 | | - .slave_alloc = iscsi_sw_tcp_slave_alloc, |
---|
| 1025 | + .dma_boundary = PAGE_SIZE - 1, |
---|
997 | 1026 | .slave_configure = iscsi_sw_tcp_slave_configure, |
---|
998 | 1027 | .target_alloc = iscsi_target_alloc, |
---|
999 | 1028 | .proc_name = "iscsi_tcp", |
---|