Blame view
drivers/scsi/iscsi_tcp.c
27.5 KB
7ba247138 [SCSI] open-iscsi... |
1 2 3 4 5 |
/* * iSCSI Initiator over TCP/IP Data-Path * * Copyright (C) 2004 Dmitry Yusupov * Copyright (C) 2004 Alex Aizman |
5bb0b55a3 [SCSI] iscsi: con... |
6 7 |
* Copyright (C) 2005 - 2006 Mike Christie * Copyright (C) 2006 Red Hat, Inc. All rights reserved. |
7ba247138 [SCSI] open-iscsi... |
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
* maintained by open-iscsi@googlegroups.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * See the file COPYING included with this distribution for more details. * * Credits: * Christoph Hellwig * FUJITA Tomonori * Arne Redlich * Zhenyu Wang */ #include <linux/types.h> |
7ba247138 [SCSI] open-iscsi... |
30 |
#include <linux/inet.h> |
5a0e3ad6a include cleanup: ... |
31 |
#include <linux/slab.h> |
4e7aba73f [SCSI] iscsi_tcp:... |
32 |
#include <linux/file.h> |
7ba247138 [SCSI] open-iscsi... |
33 34 35 36 37 |
#include <linux/blkdev.h> #include <linux/crypto.h> #include <linux/delay.h> #include <linux/kfifo.h> #include <linux/scatterlist.h> |
acf3368ff scsi: Fix up file... |
38 |
#include <linux/module.h> |
7ba247138 [SCSI] open-iscsi... |
39 40 |
#include <net/tcp.h> #include <scsi/scsi_cmnd.h> |
d1d81c01f [SCSI] iscsi_tcp:... |
41 |
#include <scsi/scsi_device.h> |
7ba247138 [SCSI] open-iscsi... |
42 43 44 45 46 |
#include <scsi/scsi_host.h> #include <scsi/scsi.h> #include <scsi/scsi_transport_iscsi.h> #include "iscsi_tcp.h" |
38e1a8f54 [SCSI] iscsi_tcp:... |
47 48 |
MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, " "Dmitry Yusupov <dmitry_yus@yahoo.com>, " |
7ba247138 [SCSI] open-iscsi... |
49 50 51 |
"Alex Aizman <itn780@yahoo.com>"); MODULE_DESCRIPTION("iSCSI/TCP data-path"); MODULE_LICENSE("GPL"); |
7ba247138 [SCSI] open-iscsi... |
52 |
|
38e1a8f54 [SCSI] iscsi_tcp:... |
53 54 55 |
static struct scsi_transport_template *iscsi_sw_tcp_scsi_transport; static struct scsi_host_template iscsi_sw_tcp_sht; static struct iscsi_transport iscsi_sw_tcp_transport; |
756135215 [SCSI] iscsi: rem... |
56 |
|
7ba247138 [SCSI] open-iscsi... |
57 58 |
static unsigned int iscsi_max_lun = 512; module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO); |
c93f87c72 [SCSI] iscsi_tcp:... |
59 60 61 62 63 64 65 66 67 68 69 70 71 |
static int iscsi_sw_tcp_dbg; module_param_named(debug_iscsi_tcp, iscsi_sw_tcp_dbg, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug_iscsi_tcp, "Turn on debugging for iscsi_tcp module " "Set to 1 to turn on, and zero to turn off. Default is off."); #define ISCSI_SW_TCP_DBG(_conn, dbg_fmt, arg...) \ do { \ if (iscsi_sw_tcp_dbg) \ iscsi_conn_printk(KERN_INFO, _conn, \ "%s " dbg_fmt, \ __func__, ##arg); \ } while (0); |
da32dd681 [SCSI] iscsi_tcp:... |
72 |
/** |
38e1a8f54 [SCSI] iscsi_tcp:... |
73 |
* iscsi_sw_tcp_recv - TCP receive in sendfile fashion |
63c62f1cb [SCSI] iscsi_tcp:... |
74 75 76 77 |
* @rd_desc: read descriptor * @skb: socket buffer * @offset: offset in skb * @len: skb->len - offset |
38e1a8f54 [SCSI] iscsi_tcp:... |
78 79 80 |
*/ static int iscsi_sw_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, unsigned int offset, size_t len) |
63c62f1cb [SCSI] iscsi_tcp:... |
81 82 83 84 |
{ struct iscsi_conn *conn = rd_desc->arg.data; unsigned int consumed, total_consumed = 0; int status; |
c93f87c72 [SCSI] iscsi_tcp:... |
85 86 |
ISCSI_SW_TCP_DBG(conn, "in %d bytes ", skb->len - offset); |
63c62f1cb [SCSI] iscsi_tcp:... |
87 88 89 90 91 92 93 |
do { status = 0; consumed = iscsi_tcp_recv_skb(conn, skb, offset, 0, &status); offset += consumed; total_consumed += consumed; } while (consumed != 0 && status != ISCSI_TCP_SKB_DONE); |
c93f87c72 [SCSI] iscsi_tcp:... |
94 95 96 |
ISCSI_SW_TCP_DBG(conn, "read %d bytes status %d ", skb->len - offset, status); |
63c62f1cb [SCSI] iscsi_tcp:... |
97 |
return total_consumed; |
7ba247138 [SCSI] open-iscsi... |
98 |
} |
523eeac67 [SCSI] iscsi_tcp:... |
99 100 101 102 103 104 105 |
/** * iscsi_sw_sk_state_check - check socket state * @sk: socket * * If the socket is in CLOSE or CLOSE_WAIT we should * not close the connection if there is still some * data pending. |
03adb5f91 [SCSI] iscsi_tcp:... |
106 107 |
* * Must be called with sk_callback_lock. |
523eeac67 [SCSI] iscsi_tcp:... |
108 109 110 |
*/ static inline int iscsi_sw_sk_state_check(struct sock *sk) { |
03adb5f91 [SCSI] iscsi_tcp:... |
111 |
struct iscsi_conn *conn = sk->sk_user_data; |
523eeac67 [SCSI] iscsi_tcp:... |
112 |
|
d1af8a328 [SCSI] iscsi_tcp:... |
113 114 115 116 117 118 119 |
if ((sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) && !atomic_read(&sk->sk_rmem_alloc)) { ISCSI_SW_TCP_DBG(conn, "TCP_CLOSE|TCP_CLOSE_WAIT "); iscsi_conn_failure(conn, ISCSI_ERR_TCP_CONN_CLOSE); return -ECONNRESET; } |
523eeac67 [SCSI] iscsi_tcp:... |
120 121 |
return 0; } |
38e1a8f54 [SCSI] iscsi_tcp:... |
122 |
static void iscsi_sw_tcp_data_ready(struct sock *sk, int flag) |
7ba247138 [SCSI] open-iscsi... |
123 |
{ |
03adb5f91 [SCSI] iscsi_tcp:... |
124 125 |
struct iscsi_conn *conn; struct iscsi_tcp_conn *tcp_conn; |
7ba247138 [SCSI] open-iscsi... |
126 127 128 |
read_descriptor_t rd_desc; read_lock(&sk->sk_callback_lock); |
03adb5f91 [SCSI] iscsi_tcp:... |
129 130 131 132 133 134 |
conn = sk->sk_user_data; if (!conn) { read_unlock(&sk->sk_callback_lock); return; } tcp_conn = conn->dd_data; |
7ba247138 [SCSI] open-iscsi... |
135 |
|
665b44aee [SCSI] iscsi: deq... |
136 |
/* |
da32dd681 [SCSI] iscsi_tcp:... |
137 |
* Use rd_desc to pass 'conn' to iscsi_tcp_recv. |
665b44aee [SCSI] iscsi: deq... |
138 |
* We set count to 1 because we want the network layer to |
da32dd681 [SCSI] iscsi_tcp:... |
139 |
* hand us all the skbs that are available. iscsi_tcp_recv |
665b44aee [SCSI] iscsi: deq... |
140 141 |
* handled pdus that cross buffers or pdus that still need data. */ |
7ba247138 [SCSI] open-iscsi... |
142 |
rd_desc.arg.data = conn; |
665b44aee [SCSI] iscsi: deq... |
143 |
rd_desc.count = 1; |
38e1a8f54 [SCSI] iscsi_tcp:... |
144 |
tcp_read_sock(sk, &rd_desc, iscsi_sw_tcp_recv); |
7ba247138 [SCSI] open-iscsi... |
145 |
|
d1af8a328 [SCSI] iscsi_tcp:... |
146 |
iscsi_sw_sk_state_check(sk); |
523eeac67 [SCSI] iscsi_tcp:... |
147 |
|
da32dd681 [SCSI] iscsi_tcp:... |
148 149 |
/* If we had to (atomically) map a highmem page, * unmap it now. */ |
a8ac6311c [SCSI] iscsi: con... |
150 |
iscsi_tcp_segment_unmap(&tcp_conn->in.segment); |
03adb5f91 [SCSI] iscsi_tcp:... |
151 |
read_unlock(&sk->sk_callback_lock); |
7ba247138 [SCSI] open-iscsi... |
152 |
} |
38e1a8f54 [SCSI] iscsi_tcp:... |
153 |
static void iscsi_sw_tcp_state_change(struct sock *sk) |
7ba247138 [SCSI] open-iscsi... |
154 |
{ |
5bb0b55a3 [SCSI] iscsi: con... |
155 |
struct iscsi_tcp_conn *tcp_conn; |
38e1a8f54 [SCSI] iscsi_tcp:... |
156 |
struct iscsi_sw_tcp_conn *tcp_sw_conn; |
7ba247138 [SCSI] open-iscsi... |
157 158 159 160 161 |
struct iscsi_conn *conn; struct iscsi_session *session; void (*old_state_change)(struct sock *); read_lock(&sk->sk_callback_lock); |
03adb5f91 [SCSI] iscsi_tcp:... |
162 163 164 165 166 |
conn = sk->sk_user_data; if (!conn) { read_unlock(&sk->sk_callback_lock); return; } |
7ba247138 [SCSI] open-iscsi... |
167 |
session = conn->session; |
d1af8a328 [SCSI] iscsi_tcp:... |
168 |
iscsi_sw_sk_state_check(sk); |
7ba247138 [SCSI] open-iscsi... |
169 |
|
5bb0b55a3 [SCSI] iscsi: con... |
170 |
tcp_conn = conn->dd_data; |
38e1a8f54 [SCSI] iscsi_tcp:... |
171 172 |
tcp_sw_conn = tcp_conn->dd_data; old_state_change = tcp_sw_conn->old_state_change; |
7ba247138 [SCSI] open-iscsi... |
173 174 175 176 177 178 179 180 181 182 |
read_unlock(&sk->sk_callback_lock); old_state_change(sk); } /** * iscsi_write_space - Called when more output buffer space is available * @sk: socket space is available for **/ |
38e1a8f54 [SCSI] iscsi_tcp:... |
183 |
static void iscsi_sw_tcp_write_space(struct sock *sk) |
7ba247138 [SCSI] open-iscsi... |
184 |
{ |
03adb5f91 [SCSI] iscsi_tcp:... |
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
struct iscsi_conn *conn; struct iscsi_tcp_conn *tcp_conn; struct iscsi_sw_tcp_conn *tcp_sw_conn; void (*old_write_space)(struct sock *); read_lock_bh(&sk->sk_callback_lock); conn = sk->sk_user_data; if (!conn) { read_unlock_bh(&sk->sk_callback_lock); return; } tcp_conn = conn->dd_data; tcp_sw_conn = tcp_conn->dd_data; old_write_space = tcp_sw_conn->old_write_space; read_unlock_bh(&sk->sk_callback_lock); old_write_space(sk); |
5bb0b55a3 [SCSI] iscsi: con... |
203 |
|
c93f87c72 [SCSI] iscsi_tcp:... |
204 205 |
ISCSI_SW_TCP_DBG(conn, "iscsi_write_space "); |
32ae763e3 [SCSI] iscsi lib:... |
206 |
iscsi_conn_queue_work(conn); |
7ba247138 [SCSI] open-iscsi... |
207 |
} |
38e1a8f54 [SCSI] iscsi_tcp:... |
208 |
static void iscsi_sw_tcp_conn_set_callbacks(struct iscsi_conn *conn) |
7ba247138 [SCSI] open-iscsi... |
209 |
{ |
5bb0b55a3 [SCSI] iscsi: con... |
210 |
struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
38e1a8f54 [SCSI] iscsi_tcp:... |
211 212 |
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; struct sock *sk = tcp_sw_conn->sock->sk; |
7ba247138 [SCSI] open-iscsi... |
213 214 215 216 |
/* assign new callbacks */ write_lock_bh(&sk->sk_callback_lock); sk->sk_user_data = conn; |
38e1a8f54 [SCSI] iscsi_tcp:... |
217 218 219 220 221 222 |
tcp_sw_conn->old_data_ready = sk->sk_data_ready; tcp_sw_conn->old_state_change = sk->sk_state_change; tcp_sw_conn->old_write_space = sk->sk_write_space; sk->sk_data_ready = iscsi_sw_tcp_data_ready; sk->sk_state_change = iscsi_sw_tcp_state_change; sk->sk_write_space = iscsi_sw_tcp_write_space; |
7ba247138 [SCSI] open-iscsi... |
223 224 |
write_unlock_bh(&sk->sk_callback_lock); } |
38e1a8f54 [SCSI] iscsi_tcp:... |
225 |
static void |
c484a50a4 [SCSI] iscsi_tcp:... |
226 |
iscsi_sw_tcp_conn_restore_callbacks(struct iscsi_conn *conn) |
7ba247138 [SCSI] open-iscsi... |
227 |
{ |
c484a50a4 [SCSI] iscsi_tcp:... |
228 229 |
struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; |
38e1a8f54 [SCSI] iscsi_tcp:... |
230 |
struct sock *sk = tcp_sw_conn->sock->sk; |
7ba247138 [SCSI] open-iscsi... |
231 232 233 234 |
/* restore socket callbacks, see also: iscsi_conn_set_callbacks() */ write_lock_bh(&sk->sk_callback_lock); sk->sk_user_data = NULL; |
38e1a8f54 [SCSI] iscsi_tcp:... |
235 236 237 |
sk->sk_data_ready = tcp_sw_conn->old_data_ready; sk->sk_state_change = tcp_sw_conn->old_state_change; sk->sk_write_space = tcp_sw_conn->old_write_space; |
7ba247138 [SCSI] open-iscsi... |
238 239 240 241 242 |
sk->sk_no_check = 0; write_unlock_bh(&sk->sk_callback_lock); } /** |
38e1a8f54 [SCSI] iscsi_tcp:... |
243 |
* iscsi_sw_tcp_xmit_segment - transmit segment |
6df19a791 [SCSI] libiscsi_t... |
244 |
* @tcp_conn: the iSCSI TCP connection |
38e1a8f54 [SCSI] iscsi_tcp:... |
245 246 247 248 249 250 251 252 253 254 |
* @segment: the buffer to transmnit * * This function transmits as much of the buffer as * the network layer will accept, and returns the number of * bytes transmitted. * * If CRC hashing is enabled, the function will compute the * hash as it goes. When the entire segment has been transmitted, * it will retrieve the hash value and send it as well. */ |
6df19a791 [SCSI] libiscsi_t... |
255 |
static int iscsi_sw_tcp_xmit_segment(struct iscsi_tcp_conn *tcp_conn, |
38e1a8f54 [SCSI] iscsi_tcp:... |
256 257 |
struct iscsi_segment *segment) { |
6df19a791 [SCSI] libiscsi_t... |
258 |
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; |
38e1a8f54 [SCSI] iscsi_tcp:... |
259 260 261 |
struct socket *sk = tcp_sw_conn->sock; unsigned int copied = 0; int r = 0; |
6df19a791 [SCSI] libiscsi_t... |
262 |
while (!iscsi_tcp_segment_done(tcp_conn, segment, 0, r)) { |
38e1a8f54 [SCSI] iscsi_tcp:... |
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 |
struct scatterlist *sg; unsigned int offset, copy; int flags = 0; r = 0; offset = segment->copied; copy = segment->size - offset; if (segment->total_copied + segment->size < segment->total_size) flags |= MSG_MORE; /* Use sendpage if we can; else fall back to sendmsg */ if (!segment->data) { sg = segment->sg; offset += segment->sg_offset + sg->offset; r = tcp_sw_conn->sendpage(sk, sg_page(sg), offset, copy, flags); } else { struct msghdr msg = { .msg_flags = flags }; struct kvec iov = { .iov_base = segment->data + offset, .iov_len = copy }; r = kernel_sendmsg(sk, &msg, &iov, 1, copy); } if (r < 0) { iscsi_tcp_segment_unmap(segment); |
38e1a8f54 [SCSI] iscsi_tcp:... |
292 293 294 295 296 297 298 299 300 |
return r; } copied += r; } return copied; } /** * iscsi_sw_tcp_xmit - TCP transmit |
a8ac6311c [SCSI] iscsi: con... |
301 |
**/ |
38e1a8f54 [SCSI] iscsi_tcp:... |
302 |
static int iscsi_sw_tcp_xmit(struct iscsi_conn *conn) |
7ba247138 [SCSI] open-iscsi... |
303 |
{ |
5bb0b55a3 [SCSI] iscsi: con... |
304 |
struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
38e1a8f54 [SCSI] iscsi_tcp:... |
305 306 |
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; struct iscsi_segment *segment = &tcp_sw_conn->out.segment; |
a8ac6311c [SCSI] iscsi: con... |
307 308 |
unsigned int consumed = 0; int rc = 0; |
7ba247138 [SCSI] open-iscsi... |
309 |
|
a8ac6311c [SCSI] iscsi: con... |
310 |
while (1) { |
6df19a791 [SCSI] libiscsi_t... |
311 |
rc = iscsi_sw_tcp_xmit_segment(tcp_conn, segment); |
32382492e iscsi_tcp: propog... |
312 313 |
/* * We may not have been able to send data because the conn |
25985edce Fix common misspe... |
314 |
* is getting stopped. libiscsi will know so propagate err |
32382492e iscsi_tcp: propog... |
315 316 317 318 319 |
* for it to do the right thing. */ if (rc == -EAGAIN) return rc; else if (rc < 0) { |
6f481e3ce [SCSI] iscsi_tcp:... |
320 |
rc = ISCSI_ERR_XMIT_FAILED; |
a8ac6311c [SCSI] iscsi: con... |
321 |
goto error; |
32382492e iscsi_tcp: propog... |
322 |
} else if (rc == 0) |
a8ac6311c [SCSI] iscsi: con... |
323 324 325 326 327 328 329 |
break; consumed += rc; if (segment->total_copied >= segment->total_size) { if (segment->done != NULL) { rc = segment->done(tcp_conn, segment); |
6f481e3ce [SCSI] iscsi_tcp:... |
330 |
if (rc != 0) |
a8ac6311c [SCSI] iscsi: con... |
331 332 333 |
goto error; } } |
3219e5294 [SCSI] iscsi: fix... |
334 |
} |
c93f87c72 [SCSI] iscsi_tcp:... |
335 336 |
ISCSI_SW_TCP_DBG(conn, "xmit %d bytes ", consumed); |
a8ac6311c [SCSI] iscsi: con... |
337 338 339 340 341 342 343 |
conn->txdata_octets += consumed; return consumed; error: /* Transmit error. We could initiate error recovery * here. */ |
c93f87c72 [SCSI] iscsi_tcp:... |
344 345 |
ISCSI_SW_TCP_DBG(conn, "Error sending PDU, errno=%d ", rc); |
6f481e3ce [SCSI] iscsi_tcp:... |
346 347 |
iscsi_conn_failure(conn, rc); return -EIO; |
7ba247138 [SCSI] open-iscsi... |
348 349 350 |
} /** |
a8ac6311c [SCSI] iscsi: con... |
351 352 |
* iscsi_tcp_xmit_qlen - return the number of bytes queued for xmit */ |
38e1a8f54 [SCSI] iscsi_tcp:... |
353 |
static inline int iscsi_sw_tcp_xmit_qlen(struct iscsi_conn *conn) |
7ba247138 [SCSI] open-iscsi... |
354 |
{ |
a8ac6311c [SCSI] iscsi: con... |
355 |
struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
38e1a8f54 [SCSI] iscsi_tcp:... |
356 357 |
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; struct iscsi_segment *segment = &tcp_sw_conn->out.segment; |
7ba247138 [SCSI] open-iscsi... |
358 |
|
a8ac6311c [SCSI] iscsi: con... |
359 |
return segment->total_copied - segment->total_size; |
7ba247138 [SCSI] open-iscsi... |
360 |
} |
38e1a8f54 [SCSI] iscsi_tcp:... |
361 |
static int iscsi_sw_tcp_pdu_xmit(struct iscsi_task *task) |
7ba247138 [SCSI] open-iscsi... |
362 |
{ |
e5a7efeff [SCSI] iscsi_tcp:... |
363 |
struct iscsi_conn *conn = task->conn; |
a8ac6311c [SCSI] iscsi: con... |
364 |
int rc; |
38e1a8f54 [SCSI] iscsi_tcp:... |
365 366 |
while (iscsi_sw_tcp_xmit_qlen(conn)) { rc = iscsi_sw_tcp_xmit(conn); |
a8ac6311c [SCSI] iscsi: con... |
367 |
if (rc == 0) |
7ba247138 [SCSI] open-iscsi... |
368 |
return -EAGAIN; |
a8ac6311c [SCSI] iscsi: con... |
369 370 |
if (rc < 0) return rc; |
3219e5294 [SCSI] iscsi: fix... |
371 |
} |
7ba247138 [SCSI] open-iscsi... |
372 |
|
a8ac6311c [SCSI] iscsi: con... |
373 |
return 0; |
7ba247138 [SCSI] open-iscsi... |
374 |
} |
a8ac6311c [SCSI] iscsi: con... |
375 376 377 378 |
/* * This is called when we're done sending the header. * Simply copy the data_segment to the send segment, and return. */ |
38e1a8f54 [SCSI] iscsi_tcp:... |
379 380 |
static int iscsi_sw_tcp_send_hdr_done(struct iscsi_tcp_conn *tcp_conn, struct iscsi_segment *segment) |
7ba247138 [SCSI] open-iscsi... |
381 |
{ |
38e1a8f54 [SCSI] iscsi_tcp:... |
382 383 384 |
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; tcp_sw_conn->out.segment = tcp_sw_conn->out.data_segment; |
c93f87c72 [SCSI] iscsi_tcp:... |
385 386 387 388 389 |
ISCSI_SW_TCP_DBG(tcp_conn->iscsi_conn, "Header done. Next segment size %u total_size %u ", tcp_sw_conn->out.segment.size, tcp_sw_conn->out.segment.total_size); |
a8ac6311c [SCSI] iscsi: con... |
390 391 |
return 0; } |
38e1a8f54 [SCSI] iscsi_tcp:... |
392 393 |
static void iscsi_sw_tcp_send_hdr_prep(struct iscsi_conn *conn, void *hdr, size_t hdrlen) |
a8ac6311c [SCSI] iscsi: con... |
394 395 |
{ struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
38e1a8f54 [SCSI] iscsi_tcp:... |
396 |
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; |
a8ac6311c [SCSI] iscsi: con... |
397 |
|
c93f87c72 [SCSI] iscsi_tcp:... |
398 399 400 |
ISCSI_SW_TCP_DBG(conn, "%s ", conn->hdrdgst_en ? "digest enabled" : "digest disabled"); |
a8ac6311c [SCSI] iscsi: con... |
401 402 403 |
/* Clear the data segment - needs to be filled in by the * caller using iscsi_tcp_send_data_prep() */ |
38e1a8f54 [SCSI] iscsi_tcp:... |
404 405 |
memset(&tcp_sw_conn->out.data_segment, 0, sizeof(struct iscsi_segment)); |
a8ac6311c [SCSI] iscsi: con... |
406 407 408 |
/* If header digest is enabled, compute the CRC and * place the digest into the same buffer. We make |
135a8ad4e [SCSI] iscsi_tcp:... |
409 |
* sure that both iscsi_tcp_task and mtask have |
a8ac6311c [SCSI] iscsi: con... |
410 411 412 |
* sufficient room. */ if (conn->hdrdgst_en) { |
38e1a8f54 [SCSI] iscsi_tcp:... |
413 |
iscsi_tcp_dgst_header(&tcp_sw_conn->tx_hash, hdr, hdrlen, |
a8ac6311c [SCSI] iscsi: con... |
414 415 416 417 418 419 420 |
hdr + hdrlen); hdrlen += ISCSI_DIGEST_SIZE; } /* Remember header pointer for later, when we need * to decide whether there's a payload to go along * with the header. */ |
38e1a8f54 [SCSI] iscsi_tcp:... |
421 |
tcp_sw_conn->out.hdr = hdr; |
a8ac6311c [SCSI] iscsi: con... |
422 |
|
38e1a8f54 [SCSI] iscsi_tcp:... |
423 424 |
iscsi_segment_init_linear(&tcp_sw_conn->out.segment, hdr, hdrlen, iscsi_sw_tcp_send_hdr_done, NULL); |
a8ac6311c [SCSI] iscsi: con... |
425 426 427 428 429 430 431 432 |
} /* * Prepare the send buffer for the payload data. * Padding and checksumming will all be taken care * of by the iscsi_segment routines. */ static int |
38e1a8f54 [SCSI] iscsi_tcp:... |
433 434 435 |
iscsi_sw_tcp_send_data_prep(struct iscsi_conn *conn, struct scatterlist *sg, unsigned int count, unsigned int offset, unsigned int len) |
a8ac6311c [SCSI] iscsi: con... |
436 437 |
{ struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
38e1a8f54 [SCSI] iscsi_tcp:... |
438 |
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; |
a8ac6311c [SCSI] iscsi: con... |
439 440 |
struct hash_desc *tx_hash = NULL; unsigned int hdr_spec_len; |
c93f87c72 [SCSI] iscsi_tcp:... |
441 442 443 444 |
ISCSI_SW_TCP_DBG(conn, "offset=%d, datalen=%d %s ", offset, len, conn->datadgst_en ? "digest enabled" : "digest disabled"); |
a8ac6311c [SCSI] iscsi: con... |
445 446 447 |
/* Make sure the datalen matches what the caller said he would send. */ |
38e1a8f54 [SCSI] iscsi_tcp:... |
448 |
hdr_spec_len = ntoh24(tcp_sw_conn->out.hdr->dlength); |
a8ac6311c [SCSI] iscsi: con... |
449 450 451 |
WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len)); if (conn->datadgst_en) |
38e1a8f54 [SCSI] iscsi_tcp:... |
452 |
tx_hash = &tcp_sw_conn->tx_hash; |
a8ac6311c [SCSI] iscsi: con... |
453 |
|
38e1a8f54 [SCSI] iscsi_tcp:... |
454 455 456 |
return iscsi_segment_seek_sg(&tcp_sw_conn->out.data_segment, sg, count, offset, len, NULL, tx_hash); |
a8ac6311c [SCSI] iscsi: con... |
457 458 459 |
} static void |
38e1a8f54 [SCSI] iscsi_tcp:... |
460 |
iscsi_sw_tcp_send_linear_data_prep(struct iscsi_conn *conn, void *data, |
a8ac6311c [SCSI] iscsi: con... |
461 462 463 |
size_t len) { struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
38e1a8f54 [SCSI] iscsi_tcp:... |
464 |
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; |
a8ac6311c [SCSI] iscsi: con... |
465 466 |
struct hash_desc *tx_hash = NULL; unsigned int hdr_spec_len; |
c93f87c72 [SCSI] iscsi_tcp:... |
467 468 469 |
ISCSI_SW_TCP_DBG(conn, "datalen=%zd %s ", len, conn->datadgst_en ? "digest enabled" : "digest disabled"); |
a8ac6311c [SCSI] iscsi: con... |
470 471 472 |
/* Make sure the datalen matches what the caller said he would send. */ |
38e1a8f54 [SCSI] iscsi_tcp:... |
473 |
hdr_spec_len = ntoh24(tcp_sw_conn->out.hdr->dlength); |
a8ac6311c [SCSI] iscsi: con... |
474 475 476 |
WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len)); if (conn->datadgst_en) |
38e1a8f54 [SCSI] iscsi_tcp:... |
477 |
tx_hash = &tcp_sw_conn->tx_hash; |
a8ac6311c [SCSI] iscsi: con... |
478 |
|
38e1a8f54 [SCSI] iscsi_tcp:... |
479 |
iscsi_segment_init_linear(&tcp_sw_conn->out.data_segment, |
a8ac6311c [SCSI] iscsi: con... |
480 |
data, len, NULL, tx_hash); |
7ba247138 [SCSI] open-iscsi... |
481 |
} |
38e1a8f54 [SCSI] iscsi_tcp:... |
482 483 |
static int iscsi_sw_tcp_pdu_init(struct iscsi_task *task, unsigned int offset, unsigned int count) |
e5a7efeff [SCSI] iscsi_tcp:... |
484 485 486 |
{ struct iscsi_conn *conn = task->conn; int err = 0; |
38e1a8f54 [SCSI] iscsi_tcp:... |
487 |
iscsi_sw_tcp_send_hdr_prep(conn, task->hdr, task->hdr_len); |
e5a7efeff [SCSI] iscsi_tcp:... |
488 489 490 491 492 |
if (!count) return 0; if (!task->sc) |
38e1a8f54 [SCSI] iscsi_tcp:... |
493 |
iscsi_sw_tcp_send_linear_data_prep(conn, task->data, count); |
e5a7efeff [SCSI] iscsi_tcp:... |
494 495 |
else { struct scsi_data_buffer *sdb = scsi_out(task->sc); |
38e1a8f54 [SCSI] iscsi_tcp:... |
496 497 498 |
err = iscsi_sw_tcp_send_data_prep(conn, sdb->table.sgl, sdb->table.nents, offset, count); |
e5a7efeff [SCSI] iscsi_tcp:... |
499 500 501 |
} if (err) { |
9a6510eb3 [SCSI] iscsi_tcp:... |
502 |
/* got invalid offset/len */ |
e5a7efeff [SCSI] iscsi_tcp:... |
503 504 505 506 |
return -EIO; } return 0; } |
2ff79d52d [SCSI] libiscsi: ... |
507 |
static int iscsi_sw_tcp_pdu_alloc(struct iscsi_task *task, uint8_t opcode) |
7ba247138 [SCSI] open-iscsi... |
508 |
{ |
135a8ad4e [SCSI] iscsi_tcp:... |
509 |
struct iscsi_tcp_task *tcp_task = task->dd_data; |
7ba247138 [SCSI] open-iscsi... |
510 |
|
38e1a8f54 [SCSI] iscsi_tcp:... |
511 512 |
task->hdr = task->dd_data + sizeof(*tcp_task); task->hdr_max = sizeof(struct iscsi_sw_tcp_hdrbuf) - ISCSI_DIGEST_SIZE; |
a8ac6311c [SCSI] iscsi: con... |
513 |
return 0; |
7ba247138 [SCSI] open-iscsi... |
514 |
} |
5bb0b55a3 [SCSI] iscsi: con... |
515 |
static struct iscsi_cls_conn * |
38e1a8f54 [SCSI] iscsi_tcp:... |
516 517 |
iscsi_sw_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) |
7ba247138 [SCSI] open-iscsi... |
518 |
{ |
5bb0b55a3 [SCSI] iscsi: con... |
519 520 521 |
struct iscsi_conn *conn; struct iscsi_cls_conn *cls_conn; struct iscsi_tcp_conn *tcp_conn; |
38e1a8f54 [SCSI] iscsi_tcp:... |
522 |
struct iscsi_sw_tcp_conn *tcp_sw_conn; |
7ba247138 [SCSI] open-iscsi... |
523 |
|
38e1a8f54 [SCSI] iscsi_tcp:... |
524 525 |
cls_conn = iscsi_tcp_conn_setup(cls_session, sizeof(*tcp_sw_conn), conn_idx); |
5bb0b55a3 [SCSI] iscsi: con... |
526 527 528 |
if (!cls_conn) return NULL; conn = cls_conn->dd_data; |
5d91e209f [SCSI] iscsi: rem... |
529 |
tcp_conn = conn->dd_data; |
38e1a8f54 [SCSI] iscsi_tcp:... |
530 |
tcp_sw_conn = tcp_conn->dd_data; |
7ba247138 [SCSI] open-iscsi... |
531 |
|
38e1a8f54 [SCSI] iscsi_tcp:... |
532 533 534 535 |
tcp_sw_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0, CRYPTO_ALG_ASYNC); tcp_sw_conn->tx_hash.flags = 0; if (IS_ERR(tcp_sw_conn->tx_hash.tfm)) |
5d91e209f [SCSI] iscsi: rem... |
536 |
goto free_conn; |
dd8c0d958 [SCSI] scsi_tcp: ... |
537 |
|
38e1a8f54 [SCSI] iscsi_tcp:... |
538 539 540 541 |
tcp_sw_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0, CRYPTO_ALG_ASYNC); tcp_sw_conn->rx_hash.flags = 0; if (IS_ERR(tcp_sw_conn->rx_hash.tfm)) |
dd8c0d958 [SCSI] scsi_tcp: ... |
542 |
goto free_tx_tfm; |
38e1a8f54 [SCSI] iscsi_tcp:... |
543 |
tcp_conn->rx_hash = &tcp_sw_conn->rx_hash; |
dd8c0d958 [SCSI] scsi_tcp: ... |
544 |
|
5bb0b55a3 [SCSI] iscsi: con... |
545 |
return cls_conn; |
7ba247138 [SCSI] open-iscsi... |
546 |
|
dd8c0d958 [SCSI] scsi_tcp: ... |
547 |
free_tx_tfm: |
38e1a8f54 [SCSI] iscsi_tcp:... |
548 |
crypto_free_hash(tcp_sw_conn->tx_hash.tfm); |
5d91e209f [SCSI] iscsi: rem... |
549 |
free_conn: |
322d739da [SCSI] iscsi: fix... |
550 551 552 553 554 555 |
iscsi_conn_printk(KERN_ERR, conn, "Could not create connection due to crc32c " "loading error. Make sure the crc32c " "module is built as a module or into the " "kernel "); |
38e1a8f54 [SCSI] iscsi_tcp:... |
556 |
iscsi_tcp_conn_teardown(cls_conn); |
5bb0b55a3 [SCSI] iscsi: con... |
557 |
return NULL; |
7ba247138 [SCSI] open-iscsi... |
558 |
} |
38e1a8f54 [SCSI] iscsi_tcp:... |
559 |
static void iscsi_sw_tcp_release_conn(struct iscsi_conn *conn) |
1c83469d3 [SCSI] iscsi bugf... |
560 |
{ |
222369619 [SCSI] iscsi clas... |
561 |
struct iscsi_session *session = conn->session; |
1c83469d3 [SCSI] iscsi bugf... |
562 |
struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
38e1a8f54 [SCSI] iscsi_tcp:... |
563 564 |
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; struct socket *sock = tcp_sw_conn->sock; |
1c83469d3 [SCSI] iscsi bugf... |
565 |
|
222369619 [SCSI] iscsi clas... |
566 |
if (!sock) |
1c83469d3 [SCSI] iscsi bugf... |
567 |
return; |
222369619 [SCSI] iscsi clas... |
568 |
sock_hold(sock->sk); |
c484a50a4 [SCSI] iscsi_tcp:... |
569 |
iscsi_sw_tcp_conn_restore_callbacks(conn); |
222369619 [SCSI] iscsi clas... |
570 |
sock_put(sock->sk); |
1c83469d3 [SCSI] iscsi bugf... |
571 |
|
222369619 [SCSI] iscsi clas... |
572 |
spin_lock_bh(&session->lock); |
38e1a8f54 [SCSI] iscsi_tcp:... |
573 |
tcp_sw_conn->sock = NULL; |
222369619 [SCSI] iscsi clas... |
574 575 |
spin_unlock_bh(&session->lock); sockfd_put(sock); |
1c83469d3 [SCSI] iscsi bugf... |
576 |
} |
38e1a8f54 [SCSI] iscsi_tcp:... |
577 |
static void iscsi_sw_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn) |
7ba247138 [SCSI] open-iscsi... |
578 |
{ |
5bb0b55a3 [SCSI] iscsi: con... |
579 580 |
struct iscsi_conn *conn = cls_conn->dd_data; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
38e1a8f54 [SCSI] iscsi_tcp:... |
581 |
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; |
7ba247138 [SCSI] open-iscsi... |
582 |
|
38e1a8f54 [SCSI] iscsi_tcp:... |
583 |
iscsi_sw_tcp_release_conn(conn); |
7ba247138 [SCSI] open-iscsi... |
584 |
|
38e1a8f54 [SCSI] iscsi_tcp:... |
585 586 587 588 |
if (tcp_sw_conn->tx_hash.tfm) crypto_free_hash(tcp_sw_conn->tx_hash.tfm); if (tcp_sw_conn->rx_hash.tfm) crypto_free_hash(tcp_sw_conn->rx_hash.tfm); |
7ba247138 [SCSI] open-iscsi... |
589 |
|
38e1a8f54 [SCSI] iscsi_tcp:... |
590 |
iscsi_tcp_conn_teardown(cls_conn); |
5bb0b55a3 [SCSI] iscsi: con... |
591 |
} |
7ba247138 [SCSI] open-iscsi... |
592 |
|
38e1a8f54 [SCSI] iscsi_tcp:... |
593 |
static void iscsi_sw_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) |
1c83469d3 [SCSI] iscsi bugf... |
594 595 |
{ struct iscsi_conn *conn = cls_conn->dd_data; |
913e5bf43 [SCSI] libiscsi, ... |
596 |
struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
38e1a8f54 [SCSI] iscsi_tcp:... |
597 |
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; |
b64e77f70 [SCSI] iscsi_tcp:... |
598 |
struct socket *sock = tcp_sw_conn->sock; |
913e5bf43 [SCSI] libiscsi, ... |
599 600 |
/* userspace may have goofed up and not bound us */ |
b64e77f70 [SCSI] iscsi_tcp:... |
601 |
if (!sock) |
913e5bf43 [SCSI] libiscsi, ... |
602 |
return; |
1c83469d3 [SCSI] iscsi bugf... |
603 |
|
8c38a2951 [SCSI] iscsi_tcp:... |
604 605 |
sock->sk->sk_err = EIO; wake_up_interruptible(sk_sleep(sock->sk)); |
b64e77f70 [SCSI] iscsi_tcp:... |
606 |
|
03adb5f91 [SCSI] iscsi_tcp:... |
607 608 609 610 |
/* stop xmit side */ iscsi_suspend_tx(conn); /* stop recv side and release socket */ |
38e1a8f54 [SCSI] iscsi_tcp:... |
611 |
iscsi_sw_tcp_release_conn(conn); |
03adb5f91 [SCSI] iscsi_tcp:... |
612 613 |
iscsi_conn_stop(cls_conn, flag); |
1c83469d3 [SCSI] iscsi bugf... |
614 |
} |
5bb0b55a3 [SCSI] iscsi: con... |
615 |
static int |
38e1a8f54 [SCSI] iscsi_tcp:... |
616 617 618 |
iscsi_sw_tcp_conn_bind(struct iscsi_cls_session *cls_session, struct iscsi_cls_conn *cls_conn, uint64_t transport_eph, int is_leading) |
5bb0b55a3 [SCSI] iscsi: con... |
619 |
{ |
a79af8a64 [SCSI] iscsi_tcp:... |
620 |
struct iscsi_session *session = cls_session->dd_data; |
5bb0b55a3 [SCSI] iscsi: con... |
621 622 |
struct iscsi_conn *conn = cls_conn->dd_data; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
38e1a8f54 [SCSI] iscsi_tcp:... |
623 |
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; |
5bb0b55a3 [SCSI] iscsi: con... |
624 625 626 |
struct sock *sk; struct socket *sock; int err; |
7ba247138 [SCSI] open-iscsi... |
627 |
|
5bb0b55a3 [SCSI] iscsi: con... |
628 |
/* lookup for existing socket */ |
264faaaa1 [SCSI] iscsi: add... |
629 |
sock = sockfd_lookup((int)transport_eph, &err); |
5bb0b55a3 [SCSI] iscsi: con... |
630 |
if (!sock) { |
322d739da [SCSI] iscsi: fix... |
631 632 633 |
iscsi_conn_printk(KERN_ERR, conn, "sockfd_lookup failed %d ", err); |
5bb0b55a3 [SCSI] iscsi: con... |
634 |
return -EEXIST; |
7ba247138 [SCSI] open-iscsi... |
635 |
} |
5bb0b55a3 [SCSI] iscsi: con... |
636 637 |
err = iscsi_conn_bind(cls_session, cls_conn, is_leading); if (err) |
222369619 [SCSI] iscsi clas... |
638 |
goto free_socket; |
7ba247138 [SCSI] open-iscsi... |
639 |
|
a79af8a64 [SCSI] iscsi_tcp:... |
640 |
spin_lock_bh(&session->lock); |
67a611149 [SCSI] iscsi: don... |
641 |
/* bind iSCSI connection and socket */ |
38e1a8f54 [SCSI] iscsi_tcp:... |
642 |
tcp_sw_conn->sock = sock; |
a79af8a64 [SCSI] iscsi_tcp:... |
643 |
spin_unlock_bh(&session->lock); |
7ba247138 [SCSI] open-iscsi... |
644 |
|
67a611149 [SCSI] iscsi: don... |
645 646 647 648 649 |
/* setup Socket parameters */ sk = sock->sk; sk->sk_reuse = 1; sk->sk_sndtimeo = 15 * HZ; /* FIXME: make it configurable */ sk->sk_allocation = GFP_ATOMIC; |
7ba247138 [SCSI] open-iscsi... |
650 |
|
38e1a8f54 [SCSI] iscsi_tcp:... |
651 652 |
iscsi_sw_tcp_conn_set_callbacks(conn); tcp_sw_conn->sendpage = tcp_sw_conn->sock->ops->sendpage; |
67a611149 [SCSI] iscsi: don... |
653 654 655 |
/* * set receive state machine into initial state */ |
da32dd681 [SCSI] iscsi_tcp:... |
656 |
iscsi_tcp_hdr_recv_prep(tcp_conn); |
7ba247138 [SCSI] open-iscsi... |
657 |
return 0; |
222369619 [SCSI] iscsi clas... |
658 659 660 661 |
free_socket: sockfd_put(sock); return err; |
7ba247138 [SCSI] open-iscsi... |
662 |
} |
38e1a8f54 [SCSI] iscsi_tcp:... |
663 664 665 |
static int iscsi_sw_tcp_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, char *buf, int buflen) |
7ba247138 [SCSI] open-iscsi... |
666 |
{ |
7b7232f3f [SCSI] iscsi upda... |
667 |
struct iscsi_conn *conn = cls_conn->dd_data; |
7ba247138 [SCSI] open-iscsi... |
668 |
struct iscsi_session *session = conn->session; |
5bb0b55a3 [SCSI] iscsi: con... |
669 |
struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
38e1a8f54 [SCSI] iscsi_tcp:... |
670 |
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; |
5c75b7fcf [SCSI] iscsi: con... |
671 |
int value; |
7ba247138 [SCSI] open-iscsi... |
672 |
|
7ba247138 [SCSI] open-iscsi... |
673 |
switch(param) { |
7ba247138 [SCSI] open-iscsi... |
674 |
case ISCSI_PARAM_HDRDGST_EN: |
5c75b7fcf [SCSI] iscsi: con... |
675 |
iscsi_set_param(cls_conn, param, buf, buflen); |
7ba247138 [SCSI] open-iscsi... |
676 677 |
break; case ISCSI_PARAM_DATADGST_EN: |
5c75b7fcf [SCSI] iscsi: con... |
678 |
iscsi_set_param(cls_conn, param, buf, buflen); |
38e1a8f54 [SCSI] iscsi_tcp:... |
679 680 |
tcp_sw_conn->sendpage = conn->datadgst_en ? sock_no_sendpage : tcp_sw_conn->sock->ops->sendpage; |
7ba247138 [SCSI] open-iscsi... |
681 |
break; |
7ba247138 [SCSI] open-iscsi... |
682 |
case ISCSI_PARAM_MAX_R2T: |
5c75b7fcf [SCSI] iscsi: con... |
683 |
sscanf(buf, "%d", &value); |
df93ffcd7 [SCSI] iscsi_tcp:... |
684 685 686 |
if (value <= 0 || !is_power_of_2(value)) return -EINVAL; if (session->max_r2t == value) |
7ba247138 [SCSI] open-iscsi... |
687 |
break; |
38e1a8f54 [SCSI] iscsi_tcp:... |
688 |
iscsi_tcp_r2tpool_free(session); |
5c75b7fcf [SCSI] iscsi: con... |
689 |
iscsi_set_param(cls_conn, param, buf, buflen); |
38e1a8f54 [SCSI] iscsi_tcp:... |
690 |
if (iscsi_tcp_r2tpool_alloc(session)) |
7ba247138 [SCSI] open-iscsi... |
691 692 |
return -ENOMEM; break; |
7ba247138 [SCSI] open-iscsi... |
693 |
default: |
5c75b7fcf [SCSI] iscsi: con... |
694 |
return iscsi_set_param(cls_conn, param, buf, buflen); |
7ba247138 [SCSI] open-iscsi... |
695 696 697 698 |
} return 0; } |
38e1a8f54 [SCSI] iscsi_tcp:... |
699 700 |
static int iscsi_sw_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, char *buf) |
7b8631b53 [SCSI] iscsi: sep... |
701 |
{ |
7b7232f3f [SCSI] iscsi upda... |
702 |
struct iscsi_conn *conn = cls_conn->dd_data; |
a79af8a64 [SCSI] iscsi_tcp:... |
703 704 705 706 |
struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; struct sockaddr_in6 addr; int rc, len; |
7b8631b53 [SCSI] iscsi: sep... |
707 708 |
switch(param) { |
fd7255f51 [SCSI] iscsi: add... |
709 |
case ISCSI_PARAM_CONN_PORT: |
fd7255f51 [SCSI] iscsi: add... |
710 |
case ISCSI_PARAM_CONN_ADDRESS: |
222369619 [SCSI] iscsi clas... |
711 |
spin_lock_bh(&conn->session->lock); |
a79af8a64 [SCSI] iscsi_tcp:... |
712 713 714 715 716 717 |
if (!tcp_sw_conn || !tcp_sw_conn->sock) { spin_unlock_bh(&conn->session->lock); return -ENOTCONN; } rc = kernel_getpeername(tcp_sw_conn->sock, (struct sockaddr *)&addr, &len); |
222369619 [SCSI] iscsi clas... |
718 |
spin_unlock_bh(&conn->session->lock); |
a79af8a64 [SCSI] iscsi_tcp:... |
719 720 721 722 723 |
if (rc) return rc; return iscsi_conn_get_addr_param((struct sockaddr_storage *) &addr, param, buf); |
fd7255f51 [SCSI] iscsi: add... |
724 |
default: |
5c75b7fcf [SCSI] iscsi: con... |
725 |
return iscsi_conn_get_param(cls_conn, param, buf); |
fd7255f51 [SCSI] iscsi: add... |
726 |
} |
a79af8a64 [SCSI] iscsi_tcp:... |
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 |
return 0; } static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, char *buf) { struct iscsi_sw_tcp_host *tcp_sw_host = iscsi_host_priv(shost); struct iscsi_session *session = tcp_sw_host->session; struct iscsi_conn *conn; struct iscsi_tcp_conn *tcp_conn; struct iscsi_sw_tcp_conn *tcp_sw_conn; struct sockaddr_in6 addr; int rc, len; switch (param) { case ISCSI_HOST_PARAM_IPADDRESS: spin_lock_bh(&session->lock); conn = session->leadconn; if (!conn) { spin_unlock_bh(&session->lock); return -ENOTCONN; } tcp_conn = conn->dd_data; tcp_sw_conn = tcp_conn->dd_data; if (!tcp_sw_conn->sock) { spin_unlock_bh(&session->lock); return -ENOTCONN; } rc = kernel_getsockname(tcp_sw_conn->sock, (struct sockaddr *)&addr, &len); spin_unlock_bh(&session->lock); if (rc) return rc; return iscsi_conn_get_addr_param((struct sockaddr_storage *) &addr, param, buf); default: return iscsi_host_get_param(shost, param, buf); } return 0; |
fd7255f51 [SCSI] iscsi: add... |
770 |
} |
7ba247138 [SCSI] open-iscsi... |
771 |
static void |
38e1a8f54 [SCSI] iscsi_tcp:... |
772 773 |
iscsi_sw_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats) |
7ba247138 [SCSI] open-iscsi... |
774 |
{ |
7b7232f3f [SCSI] iscsi upda... |
775 |
struct iscsi_conn *conn = cls_conn->dd_data; |
5bb0b55a3 [SCSI] iscsi: con... |
776 |
struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
38e1a8f54 [SCSI] iscsi_tcp:... |
777 |
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; |
7ba247138 [SCSI] open-iscsi... |
778 |
|
7ba247138 [SCSI] open-iscsi... |
779 780 |
stats->custom_length = 3; strcpy(stats->custom[0].desc, "tx_sendpage_failures"); |
38e1a8f54 [SCSI] iscsi_tcp:... |
781 |
stats->custom[0].value = tcp_sw_conn->sendpage_failures_cnt; |
7ba247138 [SCSI] open-iscsi... |
782 |
strcpy(stats->custom[1].desc, "rx_discontiguous_hdr"); |
38e1a8f54 [SCSI] iscsi_tcp:... |
783 |
stats->custom[1].value = tcp_sw_conn->discontiguous_hdr_cnt; |
7ba247138 [SCSI] open-iscsi... |
784 785 |
strcpy(stats->custom[2].desc, "eh_abort_cnt"); stats->custom[2].value = conn->eh_abort_cnt; |
38e1a8f54 [SCSI] iscsi_tcp:... |
786 787 |
iscsi_tcp_conn_get_stats(cls_conn, stats); |
7ba247138 [SCSI] open-iscsi... |
788 |
} |
5bb0b55a3 [SCSI] iscsi: con... |
789 |
static struct iscsi_cls_session * |
38e1a8f54 [SCSI] iscsi_tcp:... |
790 |
iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, |
5e7facb77 [SCSI] iscsi clas... |
791 |
uint16_t qdepth, uint32_t initial_cmdsn) |
7ba247138 [SCSI] open-iscsi... |
792 |
{ |
5bb0b55a3 [SCSI] iscsi: con... |
793 794 |
struct iscsi_cls_session *cls_session; struct iscsi_session *session; |
a79af8a64 [SCSI] iscsi_tcp:... |
795 |
struct iscsi_sw_tcp_host *tcp_sw_host; |
06520edea [SCSI] iscsi_tcp:... |
796 |
struct Scsi_Host *shost; |
7ba247138 [SCSI] open-iscsi... |
797 |
|
06520edea [SCSI] iscsi_tcp:... |
798 799 800 |
if (ep) { printk(KERN_ERR "iscsi_tcp: invalid ep %p. ", ep); |
756135215 [SCSI] iscsi: rem... |
801 802 |
return NULL; } |
a79af8a64 [SCSI] iscsi_tcp:... |
803 804 |
shost = iscsi_host_alloc(&iscsi_sw_tcp_sht, sizeof(struct iscsi_sw_tcp_host), 1); |
756135215 [SCSI] iscsi: rem... |
805 |
if (!shost) |
5bb0b55a3 [SCSI] iscsi: con... |
806 |
return NULL; |
38e1a8f54 [SCSI] iscsi_tcp:... |
807 |
shost->transportt = iscsi_sw_tcp_scsi_transport; |
4d1083509 [SCSI] iscsi lib:... |
808 |
shost->cmd_per_lun = qdepth; |
756135215 [SCSI] iscsi: rem... |
809 810 811 |
shost->max_lun = iscsi_max_lun; shost->max_id = 0; shost->max_channel = 0; |
30e9ba9f2 [SCSI] iscsi_tcp:... |
812 |
shost->max_cmd_len = SCSI_MAX_VARLEN_CDB_SIZE; |
756135215 [SCSI] iscsi: rem... |
813 |
|
a4804cd6e [SCSI] iscsi: add... |
814 |
if (iscsi_host_add(shost, NULL)) |
756135215 [SCSI] iscsi: rem... |
815 |
goto free_host; |
756135215 [SCSI] iscsi: rem... |
816 |
|
38e1a8f54 [SCSI] iscsi_tcp:... |
817 |
cls_session = iscsi_session_setup(&iscsi_sw_tcp_transport, shost, |
b8b9e1b81 [SCSI] libiscsi: ... |
818 |
cmds_max, 0, |
38e1a8f54 [SCSI] iscsi_tcp:... |
819 820 |
sizeof(struct iscsi_tcp_task) + sizeof(struct iscsi_sw_tcp_hdrbuf), |
7970634b8 [SCSI] iscsi clas... |
821 |
initial_cmdsn, 0); |
756135215 [SCSI] iscsi: rem... |
822 823 824 |
if (!cls_session) goto remove_host; session = cls_session->dd_data; |
a79af8a64 [SCSI] iscsi_tcp:... |
825 826 |
tcp_sw_host = iscsi_host_priv(shost); tcp_sw_host->session = session; |
7ba247138 [SCSI] open-iscsi... |
827 |
|
fbc514b4e [SCSI] iscsi_tcp:... |
828 |
shost->can_queue = session->scsi_cmds_max; |
38e1a8f54 [SCSI] iscsi_tcp:... |
829 |
if (iscsi_tcp_r2tpool_alloc(session)) |
756135215 [SCSI] iscsi: rem... |
830 |
goto remove_session; |
5bb0b55a3 [SCSI] iscsi: con... |
831 |
return cls_session; |
756135215 [SCSI] iscsi: rem... |
832 |
remove_session: |
5bb0b55a3 [SCSI] iscsi: con... |
833 |
iscsi_session_teardown(cls_session); |
756135215 [SCSI] iscsi: rem... |
834 |
remove_host: |
a4804cd6e [SCSI] iscsi: add... |
835 |
iscsi_host_remove(shost); |
756135215 [SCSI] iscsi: rem... |
836 |
free_host: |
a4804cd6e [SCSI] iscsi: add... |
837 |
iscsi_host_free(shost); |
5bb0b55a3 [SCSI] iscsi: con... |
838 839 |
return NULL; } |
38e1a8f54 [SCSI] iscsi_tcp:... |
840 |
static void iscsi_sw_tcp_session_destroy(struct iscsi_cls_session *cls_session) |
5bb0b55a3 [SCSI] iscsi: con... |
841 |
{ |
756135215 [SCSI] iscsi: rem... |
842 |
struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); |
38e1a8f54 [SCSI] iscsi_tcp:... |
843 |
iscsi_tcp_r2tpool_free(cls_session->dd_data); |
e5bd7b54e [SCSI] libiscsi: ... |
844 |
iscsi_session_teardown(cls_session); |
756135215 [SCSI] iscsi: rem... |
845 |
|
a4804cd6e [SCSI] iscsi: add... |
846 847 |
iscsi_host_remove(shost); iscsi_host_free(shost); |
7ba247138 [SCSI] open-iscsi... |
848 |
} |
587a1f165 switch ->is_visib... |
849 |
static umode_t iscsi_sw_tcp_attr_is_visible(int param_type, int param) |
3128c6c73 [SCSI] iscsi cls:... |
850 851 |
{ switch (param_type) { |
f27fb2ef7 [SCSI] iscsi clas... |
852 853 854 855 856 857 858 859 860 861 |
case ISCSI_HOST_PARAM: switch (param) { case ISCSI_HOST_PARAM_NETDEV_NAME: case ISCSI_HOST_PARAM_HWADDRESS: case ISCSI_HOST_PARAM_IPADDRESS: case ISCSI_HOST_PARAM_INITIATOR_NAME: return S_IRUGO; default: return 0; } |
3128c6c73 [SCSI] iscsi cls:... |
862 863 864 865 866 867 868 869 870 871 872 873 874 |
case ISCSI_PARAM: switch (param) { case ISCSI_PARAM_MAX_RECV_DLENGTH: case ISCSI_PARAM_MAX_XMIT_DLENGTH: case ISCSI_PARAM_HDRDGST_EN: case ISCSI_PARAM_DATADGST_EN: case ISCSI_PARAM_CONN_ADDRESS: case ISCSI_PARAM_CONN_PORT: case ISCSI_PARAM_EXP_STATSN: case ISCSI_PARAM_PERSISTENT_ADDRESS: case ISCSI_PARAM_PERSISTENT_PORT: case ISCSI_PARAM_PING_TMO: case ISCSI_PARAM_RECV_TMO: |
1d063c172 [SCSI] iscsi clas... |
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 |
case ISCSI_PARAM_INITIAL_R2T_EN: case ISCSI_PARAM_MAX_R2T: case ISCSI_PARAM_IMM_DATA_EN: case ISCSI_PARAM_FIRST_BURST: case ISCSI_PARAM_MAX_BURST: case ISCSI_PARAM_PDU_INORDER_EN: case ISCSI_PARAM_DATASEQ_INORDER_EN: case ISCSI_PARAM_ERL: case ISCSI_PARAM_TARGET_NAME: case ISCSI_PARAM_TPGT: case ISCSI_PARAM_USERNAME: case ISCSI_PARAM_PASSWORD: case ISCSI_PARAM_USERNAME_IN: case ISCSI_PARAM_PASSWORD_IN: case ISCSI_PARAM_FAST_ABORT: case ISCSI_PARAM_ABORT_TMO: case ISCSI_PARAM_LU_RESET_TMO: case ISCSI_PARAM_TGT_RESET_TMO: case ISCSI_PARAM_IFACE_NAME: case ISCSI_PARAM_INITIATOR_NAME: |
3128c6c73 [SCSI] iscsi cls:... |
895 896 897 898 899 900 901 902 |
return S_IRUGO; default: return 0; } } return 0; } |
091e6dbec [SCSI] iscsi tcp:... |
903 904 905 906 907 |
static int iscsi_sw_tcp_slave_alloc(struct scsi_device *sdev) { set_bit(QUEUE_FLAG_BIDI, &sdev->request_queue->queue_flags); return 0; } |
38e1a8f54 [SCSI] iscsi_tcp:... |
908 |
static int iscsi_sw_tcp_slave_configure(struct scsi_device *sdev) |
d1d81c01f [SCSI] iscsi_tcp:... |
909 |
{ |
b6d44fe95 [SCSI] iscsi_tcp:... |
910 |
blk_queue_bounce_limit(sdev->request_queue, BLK_BOUNCE_ANY); |
d1d81c01f [SCSI] iscsi_tcp:... |
911 912 913 |
blk_queue_dma_alignment(sdev->request_queue, 0); return 0; } |
38e1a8f54 [SCSI] iscsi_tcp:... |
914 |
static struct scsi_host_template iscsi_sw_tcp_sht = { |
7974392c0 [SCSI] iscsi_tcp,... |
915 |
.module = THIS_MODULE, |
f4246b33c [SCSI] iscsi bugf... |
916 |
.name = "iSCSI Initiator over TCP/IP", |
5bb0b55a3 [SCSI] iscsi: con... |
917 918 |
.queuecommand = iscsi_queuecommand, .change_queue_depth = iscsi_change_queue_depth, |
1548271ec [SCSI] libiscsi: ... |
919 |
.can_queue = ISCSI_DEF_XMIT_CMDS_MAX - 1, |
66bbe0ce1 [SCSI] iscsi_tcp:... |
920 |
.sg_tablesize = 4096, |
8231f0edd [SCSI] iscsi_tcp:... |
921 |
.max_sectors = 0xFFFF, |
5bb0b55a3 [SCSI] iscsi: con... |
922 923 |
.cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, .eh_abort_handler = iscsi_eh_abort, |
843c0a8a7 [SCSI] libiscsi, ... |
924 |
.eh_device_reset_handler= iscsi_eh_device_reset, |
309ce156a [SCSI] libiscsi: ... |
925 |
.eh_target_reset_handler = iscsi_eh_recover_target, |
5bb0b55a3 [SCSI] iscsi: con... |
926 |
.use_clustering = DISABLE_CLUSTERING, |
091e6dbec [SCSI] iscsi tcp:... |
927 |
.slave_alloc = iscsi_sw_tcp_slave_alloc, |
38e1a8f54 [SCSI] iscsi_tcp:... |
928 |
.slave_configure = iscsi_sw_tcp_slave_configure, |
6b5d6c443 [SCSI] cxgb3i, is... |
929 |
.target_alloc = iscsi_target_alloc, |
5bb0b55a3 [SCSI] iscsi: con... |
930 931 932 |
.proc_name = "iscsi_tcp", .this_id = -1, }; |
38e1a8f54 [SCSI] iscsi_tcp:... |
933 |
static struct iscsi_transport iscsi_sw_tcp_transport = { |
7ba247138 [SCSI] open-iscsi... |
934 935 936 937 |
.owner = THIS_MODULE, .name = "tcp", .caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_HDRDGST | CAP_DATADGST, |
5bb0b55a3 [SCSI] iscsi: con... |
938 |
/* session management */ |
38e1a8f54 [SCSI] iscsi_tcp:... |
939 940 |
.create_session = iscsi_sw_tcp_session_create, .destroy_session = iscsi_sw_tcp_session_destroy, |
5bb0b55a3 [SCSI] iscsi: con... |
941 |
/* connection management */ |
38e1a8f54 [SCSI] iscsi_tcp:... |
942 943 944 |
.create_conn = iscsi_sw_tcp_conn_create, .bind_conn = iscsi_sw_tcp_conn_bind, .destroy_conn = iscsi_sw_tcp_conn_destroy, |
3128c6c73 [SCSI] iscsi cls:... |
945 |
.attr_is_visible = iscsi_sw_tcp_attr_is_visible, |
38e1a8f54 [SCSI] iscsi_tcp:... |
946 947 |
.set_param = iscsi_sw_tcp_conn_set_param, .get_conn_param = iscsi_sw_tcp_conn_get_param, |
7b8631b53 [SCSI] iscsi: sep... |
948 |
.get_session_param = iscsi_session_get_param, |
7ba247138 [SCSI] open-iscsi... |
949 |
.start_conn = iscsi_conn_start, |
38e1a8f54 [SCSI] iscsi_tcp:... |
950 |
.stop_conn = iscsi_sw_tcp_conn_stop, |
0801c242a [SCSI] libiscsi, ... |
951 |
/* iscsi host params */ |
a79af8a64 [SCSI] iscsi_tcp:... |
952 |
.get_host_param = iscsi_sw_tcp_host_get_param, |
0801c242a [SCSI] libiscsi, ... |
953 |
.set_host_param = iscsi_host_set_param, |
5bb0b55a3 [SCSI] iscsi: con... |
954 |
/* IO */ |
7ba247138 [SCSI] open-iscsi... |
955 |
.send_pdu = iscsi_conn_send_pdu, |
38e1a8f54 [SCSI] iscsi_tcp:... |
956 |
.get_stats = iscsi_sw_tcp_conn_get_stats, |
e5a7efeff [SCSI] iscsi_tcp:... |
957 |
/* iscsi task/cmd helpers */ |
fbc514b4e [SCSI] iscsi_tcp:... |
958 959 960 |
.init_task = iscsi_tcp_task_init, .xmit_task = iscsi_tcp_task_xmit, .cleanup_task = iscsi_tcp_cleanup_task, |
e5a7efeff [SCSI] iscsi_tcp:... |
961 |
/* low level pdu helpers */ |
38e1a8f54 [SCSI] iscsi_tcp:... |
962 963 964 |
.xmit_pdu = iscsi_sw_tcp_pdu_xmit, .init_pdu = iscsi_sw_tcp_pdu_init, .alloc_pdu = iscsi_sw_tcp_pdu_alloc, |
5bb0b55a3 [SCSI] iscsi: con... |
965 |
/* recovery */ |
30a6c6523 [SCSI] iscsi: fix... |
966 |
.session_recovery_timedout = iscsi_session_recovery_timedout, |
7ba247138 [SCSI] open-iscsi... |
967 |
}; |
38e1a8f54 [SCSI] iscsi_tcp:... |
968 |
static int __init iscsi_sw_tcp_init(void) |
7ba247138 [SCSI] open-iscsi... |
969 |
{ |
7ba247138 [SCSI] open-iscsi... |
970 |
if (iscsi_max_lun < 1) { |
be2df72e7 [SCSI] iscsi: ali... |
971 972 973 |
printk(KERN_ERR "iscsi_tcp: Invalid max_lun value of %u ", iscsi_max_lun); |
7ba247138 [SCSI] open-iscsi... |
974 975 |
return -EINVAL; } |
7ba247138 [SCSI] open-iscsi... |
976 |
|
38e1a8f54 [SCSI] iscsi_tcp:... |
977 978 979 |
iscsi_sw_tcp_scsi_transport = iscsi_register_transport( &iscsi_sw_tcp_transport); if (!iscsi_sw_tcp_scsi_transport) |
ffbfe9253 [SCSI] iscsi: kil... |
980 |
return -ENODEV; |
7ba247138 [SCSI] open-iscsi... |
981 |
|
7b8631b53 [SCSI] iscsi: sep... |
982 |
return 0; |
7ba247138 [SCSI] open-iscsi... |
983 |
} |
38e1a8f54 [SCSI] iscsi_tcp:... |
984 |
static void __exit iscsi_sw_tcp_exit(void) |
7ba247138 [SCSI] open-iscsi... |
985 |
{ |
38e1a8f54 [SCSI] iscsi_tcp:... |
986 |
iscsi_unregister_transport(&iscsi_sw_tcp_transport); |
7ba247138 [SCSI] open-iscsi... |
987 |
} |
38e1a8f54 [SCSI] iscsi_tcp:... |
988 989 |
module_init(iscsi_sw_tcp_init); module_exit(iscsi_sw_tcp_exit); |