blob: 08357a6c7e096dd92cb5cf92ca9e00594ddb83d0 [file] [log] [blame]
Alex Aizman7ba24712005-08-04 19:30:08 -07001/*
2 * iSCSI Initiator over TCP/IP Data-Path
3 *
4 * Copyright (C) 2004 Dmitry Yusupov
5 * Copyright (C) 2004 Alex Aizman
Mike Christie5bb0b552006-04-06 21:26:46 -05006 * Copyright (C) 2005 - 2006 Mike Christie
7 * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
Alex Aizman7ba24712005-08-04 19:30:08 -07008 * 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 *
20 * See the file COPYING included with this distribution for more details.
21 *
22 * Credits:
23 * Christoph Hellwig
24 * FUJITA Tomonori
25 * Arne Redlich
26 * Zhenyu Wang
27 */
28
29#include <linux/types.h>
30#include <linux/list.h>
31#include <linux/inet.h>
32#include <linux/blkdev.h>
33#include <linux/crypto.h>
34#include <linux/delay.h>
35#include <linux/kfifo.h>
36#include <linux/scatterlist.h>
Arjan van de Ven0b950672006-01-11 13:16:10 +010037#include <linux/mutex.h>
Alex Aizman7ba24712005-08-04 19:30:08 -070038#include <net/tcp.h>
39#include <scsi/scsi_cmnd.h>
Alex Aizman7ba24712005-08-04 19:30:08 -070040#include <scsi/scsi_host.h>
41#include <scsi/scsi.h>
42#include <scsi/scsi_transport_iscsi.h>
43
44#include "iscsi_tcp.h"
45
46MODULE_AUTHOR("Dmitry Yusupov <dmitry_yus@yahoo.com>, "
47 "Alex Aizman <itn780@yahoo.com>");
48MODULE_DESCRIPTION("iSCSI/TCP data-path");
49MODULE_LICENSE("GPL");
Mike Christie4d841d62005-11-29 23:13:01 -060050MODULE_VERSION("0:4.445");
Alex Aizman7ba24712005-08-04 19:30:08 -070051/* #define DEBUG_TCP */
Alex Aizman7ba24712005-08-04 19:30:08 -070052#define DEBUG_ASSERT
53
54#ifdef DEBUG_TCP
Mike Christie5bb0b552006-04-06 21:26:46 -050055#define debug_tcp(fmt...) printk(KERN_INFO "tcp: " fmt)
Alex Aizman7ba24712005-08-04 19:30:08 -070056#else
57#define debug_tcp(fmt...)
58#endif
59
Alex Aizman7ba24712005-08-04 19:30:08 -070060#ifndef DEBUG_ASSERT
61#ifdef BUG_ON
62#undef BUG_ON
63#endif
64#define BUG_ON(expr)
65#endif
66
Alex Aizman7ba24712005-08-04 19:30:08 -070067static unsigned int iscsi_max_lun = 512;
68module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
69
Alex Aizman7ba24712005-08-04 19:30:08 -070070static inline void
Alex Aizman7ba24712005-08-04 19:30:08 -070071iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size)
72{
Mike Christie7cae5152006-01-13 18:05:47 -060073 ibuf->sg.page = virt_to_page(vbuf);
74 ibuf->sg.offset = offset_in_page(vbuf);
Alex Aizman7ba24712005-08-04 19:30:08 -070075 ibuf->sg.length = size;
76 ibuf->sent = 0;
Mike Christie7cae5152006-01-13 18:05:47 -060077 ibuf->use_sendmsg = 1;
Alex Aizman7ba24712005-08-04 19:30:08 -070078}
79
80static inline void
81iscsi_buf_init_sg(struct iscsi_buf *ibuf, struct scatterlist *sg)
82{
Mike Christie7cae5152006-01-13 18:05:47 -060083 ibuf->sg.page = sg->page;
84 ibuf->sg.offset = sg->offset;
85 ibuf->sg.length = sg->length;
Alex Aizman7ba24712005-08-04 19:30:08 -070086 /*
87 * Fastpath: sg element fits into single page
88 */
Mike Christiea1e80c22006-01-13 18:05:56 -060089 if (sg->length + sg->offset <= PAGE_SIZE && !PageSlab(sg->page))
Mike Christie7cae5152006-01-13 18:05:47 -060090 ibuf->use_sendmsg = 0;
91 else
92 ibuf->use_sendmsg = 1;
Alex Aizman7ba24712005-08-04 19:30:08 -070093 ibuf->sent = 0;
94}
95
96static inline int
97iscsi_buf_left(struct iscsi_buf *ibuf)
98{
99 int rc;
100
101 rc = ibuf->sg.length - ibuf->sent;
102 BUG_ON(rc < 0);
103 return rc;
104}
105
106static inline void
Mike Christieaf973482005-09-12 21:01:32 -0500107iscsi_hdr_digest(struct iscsi_conn *conn, struct iscsi_buf *buf,
108 u8* crc)
Alex Aizman7ba24712005-08-04 19:30:08 -0700109{
Mike Christie5bb0b552006-04-06 21:26:46 -0500110 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
111
112 crypto_digest_digest(tcp_conn->tx_tfm, &buf->sg, 1, crc);
Mike Christieaf973482005-09-12 21:01:32 -0500113 buf->sg.length += sizeof(uint32_t);
Alex Aizman7ba24712005-08-04 19:30:08 -0700114}
115
Alex Aizman7ba24712005-08-04 19:30:08 -0700116static inline int
Mike Christie5bb0b552006-04-06 21:26:46 -0500117iscsi_hdr_extract(struct iscsi_tcp_conn *tcp_conn)
Alex Aizman7ba24712005-08-04 19:30:08 -0700118{
Mike Christie5bb0b552006-04-06 21:26:46 -0500119 struct sk_buff *skb = tcp_conn->in.skb;
Alex Aizman7ba24712005-08-04 19:30:08 -0700120
Mike Christie5bb0b552006-04-06 21:26:46 -0500121 tcp_conn->in.zero_copy_hdr = 0;
Alex Aizman7ba24712005-08-04 19:30:08 -0700122
Mike Christie5bb0b552006-04-06 21:26:46 -0500123 if (tcp_conn->in.copy >= tcp_conn->hdr_size &&
124 tcp_conn->in_progress == IN_PROGRESS_WAIT_HEADER) {
Alex Aizman7ba24712005-08-04 19:30:08 -0700125 /*
126 * Zero-copy PDU Header: using connection context
127 * to store header pointer.
128 */
129 if (skb_shinfo(skb)->frag_list == NULL &&
Mike Christie5bb0b552006-04-06 21:26:46 -0500130 !skb_shinfo(skb)->nr_frags) {
131 tcp_conn->in.hdr = (struct iscsi_hdr *)
132 ((char*)skb->data + tcp_conn->in.offset);
133 tcp_conn->in.zero_copy_hdr = 1;
134 } else {
Alex Aizman7ba24712005-08-04 19:30:08 -0700135 /* ignoring return code since we checked
136 * in.copy before */
Mike Christie5bb0b552006-04-06 21:26:46 -0500137 skb_copy_bits(skb, tcp_conn->in.offset,
138 &tcp_conn->hdr, tcp_conn->hdr_size);
139 tcp_conn->in.hdr = &tcp_conn->hdr;
Alex Aizman7ba24712005-08-04 19:30:08 -0700140 }
Mike Christie5bb0b552006-04-06 21:26:46 -0500141 tcp_conn->in.offset += tcp_conn->hdr_size;
142 tcp_conn->in.copy -= tcp_conn->hdr_size;
Alex Aizman7ba24712005-08-04 19:30:08 -0700143 } else {
144 int hdr_remains;
145 int copylen;
146
147 /*
148 * PDU header scattered across SKB's,
149 * copying it... This'll happen quite rarely.
150 */
151
Mike Christie5bb0b552006-04-06 21:26:46 -0500152 if (tcp_conn->in_progress == IN_PROGRESS_WAIT_HEADER)
153 tcp_conn->in.hdr_offset = 0;
Alex Aizman7ba24712005-08-04 19:30:08 -0700154
Mike Christie5bb0b552006-04-06 21:26:46 -0500155 hdr_remains = tcp_conn->hdr_size - tcp_conn->in.hdr_offset;
Alex Aizman7ba24712005-08-04 19:30:08 -0700156 BUG_ON(hdr_remains <= 0);
157
Mike Christie5bb0b552006-04-06 21:26:46 -0500158 copylen = min(tcp_conn->in.copy, hdr_remains);
159 skb_copy_bits(skb, tcp_conn->in.offset,
160 (char*)&tcp_conn->hdr + tcp_conn->in.hdr_offset,
161 copylen);
Alex Aizman7ba24712005-08-04 19:30:08 -0700162
163 debug_tcp("PDU gather offset %d bytes %d in.offset %d "
Mike Christie5bb0b552006-04-06 21:26:46 -0500164 "in.copy %d\n", tcp_conn->in.hdr_offset, copylen,
165 tcp_conn->in.offset, tcp_conn->in.copy);
Alex Aizman7ba24712005-08-04 19:30:08 -0700166
Mike Christie5bb0b552006-04-06 21:26:46 -0500167 tcp_conn->in.offset += copylen;
168 tcp_conn->in.copy -= copylen;
Alex Aizman7ba24712005-08-04 19:30:08 -0700169 if (copylen < hdr_remains) {
Mike Christie5bb0b552006-04-06 21:26:46 -0500170 tcp_conn->in_progress = IN_PROGRESS_HEADER_GATHER;
171 tcp_conn->in.hdr_offset += copylen;
Alex Aizman7ba24712005-08-04 19:30:08 -0700172 return -EAGAIN;
173 }
Mike Christie5bb0b552006-04-06 21:26:46 -0500174 tcp_conn->in.hdr = &tcp_conn->hdr;
175 tcp_conn->discontiguous_hdr_cnt++;
176 tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
Alex Aizman7ba24712005-08-04 19:30:08 -0700177 }
178
179 return 0;
180}
181
Mike Christie30a6c652006-04-06 21:13:39 -0500182/*
183 * must be called with session lock
184 */
185static void
186__iscsi_ctask_cleanup(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
Alex Aizman7ba24712005-08-04 19:30:08 -0700187{
Mike Christie5bb0b552006-04-06 21:26:46 -0500188 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
Mike Christie30a6c652006-04-06 21:13:39 -0500189 struct scsi_cmnd *sc;
Alex Aizman7ba24712005-08-04 19:30:08 -0700190
Mike Christie30a6c652006-04-06 21:13:39 -0500191 sc = ctask->sc;
192 if (unlikely(!sc))
Alex Aizman7ba24712005-08-04 19:30:08 -0700193 return;
Mike Christie30a6c652006-04-06 21:13:39 -0500194
Mike Christie5bb0b552006-04-06 21:26:46 -0500195 tcp_ctask->xmstate = XMSTATE_IDLE;
196 tcp_ctask->r2t = NULL;
Alex Aizman7ba24712005-08-04 19:30:08 -0700197}
198
199/**
200 * iscsi_data_rsp - SCSI Data-In Response processing
201 * @conn: iscsi connection
202 * @ctask: scsi command task
203 **/
204static int
205iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
206{
207 int rc;
Mike Christie5bb0b552006-04-06 21:26:46 -0500208 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
209 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
210 struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr;
Alex Aizman7ba24712005-08-04 19:30:08 -0700211 struct iscsi_session *session = conn->session;
212 int datasn = be32_to_cpu(rhdr->datasn);
213
214 rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr);
215 if (rc)
216 return rc;
217 /*
218 * setup Data-In byte counter (gets decremented..)
219 */
Mike Christie5bb0b552006-04-06 21:26:46 -0500220 ctask->data_count = tcp_conn->in.datalen;
Alex Aizman7ba24712005-08-04 19:30:08 -0700221
Mike Christie5bb0b552006-04-06 21:26:46 -0500222 if (tcp_conn->in.datalen == 0)
Alex Aizman7ba24712005-08-04 19:30:08 -0700223 return 0;
224
225 if (ctask->datasn != datasn)
226 return ISCSI_ERR_DATASN;
227
228 ctask->datasn++;
229
Mike Christie5bb0b552006-04-06 21:26:46 -0500230 tcp_ctask->data_offset = be32_to_cpu(rhdr->offset);
231 if (tcp_ctask->data_offset + tcp_conn->in.datalen > ctask->total_length)
Alex Aizman7ba24712005-08-04 19:30:08 -0700232 return ISCSI_ERR_DATA_OFFSET;
233
234 if (rhdr->flags & ISCSI_FLAG_DATA_STATUS) {
235 struct scsi_cmnd *sc = ctask->sc;
236
237 conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
zhenyu.z.wang@intel.combf310b82006-01-13 18:05:38 -0600238 if (rhdr->flags & ISCSI_FLAG_DATA_UNDERFLOW) {
Alex Aizman7ba24712005-08-04 19:30:08 -0700239 int res_count = be32_to_cpu(rhdr->residual_count);
240
241 if (res_count > 0 &&
242 res_count <= sc->request_bufflen) {
243 sc->resid = res_count;
244 sc->result = (DID_OK << 16) | rhdr->cmd_status;
245 } else
246 sc->result = (DID_BAD_TARGET << 16) |
247 rhdr->cmd_status;
zhenyu.z.wang@intel.combf310b82006-01-13 18:05:38 -0600248 } else if (rhdr->flags & ISCSI_FLAG_DATA_OVERFLOW) {
Alex Aizman7ba24712005-08-04 19:30:08 -0700249 sc->resid = be32_to_cpu(rhdr->residual_count);
250 sc->result = (DID_OK << 16) | rhdr->cmd_status;
251 } else
252 sc->result = (DID_OK << 16) | rhdr->cmd_status;
253 }
254
255 conn->datain_pdus_cnt++;
256 return 0;
257}
258
259/**
260 * iscsi_solicit_data_init - initialize first Data-Out
261 * @conn: iscsi connection
262 * @ctask: scsi command task
263 * @r2t: R2T info
264 *
265 * Notes:
266 * Initialize first Data-Out within this R2T sequence and finds
267 * proper data_offset within this SCSI command.
268 *
269 * This function is called with connection lock taken.
270 **/
271static void
272iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
273 struct iscsi_r2t_info *r2t)
274{
275 struct iscsi_data *hdr;
Alex Aizman7ba24712005-08-04 19:30:08 -0700276 struct scsi_cmnd *sc = ctask->sc;
Mike Christie5bb0b552006-04-06 21:26:46 -0500277 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
Alex Aizman7ba24712005-08-04 19:30:08 -0700278
Mike Christieffbfe922006-05-18 20:31:36 -0500279 hdr = &r2t->dtask.hdr;
Alex Aizman7ba24712005-08-04 19:30:08 -0700280 memset(hdr, 0, sizeof(struct iscsi_data));
281 hdr->ttt = r2t->ttt;
282 hdr->datasn = cpu_to_be32(r2t->solicit_datasn);
283 r2t->solicit_datasn++;
284 hdr->opcode = ISCSI_OP_SCSI_DATA_OUT;
Mike Christie5bb0b552006-04-06 21:26:46 -0500285 memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun));
286 hdr->itt = ctask->hdr->itt;
Alex Aizman7ba24712005-08-04 19:30:08 -0700287 hdr->exp_statsn = r2t->exp_statsn;
288 hdr->offset = cpu_to_be32(r2t->data_offset);
289 if (r2t->data_length > conn->max_xmit_dlength) {
290 hton24(hdr->dlength, conn->max_xmit_dlength);
291 r2t->data_count = conn->max_xmit_dlength;
292 hdr->flags = 0;
293 } else {
294 hton24(hdr->dlength, r2t->data_length);
295 r2t->data_count = r2t->data_length;
296 hdr->flags = ISCSI_FLAG_CMD_FINAL;
297 }
298 conn->dataout_pdus_cnt++;
299
300 r2t->sent = 0;
301
Mike Christie6e458cc2006-05-18 20:31:31 -0500302 iscsi_buf_init_iov(&r2t->headbuf, (char*)hdr,
Mike Christieaf973482005-09-12 21:01:32 -0500303 sizeof(struct iscsi_hdr));
Alex Aizman7ba24712005-08-04 19:30:08 -0700304
Alex Aizman7ba24712005-08-04 19:30:08 -0700305 if (sc->use_sg) {
306 int i, sg_count = 0;
307 struct scatterlist *sg = sc->request_buffer;
308
309 r2t->sg = NULL;
310 for (i = 0; i < sc->use_sg; i++, sg += 1) {
311 /* FIXME: prefetch ? */
312 if (sg_count + sg->length > r2t->data_offset) {
313 int page_offset;
314
315 /* sg page found! */
316
317 /* offset within this page */
318 page_offset = r2t->data_offset - sg_count;
319
320 /* fill in this buffer */
321 iscsi_buf_init_sg(&r2t->sendbuf, sg);
322 r2t->sendbuf.sg.offset += page_offset;
323 r2t->sendbuf.sg.length -= page_offset;
324
325 /* xmit logic will continue with next one */
326 r2t->sg = sg + 1;
327 break;
328 }
329 sg_count += sg->length;
330 }
331 BUG_ON(r2t->sg == NULL);
332 } else
Mike Christie5bb0b552006-04-06 21:26:46 -0500333 iscsi_buf_init_iov(&tcp_ctask->sendbuf,
Alex Aizman7ba24712005-08-04 19:30:08 -0700334 (char*)sc->request_buffer + r2t->data_offset,
335 r2t->data_count);
Alex Aizman7ba24712005-08-04 19:30:08 -0700336}
337
338/**
339 * iscsi_r2t_rsp - iSCSI R2T Response processing
340 * @conn: iscsi connection
341 * @ctask: scsi command task
342 **/
343static int
344iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
345{
346 struct iscsi_r2t_info *r2t;
347 struct iscsi_session *session = conn->session;
Mike Christie5bb0b552006-04-06 21:26:46 -0500348 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
349 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
350 struct iscsi_r2t_rsp *rhdr = (struct iscsi_r2t_rsp *)tcp_conn->in.hdr;
Alex Aizman7ba24712005-08-04 19:30:08 -0700351 int r2tsn = be32_to_cpu(rhdr->r2tsn);
352 int rc;
353
Mike Christie5bb0b552006-04-06 21:26:46 -0500354 if (tcp_conn->in.datalen)
Alex Aizman7ba24712005-08-04 19:30:08 -0700355 return ISCSI_ERR_DATALEN;
356
Mike Christie5bb0b552006-04-06 21:26:46 -0500357 if (tcp_ctask->exp_r2tsn && tcp_ctask->exp_r2tsn != r2tsn)
Alex Aizman7ba24712005-08-04 19:30:08 -0700358 return ISCSI_ERR_R2TSN;
359
360 rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr);
361 if (rc)
362 return rc;
363
364 /* FIXME: use R2TSN to detect missing R2T */
365
366 /* fill-in new R2T associated with the task */
367 spin_lock(&session->lock);
368 if (!ctask->sc || ctask->mtask ||
369 session->state != ISCSI_STATE_LOGGED_IN) {
370 printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in "
371 "recovery...\n", ctask->itt);
372 spin_unlock(&session->lock);
373 return 0;
374 }
Mike Christie5bb0b552006-04-06 21:26:46 -0500375 rc = __kfifo_get(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*));
Alex Aizman7ba24712005-08-04 19:30:08 -0700376 BUG_ON(!rc);
377
378 r2t->exp_statsn = rhdr->statsn;
379 r2t->data_length = be32_to_cpu(rhdr->data_length);
380 if (r2t->data_length == 0 ||
381 r2t->data_length > session->max_burst) {
382 spin_unlock(&session->lock);
383 return ISCSI_ERR_DATALEN;
384 }
385
386 r2t->data_offset = be32_to_cpu(rhdr->data_offset);
387 if (r2t->data_offset + r2t->data_length > ctask->total_length) {
388 spin_unlock(&session->lock);
389 return ISCSI_ERR_DATALEN;
390 }
391
392 r2t->ttt = rhdr->ttt; /* no flip */
393 r2t->solicit_datasn = 0;
394
395 iscsi_solicit_data_init(conn, ctask, r2t);
396
Mike Christie5bb0b552006-04-06 21:26:46 -0500397 tcp_ctask->exp_r2tsn = r2tsn + 1;
398 tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
399 __kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*));
400 __kfifo_put(conn->xmitqueue, (void*)&ctask, sizeof(void*));
Alex Aizman7ba24712005-08-04 19:30:08 -0700401
Mike Christie55e32992006-01-13 18:05:53 -0600402 scsi_queue_work(session->host, &conn->xmitwork);
Alex Aizman7ba24712005-08-04 19:30:08 -0700403 conn->r2t_pdus_cnt++;
404 spin_unlock(&session->lock);
405
406 return 0;
407}
408
409static int
Mike Christie5bb0b552006-04-06 21:26:46 -0500410iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
Alex Aizman7ba24712005-08-04 19:30:08 -0700411{
Mike Christie5bb0b552006-04-06 21:26:46 -0500412 int rc = 0, opcode, ahslen;
Alex Aizman7ba24712005-08-04 19:30:08 -0700413 struct iscsi_hdr *hdr;
Alex Aizman7ba24712005-08-04 19:30:08 -0700414 struct iscsi_session *session = conn->session;
Mike Christie5bb0b552006-04-06 21:26:46 -0500415 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
416 uint32_t cdgst, rdgst = 0, itt;
Alex Aizman7ba24712005-08-04 19:30:08 -0700417
Mike Christie5bb0b552006-04-06 21:26:46 -0500418 hdr = tcp_conn->in.hdr;
Alex Aizman7ba24712005-08-04 19:30:08 -0700419
420 /* verify PDU length */
Mike Christie5bb0b552006-04-06 21:26:46 -0500421 tcp_conn->in.datalen = ntoh24(hdr->dlength);
422 if (tcp_conn->in.datalen > conn->max_recv_dlength) {
Alex Aizman7ba24712005-08-04 19:30:08 -0700423 printk(KERN_ERR "iscsi_tcp: datalen %d > %d\n",
Mike Christie5bb0b552006-04-06 21:26:46 -0500424 tcp_conn->in.datalen, conn->max_recv_dlength);
Alex Aizman7ba24712005-08-04 19:30:08 -0700425 return ISCSI_ERR_DATALEN;
426 }
Mike Christie5bb0b552006-04-06 21:26:46 -0500427 tcp_conn->data_copied = 0;
Alex Aizman7ba24712005-08-04 19:30:08 -0700428
429 /* read AHS */
Mike Christie5bb0b552006-04-06 21:26:46 -0500430 ahslen = hdr->hlength << 2;
431 tcp_conn->in.offset += ahslen;
432 tcp_conn->in.copy -= ahslen;
433 if (tcp_conn->in.copy < 0) {
Alex Aizman7ba24712005-08-04 19:30:08 -0700434 printk(KERN_ERR "iscsi_tcp: can't handle AHS with length "
Mike Christie5bb0b552006-04-06 21:26:46 -0500435 "%d bytes\n", ahslen);
Alex Aizman7ba24712005-08-04 19:30:08 -0700436 return ISCSI_ERR_AHSLEN;
437 }
438
439 /* calculate read padding */
Mike Christie5bb0b552006-04-06 21:26:46 -0500440 tcp_conn->in.padding = tcp_conn->in.datalen & (ISCSI_PAD_LEN-1);
441 if (tcp_conn->in.padding) {
442 tcp_conn->in.padding = ISCSI_PAD_LEN - tcp_conn->in.padding;
443 debug_scsi("read padding %d bytes\n", tcp_conn->in.padding);
Alex Aizman7ba24712005-08-04 19:30:08 -0700444 }
445
446 if (conn->hdrdgst_en) {
447 struct scatterlist sg;
448
449 sg_init_one(&sg, (u8 *)hdr,
Mike Christie5bb0b552006-04-06 21:26:46 -0500450 sizeof(struct iscsi_hdr) + ahslen);
451 crypto_digest_digest(tcp_conn->rx_tfm, &sg, 1, (u8 *)&cdgst);
Alex Aizman7ba24712005-08-04 19:30:08 -0700452 rdgst = *(uint32_t*)((char*)hdr + sizeof(struct iscsi_hdr) +
Mike Christie5bb0b552006-04-06 21:26:46 -0500453 ahslen);
Mike Christie8a47cd32005-11-30 02:27:19 -0600454 if (cdgst != rdgst) {
Mike Christie5bb0b552006-04-06 21:26:46 -0500455 printk(KERN_ERR "iscsi_tcp: hdrdgst error "
456 "recv 0x%x calc 0x%x\n", rdgst, cdgst);
Mike Christie8a47cd32005-11-30 02:27:19 -0600457 return ISCSI_ERR_HDR_DGST;
458 }
Alex Aizman7ba24712005-08-04 19:30:08 -0700459 }
460
Mike Christie5bb0b552006-04-06 21:26:46 -0500461 opcode = hdr->opcode & ISCSI_OPCODE_MASK;
Alex Aizman7ba24712005-08-04 19:30:08 -0700462 /* verify itt (itt encoding: age+cid+itt) */
Mike Christie5bb0b552006-04-06 21:26:46 -0500463 rc = iscsi_verify_itt(conn, hdr, &itt);
464 if (rc == ISCSI_ERR_NO_SCSI_CMD) {
465 tcp_conn->in.datalen = 0; /* force drop */
466 return 0;
467 } else if (rc)
468 return rc;
Alex Aizman7ba24712005-08-04 19:30:08 -0700469
470 debug_tcp("opcode 0x%x offset %d copy %d ahslen %d datalen %d\n",
Mike Christie5bb0b552006-04-06 21:26:46 -0500471 opcode, tcp_conn->in.offset, tcp_conn->in.copy,
472 ahslen, tcp_conn->in.datalen);
Alex Aizman7ba24712005-08-04 19:30:08 -0700473
Mike Christie5bb0b552006-04-06 21:26:46 -0500474 switch(opcode) {
475 case ISCSI_OP_SCSI_DATA_IN:
476 tcp_conn->in.ctask = session->cmds[itt];
477 rc = iscsi_data_rsp(conn, tcp_conn->in.ctask);
478 /* fall through */
479 case ISCSI_OP_SCSI_CMD_RSP:
480 tcp_conn->in.ctask = session->cmds[itt];
481 if (tcp_conn->in.datalen)
482 goto copy_hdr;
Alex Aizman7ba24712005-08-04 19:30:08 -0700483
Mike Christie5bb0b552006-04-06 21:26:46 -0500484 spin_lock(&session->lock);
485 __iscsi_ctask_cleanup(conn, tcp_conn->in.ctask);
486 rc = __iscsi_complete_pdu(conn, hdr, NULL, 0);
487 spin_unlock(&session->lock);
488 break;
489 case ISCSI_OP_R2T:
490 tcp_conn->in.ctask = session->cmds[itt];
491 if (ahslen)
492 rc = ISCSI_ERR_AHSLEN;
493 else if (tcp_conn->in.ctask->sc->sc_data_direction ==
494 DMA_TO_DEVICE)
495 rc = iscsi_r2t_rsp(conn, tcp_conn->in.ctask);
496 else
497 rc = ISCSI_ERR_PROTO;
498 break;
499 case ISCSI_OP_LOGIN_RSP:
500 case ISCSI_OP_TEXT_RSP:
501 case ISCSI_OP_LOGOUT_RSP:
502 case ISCSI_OP_NOOP_IN:
503 case ISCSI_OP_REJECT:
504 case ISCSI_OP_ASYNC_EVENT:
505 if (tcp_conn->in.datalen)
506 goto copy_hdr;
507 /* fall through */
508 case ISCSI_OP_SCSI_TMFUNC_RSP:
509 rc = iscsi_complete_pdu(conn, hdr, NULL, 0);
510 break;
511 default:
512 rc = ISCSI_ERR_BAD_OPCODE;
513 break;
514 }
Alex Aizman7ba24712005-08-04 19:30:08 -0700515
516 return rc;
Mike Christie5bb0b552006-04-06 21:26:46 -0500517
518copy_hdr:
519 /*
520 * if we did zero copy for the header but we will need multiple
521 * skbs to complete the command then we have to copy the header
522 * for later use
523 */
524 if (tcp_conn->in.zero_copy_hdr && tcp_conn->in.copy <
525 (tcp_conn->in.datalen + tcp_conn->in.padding +
526 (conn->datadgst_en ? 4 : 0))) {
527 debug_tcp("Copying header for later use. in.copy %d in.datalen"
528 " %d\n", tcp_conn->in.copy, tcp_conn->in.datalen);
529 memcpy(&tcp_conn->hdr, tcp_conn->in.hdr,
530 sizeof(struct iscsi_hdr));
531 tcp_conn->in.hdr = &tcp_conn->hdr;
532 tcp_conn->in.zero_copy_hdr = 0;
533 }
534 return 0;
Alex Aizman7ba24712005-08-04 19:30:08 -0700535}
536
537/**
538 * iscsi_ctask_copy - copy skb bits to the destanation cmd task
Mike Christie5bb0b552006-04-06 21:26:46 -0500539 * @conn: iscsi tcp connection
Alex Aizman7ba24712005-08-04 19:30:08 -0700540 * @ctask: scsi command task
541 * @buf: buffer to copy to
542 * @buf_size: size of buffer
543 * @offset: offset within the buffer
544 *
545 * Notes:
546 * The function calls skb_copy_bits() and updates per-connection and
547 * per-cmd byte counters.
548 *
549 * Read counters (in bytes):
550 *
551 * conn->in.offset offset within in progress SKB
552 * conn->in.copy left to copy from in progress SKB
553 * including padding
554 * conn->in.copied copied already from in progress SKB
555 * conn->data_copied copied already from in progress buffer
556 * ctask->sent total bytes sent up to the MidLayer
557 * ctask->data_count left to copy from in progress Data-In
558 * buf_left left to copy from in progress buffer
559 **/
560static inline int
Mike Christie5bb0b552006-04-06 21:26:46 -0500561iscsi_ctask_copy(struct iscsi_tcp_conn *tcp_conn, struct iscsi_cmd_task *ctask,
Alex Aizman7ba24712005-08-04 19:30:08 -0700562 void *buf, int buf_size, int offset)
563{
Mike Christie5bb0b552006-04-06 21:26:46 -0500564 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
565 int buf_left = buf_size - (tcp_conn->data_copied + offset);
566 int size = min(tcp_conn->in.copy, buf_left);
Alex Aizman7ba24712005-08-04 19:30:08 -0700567 int rc;
568
569 size = min(size, ctask->data_count);
570
571 debug_tcp("ctask_copy %d bytes at offset %d copied %d\n",
Mike Christie5bb0b552006-04-06 21:26:46 -0500572 size, tcp_conn->in.offset, tcp_conn->in.copied);
Alex Aizman7ba24712005-08-04 19:30:08 -0700573
574 BUG_ON(size <= 0);
Mike Christie5bb0b552006-04-06 21:26:46 -0500575 BUG_ON(tcp_ctask->sent + size > ctask->total_length);
Alex Aizman7ba24712005-08-04 19:30:08 -0700576
Mike Christie5bb0b552006-04-06 21:26:46 -0500577 rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
578 (char*)buf + (offset + tcp_conn->data_copied), size);
Alex Aizman7ba24712005-08-04 19:30:08 -0700579 /* must fit into skb->len */
580 BUG_ON(rc);
581
Mike Christie5bb0b552006-04-06 21:26:46 -0500582 tcp_conn->in.offset += size;
583 tcp_conn->in.copy -= size;
584 tcp_conn->in.copied += size;
585 tcp_conn->data_copied += size;
586 tcp_ctask->sent += size;
Alex Aizman7ba24712005-08-04 19:30:08 -0700587 ctask->data_count -= size;
588
Mike Christie5bb0b552006-04-06 21:26:46 -0500589 BUG_ON(tcp_conn->in.copy < 0);
Alex Aizman7ba24712005-08-04 19:30:08 -0700590 BUG_ON(ctask->data_count < 0);
591
Mike Christie5bb0b552006-04-06 21:26:46 -0500592 if (buf_size != (tcp_conn->data_copied + offset)) {
Alex Aizman7ba24712005-08-04 19:30:08 -0700593 if (!ctask->data_count) {
Mike Christie5bb0b552006-04-06 21:26:46 -0500594 BUG_ON(buf_size - tcp_conn->data_copied < 0);
Alex Aizman7ba24712005-08-04 19:30:08 -0700595 /* done with this PDU */
Mike Christie5bb0b552006-04-06 21:26:46 -0500596 return buf_size - tcp_conn->data_copied;
Alex Aizman7ba24712005-08-04 19:30:08 -0700597 }
598 return -EAGAIN;
599 }
600
601 /* done with this buffer or with both - PDU and buffer */
Mike Christie5bb0b552006-04-06 21:26:46 -0500602 tcp_conn->data_copied = 0;
Alex Aizman7ba24712005-08-04 19:30:08 -0700603 return 0;
604}
605
606/**
607 * iscsi_tcp_copy - copy skb bits to the destanation buffer
Mike Christie5bb0b552006-04-06 21:26:46 -0500608 * @conn: iscsi tcp connection
Alex Aizman7ba24712005-08-04 19:30:08 -0700609 *
610 * Notes:
611 * The function calls skb_copy_bits() and updates per-connection
612 * byte counters.
613 **/
614static inline int
Mike Christie5bb0b552006-04-06 21:26:46 -0500615iscsi_tcp_copy(struct iscsi_tcp_conn *tcp_conn)
Alex Aizman7ba24712005-08-04 19:30:08 -0700616{
Mike Christie5bb0b552006-04-06 21:26:46 -0500617 void *buf = tcp_conn->data;
618 int buf_size = tcp_conn->in.datalen;
619 int buf_left = buf_size - tcp_conn->data_copied;
620 int size = min(tcp_conn->in.copy, buf_left);
Alex Aizman7ba24712005-08-04 19:30:08 -0700621 int rc;
622
623 debug_tcp("tcp_copy %d bytes at offset %d copied %d\n",
Mike Christie5bb0b552006-04-06 21:26:46 -0500624 size, tcp_conn->in.offset, tcp_conn->data_copied);
Alex Aizman7ba24712005-08-04 19:30:08 -0700625 BUG_ON(size <= 0);
626
Mike Christie5bb0b552006-04-06 21:26:46 -0500627 rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
628 (char*)buf + tcp_conn->data_copied, size);
Alex Aizman7ba24712005-08-04 19:30:08 -0700629 BUG_ON(rc);
630
Mike Christie5bb0b552006-04-06 21:26:46 -0500631 tcp_conn->in.offset += size;
632 tcp_conn->in.copy -= size;
633 tcp_conn->in.copied += size;
634 tcp_conn->data_copied += size;
Alex Aizman7ba24712005-08-04 19:30:08 -0700635
Mike Christie5bb0b552006-04-06 21:26:46 -0500636 if (buf_size != tcp_conn->data_copied)
Alex Aizman7ba24712005-08-04 19:30:08 -0700637 return -EAGAIN;
638
639 return 0;
640}
641
642static inline void
Mike Christie5bb0b552006-04-06 21:26:46 -0500643partial_sg_digest_update(struct iscsi_tcp_conn *tcp_conn,
644 struct scatterlist *sg, int offset, int length)
Alex Aizman7ba24712005-08-04 19:30:08 -0700645{
646 struct scatterlist temp;
647
648 memcpy(&temp, sg, sizeof(struct scatterlist));
649 temp.offset = offset;
650 temp.length = length;
Mike Christie5bb0b552006-04-06 21:26:46 -0500651 crypto_digest_update(tcp_conn->data_rx_tfm, &temp, 1);
Alex Aizman7ba24712005-08-04 19:30:08 -0700652}
653
Mike Christief6cfba12005-11-29 23:12:57 -0600654static void
Mike Christie5bb0b552006-04-06 21:26:46 -0500655iscsi_recv_digest_update(struct iscsi_tcp_conn *tcp_conn, char* buf, int len)
Mike Christief6cfba12005-11-29 23:12:57 -0600656{
657 struct scatterlist tmp;
658
659 sg_init_one(&tmp, buf, len);
Mike Christie5bb0b552006-04-06 21:26:46 -0500660 crypto_digest_update(tcp_conn->data_rx_tfm, &tmp, 1);
Mike Christief6cfba12005-11-29 23:12:57 -0600661}
662
Alex Aizman7ba24712005-08-04 19:30:08 -0700663static int iscsi_scsi_data_in(struct iscsi_conn *conn)
664{
Mike Christie5bb0b552006-04-06 21:26:46 -0500665 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
666 struct iscsi_cmd_task *ctask = tcp_conn->in.ctask;
667 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
Alex Aizman7ba24712005-08-04 19:30:08 -0700668 struct scsi_cmnd *sc = ctask->sc;
Mike Christief6cfba12005-11-29 23:12:57 -0600669 struct scatterlist *sg;
Alex Aizman7ba24712005-08-04 19:30:08 -0700670 int i, offset, rc = 0;
671
672 BUG_ON((void*)ctask != sc->SCp.ptr);
673
674 /*
675 * copying Data-In into the Scsi_Cmnd
676 */
677 if (!sc->use_sg) {
678 i = ctask->data_count;
Mike Christie5bb0b552006-04-06 21:26:46 -0500679 rc = iscsi_ctask_copy(tcp_conn, ctask, sc->request_buffer,
680 sc->request_bufflen,
681 tcp_ctask->data_offset);
Alex Aizman7ba24712005-08-04 19:30:08 -0700682 if (rc == -EAGAIN)
683 return rc;
FUJITA Tomonori42f72aa2006-01-13 18:05:35 -0600684 if (conn->datadgst_en)
Mike Christie5bb0b552006-04-06 21:26:46 -0500685 iscsi_recv_digest_update(tcp_conn, sc->request_buffer,
686 i);
Alex Aizman7ba24712005-08-04 19:30:08 -0700687 rc = 0;
688 goto done;
689 }
690
Mike Christie5bb0b552006-04-06 21:26:46 -0500691 offset = tcp_ctask->data_offset;
Alex Aizman7ba24712005-08-04 19:30:08 -0700692 sg = sc->request_buffer;
693
Mike Christie5bb0b552006-04-06 21:26:46 -0500694 if (tcp_ctask->data_offset)
695 for (i = 0; i < tcp_ctask->sg_count; i++)
Alex Aizman7ba24712005-08-04 19:30:08 -0700696 offset -= sg[i].length;
697 /* we've passed through partial sg*/
698 if (offset < 0)
699 offset = 0;
700
Mike Christie5bb0b552006-04-06 21:26:46 -0500701 for (i = tcp_ctask->sg_count; i < sc->use_sg; i++) {
Alex Aizman7ba24712005-08-04 19:30:08 -0700702 char *dest;
703
704 dest = kmap_atomic(sg[i].page, KM_SOFTIRQ0);
Mike Christie5bb0b552006-04-06 21:26:46 -0500705 rc = iscsi_ctask_copy(tcp_conn, ctask, dest + sg[i].offset,
Alex Aizman7ba24712005-08-04 19:30:08 -0700706 sg[i].length, offset);
707 kunmap_atomic(dest, KM_SOFTIRQ0);
708 if (rc == -EAGAIN)
709 /* continue with the next SKB/PDU */
710 return rc;
711 if (!rc) {
712 if (conn->datadgst_en) {
713 if (!offset)
Mike Christie5bb0b552006-04-06 21:26:46 -0500714 crypto_digest_update(
715 tcp_conn->data_rx_tfm,
716 &sg[i], 1);
Alex Aizman7ba24712005-08-04 19:30:08 -0700717 else
Mike Christie5bb0b552006-04-06 21:26:46 -0500718 partial_sg_digest_update(tcp_conn,
719 &sg[i],
Alex Aizman7ba24712005-08-04 19:30:08 -0700720 sg[i].offset + offset,
721 sg[i].length - offset);
722 }
723 offset = 0;
Mike Christie5bb0b552006-04-06 21:26:46 -0500724 tcp_ctask->sg_count++;
Alex Aizman7ba24712005-08-04 19:30:08 -0700725 }
726
727 if (!ctask->data_count) {
728 if (rc && conn->datadgst_en)
729 /*
730 * data-in is complete, but buffer not...
731 */
Mike Christie5bb0b552006-04-06 21:26:46 -0500732 partial_sg_digest_update(tcp_conn, &sg[i],
Alex Aizman7ba24712005-08-04 19:30:08 -0700733 sg[i].offset, sg[i].length-rc);
734 rc = 0;
735 break;
736 }
737
Mike Christie5bb0b552006-04-06 21:26:46 -0500738 if (!tcp_conn->in.copy)
Alex Aizman7ba24712005-08-04 19:30:08 -0700739 return -EAGAIN;
740 }
741 BUG_ON(ctask->data_count);
742
743done:
744 /* check for non-exceptional status */
Mike Christie5bb0b552006-04-06 21:26:46 -0500745 if (tcp_conn->in.hdr->flags & ISCSI_FLAG_DATA_STATUS) {
Alex Aizman7ba24712005-08-04 19:30:08 -0700746 debug_scsi("done [sc %lx res %d itt 0x%x]\n",
747 (long)sc, sc->result, ctask->itt);
Mike Christie5bb0b552006-04-06 21:26:46 -0500748 spin_lock(&conn->session->lock);
749 __iscsi_ctask_cleanup(conn, ctask);
750 __iscsi_complete_pdu(conn, tcp_conn->in.hdr, NULL, 0);
751 spin_unlock(&conn->session->lock);
Alex Aizman7ba24712005-08-04 19:30:08 -0700752 }
753
754 return rc;
755}
756
757static int
758iscsi_data_recv(struct iscsi_conn *conn)
759{
Mike Christie5bb0b552006-04-06 21:26:46 -0500760 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
761 int rc = 0, opcode;
Alex Aizman7ba24712005-08-04 19:30:08 -0700762
Mike Christie5bb0b552006-04-06 21:26:46 -0500763 opcode = tcp_conn->in.hdr->opcode & ISCSI_OPCODE_MASK;
764 switch (opcode) {
Alex Aizman7ba24712005-08-04 19:30:08 -0700765 case ISCSI_OP_SCSI_DATA_IN:
766 rc = iscsi_scsi_data_in(conn);
767 break;
Mike Christie5bb0b552006-04-06 21:26:46 -0500768 case ISCSI_OP_SCSI_CMD_RSP:
769 spin_lock(&conn->session->lock);
770 __iscsi_ctask_cleanup(conn, tcp_conn->in.ctask);
771 spin_unlock(&conn->session->lock);
Alex Aizman7ba24712005-08-04 19:30:08 -0700772 case ISCSI_OP_TEXT_RSP:
773 case ISCSI_OP_LOGIN_RSP:
Mike Christie5bb0b552006-04-06 21:26:46 -0500774 case ISCSI_OP_NOOP_IN:
775 case ISCSI_OP_ASYNC_EVENT:
776 case ISCSI_OP_REJECT:
Alex Aizman7ba24712005-08-04 19:30:08 -0700777 /*
778 * Collect data segment to the connection's data
779 * placeholder
780 */
Mike Christie5bb0b552006-04-06 21:26:46 -0500781 if (iscsi_tcp_copy(tcp_conn)) {
Alex Aizman7ba24712005-08-04 19:30:08 -0700782 rc = -EAGAIN;
783 goto exit;
784 }
785
Mike Christie5bb0b552006-04-06 21:26:46 -0500786 rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, tcp_conn->data,
787 tcp_conn->in.datalen);
788 if (!rc && conn->datadgst_en && opcode != ISCSI_OP_LOGIN_RSP)
789 iscsi_recv_digest_update(tcp_conn, tcp_conn->data,
790 tcp_conn->in.datalen);
791 break;
Alex Aizman7ba24712005-08-04 19:30:08 -0700792 default:
793 BUG_ON(1);
794 }
795exit:
796 return rc;
797}
798
799/**
800 * iscsi_tcp_data_recv - TCP receive in sendfile fashion
801 * @rd_desc: read descriptor
802 * @skb: socket buffer
803 * @offset: offset in skb
804 * @len: skb->len - offset
805 **/
806static int
807iscsi_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
808 unsigned int offset, size_t len)
809{
810 int rc;
811 struct iscsi_conn *conn = rd_desc->arg.data;
Mike Christie5bb0b552006-04-06 21:26:46 -0500812 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
Alex Aizman7ba24712005-08-04 19:30:08 -0700813 int processed;
814 char pad[ISCSI_PAD_LEN];
815 struct scatterlist sg;
816
817 /*
818 * Save current SKB and its offset in the corresponding
819 * connection context.
820 */
Mike Christie5bb0b552006-04-06 21:26:46 -0500821 tcp_conn->in.copy = skb->len - offset;
822 tcp_conn->in.offset = offset;
823 tcp_conn->in.skb = skb;
824 tcp_conn->in.len = tcp_conn->in.copy;
825 BUG_ON(tcp_conn->in.copy <= 0);
826 debug_tcp("in %d bytes\n", tcp_conn->in.copy);
Alex Aizman7ba24712005-08-04 19:30:08 -0700827
828more:
Mike Christie5bb0b552006-04-06 21:26:46 -0500829 tcp_conn->in.copied = 0;
Alex Aizman7ba24712005-08-04 19:30:08 -0700830 rc = 0;
831
832 if (unlikely(conn->suspend_rx)) {
833 debug_tcp("conn %d Rx suspended!\n", conn->id);
834 return 0;
835 }
836
Mike Christie5bb0b552006-04-06 21:26:46 -0500837 if (tcp_conn->in_progress == IN_PROGRESS_WAIT_HEADER ||
838 tcp_conn->in_progress == IN_PROGRESS_HEADER_GATHER) {
839 rc = iscsi_hdr_extract(tcp_conn);
Alex Aizman7ba24712005-08-04 19:30:08 -0700840 if (rc) {
841 if (rc == -EAGAIN)
842 goto nomore;
843 else {
844 iscsi_conn_failure(conn, rc);
845 return 0;
846 }
847 }
848
849 /*
850 * Verify and process incoming PDU header.
851 */
Mike Christie5bb0b552006-04-06 21:26:46 -0500852 rc = iscsi_tcp_hdr_recv(conn);
853 if (!rc && tcp_conn->in.datalen) {
Mike Christie8a47cd32005-11-30 02:27:19 -0600854 if (conn->datadgst_en) {
Mike Christie5bb0b552006-04-06 21:26:46 -0500855 BUG_ON(!tcp_conn->data_rx_tfm);
856 crypto_digest_init(tcp_conn->data_rx_tfm);
Alex Aizman7ba24712005-08-04 19:30:08 -0700857 }
Mike Christie5bb0b552006-04-06 21:26:46 -0500858 tcp_conn->in_progress = IN_PROGRESS_DATA_RECV;
Alex Aizman7ba24712005-08-04 19:30:08 -0700859 } else if (rc) {
860 iscsi_conn_failure(conn, rc);
861 return 0;
862 }
863 }
864
Mike Christie5bb0b552006-04-06 21:26:46 -0500865 if (tcp_conn->in_progress == IN_PROGRESS_DDIGEST_RECV) {
Mike Christief6cfba12005-11-29 23:12:57 -0600866 uint32_t recv_digest;
Mike Christie5bb0b552006-04-06 21:26:46 -0500867
Alex Aizman7ba24712005-08-04 19:30:08 -0700868 debug_tcp("extra data_recv offset %d copy %d\n",
Mike Christie5bb0b552006-04-06 21:26:46 -0500869 tcp_conn->in.offset, tcp_conn->in.copy);
870 skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
Mike Christief6cfba12005-11-29 23:12:57 -0600871 &recv_digest, 4);
Mike Christie5bb0b552006-04-06 21:26:46 -0500872 tcp_conn->in.offset += 4;
873 tcp_conn->in.copy -= 4;
874 if (recv_digest != tcp_conn->in.datadgst) {
Mike Christief6cfba12005-11-29 23:12:57 -0600875 debug_tcp("iscsi_tcp: data digest error!"
876 "0x%x != 0x%x\n", recv_digest,
Mike Christie5bb0b552006-04-06 21:26:46 -0500877 tcp_conn->in.datadgst);
Mike Christief6cfba12005-11-29 23:12:57 -0600878 iscsi_conn_failure(conn, ISCSI_ERR_DATA_DGST);
879 return 0;
880 } else {
881 debug_tcp("iscsi_tcp: data digest match!"
882 "0x%x == 0x%x\n", recv_digest,
Mike Christie5bb0b552006-04-06 21:26:46 -0500883 tcp_conn->in.datadgst);
884 tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
Alex Aizman7ba24712005-08-04 19:30:08 -0700885 }
886 }
887
Mike Christie5bb0b552006-04-06 21:26:46 -0500888 if (tcp_conn->in_progress == IN_PROGRESS_DATA_RECV &&
889 tcp_conn->in.copy) {
Alex Aizman7ba24712005-08-04 19:30:08 -0700890
891 debug_tcp("data_recv offset %d copy %d\n",
Mike Christie5bb0b552006-04-06 21:26:46 -0500892 tcp_conn->in.offset, tcp_conn->in.copy);
Alex Aizman7ba24712005-08-04 19:30:08 -0700893
894 rc = iscsi_data_recv(conn);
895 if (rc) {
Mike Christie665b44a2006-05-02 19:46:49 -0500896 if (rc == -EAGAIN)
Alex Aizman7ba24712005-08-04 19:30:08 -0700897 goto again;
Alex Aizman7ba24712005-08-04 19:30:08 -0700898 iscsi_conn_failure(conn, rc);
899 return 0;
900 }
Mike Christie5bb0b552006-04-06 21:26:46 -0500901 tcp_conn->in.copy -= tcp_conn->in.padding;
902 tcp_conn->in.offset += tcp_conn->in.padding;
Mike Christie8a47cd32005-11-30 02:27:19 -0600903 if (conn->datadgst_en) {
Mike Christie5bb0b552006-04-06 21:26:46 -0500904 if (tcp_conn->in.padding) {
905 debug_tcp("padding -> %d\n",
906 tcp_conn->in.padding);
907 memset(pad, 0, tcp_conn->in.padding);
908 sg_init_one(&sg, pad, tcp_conn->in.padding);
909 crypto_digest_update(tcp_conn->data_rx_tfm,
910 &sg, 1);
Alex Aizman7ba24712005-08-04 19:30:08 -0700911 }
Mike Christie5bb0b552006-04-06 21:26:46 -0500912 crypto_digest_final(tcp_conn->data_rx_tfm,
913 (u8 *) & tcp_conn->in.datadgst);
914 debug_tcp("rx digest 0x%x\n", tcp_conn->in.datadgst);
915 tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV;
Alex Aizman7ba24712005-08-04 19:30:08 -0700916 } else
Mike Christie5bb0b552006-04-06 21:26:46 -0500917 tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
Alex Aizman7ba24712005-08-04 19:30:08 -0700918 }
919
920 debug_tcp("f, processed %d from out of %d padding %d\n",
Mike Christie5bb0b552006-04-06 21:26:46 -0500921 tcp_conn->in.offset - offset, (int)len, tcp_conn->in.padding);
922 BUG_ON(tcp_conn->in.offset - offset > len);
Alex Aizman7ba24712005-08-04 19:30:08 -0700923
Mike Christie5bb0b552006-04-06 21:26:46 -0500924 if (tcp_conn->in.offset - offset != len) {
Alex Aizman7ba24712005-08-04 19:30:08 -0700925 debug_tcp("continue to process %d bytes\n",
Mike Christie5bb0b552006-04-06 21:26:46 -0500926 (int)len - (tcp_conn->in.offset - offset));
Alex Aizman7ba24712005-08-04 19:30:08 -0700927 goto more;
928 }
929
930nomore:
Mike Christie5bb0b552006-04-06 21:26:46 -0500931 processed = tcp_conn->in.offset - offset;
Alex Aizman7ba24712005-08-04 19:30:08 -0700932 BUG_ON(processed == 0);
933 return processed;
934
935again:
Mike Christie5bb0b552006-04-06 21:26:46 -0500936 processed = tcp_conn->in.offset - offset;
Alex Aizman7ba24712005-08-04 19:30:08 -0700937 debug_tcp("c, processed %d from out of %d rd_desc_cnt %d\n",
938 processed, (int)len, (int)rd_desc->count);
939 BUG_ON(processed == 0);
940 BUG_ON(processed > len);
941
942 conn->rxdata_octets += processed;
943 return processed;
944}
945
946static void
947iscsi_tcp_data_ready(struct sock *sk, int flag)
948{
949 struct iscsi_conn *conn = sk->sk_user_data;
950 read_descriptor_t rd_desc;
951
952 read_lock(&sk->sk_callback_lock);
953
Mike Christie665b44a2006-05-02 19:46:49 -0500954 /*
955 * Use rd_desc to pass 'conn' to iscsi_tcp_data_recv.
956 * We set count to 1 because we want the network layer to
957 * hand us all the skbs that are available. iscsi_tcp_data_recv
958 * handled pdus that cross buffers or pdus that still need data.
959 */
Alex Aizman7ba24712005-08-04 19:30:08 -0700960 rd_desc.arg.data = conn;
Mike Christie665b44a2006-05-02 19:46:49 -0500961 rd_desc.count = 1;
Alex Aizman7ba24712005-08-04 19:30:08 -0700962 tcp_read_sock(sk, &rd_desc, iscsi_tcp_data_recv);
963
964 read_unlock(&sk->sk_callback_lock);
965}
966
967static void
968iscsi_tcp_state_change(struct sock *sk)
969{
Mike Christie5bb0b552006-04-06 21:26:46 -0500970 struct iscsi_tcp_conn *tcp_conn;
Alex Aizman7ba24712005-08-04 19:30:08 -0700971 struct iscsi_conn *conn;
972 struct iscsi_session *session;
973 void (*old_state_change)(struct sock *);
974
975 read_lock(&sk->sk_callback_lock);
976
977 conn = (struct iscsi_conn*)sk->sk_user_data;
978 session = conn->session;
979
Mike Christiee6273992005-11-29 23:12:49 -0600980 if ((sk->sk_state == TCP_CLOSE_WAIT ||
981 sk->sk_state == TCP_CLOSE) &&
982 !atomic_read(&sk->sk_rmem_alloc)) {
Alex Aizman7ba24712005-08-04 19:30:08 -0700983 debug_tcp("iscsi_tcp_state_change: TCP_CLOSE|TCP_CLOSE_WAIT\n");
984 iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
985 }
986
Mike Christie5bb0b552006-04-06 21:26:46 -0500987 tcp_conn = conn->dd_data;
988 old_state_change = tcp_conn->old_state_change;
Alex Aizman7ba24712005-08-04 19:30:08 -0700989
990 read_unlock(&sk->sk_callback_lock);
991
992 old_state_change(sk);
993}
994
995/**
996 * iscsi_write_space - Called when more output buffer space is available
997 * @sk: socket space is available for
998 **/
999static void
1000iscsi_write_space(struct sock *sk)
1001{
1002 struct iscsi_conn *conn = (struct iscsi_conn*)sk->sk_user_data;
Mike Christie5bb0b552006-04-06 21:26:46 -05001003 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
1004
1005 tcp_conn->old_write_space(sk);
Alex Aizman7ba24712005-08-04 19:30:08 -07001006 debug_tcp("iscsi_write_space: cid %d\n", conn->id);
Mike Christie5bb0b552006-04-06 21:26:46 -05001007 clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
Mike Christie55e32992006-01-13 18:05:53 -06001008 scsi_queue_work(conn->session->host, &conn->xmitwork);
Alex Aizman7ba24712005-08-04 19:30:08 -07001009}
1010
1011static void
1012iscsi_conn_set_callbacks(struct iscsi_conn *conn)
1013{
Mike Christie5bb0b552006-04-06 21:26:46 -05001014 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
1015 struct sock *sk = tcp_conn->sock->sk;
Alex Aizman7ba24712005-08-04 19:30:08 -07001016
1017 /* assign new callbacks */
1018 write_lock_bh(&sk->sk_callback_lock);
1019 sk->sk_user_data = conn;
Mike Christie5bb0b552006-04-06 21:26:46 -05001020 tcp_conn->old_data_ready = sk->sk_data_ready;
1021 tcp_conn->old_state_change = sk->sk_state_change;
1022 tcp_conn->old_write_space = sk->sk_write_space;
Alex Aizman7ba24712005-08-04 19:30:08 -07001023 sk->sk_data_ready = iscsi_tcp_data_ready;
1024 sk->sk_state_change = iscsi_tcp_state_change;
1025 sk->sk_write_space = iscsi_write_space;
1026 write_unlock_bh(&sk->sk_callback_lock);
1027}
1028
1029static void
1030iscsi_conn_restore_callbacks(struct iscsi_conn *conn)
1031{
Mike Christie5bb0b552006-04-06 21:26:46 -05001032 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
1033 struct sock *sk = tcp_conn->sock->sk;
Alex Aizman7ba24712005-08-04 19:30:08 -07001034
1035 /* restore socket callbacks, see also: iscsi_conn_set_callbacks() */
1036 write_lock_bh(&sk->sk_callback_lock);
1037 sk->sk_user_data = NULL;
Mike Christie5bb0b552006-04-06 21:26:46 -05001038 sk->sk_data_ready = tcp_conn->old_data_ready;
1039 sk->sk_state_change = tcp_conn->old_state_change;
1040 sk->sk_write_space = tcp_conn->old_write_space;
Alex Aizman7ba24712005-08-04 19:30:08 -07001041 sk->sk_no_check = 0;
1042 write_unlock_bh(&sk->sk_callback_lock);
1043}
1044
1045/**
1046 * iscsi_send - generic send routine
1047 * @sk: kernel's socket
1048 * @buf: buffer to write from
1049 * @size: actual size to write
1050 * @flags: socket's flags
Alex Aizman7ba24712005-08-04 19:30:08 -07001051 */
1052static inline int
FUJITA Tomonori56851692006-01-13 18:05:44 -06001053iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags)
Alex Aizman7ba24712005-08-04 19:30:08 -07001054{
Mike Christie5bb0b552006-04-06 21:26:46 -05001055 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
1056 struct socket *sk = tcp_conn->sock;
Mike Christie7cae5152006-01-13 18:05:47 -06001057 int offset = buf->sg.offset + buf->sent;
Alex Aizman7ba24712005-08-04 19:30:08 -07001058
Mike Christie7cae5152006-01-13 18:05:47 -06001059 /*
1060 * if we got use_sg=0 or are sending something we kmallocd
1061 * then we did not have to do kmap (kmap returns page_address)
1062 *
1063 * if we got use_sg > 0, but had to drop down, we do not
1064 * set clustering so this should only happen for that
1065 * slab case.
1066 */
1067 if (buf->use_sendmsg)
1068 return sock_no_sendpage(sk, buf->sg.page, offset, size, flags);
1069 else
Mike Christie5bb0b552006-04-06 21:26:46 -05001070 return tcp_conn->sendpage(sk, buf->sg.page, offset, size,
1071 flags);
Alex Aizman7ba24712005-08-04 19:30:08 -07001072}
1073
1074/**
1075 * iscsi_sendhdr - send PDU Header via tcp_sendpage()
1076 * @conn: iscsi connection
1077 * @buf: buffer to write from
1078 * @datalen: lenght of data to be sent after the header
1079 *
1080 * Notes:
1081 * (Tx, Fast Path)
1082 **/
1083static inline int
1084iscsi_sendhdr(struct iscsi_conn *conn, struct iscsi_buf *buf, int datalen)
1085{
Mike Christie5bb0b552006-04-06 21:26:46 -05001086 struct iscsi_tcp_conn *tcp_conn;
Alex Aizman7ba24712005-08-04 19:30:08 -07001087 int flags = 0; /* MSG_DONTWAIT; */
1088 int res, size;
1089
1090 size = buf->sg.length - buf->sent;
1091 BUG_ON(buf->sent + size > buf->sg.length);
1092 if (buf->sent + size != buf->sg.length || datalen)
1093 flags |= MSG_MORE;
1094
FUJITA Tomonori56851692006-01-13 18:05:44 -06001095 res = iscsi_send(conn, buf, size, flags);
Alex Aizman7ba24712005-08-04 19:30:08 -07001096 debug_tcp("sendhdr %d bytes, sent %d res %d\n", size, buf->sent, res);
1097 if (res >= 0) {
1098 conn->txdata_octets += res;
1099 buf->sent += res;
1100 if (size != res)
1101 return -EAGAIN;
1102 return 0;
1103 } else if (res == -EAGAIN) {
Mike Christie5bb0b552006-04-06 21:26:46 -05001104 tcp_conn = conn->dd_data;
1105 tcp_conn->sendpage_failures_cnt++;
1106 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
Alex Aizman7ba24712005-08-04 19:30:08 -07001107 } else if (res == -EPIPE)
1108 iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
1109
1110 return res;
1111}
1112
1113/**
1114 * iscsi_sendpage - send one page of iSCSI Data-Out.
1115 * @conn: iscsi connection
1116 * @buf: buffer to write from
1117 * @count: remaining data
1118 * @sent: number of bytes sent
1119 *
1120 * Notes:
1121 * (Tx, Fast Path)
1122 **/
1123static inline int
1124iscsi_sendpage(struct iscsi_conn *conn, struct iscsi_buf *buf,
1125 int *count, int *sent)
1126{
Mike Christie5bb0b552006-04-06 21:26:46 -05001127 struct iscsi_tcp_conn *tcp_conn;
Alex Aizman7ba24712005-08-04 19:30:08 -07001128 int flags = 0; /* MSG_DONTWAIT; */
1129 int res, size;
1130
1131 size = buf->sg.length - buf->sent;
1132 BUG_ON(buf->sent + size > buf->sg.length);
1133 if (size > *count)
1134 size = *count;
Mike Christieb13941f2005-09-12 21:01:28 -05001135 if (buf->sent + size != buf->sg.length || *count != size)
Alex Aizman7ba24712005-08-04 19:30:08 -07001136 flags |= MSG_MORE;
1137
FUJITA Tomonori56851692006-01-13 18:05:44 -06001138 res = iscsi_send(conn, buf, size, flags);
Alex Aizman7ba24712005-08-04 19:30:08 -07001139 debug_tcp("sendpage: %d bytes, sent %d left %d sent %d res %d\n",
1140 size, buf->sent, *count, *sent, res);
1141 if (res >= 0) {
1142 conn->txdata_octets += res;
1143 buf->sent += res;
1144 *count -= res;
1145 *sent += res;
1146 if (size != res)
1147 return -EAGAIN;
1148 return 0;
1149 } else if (res == -EAGAIN) {
Mike Christie5bb0b552006-04-06 21:26:46 -05001150 tcp_conn = conn->dd_data;
1151 tcp_conn->sendpage_failures_cnt++;
1152 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
Alex Aizman7ba24712005-08-04 19:30:08 -07001153 } else if (res == -EPIPE)
1154 iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
1155
1156 return res;
1157}
1158
1159static inline void
Mike Christie5bb0b552006-04-06 21:26:46 -05001160iscsi_data_digest_init(struct iscsi_tcp_conn *tcp_conn,
1161 struct iscsi_cmd_task *ctask)
Alex Aizman7ba24712005-08-04 19:30:08 -07001162{
Mike Christie5bb0b552006-04-06 21:26:46 -05001163 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
1164
1165 BUG_ON(!tcp_conn->data_tx_tfm);
1166 crypto_digest_init(tcp_conn->data_tx_tfm);
1167 tcp_ctask->digest_count = 4;
Alex Aizman7ba24712005-08-04 19:30:08 -07001168}
1169
Arjan van de Ven858119e2006-01-14 13:20:43 -08001170static int
Alex Aizman7ba24712005-08-04 19:30:08 -07001171iscsi_digest_final_send(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
1172 struct iscsi_buf *buf, uint32_t *digest, int final)
1173{
Mike Christie5bb0b552006-04-06 21:26:46 -05001174 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
1175 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
Alex Aizman7ba24712005-08-04 19:30:08 -07001176 int rc = 0;
1177 int sent = 0;
1178
1179 if (final)
Mike Christie5bb0b552006-04-06 21:26:46 -05001180 crypto_digest_final(tcp_conn->data_tx_tfm, (u8*)digest);
Alex Aizman7ba24712005-08-04 19:30:08 -07001181
Mike Christie6e458cc2006-05-18 20:31:31 -05001182 iscsi_buf_init_iov(buf, (char*)digest, 4);
Mike Christie5bb0b552006-04-06 21:26:46 -05001183 rc = iscsi_sendpage(conn, buf, &tcp_ctask->digest_count, &sent);
Alex Aizman7ba24712005-08-04 19:30:08 -07001184 if (rc) {
Mike Christie5bb0b552006-04-06 21:26:46 -05001185 tcp_ctask->datadigest = *digest;
1186 tcp_ctask->xmstate |= XMSTATE_DATA_DIGEST;
Alex Aizman7ba24712005-08-04 19:30:08 -07001187 } else
Mike Christie5bb0b552006-04-06 21:26:46 -05001188 tcp_ctask->digest_count = 4;
Alex Aizman7ba24712005-08-04 19:30:08 -07001189 return rc;
1190}
1191
1192/**
1193 * iscsi_solicit_data_cont - initialize next Data-Out
1194 * @conn: iscsi connection
1195 * @ctask: scsi command task
1196 * @r2t: R2T info
1197 * @left: bytes left to transfer
1198 *
1199 * Notes:
1200 * Initialize next Data-Out within this R2T sequence and continue
1201 * to process next Scatter-Gather element(if any) of this SCSI command.
1202 *
1203 * Called under connection lock.
1204 **/
1205static void
1206iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
1207 struct iscsi_r2t_info *r2t, int left)
1208{
Mike Christie5bb0b552006-04-06 21:26:46 -05001209 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
Alex Aizman7ba24712005-08-04 19:30:08 -07001210 struct iscsi_data *hdr;
Alex Aizman7ba24712005-08-04 19:30:08 -07001211 struct scsi_cmnd *sc = ctask->sc;
1212 int new_offset;
1213
Mike Christieffbfe922006-05-18 20:31:36 -05001214 hdr = &r2t->dtask.hdr;
Alex Aizman7ba24712005-08-04 19:30:08 -07001215 memset(hdr, 0, sizeof(struct iscsi_data));
1216 hdr->ttt = r2t->ttt;
1217 hdr->datasn = cpu_to_be32(r2t->solicit_datasn);
1218 r2t->solicit_datasn++;
1219 hdr->opcode = ISCSI_OP_SCSI_DATA_OUT;
Mike Christie5bb0b552006-04-06 21:26:46 -05001220 memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun));
1221 hdr->itt = ctask->hdr->itt;
Alex Aizman7ba24712005-08-04 19:30:08 -07001222 hdr->exp_statsn = r2t->exp_statsn;
1223 new_offset = r2t->data_offset + r2t->sent;
1224 hdr->offset = cpu_to_be32(new_offset);
1225 if (left > conn->max_xmit_dlength) {
1226 hton24(hdr->dlength, conn->max_xmit_dlength);
1227 r2t->data_count = conn->max_xmit_dlength;
1228 } else {
1229 hton24(hdr->dlength, left);
1230 r2t->data_count = left;
1231 hdr->flags = ISCSI_FLAG_CMD_FINAL;
1232 }
1233 conn->dataout_pdus_cnt++;
1234
Mike Christie6e458cc2006-05-18 20:31:31 -05001235 iscsi_buf_init_iov(&r2t->headbuf, (char*)hdr,
Mike Christieaf973482005-09-12 21:01:32 -05001236 sizeof(struct iscsi_hdr));
Alex Aizman7ba24712005-08-04 19:30:08 -07001237
Alex Aizman7ba24712005-08-04 19:30:08 -07001238 if (sc->use_sg && !iscsi_buf_left(&r2t->sendbuf)) {
Mike Christie5bb0b552006-04-06 21:26:46 -05001239 BUG_ON(tcp_ctask->bad_sg == r2t->sg);
Alex Aizman7ba24712005-08-04 19:30:08 -07001240 iscsi_buf_init_sg(&r2t->sendbuf, r2t->sg);
1241 r2t->sg += 1;
1242 } else
Mike Christie5bb0b552006-04-06 21:26:46 -05001243 iscsi_buf_init_iov(&tcp_ctask->sendbuf,
Alex Aizman7ba24712005-08-04 19:30:08 -07001244 (char*)sc->request_buffer + new_offset,
1245 r2t->data_count);
Alex Aizman7ba24712005-08-04 19:30:08 -07001246}
1247
1248static void
1249iscsi_unsolicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
1250{
Mike Christie5bb0b552006-04-06 21:26:46 -05001251 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
Alex Aizman7ba24712005-08-04 19:30:08 -07001252 struct iscsi_data_task *dtask;
1253
Mike Christieffbfe922006-05-18 20:31:36 -05001254 dtask = tcp_ctask->dtask = &tcp_ctask->unsol_dtask;
Mike Christie5bb0b552006-04-06 21:26:46 -05001255 iscsi_prep_unsolicit_data_pdu(ctask, &dtask->hdr,
1256 tcp_ctask->r2t_data_count);
Mike Christie6e458cc2006-05-18 20:31:31 -05001257 iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)&dtask->hdr,
Mike Christieaf973482005-09-12 21:01:32 -05001258 sizeof(struct iscsi_hdr));
Alex Aizman7ba24712005-08-04 19:30:08 -07001259}
1260
1261/**
Mike Christie5bb0b552006-04-06 21:26:46 -05001262 * iscsi_tcp_cmd_init - Initialize iSCSI SCSI_READ or SCSI_WRITE commands
Alex Aizman7ba24712005-08-04 19:30:08 -07001263 * @conn: iscsi connection
1264 * @ctask: scsi command task
1265 * @sc: scsi command
1266 **/
1267static void
Mike Christie5bb0b552006-04-06 21:26:46 -05001268iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask)
Alex Aizman7ba24712005-08-04 19:30:08 -07001269{
Mike Christie5bb0b552006-04-06 21:26:46 -05001270 struct scsi_cmnd *sc = ctask->sc;
1271 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
Alex Aizman7ba24712005-08-04 19:30:08 -07001272
Mike Christie5bb0b552006-04-06 21:26:46 -05001273 BUG_ON(__kfifo_len(tcp_ctask->r2tqueue));
Alex Aizman7ba24712005-08-04 19:30:08 -07001274
Mike Christie5bb0b552006-04-06 21:26:46 -05001275 tcp_ctask->sent = 0;
1276 tcp_ctask->sg_count = 0;
Alex Aizman7ba24712005-08-04 19:30:08 -07001277
1278 if (sc->sc_data_direction == DMA_TO_DEVICE) {
Mike Christie5bb0b552006-04-06 21:26:46 -05001279 tcp_ctask->xmstate = XMSTATE_W_HDR;
1280 tcp_ctask->exp_r2tsn = 0;
Alex Aizman7ba24712005-08-04 19:30:08 -07001281 BUG_ON(ctask->total_length == 0);
Mike Christie5bb0b552006-04-06 21:26:46 -05001282
Alex Aizman7ba24712005-08-04 19:30:08 -07001283 if (sc->use_sg) {
1284 struct scatterlist *sg = sc->request_buffer;
1285
Mike Christie5bb0b552006-04-06 21:26:46 -05001286 iscsi_buf_init_sg(&tcp_ctask->sendbuf,
1287 &sg[tcp_ctask->sg_count++]);
1288 tcp_ctask->sg = sg;
1289 tcp_ctask->bad_sg = sg + sc->use_sg;
Alex Aizman7ba24712005-08-04 19:30:08 -07001290 } else
Mike Christie5bb0b552006-04-06 21:26:46 -05001291 iscsi_buf_init_iov(&tcp_ctask->sendbuf,
1292 sc->request_buffer,
1293 sc->request_bufflen);
Alex Aizman7ba24712005-08-04 19:30:08 -07001294
Mike Christie5bb0b552006-04-06 21:26:46 -05001295 if (ctask->imm_count)
1296 tcp_ctask->xmstate |= XMSTATE_IMM_DATA;
Alex Aizman7ba24712005-08-04 19:30:08 -07001297
Mike Christie5bb0b552006-04-06 21:26:46 -05001298 tcp_ctask->pad_count = ctask->total_length & (ISCSI_PAD_LEN-1);
1299 if (tcp_ctask->pad_count) {
1300 tcp_ctask->pad_count = ISCSI_PAD_LEN -
1301 tcp_ctask->pad_count;
1302 debug_scsi("write padding %d bytes\n",
1303 tcp_ctask->pad_count);
1304 tcp_ctask->xmstate |= XMSTATE_W_PAD;
1305 }
1306
1307 if (ctask->unsol_count)
1308 tcp_ctask->xmstate |= XMSTATE_UNS_HDR |
1309 XMSTATE_UNS_INIT;
1310 tcp_ctask->r2t_data_count = ctask->total_length -
Alex Aizman7ba24712005-08-04 19:30:08 -07001311 ctask->imm_count -
1312 ctask->unsol_count;
1313
1314 debug_scsi("cmd [itt %x total %d imm %d imm_data %d "
1315 "r2t_data %d]\n",
1316 ctask->itt, ctask->total_length, ctask->imm_count,
Mike Christie5bb0b552006-04-06 21:26:46 -05001317 ctask->unsol_count, tcp_ctask->r2t_data_count);
1318 } else
1319 tcp_ctask->xmstate = XMSTATE_R_HDR;
Alex Aizman7ba24712005-08-04 19:30:08 -07001320
Mike Christie6e458cc2006-05-18 20:31:31 -05001321 iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)ctask->hdr,
Mike Christieaf973482005-09-12 21:01:32 -05001322 sizeof(struct iscsi_hdr));
Alex Aizman7ba24712005-08-04 19:30:08 -07001323}
1324
1325/**
Mike Christie5bb0b552006-04-06 21:26:46 -05001326 * iscsi_tcp_mtask_xmit - xmit management(immediate) task
Alex Aizman7ba24712005-08-04 19:30:08 -07001327 * @conn: iscsi connection
1328 * @mtask: task management task
1329 *
1330 * Notes:
1331 * The function can return -EAGAIN in which case caller must
1332 * call it again later, or recover. '0' return code means successful
1333 * xmit.
1334 *
1335 * Management xmit state machine consists of two states:
1336 * IN_PROGRESS_IMM_HEAD - PDU Header xmit in progress
1337 * IN_PROGRESS_IMM_DATA - PDU Data xmit in progress
1338 **/
1339static int
Mike Christie5bb0b552006-04-06 21:26:46 -05001340iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
Alex Aizman7ba24712005-08-04 19:30:08 -07001341{
Mike Christie5bb0b552006-04-06 21:26:46 -05001342 struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
Alex Aizman7ba24712005-08-04 19:30:08 -07001343
1344 debug_scsi("mtask deq [cid %d state %x itt 0x%x]\n",
Mike Christie5bb0b552006-04-06 21:26:46 -05001345 conn->id, tcp_mtask->xmstate, mtask->itt);
Alex Aizman7ba24712005-08-04 19:30:08 -07001346
Mike Christie5bb0b552006-04-06 21:26:46 -05001347 if (tcp_mtask->xmstate & XMSTATE_IMM_HDR) {
1348 tcp_mtask->xmstate &= ~XMSTATE_IMM_HDR;
Alex Aizman7ba24712005-08-04 19:30:08 -07001349 if (mtask->data_count)
Mike Christie5bb0b552006-04-06 21:26:46 -05001350 tcp_mtask->xmstate |= XMSTATE_IMM_DATA;
Mike Christieaf973482005-09-12 21:01:32 -05001351 if (conn->c_stage != ISCSI_CONN_INITIAL_STAGE &&
Mike Christie30a6c652006-04-06 21:13:39 -05001352 conn->stop_stage != STOP_CONN_RECOVER &&
Mike Christieaf973482005-09-12 21:01:32 -05001353 conn->hdrdgst_en)
Mike Christie5bb0b552006-04-06 21:26:46 -05001354 iscsi_hdr_digest(conn, &tcp_mtask->headbuf,
1355 (u8*)tcp_mtask->hdrext);
1356 if (iscsi_sendhdr(conn, &tcp_mtask->headbuf,
1357 mtask->data_count)) {
1358 tcp_mtask->xmstate |= XMSTATE_IMM_HDR;
Alex Aizman7ba24712005-08-04 19:30:08 -07001359 if (mtask->data_count)
Mike Christie5bb0b552006-04-06 21:26:46 -05001360 tcp_mtask->xmstate &= ~XMSTATE_IMM_DATA;
Alex Aizman7ba24712005-08-04 19:30:08 -07001361 return -EAGAIN;
1362 }
1363 }
1364
Mike Christie5bb0b552006-04-06 21:26:46 -05001365 if (tcp_mtask->xmstate & XMSTATE_IMM_DATA) {
Alex Aizman7ba24712005-08-04 19:30:08 -07001366 BUG_ON(!mtask->data_count);
Mike Christie5bb0b552006-04-06 21:26:46 -05001367 tcp_mtask->xmstate &= ~XMSTATE_IMM_DATA;
Alex Aizman7ba24712005-08-04 19:30:08 -07001368 /* FIXME: implement.
1369 * Virtual buffer could be spreaded across multiple pages...
1370 */
1371 do {
Mike Christie5bb0b552006-04-06 21:26:46 -05001372 if (iscsi_sendpage(conn, &tcp_mtask->sendbuf,
1373 &mtask->data_count, &tcp_mtask->sent)) {
1374 tcp_mtask->xmstate |= XMSTATE_IMM_DATA;
Alex Aizman7ba24712005-08-04 19:30:08 -07001375 return -EAGAIN;
1376 }
1377 } while (mtask->data_count);
1378 }
1379
Mike Christie5bb0b552006-04-06 21:26:46 -05001380 BUG_ON(tcp_mtask->xmstate != XMSTATE_IDLE);
1381 if (mtask->hdr->itt == cpu_to_be32(ISCSI_RESERVED_TAG)) {
1382 struct iscsi_session *session = conn->session;
1383
1384 spin_lock_bh(&session->lock);
1385 list_del(&conn->mtask->running);
1386 __kfifo_put(session->mgmtpool.queue, (void*)&conn->mtask,
1387 sizeof(void*));
1388 spin_unlock_bh(&session->lock);
1389 }
Alex Aizman7ba24712005-08-04 19:30:08 -07001390 return 0;
1391}
1392
1393static inline int
Mike Christie5bb0b552006-04-06 21:26:46 -05001394handle_xmstate_r_hdr(struct iscsi_conn *conn,
1395 struct iscsi_tcp_cmd_task *tcp_ctask)
Alex Aizman7ba24712005-08-04 19:30:08 -07001396{
Mike Christie5bb0b552006-04-06 21:26:46 -05001397 tcp_ctask->xmstate &= ~XMSTATE_R_HDR;
FUJITA Tomonori42f72aa2006-01-13 18:05:35 -06001398 if (conn->hdrdgst_en)
Mike Christie5bb0b552006-04-06 21:26:46 -05001399 iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
1400 (u8*)tcp_ctask->hdrext);
1401 if (!iscsi_sendhdr(conn, &tcp_ctask->headbuf, 0)) {
1402 BUG_ON(tcp_ctask->xmstate != XMSTATE_IDLE);
Alex Aizman7ba24712005-08-04 19:30:08 -07001403 return 0; /* wait for Data-In */
1404 }
Mike Christie5bb0b552006-04-06 21:26:46 -05001405 tcp_ctask->xmstate |= XMSTATE_R_HDR;
Alex Aizman7ba24712005-08-04 19:30:08 -07001406 return -EAGAIN;
1407}
1408
1409static inline int
Mike Christie5bb0b552006-04-06 21:26:46 -05001410handle_xmstate_w_hdr(struct iscsi_conn *conn,
1411 struct iscsi_cmd_task *ctask)
Alex Aizman7ba24712005-08-04 19:30:08 -07001412{
Mike Christie5bb0b552006-04-06 21:26:46 -05001413 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
1414
1415 tcp_ctask->xmstate &= ~XMSTATE_W_HDR;
FUJITA Tomonori42f72aa2006-01-13 18:05:35 -06001416 if (conn->hdrdgst_en)
Mike Christie5bb0b552006-04-06 21:26:46 -05001417 iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
1418 (u8*)tcp_ctask->hdrext);
1419 if (iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count)) {
1420 tcp_ctask->xmstate |= XMSTATE_W_HDR;
Alex Aizman7ba24712005-08-04 19:30:08 -07001421 return -EAGAIN;
1422 }
1423 return 0;
1424}
1425
1426static inline int
1427handle_xmstate_data_digest(struct iscsi_conn *conn,
1428 struct iscsi_cmd_task *ctask)
1429{
Mike Christie5bb0b552006-04-06 21:26:46 -05001430 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
1431
1432 tcp_ctask->xmstate &= ~XMSTATE_DATA_DIGEST;
1433 debug_tcp("resent data digest 0x%x\n", tcp_ctask->datadigest);
1434 if (iscsi_digest_final_send(conn, ctask, &tcp_ctask->immbuf,
1435 &tcp_ctask->datadigest, 0)) {
1436 tcp_ctask->xmstate |= XMSTATE_DATA_DIGEST;
Alex Aizman7ba24712005-08-04 19:30:08 -07001437 debug_tcp("resent data digest 0x%x fail!\n",
Mike Christie5bb0b552006-04-06 21:26:46 -05001438 tcp_ctask->datadigest);
Alex Aizman7ba24712005-08-04 19:30:08 -07001439 return -EAGAIN;
1440 }
1441 return 0;
1442}
1443
1444static inline int
1445handle_xmstate_imm_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
1446{
Mike Christie5bb0b552006-04-06 21:26:46 -05001447 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
1448 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
1449
Alex Aizman7ba24712005-08-04 19:30:08 -07001450 BUG_ON(!ctask->imm_count);
Mike Christie5bb0b552006-04-06 21:26:46 -05001451 tcp_ctask->xmstate &= ~XMSTATE_IMM_DATA;
Alex Aizman7ba24712005-08-04 19:30:08 -07001452
1453 if (conn->datadgst_en) {
Mike Christie5bb0b552006-04-06 21:26:46 -05001454 iscsi_data_digest_init(tcp_conn, ctask);
1455 tcp_ctask->immdigest = 0;
Alex Aizman7ba24712005-08-04 19:30:08 -07001456 }
1457
1458 for (;;) {
Mike Christie5bb0b552006-04-06 21:26:46 -05001459 if (iscsi_sendpage(conn, &tcp_ctask->sendbuf, &ctask->imm_count,
1460 &tcp_ctask->sent)) {
1461 tcp_ctask->xmstate |= XMSTATE_IMM_DATA;
Alex Aizman7ba24712005-08-04 19:30:08 -07001462 if (conn->datadgst_en) {
Mike Christie5bb0b552006-04-06 21:26:46 -05001463 crypto_digest_final(tcp_conn->data_tx_tfm,
1464 (u8*)&tcp_ctask->immdigest);
Alex Aizman7ba24712005-08-04 19:30:08 -07001465 debug_tcp("tx imm sendpage fail 0x%x\n",
Mike Christie5bb0b552006-04-06 21:26:46 -05001466 tcp_ctask->datadigest);
Alex Aizman7ba24712005-08-04 19:30:08 -07001467 }
1468 return -EAGAIN;
1469 }
1470 if (conn->datadgst_en)
Mike Christie5bb0b552006-04-06 21:26:46 -05001471 crypto_digest_update(tcp_conn->data_tx_tfm,
1472 &tcp_ctask->sendbuf.sg, 1);
Alex Aizman7ba24712005-08-04 19:30:08 -07001473
1474 if (!ctask->imm_count)
1475 break;
Mike Christie5bb0b552006-04-06 21:26:46 -05001476 iscsi_buf_init_sg(&tcp_ctask->sendbuf,
1477 &tcp_ctask->sg[tcp_ctask->sg_count++]);
Alex Aizman7ba24712005-08-04 19:30:08 -07001478 }
1479
Mike Christie5bb0b552006-04-06 21:26:46 -05001480 if (conn->datadgst_en && !(tcp_ctask->xmstate & XMSTATE_W_PAD)) {
1481 if (iscsi_digest_final_send(conn, ctask, &tcp_ctask->immbuf,
1482 &tcp_ctask->immdigest, 1)) {
Alex Aizman7ba24712005-08-04 19:30:08 -07001483 debug_tcp("sending imm digest 0x%x fail!\n",
Mike Christie5bb0b552006-04-06 21:26:46 -05001484 tcp_ctask->immdigest);
Alex Aizman7ba24712005-08-04 19:30:08 -07001485 return -EAGAIN;
1486 }
Mike Christie5bb0b552006-04-06 21:26:46 -05001487 debug_tcp("sending imm digest 0x%x\n", tcp_ctask->immdigest);
Alex Aizman7ba24712005-08-04 19:30:08 -07001488 }
1489
1490 return 0;
1491}
1492
1493static inline int
1494handle_xmstate_uns_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
1495{
Mike Christie5bb0b552006-04-06 21:26:46 -05001496 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
Alex Aizman7ba24712005-08-04 19:30:08 -07001497 struct iscsi_data_task *dtask;
1498
Mike Christie5bb0b552006-04-06 21:26:46 -05001499 tcp_ctask->xmstate |= XMSTATE_UNS_DATA;
1500 if (tcp_ctask->xmstate & XMSTATE_UNS_INIT) {
Alex Aizman7ba24712005-08-04 19:30:08 -07001501 iscsi_unsolicit_data_init(conn, ctask);
Mike Christie5bb0b552006-04-06 21:26:46 -05001502 dtask = tcp_ctask->dtask;
Mike Christieaf973482005-09-12 21:01:32 -05001503 if (conn->hdrdgst_en)
Mike Christie5bb0b552006-04-06 21:26:46 -05001504 iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
Mike Christieaf973482005-09-12 21:01:32 -05001505 (u8*)dtask->hdrext);
Mike Christie5bb0b552006-04-06 21:26:46 -05001506 tcp_ctask->xmstate &= ~XMSTATE_UNS_INIT;
Alex Aizman7ba24712005-08-04 19:30:08 -07001507 }
Mike Christie5bb0b552006-04-06 21:26:46 -05001508 if (iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->data_count)) {
1509 tcp_ctask->xmstate &= ~XMSTATE_UNS_DATA;
1510 tcp_ctask->xmstate |= XMSTATE_UNS_HDR;
Alex Aizman7ba24712005-08-04 19:30:08 -07001511 return -EAGAIN;
1512 }
1513
1514 debug_scsi("uns dout [itt 0x%x dlen %d sent %d]\n",
Mike Christie5bb0b552006-04-06 21:26:46 -05001515 ctask->itt, ctask->unsol_count, tcp_ctask->sent);
Alex Aizman7ba24712005-08-04 19:30:08 -07001516 return 0;
1517}
1518
1519static inline int
1520handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
1521{
Mike Christie5bb0b552006-04-06 21:26:46 -05001522 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
1523 struct iscsi_data_task *dtask = tcp_ctask->dtask;
1524 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
Alex Aizman7ba24712005-08-04 19:30:08 -07001525
1526 BUG_ON(!ctask->data_count);
Mike Christie5bb0b552006-04-06 21:26:46 -05001527 tcp_ctask->xmstate &= ~XMSTATE_UNS_DATA;
Alex Aizman7ba24712005-08-04 19:30:08 -07001528
1529 if (conn->datadgst_en) {
Mike Christie5bb0b552006-04-06 21:26:46 -05001530 iscsi_data_digest_init(tcp_conn, ctask);
Alex Aizman7ba24712005-08-04 19:30:08 -07001531 dtask->digest = 0;
1532 }
1533
1534 for (;;) {
Mike Christie5bb0b552006-04-06 21:26:46 -05001535 int start = tcp_ctask->sent;
Alex Aizman7ba24712005-08-04 19:30:08 -07001536
Mike Christie5bb0b552006-04-06 21:26:46 -05001537 if (iscsi_sendpage(conn, &tcp_ctask->sendbuf,
1538 &ctask->data_count, &tcp_ctask->sent)) {
1539 ctask->unsol_count -= tcp_ctask->sent - start;
1540 tcp_ctask->xmstate |= XMSTATE_UNS_DATA;
Alex Aizman7ba24712005-08-04 19:30:08 -07001541 /* will continue with this ctask later.. */
1542 if (conn->datadgst_en) {
Mike Christie5bb0b552006-04-06 21:26:46 -05001543 crypto_digest_final(tcp_conn->data_tx_tfm,
Alex Aizman7ba24712005-08-04 19:30:08 -07001544 (u8 *)&dtask->digest);
1545 debug_tcp("tx uns data fail 0x%x\n",
1546 dtask->digest);
1547 }
1548 return -EAGAIN;
1549 }
1550
Mike Christie5bb0b552006-04-06 21:26:46 -05001551 BUG_ON(tcp_ctask->sent > ctask->total_length);
1552 ctask->unsol_count -= tcp_ctask->sent - start;
Alex Aizman7ba24712005-08-04 19:30:08 -07001553
1554 /*
1555 * XXX:we may run here with un-initial sendbuf.
1556 * so pass it
1557 */
Mike Christie5bb0b552006-04-06 21:26:46 -05001558 if (conn->datadgst_en && tcp_ctask->sent - start > 0)
1559 crypto_digest_update(tcp_conn->data_tx_tfm,
1560 &tcp_ctask->sendbuf.sg, 1);
Alex Aizman7ba24712005-08-04 19:30:08 -07001561
1562 if (!ctask->data_count)
1563 break;
Mike Christie5bb0b552006-04-06 21:26:46 -05001564 iscsi_buf_init_sg(&tcp_ctask->sendbuf,
1565 &tcp_ctask->sg[tcp_ctask->sg_count++]);
Alex Aizman7ba24712005-08-04 19:30:08 -07001566 }
1567 BUG_ON(ctask->unsol_count < 0);
1568
1569 /*
1570 * Done with the Data-Out. Next, check if we need
1571 * to send another unsolicited Data-Out.
1572 */
1573 if (ctask->unsol_count) {
1574 if (conn->datadgst_en) {
1575 if (iscsi_digest_final_send(conn, ctask,
1576 &dtask->digestbuf,
1577 &dtask->digest, 1)) {
1578 debug_tcp("send uns digest 0x%x fail\n",
1579 dtask->digest);
1580 return -EAGAIN;
1581 }
1582 debug_tcp("sending uns digest 0x%x, more uns\n",
1583 dtask->digest);
1584 }
Mike Christie5bb0b552006-04-06 21:26:46 -05001585 tcp_ctask->xmstate |= XMSTATE_UNS_INIT;
Alex Aizman7ba24712005-08-04 19:30:08 -07001586 return 1;
1587 }
1588
Mike Christie5bb0b552006-04-06 21:26:46 -05001589 if (conn->datadgst_en && !(tcp_ctask->xmstate & XMSTATE_W_PAD)) {
Alex Aizman7ba24712005-08-04 19:30:08 -07001590 if (iscsi_digest_final_send(conn, ctask,
1591 &dtask->digestbuf,
1592 &dtask->digest, 1)) {
1593 debug_tcp("send last uns digest 0x%x fail\n",
1594 dtask->digest);
1595 return -EAGAIN;
1596 }
1597 debug_tcp("sending uns digest 0x%x\n",dtask->digest);
1598 }
1599
1600 return 0;
1601}
1602
1603static inline int
1604handle_xmstate_sol_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
1605{
1606 struct iscsi_session *session = conn->session;
Mike Christie5bb0b552006-04-06 21:26:46 -05001607 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
1608 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
1609 struct iscsi_r2t_info *r2t = tcp_ctask->r2t;
Mike Christieffbfe922006-05-18 20:31:36 -05001610 struct iscsi_data_task *dtask = &r2t->dtask;
Alex Aizman7ba24712005-08-04 19:30:08 -07001611 int left;
1612
Mike Christie5bb0b552006-04-06 21:26:46 -05001613 tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA;
1614 tcp_ctask->dtask = dtask;
Alex Aizman7ba24712005-08-04 19:30:08 -07001615
1616 if (conn->datadgst_en) {
Mike Christie5bb0b552006-04-06 21:26:46 -05001617 iscsi_data_digest_init(tcp_conn, ctask);
Alex Aizman7ba24712005-08-04 19:30:08 -07001618 dtask->digest = 0;
1619 }
1620solicit_again:
1621 /*
1622 * send Data-Out whitnin this R2T sequence.
1623 */
1624 if (!r2t->data_count)
1625 goto data_out_done;
1626
1627 if (iscsi_sendpage(conn, &r2t->sendbuf, &r2t->data_count, &r2t->sent)) {
Mike Christie5bb0b552006-04-06 21:26:46 -05001628 tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
Alex Aizman7ba24712005-08-04 19:30:08 -07001629 /* will continue with this ctask later.. */
1630 if (conn->datadgst_en) {
Mike Christie5bb0b552006-04-06 21:26:46 -05001631 crypto_digest_final(tcp_conn->data_tx_tfm,
Alex Aizman7ba24712005-08-04 19:30:08 -07001632 (u8 *)&dtask->digest);
1633 debug_tcp("r2t data send fail 0x%x\n", dtask->digest);
1634 }
1635 return -EAGAIN;
1636 }
1637
1638 BUG_ON(r2t->data_count < 0);
1639 if (conn->datadgst_en)
Mike Christie5bb0b552006-04-06 21:26:46 -05001640 crypto_digest_update(tcp_conn->data_tx_tfm, &r2t->sendbuf.sg,
1641 1);
Alex Aizman7ba24712005-08-04 19:30:08 -07001642
1643 if (r2t->data_count) {
1644 BUG_ON(ctask->sc->use_sg == 0);
1645 if (!iscsi_buf_left(&r2t->sendbuf)) {
Mike Christie5bb0b552006-04-06 21:26:46 -05001646 BUG_ON(tcp_ctask->bad_sg == r2t->sg);
Alex Aizman7ba24712005-08-04 19:30:08 -07001647 iscsi_buf_init_sg(&r2t->sendbuf, r2t->sg);
1648 r2t->sg += 1;
1649 }
1650 goto solicit_again;
1651 }
1652
1653data_out_done:
1654 /*
1655 * Done with this Data-Out. Next, check if we have
1656 * to send another Data-Out for this R2T.
1657 */
1658 BUG_ON(r2t->data_length - r2t->sent < 0);
1659 left = r2t->data_length - r2t->sent;
1660 if (left) {
1661 if (conn->datadgst_en) {
1662 if (iscsi_digest_final_send(conn, ctask,
1663 &dtask->digestbuf,
1664 &dtask->digest, 1)) {
1665 debug_tcp("send r2t data digest 0x%x"
1666 "fail\n", dtask->digest);
1667 return -EAGAIN;
1668 }
1669 debug_tcp("r2t data send digest 0x%x\n",
1670 dtask->digest);
1671 }
1672 iscsi_solicit_data_cont(conn, ctask, r2t, left);
Mike Christie5bb0b552006-04-06 21:26:46 -05001673 tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
1674 tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
Alex Aizman7ba24712005-08-04 19:30:08 -07001675 return 1;
1676 }
1677
1678 /*
1679 * Done with this R2T. Check if there are more
1680 * outstanding R2Ts ready to be processed.
1681 */
Mike Christie5bb0b552006-04-06 21:26:46 -05001682 BUG_ON(tcp_ctask->r2t_data_count - r2t->data_length < 0);
Alex Aizman7ba24712005-08-04 19:30:08 -07001683 if (conn->datadgst_en) {
1684 if (iscsi_digest_final_send(conn, ctask, &dtask->digestbuf,
1685 &dtask->digest, 1)) {
1686 debug_tcp("send last r2t data digest 0x%x"
1687 "fail\n", dtask->digest);
1688 return -EAGAIN;
1689 }
1690 debug_tcp("r2t done dout digest 0x%x\n", dtask->digest);
1691 }
1692
Mike Christie5bb0b552006-04-06 21:26:46 -05001693 tcp_ctask->r2t_data_count -= r2t->data_length;
1694 tcp_ctask->r2t = NULL;
Alex Aizman7ba24712005-08-04 19:30:08 -07001695 spin_lock_bh(&session->lock);
Mike Christie5bb0b552006-04-06 21:26:46 -05001696 __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*));
Alex Aizman7ba24712005-08-04 19:30:08 -07001697 spin_unlock_bh(&session->lock);
Mike Christie5bb0b552006-04-06 21:26:46 -05001698 if (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*))) {
1699 tcp_ctask->r2t = r2t;
1700 tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
1701 tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
Alex Aizman7ba24712005-08-04 19:30:08 -07001702 return 1;
1703 }
1704
1705 return 0;
1706}
1707
1708static inline int
1709handle_xmstate_w_pad(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
1710{
Mike Christie5bb0b552006-04-06 21:26:46 -05001711 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
1712 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
1713 struct iscsi_data_task *dtask = tcp_ctask->dtask;
Alex Aizman7ba24712005-08-04 19:30:08 -07001714 int sent;
1715
Mike Christie5bb0b552006-04-06 21:26:46 -05001716 tcp_ctask->xmstate &= ~XMSTATE_W_PAD;
Mike Christie6e458cc2006-05-18 20:31:31 -05001717 iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad,
Mike Christie5bb0b552006-04-06 21:26:46 -05001718 tcp_ctask->pad_count);
1719 if (iscsi_sendpage(conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count,
1720 &sent)) {
1721 tcp_ctask->xmstate |= XMSTATE_W_PAD;
Alex Aizman7ba24712005-08-04 19:30:08 -07001722 return -EAGAIN;
1723 }
1724
1725 if (conn->datadgst_en) {
Mike Christie5bb0b552006-04-06 21:26:46 -05001726 crypto_digest_update(tcp_conn->data_tx_tfm,
1727 &tcp_ctask->sendbuf.sg, 1);
Alex Aizman7ba24712005-08-04 19:30:08 -07001728 /* imm data? */
1729 if (!dtask) {
Mike Christie5bb0b552006-04-06 21:26:46 -05001730 if (iscsi_digest_final_send(conn, ctask,
1731 &tcp_ctask->immbuf,
1732 &tcp_ctask->immdigest, 1)) {
Alex Aizman7ba24712005-08-04 19:30:08 -07001733 debug_tcp("send padding digest 0x%x"
Mike Christie5bb0b552006-04-06 21:26:46 -05001734 "fail!\n", tcp_ctask->immdigest);
Alex Aizman7ba24712005-08-04 19:30:08 -07001735 return -EAGAIN;
1736 }
1737 debug_tcp("done with padding, digest 0x%x\n",
Mike Christie5bb0b552006-04-06 21:26:46 -05001738 tcp_ctask->datadigest);
Alex Aizman7ba24712005-08-04 19:30:08 -07001739 } else {
1740 if (iscsi_digest_final_send(conn, ctask,
1741 &dtask->digestbuf,
1742 &dtask->digest, 1)) {
1743 debug_tcp("send padding digest 0x%x"
1744 "fail\n", dtask->digest);
1745 return -EAGAIN;
1746 }
1747 debug_tcp("done with padding, digest 0x%x\n",
1748 dtask->digest);
1749 }
1750 }
1751
1752 return 0;
1753}
1754
1755static int
Mike Christie5bb0b552006-04-06 21:26:46 -05001756iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
Alex Aizman7ba24712005-08-04 19:30:08 -07001757{
Mike Christie5bb0b552006-04-06 21:26:46 -05001758 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
Alex Aizman7ba24712005-08-04 19:30:08 -07001759 int rc = 0;
1760
1761 debug_scsi("ctask deq [cid %d xmstate %x itt 0x%x]\n",
Mike Christie5bb0b552006-04-06 21:26:46 -05001762 conn->id, tcp_ctask->xmstate, ctask->itt);
Alex Aizman7ba24712005-08-04 19:30:08 -07001763
1764 /*
1765 * serialize with TMF AbortTask
1766 */
1767 if (ctask->mtask)
1768 return rc;
1769
Mike Christie5bb0b552006-04-06 21:26:46 -05001770 if (tcp_ctask->xmstate & XMSTATE_R_HDR) {
1771 rc = handle_xmstate_r_hdr(conn, tcp_ctask);
Alex Aizman7ba24712005-08-04 19:30:08 -07001772 return rc;
1773 }
1774
Mike Christie5bb0b552006-04-06 21:26:46 -05001775 if (tcp_ctask->xmstate & XMSTATE_W_HDR) {
Alex Aizman7ba24712005-08-04 19:30:08 -07001776 rc = handle_xmstate_w_hdr(conn, ctask);
1777 if (rc)
1778 return rc;
1779 }
1780
1781 /* XXX: for data digest xmit recover */
Mike Christie5bb0b552006-04-06 21:26:46 -05001782 if (tcp_ctask->xmstate & XMSTATE_DATA_DIGEST) {
Alex Aizman7ba24712005-08-04 19:30:08 -07001783 rc = handle_xmstate_data_digest(conn, ctask);
1784 if (rc)
1785 return rc;
1786 }
1787
Mike Christie5bb0b552006-04-06 21:26:46 -05001788 if (tcp_ctask->xmstate & XMSTATE_IMM_DATA) {
Alex Aizman7ba24712005-08-04 19:30:08 -07001789 rc = handle_xmstate_imm_data(conn, ctask);
1790 if (rc)
1791 return rc;
1792 }
1793
Mike Christie5bb0b552006-04-06 21:26:46 -05001794 if (tcp_ctask->xmstate & XMSTATE_UNS_HDR) {
Alex Aizman7ba24712005-08-04 19:30:08 -07001795 BUG_ON(!ctask->unsol_count);
Mike Christie5bb0b552006-04-06 21:26:46 -05001796 tcp_ctask->xmstate &= ~XMSTATE_UNS_HDR;
Alex Aizman7ba24712005-08-04 19:30:08 -07001797unsolicit_head_again:
1798 rc = handle_xmstate_uns_hdr(conn, ctask);
1799 if (rc)
1800 return rc;
1801 }
1802
Mike Christie5bb0b552006-04-06 21:26:46 -05001803 if (tcp_ctask->xmstate & XMSTATE_UNS_DATA) {
Alex Aizman7ba24712005-08-04 19:30:08 -07001804 rc = handle_xmstate_uns_data(conn, ctask);
1805 if (rc == 1)
1806 goto unsolicit_head_again;
1807 else if (rc)
1808 return rc;
1809 goto done;
1810 }
1811
Mike Christie5bb0b552006-04-06 21:26:46 -05001812 if (tcp_ctask->xmstate & XMSTATE_SOL_HDR) {
Alex Aizman7ba24712005-08-04 19:30:08 -07001813 struct iscsi_r2t_info *r2t;
1814
Mike Christie5bb0b552006-04-06 21:26:46 -05001815 tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
1816 tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
1817 if (!tcp_ctask->r2t)
1818 __kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t,
Alex Aizman7ba24712005-08-04 19:30:08 -07001819 sizeof(void*));
1820solicit_head_again:
Mike Christie5bb0b552006-04-06 21:26:46 -05001821 r2t = tcp_ctask->r2t;
Mike Christieaf973482005-09-12 21:01:32 -05001822 if (conn->hdrdgst_en)
FUJITA Tomonori42f72aa2006-01-13 18:05:35 -06001823 iscsi_hdr_digest(conn, &r2t->headbuf,
Mike Christieffbfe922006-05-18 20:31:36 -05001824 (u8*)r2t->dtask.hdrext);
Alex Aizman7ba24712005-08-04 19:30:08 -07001825 if (iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count)) {
Mike Christie5bb0b552006-04-06 21:26:46 -05001826 tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA;
1827 tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
Alex Aizman7ba24712005-08-04 19:30:08 -07001828 return -EAGAIN;
1829 }
1830
1831 debug_scsi("sol dout [dsn %d itt 0x%x dlen %d sent %d]\n",
1832 r2t->solicit_datasn - 1, ctask->itt, r2t->data_count,
1833 r2t->sent);
1834 }
1835
Mike Christie5bb0b552006-04-06 21:26:46 -05001836 if (tcp_ctask->xmstate & XMSTATE_SOL_DATA) {
Alex Aizman7ba24712005-08-04 19:30:08 -07001837 rc = handle_xmstate_sol_data(conn, ctask);
1838 if (rc == 1)
1839 goto solicit_head_again;
1840 if (rc)
1841 return rc;
1842 }
1843
1844done:
1845 /*
1846 * Last thing to check is whether we need to send write
1847 * padding. Note that we check for xmstate equality, not just the bit.
1848 */
Mike Christie5bb0b552006-04-06 21:26:46 -05001849 if (tcp_ctask->xmstate == XMSTATE_W_PAD)
Alex Aizman7ba24712005-08-04 19:30:08 -07001850 rc = handle_xmstate_w_pad(conn, ctask);
1851
1852 return rc;
1853}
1854
Mike Christie7b8631b2006-01-13 18:05:50 -06001855static struct iscsi_cls_conn *
Mike Christie5bb0b552006-04-06 21:26:46 -05001856iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
Alex Aizman7ba24712005-08-04 19:30:08 -07001857{
Mike Christie7b8631b2006-01-13 18:05:50 -06001858 struct iscsi_conn *conn;
1859 struct iscsi_cls_conn *cls_conn;
Mike Christie5bb0b552006-04-06 21:26:46 -05001860 struct iscsi_tcp_conn *tcp_conn;
Alex Aizman7ba24712005-08-04 19:30:08 -07001861
Mike Christie5bb0b552006-04-06 21:26:46 -05001862 cls_conn = iscsi_conn_setup(cls_session, conn_idx);
Mike Christie7b8631b2006-01-13 18:05:50 -06001863 if (!cls_conn)
1864 return NULL;
1865 conn = cls_conn->dd_data;
Mike Christie5bb0b552006-04-06 21:26:46 -05001866 /*
1867 * due to strange issues with iser these are not set
1868 * in iscsi_conn_setup
1869 */
Alex Aizman7ba24712005-08-04 19:30:08 -07001870 conn->max_recv_dlength = DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH;
1871
Mike Christie5bb0b552006-04-06 21:26:46 -05001872 tcp_conn = kzalloc(sizeof(*tcp_conn), GFP_KERNEL);
1873 if (!tcp_conn)
1874 goto tcp_conn_alloc_fail;
Alex Aizman7ba24712005-08-04 19:30:08 -07001875
Mike Christie5bb0b552006-04-06 21:26:46 -05001876 conn->dd_data = tcp_conn;
1877 tcp_conn->iscsi_conn = conn;
1878 tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
1879 /* initial operational parameters */
1880 tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
1881 tcp_conn->data_size = DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH;
Alex Aizman7ba24712005-08-04 19:30:08 -07001882
1883 /* allocate initial PDU receive place holder */
Mike Christie5bb0b552006-04-06 21:26:46 -05001884 if (tcp_conn->data_size <= PAGE_SIZE)
1885 tcp_conn->data = kmalloc(tcp_conn->data_size, GFP_KERNEL);
Alex Aizman7ba24712005-08-04 19:30:08 -07001886 else
Mike Christie5bb0b552006-04-06 21:26:46 -05001887 tcp_conn->data = (void*)__get_free_pages(GFP_KERNEL,
1888 get_order(tcp_conn->data_size));
1889 if (!tcp_conn->data)
Alex Aizman7ba24712005-08-04 19:30:08 -07001890 goto max_recv_dlenght_alloc_fail;
1891
Mike Christie7b8631b2006-01-13 18:05:50 -06001892 return cls_conn;
Alex Aizman7ba24712005-08-04 19:30:08 -07001893
1894max_recv_dlenght_alloc_fail:
Mike Christie5bb0b552006-04-06 21:26:46 -05001895 kfree(tcp_conn);
1896tcp_conn_alloc_fail:
1897 iscsi_conn_teardown(cls_conn);
Mike Christie7b8631b2006-01-13 18:05:50 -06001898 return NULL;
Alex Aizman7ba24712005-08-04 19:30:08 -07001899}
1900
1901static void
Mike Christie5bb0b552006-04-06 21:26:46 -05001902iscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn)
Alex Aizman7ba24712005-08-04 19:30:08 -07001903{
Mike Christie7b8631b2006-01-13 18:05:50 -06001904 struct iscsi_conn *conn = cls_conn->dd_data;
Mike Christie5bb0b552006-04-06 21:26:46 -05001905 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
1906 int digest = 0;
Alex Aizman7ba24712005-08-04 19:30:08 -07001907
Mike Christie5bb0b552006-04-06 21:26:46 -05001908 if (conn->hdrdgst_en || conn->datadgst_en)
1909 digest = 1;
Alex Aizman7ba24712005-08-04 19:30:08 -07001910
Mike Christie5bb0b552006-04-06 21:26:46 -05001911 iscsi_conn_teardown(cls_conn);
Alex Aizman7ba24712005-08-04 19:30:08 -07001912
Mike Christie5bb0b552006-04-06 21:26:46 -05001913 /* now free tcp_conn */
1914 if (digest) {
1915 if (tcp_conn->tx_tfm)
1916 crypto_free_tfm(tcp_conn->tx_tfm);
1917 if (tcp_conn->rx_tfm)
1918 crypto_free_tfm(tcp_conn->rx_tfm);
1919 if (tcp_conn->data_tx_tfm)
1920 crypto_free_tfm(tcp_conn->data_tx_tfm);
1921 if (tcp_conn->data_rx_tfm)
1922 crypto_free_tfm(tcp_conn->data_rx_tfm);
Alex Aizman7ba24712005-08-04 19:30:08 -07001923 }
1924
1925 /* free conn->data, size = MaxRecvDataSegmentLength */
Mike Christie5bb0b552006-04-06 21:26:46 -05001926 if (tcp_conn->data_size <= PAGE_SIZE)
1927 kfree(tcp_conn->data);
Alex Aizman7ba24712005-08-04 19:30:08 -07001928 else
Mike Christie5bb0b552006-04-06 21:26:46 -05001929 free_pages((unsigned long)tcp_conn->data,
1930 get_order(tcp_conn->data_size));
1931 kfree(tcp_conn);
Alex Aizman7ba24712005-08-04 19:30:08 -07001932}
1933
1934static int
Mike Christie5bb0b552006-04-06 21:26:46 -05001935iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session,
Or Gerlitz264faaa2006-05-02 19:46:36 -05001936 struct iscsi_cls_conn *cls_conn, uint64_t transport_eph,
Mike Christie5bb0b552006-04-06 21:26:46 -05001937 int is_leading)
Alex Aizman7ba24712005-08-04 19:30:08 -07001938{
Mike Christie5bb0b552006-04-06 21:26:46 -05001939 struct iscsi_conn *conn = cls_conn->dd_data;
1940 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
Alex Aizman7ba24712005-08-04 19:30:08 -07001941 struct sock *sk;
1942 struct socket *sock;
1943 int err;
1944
1945 /* lookup for existing socket */
Or Gerlitz264faaa2006-05-02 19:46:36 -05001946 sock = sockfd_lookup((int)transport_eph, &err);
Alex Aizman7ba24712005-08-04 19:30:08 -07001947 if (!sock) {
1948 printk(KERN_ERR "iscsi_tcp: sockfd_lookup failed %d\n", err);
1949 return -EEXIST;
1950 }
1951
Mike Christie5bb0b552006-04-06 21:26:46 -05001952 err = iscsi_conn_bind(cls_session, cls_conn, is_leading);
1953 if (err)
1954 return err;
Alex Aizman7ba24712005-08-04 19:30:08 -07001955
1956 if (conn->stop_stage != STOP_CONN_SUSPEND) {
1957 /* bind iSCSI connection and socket */
Mike Christie5bb0b552006-04-06 21:26:46 -05001958 tcp_conn->sock = sock;
Alex Aizman7ba24712005-08-04 19:30:08 -07001959
1960 /* setup Socket parameters */
1961 sk = sock->sk;
1962 sk->sk_reuse = 1;
1963 sk->sk_sndtimeo = 15 * HZ; /* FIXME: make it configurable */
1964 sk->sk_allocation = GFP_ATOMIC;
1965
1966 /* FIXME: disable Nagle's algorithm */
1967
1968 /*
1969 * Intercept TCP callbacks for sendfile like receive
1970 * processing.
1971 */
Mike Christie5bb0b552006-04-06 21:26:46 -05001972 conn->recv_lock = &sk->sk_callback_lock;
Alex Aizman7ba24712005-08-04 19:30:08 -07001973 iscsi_conn_set_callbacks(conn);
Mike Christie5bb0b552006-04-06 21:26:46 -05001974 tcp_conn->sendpage = tcp_conn->sock->ops->sendpage;
Alex Aizman7ba24712005-08-04 19:30:08 -07001975 /*
1976 * set receive state machine into initial state
1977 */
Mike Christie5bb0b552006-04-06 21:26:46 -05001978 tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
Alex Aizman7ba24712005-08-04 19:30:08 -07001979 }
1980
Alex Aizman7ba24712005-08-04 19:30:08 -07001981 return 0;
1982}
1983
Mike Christie30a6c652006-04-06 21:13:39 -05001984static void
Mike Christie5bb0b552006-04-06 21:26:46 -05001985iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
Mike Christie30a6c652006-04-06 21:13:39 -05001986{
Mike Christie5bb0b552006-04-06 21:26:46 -05001987 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
Mike Christie30a6c652006-04-06 21:13:39 -05001988 struct iscsi_r2t_info *r2t;
Mike Christie30a6c652006-04-06 21:13:39 -05001989
1990 /* flush ctask's r2t queues */
Mike Christie5bb0b552006-04-06 21:26:46 -05001991 while (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*)))
1992 __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
1993 sizeof(void*));
Mike Christie30a6c652006-04-06 21:13:39 -05001994
1995 __iscsi_ctask_cleanup(conn, ctask);
1996}
1997
Mike Christie30a6c652006-04-06 21:13:39 -05001998static void
Mike Christie5bb0b552006-04-06 21:26:46 -05001999iscsi_tcp_suspend_conn_rx(struct iscsi_conn *conn)
Mike Christie30a6c652006-04-06 21:13:39 -05002000{
Mike Christie5bb0b552006-04-06 21:26:46 -05002001 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
Alex Aizman7ba24712005-08-04 19:30:08 -07002002 struct sock *sk;
Alex Aizman7ba24712005-08-04 19:30:08 -07002003
Mike Christie5bb0b552006-04-06 21:26:46 -05002004 if (!tcp_conn->sock)
2005 return;
2006
2007 sk = tcp_conn->sock->sk;
Alex Aizman7ba24712005-08-04 19:30:08 -07002008 write_lock_bh(&sk->sk_callback_lock);
Mike Christie5bb0b552006-04-06 21:26:46 -05002009 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
Alex Aizman7ba24712005-08-04 19:30:08 -07002010 write_unlock_bh(&sk->sk_callback_lock);
Mike Christie30a6c652006-04-06 21:13:39 -05002011}
2012
2013static void
Mike Christie5bb0b552006-04-06 21:26:46 -05002014iscsi_tcp_terminate_conn(struct iscsi_conn *conn)
Mike Christie30a6c652006-04-06 21:13:39 -05002015{
Mike Christie5bb0b552006-04-06 21:26:46 -05002016 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
2017
2018 if (!tcp_conn->sock)
Mike Christie30a6c652006-04-06 21:13:39 -05002019 return;
Mike Christie30a6c652006-04-06 21:13:39 -05002020
Mike Christie5bb0b552006-04-06 21:26:46 -05002021 sock_hold(tcp_conn->sock->sk);
Mike Christie30a6c652006-04-06 21:13:39 -05002022 iscsi_conn_restore_callbacks(conn);
Mike Christie5bb0b552006-04-06 21:26:46 -05002023 sock_put(tcp_conn->sock->sk);
Alex Aizman7ba24712005-08-04 19:30:08 -07002024
Mike Christie5bb0b552006-04-06 21:26:46 -05002025 sock_release(tcp_conn->sock);
2026 tcp_conn->sock = NULL;
2027 conn->recv_lock = NULL;
Alex Aizman7ba24712005-08-04 19:30:08 -07002028}
2029
Mike Christie5bb0b552006-04-06 21:26:46 -05002030/* called with host lock */
Mike Christie30a6c652006-04-06 21:13:39 -05002031static void
Mike Christie5bb0b552006-04-06 21:26:46 -05002032iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask,
2033 char *data, uint32_t data_size)
Mike Christie30a6c652006-04-06 21:13:39 -05002034{
Mike Christie5bb0b552006-04-06 21:26:46 -05002035 struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
Mike Christie30a6c652006-04-06 21:13:39 -05002036
Mike Christie6e458cc2006-05-18 20:31:31 -05002037 iscsi_buf_init_iov(&tcp_mtask->headbuf, (char*)mtask->hdr,
2038 sizeof(struct iscsi_hdr));
Mike Christie5bb0b552006-04-06 21:26:46 -05002039 tcp_mtask->xmstate = XMSTATE_IMM_HDR;
Alex Aizman7ba24712005-08-04 19:30:08 -07002040
Mike Christie5bb0b552006-04-06 21:26:46 -05002041 if (mtask->data_count)
2042 iscsi_buf_init_iov(&tcp_mtask->sendbuf, (char*)mtask->data,
Alex Aizman7ba24712005-08-04 19:30:08 -07002043 mtask->data_count);
Alex Aizman7ba24712005-08-04 19:30:08 -07002044}
2045
2046static int
2047iscsi_r2tpool_alloc(struct iscsi_session *session)
2048{
2049 int i;
2050 int cmd_i;
2051
2052 /*
2053 * initialize per-task: R2T pool and xmit queue
2054 */
2055 for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
2056 struct iscsi_cmd_task *ctask = session->cmds[cmd_i];
Mike Christie5bb0b552006-04-06 21:26:46 -05002057 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
Alex Aizman7ba24712005-08-04 19:30:08 -07002058
2059 /*
2060 * pre-allocated x4 as much r2ts to handle race when
2061 * target acks DataOut faster than we data_xmit() queues
2062 * could replenish r2tqueue.
2063 */
2064
2065 /* R2T pool */
Mike Christie5bb0b552006-04-06 21:26:46 -05002066 if (iscsi_pool_init(&tcp_ctask->r2tpool, session->max_r2t * 4,
2067 (void***)&tcp_ctask->r2ts,
2068 sizeof(struct iscsi_r2t_info))) {
Alex Aizman7ba24712005-08-04 19:30:08 -07002069 goto r2t_alloc_fail;
2070 }
2071
2072 /* R2T xmit queue */
Mike Christie5bb0b552006-04-06 21:26:46 -05002073 tcp_ctask->r2tqueue = kfifo_alloc(
Alex Aizman7ba24712005-08-04 19:30:08 -07002074 session->max_r2t * 4 * sizeof(void*), GFP_KERNEL, NULL);
Mike Christie5bb0b552006-04-06 21:26:46 -05002075 if (tcp_ctask->r2tqueue == ERR_PTR(-ENOMEM)) {
2076 iscsi_pool_free(&tcp_ctask->r2tpool,
2077 (void**)tcp_ctask->r2ts);
Alex Aizman7ba24712005-08-04 19:30:08 -07002078 goto r2t_alloc_fail;
2079 }
Alex Aizman7ba24712005-08-04 19:30:08 -07002080 }
2081
2082 return 0;
2083
2084r2t_alloc_fail:
2085 for (i = 0; i < cmd_i; i++) {
Mike Christie5bb0b552006-04-06 21:26:46 -05002086 struct iscsi_cmd_task *ctask = session->cmds[i];
2087 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
2088
Mike Christie5bb0b552006-04-06 21:26:46 -05002089 kfifo_free(tcp_ctask->r2tqueue);
2090 iscsi_pool_free(&tcp_ctask->r2tpool,
2091 (void**)tcp_ctask->r2ts);
Alex Aizman7ba24712005-08-04 19:30:08 -07002092 }
2093 return -ENOMEM;
2094}
2095
2096static void
2097iscsi_r2tpool_free(struct iscsi_session *session)
2098{
2099 int i;
2100
2101 for (i = 0; i < session->cmds_max; i++) {
Mike Christie5bb0b552006-04-06 21:26:46 -05002102 struct iscsi_cmd_task *ctask = session->cmds[i];
2103 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
2104
Mike Christie5bb0b552006-04-06 21:26:46 -05002105 kfifo_free(tcp_ctask->r2tqueue);
2106 iscsi_pool_free(&tcp_ctask->r2tpool,
2107 (void**)tcp_ctask->r2ts);
Alex Aizman7ba24712005-08-04 19:30:08 -07002108 }
2109}
2110
Alex Aizman7ba24712005-08-04 19:30:08 -07002111static int
Mike Christie7b7232f2006-02-01 21:06:49 -06002112iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param,
Alex Aizman7ba24712005-08-04 19:30:08 -07002113 uint32_t value)
2114{
Mike Christie7b7232f2006-02-01 21:06:49 -06002115 struct iscsi_conn *conn = cls_conn->dd_data;
Alex Aizman7ba24712005-08-04 19:30:08 -07002116 struct iscsi_session *session = conn->session;
Mike Christie5bb0b552006-04-06 21:26:46 -05002117 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
Alex Aizman7ba24712005-08-04 19:30:08 -07002118
Alex Aizman7ba24712005-08-04 19:30:08 -07002119 switch(param) {
2120 case ISCSI_PARAM_MAX_RECV_DLENGTH: {
Mike Christie5bb0b552006-04-06 21:26:46 -05002121 char *saveptr = tcp_conn->data;
Al Virob53cb2a2005-12-15 09:17:19 +00002122 gfp_t flags = GFP_KERNEL;
Alex Aizman7ba24712005-08-04 19:30:08 -07002123
Mike Christie5bb0b552006-04-06 21:26:46 -05002124 if (tcp_conn->data_size >= value) {
Alex Aizman7ba24712005-08-04 19:30:08 -07002125 conn->max_recv_dlength = value;
2126 break;
2127 }
2128
2129 spin_lock_bh(&session->lock);
2130 if (conn->stop_stage == STOP_CONN_RECOVER)
2131 flags = GFP_ATOMIC;
2132 spin_unlock_bh(&session->lock);
2133
2134 if (value <= PAGE_SIZE)
Mike Christie5bb0b552006-04-06 21:26:46 -05002135 tcp_conn->data = kmalloc(value, flags);
Alex Aizman7ba24712005-08-04 19:30:08 -07002136 else
Mike Christie5bb0b552006-04-06 21:26:46 -05002137 tcp_conn->data = (void*)__get_free_pages(flags,
Alex Aizman7ba24712005-08-04 19:30:08 -07002138 get_order(value));
Mike Christie5bb0b552006-04-06 21:26:46 -05002139 if (tcp_conn->data == NULL) {
2140 tcp_conn->data = saveptr;
Alex Aizman7ba24712005-08-04 19:30:08 -07002141 return -ENOMEM;
2142 }
Mike Christie5bb0b552006-04-06 21:26:46 -05002143 if (tcp_conn->data_size <= PAGE_SIZE)
Alex Aizman7ba24712005-08-04 19:30:08 -07002144 kfree(saveptr);
2145 else
2146 free_pages((unsigned long)saveptr,
Mike Christie5bb0b552006-04-06 21:26:46 -05002147 get_order(tcp_conn->data_size));
Alex Aizman7ba24712005-08-04 19:30:08 -07002148 conn->max_recv_dlength = value;
Mike Christie5bb0b552006-04-06 21:26:46 -05002149 tcp_conn->data_size = value;
Alex Aizman7ba24712005-08-04 19:30:08 -07002150 }
2151 break;
2152 case ISCSI_PARAM_MAX_XMIT_DLENGTH:
2153 conn->max_xmit_dlength = value;
2154 break;
2155 case ISCSI_PARAM_HDRDGST_EN:
2156 conn->hdrdgst_en = value;
Mike Christie5bb0b552006-04-06 21:26:46 -05002157 tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
Alex Aizman7ba24712005-08-04 19:30:08 -07002158 if (conn->hdrdgst_en) {
Mike Christie5bb0b552006-04-06 21:26:46 -05002159 tcp_conn->hdr_size += sizeof(__u32);
2160 if (!tcp_conn->tx_tfm)
2161 tcp_conn->tx_tfm = crypto_alloc_tfm("crc32c",
2162 0);
2163 if (!tcp_conn->tx_tfm)
Alex Aizman7ba24712005-08-04 19:30:08 -07002164 return -ENOMEM;
Mike Christie5bb0b552006-04-06 21:26:46 -05002165 if (!tcp_conn->rx_tfm)
2166 tcp_conn->rx_tfm = crypto_alloc_tfm("crc32c",
2167 0);
2168 if (!tcp_conn->rx_tfm) {
2169 crypto_free_tfm(tcp_conn->tx_tfm);
Alex Aizman7ba24712005-08-04 19:30:08 -07002170 return -ENOMEM;
2171 }
2172 } else {
Mike Christie5bb0b552006-04-06 21:26:46 -05002173 if (tcp_conn->tx_tfm)
2174 crypto_free_tfm(tcp_conn->tx_tfm);
2175 if (tcp_conn->rx_tfm)
2176 crypto_free_tfm(tcp_conn->rx_tfm);
Alex Aizman7ba24712005-08-04 19:30:08 -07002177 }
2178 break;
2179 case ISCSI_PARAM_DATADGST_EN:
2180 conn->datadgst_en = value;
2181 if (conn->datadgst_en) {
Mike Christie5bb0b552006-04-06 21:26:46 -05002182 if (!tcp_conn->data_tx_tfm)
2183 tcp_conn->data_tx_tfm =
Alex Aizman7ba24712005-08-04 19:30:08 -07002184 crypto_alloc_tfm("crc32c", 0);
Mike Christie5bb0b552006-04-06 21:26:46 -05002185 if (!tcp_conn->data_tx_tfm)
Alex Aizman7ba24712005-08-04 19:30:08 -07002186 return -ENOMEM;
Mike Christie5bb0b552006-04-06 21:26:46 -05002187 if (!tcp_conn->data_rx_tfm)
2188 tcp_conn->data_rx_tfm =
Alex Aizman7ba24712005-08-04 19:30:08 -07002189 crypto_alloc_tfm("crc32c", 0);
Mike Christie5bb0b552006-04-06 21:26:46 -05002190 if (!tcp_conn->data_rx_tfm) {
2191 crypto_free_tfm(tcp_conn->data_tx_tfm);
Alex Aizman7ba24712005-08-04 19:30:08 -07002192 return -ENOMEM;
2193 }
2194 } else {
Mike Christie5bb0b552006-04-06 21:26:46 -05002195 if (tcp_conn->data_tx_tfm)
2196 crypto_free_tfm(tcp_conn->data_tx_tfm);
2197 if (tcp_conn->data_rx_tfm)
2198 crypto_free_tfm(tcp_conn->data_rx_tfm);
Alex Aizman7ba24712005-08-04 19:30:08 -07002199 }
Mike Christie5bb0b552006-04-06 21:26:46 -05002200 tcp_conn->sendpage = conn->datadgst_en ?
2201 sock_no_sendpage : tcp_conn->sock->ops->sendpage;
Alex Aizman7ba24712005-08-04 19:30:08 -07002202 break;
2203 case ISCSI_PARAM_INITIAL_R2T_EN:
2204 session->initial_r2t_en = value;
2205 break;
2206 case ISCSI_PARAM_MAX_R2T:
2207 if (session->max_r2t == roundup_pow_of_two(value))
2208 break;
2209 iscsi_r2tpool_free(session);
2210 session->max_r2t = value;
2211 if (session->max_r2t & (session->max_r2t - 1))
2212 session->max_r2t = roundup_pow_of_two(session->max_r2t);
2213 if (iscsi_r2tpool_alloc(session))
2214 return -ENOMEM;
2215 break;
2216 case ISCSI_PARAM_IMM_DATA_EN:
2217 session->imm_data_en = value;
2218 break;
2219 case ISCSI_PARAM_FIRST_BURST:
2220 session->first_burst = value;
2221 break;
2222 case ISCSI_PARAM_MAX_BURST:
2223 session->max_burst = value;
2224 break;
2225 case ISCSI_PARAM_PDU_INORDER_EN:
2226 session->pdu_inorder_en = value;
2227 break;
2228 case ISCSI_PARAM_DATASEQ_INORDER_EN:
2229 session->dataseq_inorder_en = value;
2230 break;
2231 case ISCSI_PARAM_ERL:
2232 session->erl = value;
2233 break;
2234 case ISCSI_PARAM_IFMARKER_EN:
2235 BUG_ON(value);
2236 session->ifmarker_en = value;
2237 break;
2238 case ISCSI_PARAM_OFMARKER_EN:
2239 BUG_ON(value);
2240 session->ofmarker_en = value;
2241 break;
Mike Christie8d2860b2006-05-02 19:46:47 -05002242 case ISCSI_PARAM_EXP_STATSN:
2243 conn->exp_statsn = value;
2244 break;
Alex Aizman7ba24712005-08-04 19:30:08 -07002245 default:
2246 break;
2247 }
2248
2249 return 0;
2250}
2251
2252static int
Mike Christie7b7232f2006-02-01 21:06:49 -06002253iscsi_session_get_param(struct iscsi_cls_session *cls_session,
Mike Christie7b8631b2006-01-13 18:05:50 -06002254 enum iscsi_param param, uint32_t *value)
Alex Aizman7ba24712005-08-04 19:30:08 -07002255{
Mike Christie7b7232f2006-02-01 21:06:49 -06002256 struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
Mike Christie7b8631b2006-01-13 18:05:50 -06002257 struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
Alex Aizman7ba24712005-08-04 19:30:08 -07002258
2259 switch(param) {
Alex Aizman7ba24712005-08-04 19:30:08 -07002260 case ISCSI_PARAM_INITIAL_R2T_EN:
2261 *value = session->initial_r2t_en;
2262 break;
2263 case ISCSI_PARAM_MAX_R2T:
2264 *value = session->max_r2t;
2265 break;
2266 case ISCSI_PARAM_IMM_DATA_EN:
2267 *value = session->imm_data_en;
2268 break;
2269 case ISCSI_PARAM_FIRST_BURST:
2270 *value = session->first_burst;
2271 break;
2272 case ISCSI_PARAM_MAX_BURST:
2273 *value = session->max_burst;
2274 break;
2275 case ISCSI_PARAM_PDU_INORDER_EN:
2276 *value = session->pdu_inorder_en;
2277 break;
2278 case ISCSI_PARAM_DATASEQ_INORDER_EN:
2279 *value = session->dataseq_inorder_en;
2280 break;
2281 case ISCSI_PARAM_ERL:
2282 *value = session->erl;
2283 break;
2284 case ISCSI_PARAM_IFMARKER_EN:
2285 *value = session->ifmarker_en;
2286 break;
2287 case ISCSI_PARAM_OFMARKER_EN:
2288 *value = session->ofmarker_en;
2289 break;
2290 default:
Mike Christiefd7255f2006-04-06 21:13:36 -05002291 return -EINVAL;
Alex Aizman7ba24712005-08-04 19:30:08 -07002292 }
2293
2294 return 0;
2295}
2296
Mike Christie7b8631b2006-01-13 18:05:50 -06002297static int
Mike Christie7b7232f2006-02-01 21:06:49 -06002298iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
2299 enum iscsi_param param, uint32_t *value)
Mike Christie7b8631b2006-01-13 18:05:50 -06002300{
Mike Christie7b7232f2006-02-01 21:06:49 -06002301 struct iscsi_conn *conn = cls_conn->dd_data;
Mike Christie5bb0b552006-04-06 21:26:46 -05002302 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
Mike Christiefd7255f2006-04-06 21:13:36 -05002303 struct inet_sock *inet;
Mike Christie7b8631b2006-01-13 18:05:50 -06002304
2305 switch(param) {
2306 case ISCSI_PARAM_MAX_RECV_DLENGTH:
2307 *value = conn->max_recv_dlength;
2308 break;
2309 case ISCSI_PARAM_MAX_XMIT_DLENGTH:
2310 *value = conn->max_xmit_dlength;
2311 break;
2312 case ISCSI_PARAM_HDRDGST_EN:
2313 *value = conn->hdrdgst_en;
2314 break;
2315 case ISCSI_PARAM_DATADGST_EN:
2316 *value = conn->datadgst_en;
2317 break;
Mike Christiefd7255f2006-04-06 21:13:36 -05002318 case ISCSI_PARAM_CONN_PORT:
2319 mutex_lock(&conn->xmitmutex);
Mike Christie5bb0b552006-04-06 21:26:46 -05002320 if (!tcp_conn->sock) {
Mike Christiefd7255f2006-04-06 21:13:36 -05002321 mutex_unlock(&conn->xmitmutex);
2322 return -EINVAL;
2323 }
2324
Mike Christie5bb0b552006-04-06 21:26:46 -05002325 inet = inet_sk(tcp_conn->sock->sk);
Mike Christiefd7255f2006-04-06 21:13:36 -05002326 *value = be16_to_cpu(inet->dport);
2327 mutex_unlock(&conn->xmitmutex);
Mike Christie8d2860b2006-05-02 19:46:47 -05002328 case ISCSI_PARAM_EXP_STATSN:
2329 *value = conn->exp_statsn;
2330 break;
Mike Christie7b8631b2006-01-13 18:05:50 -06002331 default:
Mike Christiefd7255f2006-04-06 21:13:36 -05002332 return -EINVAL;
Mike Christie7b8631b2006-01-13 18:05:50 -06002333 }
2334
2335 return 0;
2336}
2337
Mike Christiefd7255f2006-04-06 21:13:36 -05002338static int
2339iscsi_conn_get_str_param(struct iscsi_cls_conn *cls_conn,
2340 enum iscsi_param param, char *buf)
2341{
2342 struct iscsi_conn *conn = cls_conn->dd_data;
Mike Christie5bb0b552006-04-06 21:26:46 -05002343 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
Mike Christiefd7255f2006-04-06 21:13:36 -05002344 struct sock *sk;
2345 struct inet_sock *inet;
2346 struct ipv6_pinfo *np;
2347 int len = 0;
2348
2349 switch (param) {
2350 case ISCSI_PARAM_CONN_ADDRESS:
2351 mutex_lock(&conn->xmitmutex);
Mike Christie5bb0b552006-04-06 21:26:46 -05002352 if (!tcp_conn->sock) {
Mike Christiefd7255f2006-04-06 21:13:36 -05002353 mutex_unlock(&conn->xmitmutex);
2354 return -EINVAL;
2355 }
2356
Mike Christie5bb0b552006-04-06 21:26:46 -05002357 sk = tcp_conn->sock->sk;
Mike Christiefd7255f2006-04-06 21:13:36 -05002358 if (sk->sk_family == PF_INET) {
2359 inet = inet_sk(sk);
2360 len = sprintf(buf, "%u.%u.%u.%u\n",
2361 NIPQUAD(inet->daddr));
2362 } else {
2363 np = inet6_sk(sk);
2364 len = sprintf(buf,
2365 "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
2366 NIP6(np->daddr));
2367 }
2368 mutex_unlock(&conn->xmitmutex);
2369 break;
2370 default:
2371 return -EINVAL;
2372 }
2373
2374 return len;
2375}
2376
Alex Aizman7ba24712005-08-04 19:30:08 -07002377static void
Mike Christie7b7232f2006-02-01 21:06:49 -06002378iscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats)
Alex Aizman7ba24712005-08-04 19:30:08 -07002379{
Mike Christie7b7232f2006-02-01 21:06:49 -06002380 struct iscsi_conn *conn = cls_conn->dd_data;
Mike Christie5bb0b552006-04-06 21:26:46 -05002381 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
Alex Aizman7ba24712005-08-04 19:30:08 -07002382
2383 stats->txdata_octets = conn->txdata_octets;
2384 stats->rxdata_octets = conn->rxdata_octets;
2385 stats->scsicmd_pdus = conn->scsicmd_pdus_cnt;
2386 stats->dataout_pdus = conn->dataout_pdus_cnt;
2387 stats->scsirsp_pdus = conn->scsirsp_pdus_cnt;
2388 stats->datain_pdus = conn->datain_pdus_cnt;
2389 stats->r2t_pdus = conn->r2t_pdus_cnt;
2390 stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt;
2391 stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt;
2392 stats->custom_length = 3;
2393 strcpy(stats->custom[0].desc, "tx_sendpage_failures");
Mike Christie5bb0b552006-04-06 21:26:46 -05002394 stats->custom[0].value = tcp_conn->sendpage_failures_cnt;
Alex Aizman7ba24712005-08-04 19:30:08 -07002395 strcpy(stats->custom[1].desc, "rx_discontiguous_hdr");
Mike Christie5bb0b552006-04-06 21:26:46 -05002396 stats->custom[1].value = tcp_conn->discontiguous_hdr_cnt;
Alex Aizman7ba24712005-08-04 19:30:08 -07002397 strcpy(stats->custom[2].desc, "eh_abort_cnt");
2398 stats->custom[2].value = conn->eh_abort_cnt;
2399}
2400
Mike Christie5bb0b552006-04-06 21:26:46 -05002401static struct iscsi_cls_session *
2402iscsi_tcp_session_create(struct iscsi_transport *iscsit,
2403 struct scsi_transport_template *scsit,
2404 uint32_t initial_cmdsn, uint32_t *hostno)
Alex Aizman7ba24712005-08-04 19:30:08 -07002405{
Mike Christie5bb0b552006-04-06 21:26:46 -05002406 struct iscsi_cls_session *cls_session;
2407 struct iscsi_session *session;
2408 uint32_t hn;
2409 int cmd_i;
Alex Aizman7ba24712005-08-04 19:30:08 -07002410
Mike Christie5bb0b552006-04-06 21:26:46 -05002411 cls_session = iscsi_session_setup(iscsit, scsit,
2412 sizeof(struct iscsi_tcp_cmd_task),
2413 sizeof(struct iscsi_tcp_mgmt_task),
2414 initial_cmdsn, &hn);
2415 if (!cls_session)
2416 return NULL;
2417 *hostno = hn;
Alex Aizman7ba24712005-08-04 19:30:08 -07002418
Mike Christie5bb0b552006-04-06 21:26:46 -05002419 session = class_to_transport_session(cls_session);
2420 for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
2421 struct iscsi_cmd_task *ctask = session->cmds[cmd_i];
2422 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
2423
2424 ctask->hdr = &tcp_ctask->hdr;
2425 }
2426
2427 for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) {
2428 struct iscsi_mgmt_task *mtask = session->mgmt_cmds[cmd_i];
2429 struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
2430
2431 mtask->hdr = &tcp_mtask->hdr;
2432 }
2433
2434 if (iscsi_r2tpool_alloc(class_to_transport_session(cls_session)))
2435 goto r2tpool_alloc_fail;
2436
2437 return cls_session;
2438
2439r2tpool_alloc_fail:
2440 iscsi_session_teardown(cls_session);
2441 return NULL;
Alex Aizman7ba24712005-08-04 19:30:08 -07002442}
2443
Mike Christie5bb0b552006-04-06 21:26:46 -05002444static void iscsi_tcp_session_destroy(struct iscsi_cls_session *cls_session)
2445{
Mike Christie5bb0b552006-04-06 21:26:46 -05002446 iscsi_r2tpool_free(class_to_transport_session(cls_session));
2447 iscsi_session_teardown(cls_session);
2448}
2449
2450static struct scsi_host_template iscsi_sht = {
2451 .name = "iSCSI Initiator over TCP/IP, v."
2452 ISCSI_VERSION_STR,
2453 .queuecommand = iscsi_queuecommand,
2454 .change_queue_depth = iscsi_change_queue_depth,
2455 .can_queue = ISCSI_XMIT_CMDS_MAX - 1,
2456 .sg_tablesize = ISCSI_SG_TABLESIZE,
2457 .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN,
2458 .eh_abort_handler = iscsi_eh_abort,
2459 .eh_host_reset_handler = iscsi_eh_host_reset,
2460 .use_clustering = DISABLE_CLUSTERING,
2461 .proc_name = "iscsi_tcp",
2462 .this_id = -1,
2463};
2464
Alex Aizman7ba24712005-08-04 19:30:08 -07002465static struct iscsi_transport iscsi_tcp_transport = {
2466 .owner = THIS_MODULE,
2467 .name = "tcp",
2468 .caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_HDRDGST
2469 | CAP_DATADGST,
Mike Christiefd7255f2006-04-06 21:13:36 -05002470 .param_mask = ISCSI_MAX_RECV_DLENGTH |
2471 ISCSI_MAX_XMIT_DLENGTH |
2472 ISCSI_HDRDGST_EN |
2473 ISCSI_DATADGST_EN |
2474 ISCSI_INITIAL_R2T_EN |
2475 ISCSI_MAX_R2T |
2476 ISCSI_IMM_DATA_EN |
2477 ISCSI_FIRST_BURST |
2478 ISCSI_MAX_BURST |
2479 ISCSI_PDU_INORDER_EN |
2480 ISCSI_DATASEQ_INORDER_EN |
2481 ISCSI_ERL |
2482 ISCSI_CONN_PORT |
Mike Christie8d2860b2006-05-02 19:46:47 -05002483 ISCSI_CONN_ADDRESS |
2484 ISCSI_EXP_STATSN,
Alex Aizman7ba24712005-08-04 19:30:08 -07002485 .host_template = &iscsi_sht,
Mike Christie7b8631b2006-01-13 18:05:50 -06002486 .conndata_size = sizeof(struct iscsi_conn),
Alex Aizman7ba24712005-08-04 19:30:08 -07002487 .max_conn = 1,
2488 .max_cmd_len = ISCSI_TCP_MAX_CMD_LEN,
Mike Christie5bb0b552006-04-06 21:26:46 -05002489 /* session management */
2490 .create_session = iscsi_tcp_session_create,
2491 .destroy_session = iscsi_tcp_session_destroy,
2492 /* connection management */
2493 .create_conn = iscsi_tcp_conn_create,
2494 .bind_conn = iscsi_tcp_conn_bind,
2495 .destroy_conn = iscsi_tcp_conn_destroy,
Alex Aizman7ba24712005-08-04 19:30:08 -07002496 .set_param = iscsi_conn_set_param,
Mike Christie7b8631b2006-01-13 18:05:50 -06002497 .get_conn_param = iscsi_conn_get_param,
Mike Christiefd7255f2006-04-06 21:13:36 -05002498 .get_conn_str_param = iscsi_conn_get_str_param,
Mike Christie7b8631b2006-01-13 18:05:50 -06002499 .get_session_param = iscsi_session_get_param,
Alex Aizman7ba24712005-08-04 19:30:08 -07002500 .start_conn = iscsi_conn_start,
2501 .stop_conn = iscsi_conn_stop,
Mike Christie5bb0b552006-04-06 21:26:46 -05002502 /* these are called as part of conn recovery */
2503 .suspend_conn_recv = iscsi_tcp_suspend_conn_rx,
2504 .terminate_conn = iscsi_tcp_terminate_conn,
2505 /* IO */
Alex Aizman7ba24712005-08-04 19:30:08 -07002506 .send_pdu = iscsi_conn_send_pdu,
2507 .get_stats = iscsi_conn_get_stats,
Mike Christie5bb0b552006-04-06 21:26:46 -05002508 .init_cmd_task = iscsi_tcp_cmd_init,
2509 .init_mgmt_task = iscsi_tcp_mgmt_init,
2510 .xmit_cmd_task = iscsi_tcp_ctask_xmit,
2511 .xmit_mgmt_task = iscsi_tcp_mtask_xmit,
2512 .cleanup_cmd_task = iscsi_tcp_cleanup_ctask,
2513 /* recovery */
Mike Christie30a6c652006-04-06 21:13:39 -05002514 .session_recovery_timedout = iscsi_session_recovery_timedout,
Alex Aizman7ba24712005-08-04 19:30:08 -07002515};
2516
2517static int __init
2518iscsi_tcp_init(void)
2519{
Alex Aizman7ba24712005-08-04 19:30:08 -07002520 if (iscsi_max_lun < 1) {
Or Gerlitzbe2df722006-05-02 19:46:43 -05002521 printk(KERN_ERR "iscsi_tcp: Invalid max_lun value of %u\n",
2522 iscsi_max_lun);
Alex Aizman7ba24712005-08-04 19:30:08 -07002523 return -EINVAL;
2524 }
2525 iscsi_tcp_transport.max_lun = iscsi_max_lun;
2526
Mike Christie7b8631b2006-01-13 18:05:50 -06002527 if (!iscsi_register_transport(&iscsi_tcp_transport))
Mike Christieffbfe922006-05-18 20:31:36 -05002528 return -ENODEV;
Alex Aizman7ba24712005-08-04 19:30:08 -07002529
Mike Christie7b8631b2006-01-13 18:05:50 -06002530 return 0;
Alex Aizman7ba24712005-08-04 19:30:08 -07002531}
2532
2533static void __exit
2534iscsi_tcp_exit(void)
2535{
2536 iscsi_unregister_transport(&iscsi_tcp_transport);
Alex Aizman7ba24712005-08-04 19:30:08 -07002537}
2538
2539module_init(iscsi_tcp_init);
2540module_exit(iscsi_tcp_exit);