diff options
Diffstat (limited to 'drivers/scsi/iscsi_tcp.c')
-rw-r--r-- | drivers/scsi/iscsi_tcp.c | 127 |
1 files changed, 98 insertions, 29 deletions
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 7ce177e30a53..da66fb524b5b 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c | |||
@@ -1870,18 +1870,22 @@ tcp_conn_alloc_fail: | |||
1870 | static void | 1870 | static void |
1871 | iscsi_tcp_release_conn(struct iscsi_conn *conn) | 1871 | iscsi_tcp_release_conn(struct iscsi_conn *conn) |
1872 | { | 1872 | { |
1873 | struct iscsi_session *session = conn->session; | ||
1873 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | 1874 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
1875 | struct socket *sock = tcp_conn->sock; | ||
1874 | 1876 | ||
1875 | if (!tcp_conn->sock) | 1877 | if (!sock) |
1876 | return; | 1878 | return; |
1877 | 1879 | ||
1878 | sock_hold(tcp_conn->sock->sk); | 1880 | sock_hold(sock->sk); |
1879 | iscsi_conn_restore_callbacks(tcp_conn); | 1881 | iscsi_conn_restore_callbacks(tcp_conn); |
1880 | sock_put(tcp_conn->sock->sk); | 1882 | sock_put(sock->sk); |
1881 | 1883 | ||
1882 | sockfd_put(tcp_conn->sock); | 1884 | spin_lock_bh(&session->lock); |
1883 | tcp_conn->sock = NULL; | 1885 | tcp_conn->sock = NULL; |
1884 | conn->recv_lock = NULL; | 1886 | conn->recv_lock = NULL; |
1887 | spin_unlock_bh(&session->lock); | ||
1888 | sockfd_put(sock); | ||
1885 | } | 1889 | } |
1886 | 1890 | ||
1887 | static void | 1891 | static void |
@@ -1912,6 +1916,46 @@ iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) | |||
1912 | tcp_conn->hdr_size = sizeof(struct iscsi_hdr); | 1916 | tcp_conn->hdr_size = sizeof(struct iscsi_hdr); |
1913 | } | 1917 | } |
1914 | 1918 | ||
1919 | static int iscsi_tcp_get_addr(struct iscsi_conn *conn, struct socket *sock, | ||
1920 | char *buf, int *port, | ||
1921 | int (*getname)(struct socket *, struct sockaddr *, | ||
1922 | int *addrlen)) | ||
1923 | { | ||
1924 | struct sockaddr_storage *addr; | ||
1925 | struct sockaddr_in6 *sin6; | ||
1926 | struct sockaddr_in *sin; | ||
1927 | int rc = 0, len; | ||
1928 | |||
1929 | addr = kmalloc(GFP_KERNEL, sizeof(*addr)); | ||
1930 | if (!addr) | ||
1931 | return -ENOMEM; | ||
1932 | |||
1933 | if (getname(sock, (struct sockaddr *) addr, &len)) { | ||
1934 | rc = -ENODEV; | ||
1935 | goto free_addr; | ||
1936 | } | ||
1937 | |||
1938 | switch (addr->ss_family) { | ||
1939 | case AF_INET: | ||
1940 | sin = (struct sockaddr_in *)addr; | ||
1941 | spin_lock_bh(&conn->session->lock); | ||
1942 | sprintf(buf, NIPQUAD_FMT, NIPQUAD(sin->sin_addr.s_addr)); | ||
1943 | *port = be16_to_cpu(sin->sin_port); | ||
1944 | spin_unlock_bh(&conn->session->lock); | ||
1945 | break; | ||
1946 | case AF_INET6: | ||
1947 | sin6 = (struct sockaddr_in6 *)addr; | ||
1948 | spin_lock_bh(&conn->session->lock); | ||
1949 | sprintf(buf, NIP6_FMT, NIP6(sin6->sin6_addr)); | ||
1950 | *port = be16_to_cpu(sin6->sin6_port); | ||
1951 | spin_unlock_bh(&conn->session->lock); | ||
1952 | break; | ||
1953 | } | ||
1954 | free_addr: | ||
1955 | kfree(addr); | ||
1956 | return rc; | ||
1957 | } | ||
1958 | |||
1915 | static int | 1959 | static int |
1916 | iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, | 1960 | iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, |
1917 | struct iscsi_cls_conn *cls_conn, uint64_t transport_eph, | 1961 | struct iscsi_cls_conn *cls_conn, uint64_t transport_eph, |
@@ -1929,10 +1973,24 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, | |||
1929 | printk(KERN_ERR "iscsi_tcp: sockfd_lookup failed %d\n", err); | 1973 | printk(KERN_ERR "iscsi_tcp: sockfd_lookup failed %d\n", err); |
1930 | return -EEXIST; | 1974 | return -EEXIST; |
1931 | } | 1975 | } |
1976 | /* | ||
1977 | * copy these values now because if we drop the session | ||
1978 | * userspace may still want to query the values since we will | ||
1979 | * be using them for the reconnect | ||
1980 | */ | ||
1981 | err = iscsi_tcp_get_addr(conn, sock, conn->portal_address, | ||
1982 | &conn->portal_port, kernel_getpeername); | ||
1983 | if (err) | ||
1984 | goto free_socket; | ||
1985 | |||
1986 | err = iscsi_tcp_get_addr(conn, sock, conn->local_address, | ||
1987 | &conn->local_port, kernel_getsockname); | ||
1988 | if (err) | ||
1989 | goto free_socket; | ||
1932 | 1990 | ||
1933 | err = iscsi_conn_bind(cls_session, cls_conn, is_leading); | 1991 | err = iscsi_conn_bind(cls_session, cls_conn, is_leading); |
1934 | if (err) | 1992 | if (err) |
1935 | return err; | 1993 | goto free_socket; |
1936 | 1994 | ||
1937 | /* bind iSCSI connection and socket */ | 1995 | /* bind iSCSI connection and socket */ |
1938 | tcp_conn->sock = sock; | 1996 | tcp_conn->sock = sock; |
@@ -1956,8 +2014,11 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, | |||
1956 | * set receive state machine into initial state | 2014 | * set receive state machine into initial state |
1957 | */ | 2015 | */ |
1958 | tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER; | 2016 | tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER; |
1959 | |||
1960 | return 0; | 2017 | return 0; |
2018 | |||
2019 | free_socket: | ||
2020 | sockfd_put(sock); | ||
2021 | return err; | ||
1961 | } | 2022 | } |
1962 | 2023 | ||
1963 | /* called with host lock */ | 2024 | /* called with host lock */ |
@@ -2077,33 +2138,18 @@ iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, | |||
2077 | enum iscsi_param param, char *buf) | 2138 | enum iscsi_param param, char *buf) |
2078 | { | 2139 | { |
2079 | struct iscsi_conn *conn = cls_conn->dd_data; | 2140 | struct iscsi_conn *conn = cls_conn->dd_data; |
2080 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | ||
2081 | struct inet_sock *inet; | ||
2082 | struct ipv6_pinfo *np; | ||
2083 | struct sock *sk; | ||
2084 | int len; | 2141 | int len; |
2085 | 2142 | ||
2086 | switch(param) { | 2143 | switch(param) { |
2087 | case ISCSI_PARAM_CONN_PORT: | 2144 | case ISCSI_PARAM_CONN_PORT: |
2088 | if (!tcp_conn->sock) | 2145 | spin_lock_bh(&conn->session->lock); |
2089 | return -EINVAL; | 2146 | len = sprintf(buf, "%hu\n", conn->portal_port); |
2090 | 2147 | spin_unlock_bh(&conn->session->lock); | |
2091 | inet = inet_sk(tcp_conn->sock->sk); | ||
2092 | len = sprintf(buf, "%hu\n", be16_to_cpu(inet->dport)); | ||
2093 | break; | 2148 | break; |
2094 | case ISCSI_PARAM_CONN_ADDRESS: | 2149 | case ISCSI_PARAM_CONN_ADDRESS: |
2095 | if (!tcp_conn->sock) | 2150 | spin_lock_bh(&conn->session->lock); |
2096 | return -EINVAL; | 2151 | len = sprintf(buf, "%s\n", conn->portal_address); |
2097 | 2152 | spin_unlock_bh(&conn->session->lock); | |
2098 | sk = tcp_conn->sock->sk; | ||
2099 | if (sk->sk_family == PF_INET) { | ||
2100 | inet = inet_sk(sk); | ||
2101 | len = sprintf(buf, NIPQUAD_FMT "\n", | ||
2102 | NIPQUAD(inet->daddr)); | ||
2103 | } else { | ||
2104 | np = inet6_sk(sk); | ||
2105 | len = sprintf(buf, NIP6_FMT "\n", NIP6(np->daddr)); | ||
2106 | } | ||
2107 | break; | 2153 | break; |
2108 | default: | 2154 | default: |
2109 | return iscsi_conn_get_param(cls_conn, param, buf); | 2155 | return iscsi_conn_get_param(cls_conn, param, buf); |
@@ -2112,6 +2158,29 @@ iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, | |||
2112 | return len; | 2158 | return len; |
2113 | } | 2159 | } |
2114 | 2160 | ||
2161 | static int | ||
2162 | iscsi_tcp_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, | ||
2163 | char *buf) | ||
2164 | { | ||
2165 | struct iscsi_session *session = iscsi_hostdata(shost->hostdata); | ||
2166 | int len; | ||
2167 | |||
2168 | switch (param) { | ||
2169 | case ISCSI_HOST_PARAM_IPADDRESS: | ||
2170 | spin_lock_bh(&session->lock); | ||
2171 | if (!session->leadconn) | ||
2172 | len = -ENODEV; | ||
2173 | else | ||
2174 | len = sprintf(buf, "%s\n", | ||
2175 | session->leadconn->local_address); | ||
2176 | spin_unlock_bh(&session->lock); | ||
2177 | break; | ||
2178 | default: | ||
2179 | return iscsi_host_get_param(shost, param, buf); | ||
2180 | } | ||
2181 | return len; | ||
2182 | } | ||
2183 | |||
2115 | static void | 2184 | static void |
2116 | iscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats) | 2185 | iscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats) |
2117 | { | 2186 | { |
@@ -2233,7 +2302,7 @@ static struct iscsi_transport iscsi_tcp_transport = { | |||
2233 | ISCSI_TARGET_NAME | ISCSI_TPGT | | 2302 | ISCSI_TARGET_NAME | ISCSI_TPGT | |
2234 | ISCSI_USERNAME | ISCSI_PASSWORD | | 2303 | ISCSI_USERNAME | ISCSI_PASSWORD | |
2235 | ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN, | 2304 | ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN, |
2236 | .host_param_mask = ISCSI_HOST_HWADDRESS | | 2305 | .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | |
2237 | ISCSI_HOST_INITIATOR_NAME, | 2306 | ISCSI_HOST_INITIATOR_NAME, |
2238 | .host_template = &iscsi_sht, | 2307 | .host_template = &iscsi_sht, |
2239 | .conndata_size = sizeof(struct iscsi_conn), | 2308 | .conndata_size = sizeof(struct iscsi_conn), |
@@ -2252,7 +2321,7 @@ static struct iscsi_transport iscsi_tcp_transport = { | |||
2252 | .start_conn = iscsi_conn_start, | 2321 | .start_conn = iscsi_conn_start, |
2253 | .stop_conn = iscsi_tcp_conn_stop, | 2322 | .stop_conn = iscsi_tcp_conn_stop, |
2254 | /* iscsi host params */ | 2323 | /* iscsi host params */ |
2255 | .get_host_param = iscsi_host_get_param, | 2324 | .get_host_param = iscsi_tcp_host_get_param, |
2256 | .set_host_param = iscsi_host_set_param, | 2325 | .set_host_param = iscsi_host_set_param, |
2257 | /* IO */ | 2326 | /* IO */ |
2258 | .send_pdu = iscsi_conn_send_pdu, | 2327 | .send_pdu = iscsi_conn_send_pdu, |