aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/ulp/iser
diff options
context:
space:
mode:
authorOr Gerlitz <ogerlitz@voltaire.com>2006-05-11 03:00:44 -0400
committerRoland Dreier <rolandd@cisco.com>2006-06-22 10:51:07 -0400
commit65e7ae7bfc71219f13162b3bbad44e6471cd67f9 (patch)
tree90bb6c39fe78b3ef4ff0949ce7b4fc369523acd7 /drivers/infiniband/ulp/iser
parent49cd5382f629bde2aee9f817cefb271106dc47ee (diff)
IB/iser: iSCSI iSER transport provider high level code
This file contains the code that registeres with the iscsi transport manager and with the SCSI Mid Layer, where much of the provided functions to iSCSI and SCSI are implemented in libiscsi. Signed-off-by: Or Gerlitz <ogerlitz@voltaire.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/ulp/iser')
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c790
1 files changed, 790 insertions, 0 deletions
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
new file mode 100644
index 000000000000..4c3f2de2a06e
--- /dev/null
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -0,0 +1,790 @@
1/*
2 * iSCSI Initiator over iSER Data-Path
3 *
4 * Copyright (C) 2004 Dmitry Yusupov
5 * Copyright (C) 2004 Alex Aizman
6 * Copyright (C) 2005 Mike Christie
7 * Copyright (c) 2005, 2006 Voltaire, Inc. All rights reserved.
8 * maintained by openib-general@openib.org
9 *
10 * This software is available to you under a choice of one of two
11 * licenses. You may choose to be licensed under the terms of the GNU
12 * General Public License (GPL) Version 2, available from the file
13 * COPYING in the main directory of this source tree, or the
14 * OpenIB.org BSD license below:
15 *
16 * Redistribution and use in source and binary forms, with or
17 * without modification, are permitted provided that the following
18 * conditions are met:
19 *
20 * - Redistributions of source code must retain the above
21 * copyright notice, this list of conditions and the following
22 * disclaimer.
23 *
24 * - Redistributions in binary form must reproduce the above
25 * copyright notice, this list of conditions and the following
26 * disclaimer in the documentation and/or other materials
27 * provided with the distribution.
28 *
29 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
33 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
34 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
35 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36 * SOFTWARE.
37 *
38 * Credits:
39 * Christoph Hellwig
40 * FUJITA Tomonori
41 * Arne Redlich
42 * Zhenyu Wang
43 * Modified by:
44 * Erez Zilber
45 *
46 *
47 * $Id: iscsi_iser.c 6965 2006-05-07 11:36:20Z ogerlitz $
48 */
49
50#include <linux/types.h>
51#include <linux/list.h>
52#include <linux/hardirq.h>
53#include <linux/kfifo.h>
54#include <linux/blkdev.h>
55#include <linux/init.h>
56#include <linux/ioctl.h>
57#include <linux/devfs_fs_kernel.h>
58#include <linux/cdev.h>
59#include <linux/in.h>
60#include <linux/net.h>
61#include <linux/scatterlist.h>
62#include <linux/delay.h>
63
64#include <net/sock.h>
65
66#include <asm/uaccess.h>
67
68#include <scsi/scsi_cmnd.h>
69#include <scsi/scsi_device.h>
70#include <scsi/scsi_eh.h>
71#include <scsi/scsi_tcq.h>
72#include <scsi/scsi_host.h>
73#include <scsi/scsi.h>
74#include <scsi/scsi_transport_iscsi.h>
75
76#include "iscsi_iser.h"
77
78static unsigned int iscsi_max_lun = 512;
79module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
80
81int iser_debug_level = 0;
82
83MODULE_DESCRIPTION("iSER (iSCSI Extensions for RDMA) Datamover "
84 "v" DRV_VER " (" DRV_DATE ")");
85MODULE_LICENSE("Dual BSD/GPL");
86MODULE_AUTHOR("Alex Nezhinsky, Dan Bar Dov, Or Gerlitz");
87
88module_param_named(debug_level, iser_debug_level, int, 0644);
89MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0 (default:disabled)");
90
91struct iser_global ig;
92
93void
94iscsi_iser_recv(struct iscsi_conn *conn,
95 struct iscsi_hdr *hdr, char *rx_data, int rx_data_len)
96{
97 int rc = 0;
98 uint32_t ret_itt;
99 int datalen;
100 int ahslen;
101
102 /* verify PDU length */
103 datalen = ntoh24(hdr->dlength);
104 if (datalen != rx_data_len) {
105 printk(KERN_ERR "iscsi_iser: datalen %d (hdr) != %d (IB) \n",
106 datalen, rx_data_len);
107 rc = ISCSI_ERR_DATALEN;
108 goto error;
109 }
110
111 /* read AHS */
112 ahslen = hdr->hlength * 4;
113
114 /* verify itt (itt encoding: age+cid+itt) */
115 rc = iscsi_verify_itt(conn, hdr, &ret_itt);
116
117 if (!rc)
118 rc = iscsi_complete_pdu(conn, hdr, rx_data, rx_data_len);
119
120 if (rc && rc != ISCSI_ERR_NO_SCSI_CMD)
121 goto error;
122
123 return;
124error:
125 iscsi_conn_failure(conn, rc);
126}
127
128
129/**
130 * iscsi_iser_cmd_init - Initialize iSCSI SCSI_READ or SCSI_WRITE commands
131 *
132 **/
133static void
134iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask)
135{
136 struct iscsi_iser_conn *iser_conn = ctask->conn->dd_data;
137 struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
138 struct scsi_cmnd *sc = ctask->sc;
139
140 iser_ctask->command_sent = 0;
141 iser_ctask->iser_conn = iser_conn;
142
143 if (sc->sc_data_direction == DMA_TO_DEVICE) {
144 BUG_ON(ctask->total_length == 0);
145 /* bytes to be sent via RDMA operations */
146 iser_ctask->rdma_data_count = ctask->total_length -
147 ctask->imm_count -
148 ctask->unsol_count;
149
150 debug_scsi("cmd [itt %x total %d imm %d unsol_data %d "
151 "rdma_data %d]\n",
152 ctask->itt, ctask->total_length, ctask->imm_count,
153 ctask->unsol_count, iser_ctask->rdma_data_count);
154 } else
155 /* bytes to be sent via RDMA operations */
156 iser_ctask->rdma_data_count = ctask->total_length;
157
158 iser_ctask_rdma_init(iser_ctask);
159}
160
161/**
162 * iscsi_mtask_xmit - xmit management(immediate) task
163 * @conn: iscsi connection
164 * @mtask: task management task
165 *
166 * Notes:
167 * The function can return -EAGAIN in which case caller must
168 * call it again later, or recover. '0' return code means successful
169 * xmit.
170 *
171 **/
172static int
173iscsi_iser_mtask_xmit(struct iscsi_conn *conn,
174 struct iscsi_mgmt_task *mtask)
175{
176 int error = 0;
177
178 debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id, mtask->itt);
179
180 error = iser_send_control(conn, mtask);
181
182 /* since iser xmits control with zero copy, mtasks can not be recycled
183 * right after sending them.
184 * The recycling scheme is based on whether a response is expected
185 * - if yes, the mtask is recycled at iscsi_complete_pdu
186 * - if no, the mtask is recycled at iser_snd_completion
187 */
188 if (error && error != -EAGAIN)
189 iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
190
191 return error;
192}
193
194static int
195iscsi_iser_ctask_xmit_unsol_data(struct iscsi_conn *conn,
196 struct iscsi_cmd_task *ctask)
197{
198 struct iscsi_data hdr;
199 int error = 0;
200 struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
201
202 /* Send data-out PDUs while there's still unsolicited data to send */
203 while (ctask->unsol_count > 0) {
204 iscsi_prep_unsolicit_data_pdu(ctask, &hdr,
205 iser_ctask->rdma_data_count);
206
207 debug_scsi("Sending data-out: itt 0x%x, data count %d\n",
208 hdr.itt, ctask->data_count);
209
210 /* the buffer description has been passed with the command */
211 /* Send the command */
212 error = iser_send_data_out(conn, ctask, &hdr);
213 if (error) {
214 ctask->unsol_datasn--;
215 goto iscsi_iser_ctask_xmit_unsol_data_exit;
216 }
217 ctask->unsol_count -= ctask->data_count;
218 debug_scsi("Need to send %d more as data-out PDUs\n",
219 ctask->unsol_count);
220 }
221
222iscsi_iser_ctask_xmit_unsol_data_exit:
223 return error;
224}
225
226static int
227iscsi_iser_ctask_xmit(struct iscsi_conn *conn,
228 struct iscsi_cmd_task *ctask)
229{
230 struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
231 int error = 0;
232
233 debug_scsi("ctask deq [cid %d itt 0x%x]\n",
234 conn->id, ctask->itt);
235
236 /*
237 * serialize with TMF AbortTask
238 */
239 if (ctask->mtask)
240 return error;
241
242 /* Send the cmd PDU */
243 if (!iser_ctask->command_sent) {
244 error = iser_send_command(conn, ctask);
245 if (error)
246 goto iscsi_iser_ctask_xmit_exit;
247 iser_ctask->command_sent = 1;
248 }
249
250 /* Send unsolicited data-out PDU(s) if necessary */
251 if (ctask->unsol_count)
252 error = iscsi_iser_ctask_xmit_unsol_data(conn, ctask);
253
254 iscsi_iser_ctask_xmit_exit:
255 if (error && error != -EAGAIN)
256 iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
257 return error;
258}
259
260static void
261iscsi_iser_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
262{
263 struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
264
265 if (iser_ctask->status == ISER_TASK_STATUS_STARTED) {
266 iser_ctask->status = ISER_TASK_STATUS_COMPLETED;
267 iser_ctask_rdma_finalize(iser_ctask);
268 }
269}
270
271static struct iser_conn *
272iscsi_iser_ib_conn_lookup(__u64 ep_handle)
273{
274 struct iser_conn *ib_conn;
275 struct iser_conn *uib_conn = (struct iser_conn *)(unsigned long)ep_handle;
276
277 mutex_lock(&ig.connlist_mutex);
278 list_for_each_entry(ib_conn, &ig.connlist, conn_list) {
279 if (ib_conn == uib_conn) {
280 mutex_unlock(&ig.connlist_mutex);
281 return ib_conn;
282 }
283 }
284 mutex_unlock(&ig.connlist_mutex);
285 iser_err("no conn exists for eph %llx\n",(unsigned long long)ep_handle);
286 return NULL;
287}
288
289static struct iscsi_cls_conn *
290iscsi_iser_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
291{
292 struct iscsi_conn *conn;
293 struct iscsi_cls_conn *cls_conn;
294 struct iscsi_iser_conn *iser_conn;
295
296 cls_conn = iscsi_conn_setup(cls_session, conn_idx);
297 if (!cls_conn)
298 return NULL;
299 conn = cls_conn->dd_data;
300
301 /*
302 * due to issues with the login code re iser sematics
303 * this not set in iscsi_conn_setup - FIXME
304 */
305 conn->max_recv_dlength = 128;
306
307 iser_conn = kzalloc(sizeof(*iser_conn), GFP_KERNEL);
308 if (!iser_conn)
309 goto conn_alloc_fail;
310
311 /* currently this is the only field which need to be initiated */
312 rwlock_init(&iser_conn->lock);
313
314 conn->dd_data = iser_conn;
315 iser_conn->iscsi_conn = conn;
316
317 return cls_conn;
318
319conn_alloc_fail:
320 iscsi_conn_teardown(cls_conn);
321 return NULL;
322}
323
324static void
325iscsi_iser_conn_destroy(struct iscsi_cls_conn *cls_conn)
326{
327 struct iscsi_conn *conn = cls_conn->dd_data;
328 struct iscsi_iser_conn *iser_conn = conn->dd_data;
329
330 iscsi_conn_teardown(cls_conn);
331 kfree(iser_conn);
332}
333
334static int
335iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session,
336 struct iscsi_cls_conn *cls_conn, uint64_t transport_eph,
337 int is_leading)
338{
339 struct iscsi_conn *conn = cls_conn->dd_data;
340 struct iscsi_iser_conn *iser_conn;
341 struct iser_conn *ib_conn;
342 int error;
343
344 error = iscsi_conn_bind(cls_session, cls_conn, is_leading);
345 if (error)
346 return error;
347
348 /* the transport ep handle comes from user space so it must be
349 * verified against the global ib connections list */
350 ib_conn = iscsi_iser_ib_conn_lookup(transport_eph);
351 if (!ib_conn) {
352 iser_err("can't bind eph %llx\n",
353 (unsigned long long)transport_eph);
354 return -EINVAL;
355 }
356 /* binds the iSER connection retrieved from the previously
357 * connected ep_handle to the iSCSI layer connection. exchanges
358 * connection pointers */
359 iser_err("binding iscsi conn %p to iser_conn %p\n",conn,ib_conn);
360 iser_conn = conn->dd_data;
361 ib_conn->iser_conn = iser_conn;
362 iser_conn->ib_conn = ib_conn;
363
364 conn->recv_lock = &iser_conn->lock;
365
366 return 0;
367}
368
369static int
370iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn)
371{
372 struct iscsi_conn *conn = cls_conn->dd_data;
373 int err;
374
375 err = iscsi_conn_start(cls_conn);
376 if (err)
377 return err;
378
379 return iser_conn_set_full_featured_mode(conn);
380}
381
382static void
383iscsi_iser_conn_terminate(struct iscsi_conn *conn)
384{
385 struct iscsi_iser_conn *iser_conn = conn->dd_data;
386 struct iser_conn *ib_conn = iser_conn->ib_conn;
387
388 BUG_ON(!ib_conn);
389 /* starts conn teardown process, waits until all previously *
390 * posted buffers get flushed, deallocates all conn resources */
391 iser_conn_terminate(ib_conn);
392 iser_conn->ib_conn = NULL;
393 conn->recv_lock = NULL;
394}
395
396
397static struct iscsi_transport iscsi_iser_transport;
398
399static struct iscsi_cls_session *
400iscsi_iser_session_create(struct iscsi_transport *iscsit,
401 struct scsi_transport_template *scsit,
402 uint32_t initial_cmdsn, uint32_t *hostno)
403{
404 struct iscsi_cls_session *cls_session;
405 struct iscsi_session *session;
406 int i;
407 uint32_t hn;
408 struct iscsi_cmd_task *ctask;
409 struct iscsi_mgmt_task *mtask;
410 struct iscsi_iser_cmd_task *iser_ctask;
411 struct iser_desc *desc;
412
413 cls_session = iscsi_session_setup(iscsit, scsit,
414 sizeof(struct iscsi_iser_cmd_task),
415 sizeof(struct iser_desc),
416 initial_cmdsn, &hn);
417 if (!cls_session)
418 return NULL;
419
420 *hostno = hn;
421 session = class_to_transport_session(cls_session);
422
423 /* libiscsi setup itts, data and pool so just set desc fields */
424 for (i = 0; i < session->cmds_max; i++) {
425 ctask = session->cmds[i];
426 iser_ctask = ctask->dd_data;
427 ctask->hdr = (struct iscsi_cmd *)&iser_ctask->desc.iscsi_header;
428 }
429
430 for (i = 0; i < session->mgmtpool_max; i++) {
431 mtask = session->mgmt_cmds[i];
432 desc = mtask->dd_data;
433 mtask->hdr = &desc->iscsi_header;
434 desc->data = mtask->data;
435 }
436
437 return cls_session;
438}
439
440static int
441iscsi_iser_conn_set_param(struct iscsi_cls_conn *cls_conn,
442 enum iscsi_param param, uint32_t value)
443{
444 struct iscsi_conn *conn = cls_conn->dd_data;
445 struct iscsi_session *session = conn->session;
446
447 spin_lock_bh(&session->lock);
448 if (conn->c_stage != ISCSI_CONN_INITIAL_STAGE &&
449 conn->stop_stage != STOP_CONN_RECOVER) {
450 printk(KERN_ERR "iscsi_iser: can not change parameter [%d]\n",
451 param);
452 spin_unlock_bh(&session->lock);
453 return 0;
454 }
455 spin_unlock_bh(&session->lock);
456
457 switch (param) {
458 case ISCSI_PARAM_MAX_RECV_DLENGTH:
459 /* TBD */
460 break;
461 case ISCSI_PARAM_MAX_XMIT_DLENGTH:
462 conn->max_xmit_dlength = value;
463 break;
464 case ISCSI_PARAM_HDRDGST_EN:
465 if (value) {
466 printk(KERN_ERR "DataDigest wasn't negotiated to None");
467 return -EPROTO;
468 }
469 break;
470 case ISCSI_PARAM_DATADGST_EN:
471 if (value) {
472 printk(KERN_ERR "DataDigest wasn't negotiated to None");
473 return -EPROTO;
474 }
475 break;
476 case ISCSI_PARAM_INITIAL_R2T_EN:
477 session->initial_r2t_en = value;
478 break;
479 case ISCSI_PARAM_IMM_DATA_EN:
480 session->imm_data_en = value;
481 break;
482 case ISCSI_PARAM_FIRST_BURST:
483 session->first_burst = value;
484 break;
485 case ISCSI_PARAM_MAX_BURST:
486 session->max_burst = value;
487 break;
488 case ISCSI_PARAM_PDU_INORDER_EN:
489 session->pdu_inorder_en = value;
490 break;
491 case ISCSI_PARAM_DATASEQ_INORDER_EN:
492 session->dataseq_inorder_en = value;
493 break;
494 case ISCSI_PARAM_ERL:
495 session->erl = value;
496 break;
497 case ISCSI_PARAM_IFMARKER_EN:
498 if (value) {
499 printk(KERN_ERR "IFMarker wasn't negotiated to No");
500 return -EPROTO;
501 }
502 break;
503 case ISCSI_PARAM_OFMARKER_EN:
504 if (value) {
505 printk(KERN_ERR "OFMarker wasn't negotiated to No");
506 return -EPROTO;
507 }
508 break;
509 default:
510 break;
511 }
512
513 return 0;
514}
515
516static int
517iscsi_iser_session_get_param(struct iscsi_cls_session *cls_session,
518 enum iscsi_param param, uint32_t *value)
519{
520 struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
521 struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
522
523 switch (param) {
524 case ISCSI_PARAM_INITIAL_R2T_EN:
525 *value = session->initial_r2t_en;
526 break;
527 case ISCSI_PARAM_MAX_R2T:
528 *value = session->max_r2t;
529 break;
530 case ISCSI_PARAM_IMM_DATA_EN:
531 *value = session->imm_data_en;
532 break;
533 case ISCSI_PARAM_FIRST_BURST:
534 *value = session->first_burst;
535 break;
536 case ISCSI_PARAM_MAX_BURST:
537 *value = session->max_burst;
538 break;
539 case ISCSI_PARAM_PDU_INORDER_EN:
540 *value = session->pdu_inorder_en;
541 break;
542 case ISCSI_PARAM_DATASEQ_INORDER_EN:
543 *value = session->dataseq_inorder_en;
544 break;
545 case ISCSI_PARAM_ERL:
546 *value = session->erl;
547 break;
548 case ISCSI_PARAM_IFMARKER_EN:
549 *value = 0;
550 break;
551 case ISCSI_PARAM_OFMARKER_EN:
552 *value = 0;
553 break;
554 default:
555 return ISCSI_ERR_PARAM_NOT_FOUND;
556 }
557
558 return 0;
559}
560
561static int
562iscsi_iser_conn_get_param(struct iscsi_cls_conn *cls_conn,
563 enum iscsi_param param, uint32_t *value)
564{
565 struct iscsi_conn *conn = cls_conn->dd_data;
566
567 switch(param) {
568 case ISCSI_PARAM_MAX_RECV_DLENGTH:
569 *value = conn->max_recv_dlength;
570 break;
571 case ISCSI_PARAM_MAX_XMIT_DLENGTH:
572 *value = conn->max_xmit_dlength;
573 break;
574 case ISCSI_PARAM_HDRDGST_EN:
575 *value = 0;
576 break;
577 case ISCSI_PARAM_DATADGST_EN:
578 *value = 0;
579 break;
580 /*case ISCSI_PARAM_TARGET_RECV_DLENGTH:
581 *value = conn->target_recv_dlength;
582 break;
583 case ISCSI_PARAM_INITIATOR_RECV_DLENGTH:
584 *value = conn->initiator_recv_dlength;
585 break;*/
586 default:
587 return ISCSI_ERR_PARAM_NOT_FOUND;
588 }
589
590 return 0;
591}
592
593
594static void
595iscsi_iser_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats)
596{
597 struct iscsi_conn *conn = cls_conn->dd_data;
598
599 stats->txdata_octets = conn->txdata_octets;
600 stats->rxdata_octets = conn->rxdata_octets;
601 stats->scsicmd_pdus = conn->scsicmd_pdus_cnt;
602 stats->dataout_pdus = conn->dataout_pdus_cnt;
603 stats->scsirsp_pdus = conn->scsirsp_pdus_cnt;
604 stats->datain_pdus = conn->datain_pdus_cnt; /* always 0 */
605 stats->r2t_pdus = conn->r2t_pdus_cnt; /* always 0 */
606 stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt;
607 stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt;
608 stats->custom_length = 3;
609 strcpy(stats->custom[0].desc, "qp_tx_queue_full");
610 stats->custom[0].value = 0; /* TB iser_conn->qp_tx_queue_full; */
611 strcpy(stats->custom[1].desc, "fmr_map_not_avail");
612 stats->custom[1].value = 0; /* TB iser_conn->fmr_map_not_avail */;
613 strcpy(stats->custom[2].desc, "eh_abort_cnt");
614 stats->custom[2].value = conn->eh_abort_cnt;
615}
616
617static int
618iscsi_iser_ep_connect(struct sockaddr *dst_addr, int non_blocking,
619 __u64 *ep_handle)
620{
621 int err;
622 struct iser_conn *ib_conn;
623
624 err = iser_conn_init(&ib_conn);
625 if (err)
626 goto out;
627
628 err = iser_connect(ib_conn, NULL, (struct sockaddr_in *)dst_addr, non_blocking);
629 if (!err)
630 *ep_handle = (__u64)(unsigned long)ib_conn;
631
632out:
633 return err;
634}
635
636static int
637iscsi_iser_ep_poll(__u64 ep_handle, int timeout_ms)
638{
639 struct iser_conn *ib_conn = iscsi_iser_ib_conn_lookup(ep_handle);
640 int rc;
641
642 if (!ib_conn)
643 return -EINVAL;
644
645 rc = wait_event_interruptible_timeout(ib_conn->wait,
646 ib_conn->state == ISER_CONN_UP,
647 msecs_to_jiffies(timeout_ms));
648
649 /* if conn establishment failed, return error code to iscsi */
650 if (!rc &&
651 (ib_conn->state == ISER_CONN_TERMINATING ||
652 ib_conn->state == ISER_CONN_DOWN))
653 rc = -1;
654
655 iser_err("ib conn %p rc = %d\n", ib_conn, rc);
656
657 if (rc > 0)
658 return 1; /* success, this is the equivalent of POLLOUT */
659 else if (!rc)
660 return 0; /* timeout */
661 else
662 return rc; /* signal */
663}
664
665static void
666iscsi_iser_ep_disconnect(__u64 ep_handle)
667{
668 struct iser_conn *ib_conn = iscsi_iser_ib_conn_lookup(ep_handle);
669
670 if (!ib_conn)
671 return;
672
673 iser_err("ib conn %p state %d\n",ib_conn, ib_conn->state);
674
675 iser_conn_terminate(ib_conn);
676}
677
678static struct scsi_host_template iscsi_iser_sht = {
679 .name = "iSCSI Initiator over iSER, v." DRV_VER,
680 .queuecommand = iscsi_queuecommand,
681 .can_queue = ISCSI_XMIT_CMDS_MAX - 1,
682 .sg_tablesize = ISCSI_ISER_SG_TABLESIZE,
683 .cmd_per_lun = ISCSI_MAX_CMD_PER_LUN,
684 .eh_abort_handler = iscsi_eh_abort,
685 .eh_host_reset_handler = iscsi_eh_host_reset,
686 .use_clustering = DISABLE_CLUSTERING,
687 .proc_name = "iscsi_iser",
688 .this_id = -1,
689};
690
691static struct iscsi_transport iscsi_iser_transport = {
692 .owner = THIS_MODULE,
693 .name = "iser",
694 .caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T,
695 .param_mask = ISCSI_MAX_RECV_DLENGTH |
696 ISCSI_MAX_XMIT_DLENGTH |
697 ISCSI_HDRDGST_EN |
698 ISCSI_DATADGST_EN |
699 ISCSI_INITIAL_R2T_EN |
700 ISCSI_MAX_R2T |
701 ISCSI_IMM_DATA_EN |
702 ISCSI_FIRST_BURST |
703 ISCSI_MAX_BURST |
704 ISCSI_PDU_INORDER_EN |
705 ISCSI_DATASEQ_INORDER_EN,
706 .host_template = &iscsi_iser_sht,
707 .conndata_size = sizeof(struct iscsi_conn),
708 .max_lun = ISCSI_ISER_MAX_LUN,
709 .max_cmd_len = ISCSI_ISER_MAX_CMD_LEN,
710 /* session management */
711 .create_session = iscsi_iser_session_create,
712 .destroy_session = iscsi_session_teardown,
713 /* connection management */
714 .create_conn = iscsi_iser_conn_create,
715 .bind_conn = iscsi_iser_conn_bind,
716 .destroy_conn = iscsi_iser_conn_destroy,
717 .set_param = iscsi_iser_conn_set_param,
718 .get_conn_param = iscsi_iser_conn_get_param,
719 .get_session_param = iscsi_iser_session_get_param,
720 .start_conn = iscsi_iser_conn_start,
721 .stop_conn = iscsi_conn_stop,
722 /* these are called as part of conn recovery */
723 .suspend_conn_recv = NULL, /* FIXME is/how this relvant to iser? */
724 .terminate_conn = iscsi_iser_conn_terminate,
725 /* IO */
726 .send_pdu = iscsi_conn_send_pdu,
727 .get_stats = iscsi_iser_conn_get_stats,
728 .init_cmd_task = iscsi_iser_cmd_init,
729 .xmit_cmd_task = iscsi_iser_ctask_xmit,
730 .xmit_mgmt_task = iscsi_iser_mtask_xmit,
731 .cleanup_cmd_task = iscsi_iser_cleanup_ctask,
732 /* recovery */
733 .session_recovery_timedout = iscsi_session_recovery_timedout,
734
735 .ep_connect = iscsi_iser_ep_connect,
736 .ep_poll = iscsi_iser_ep_poll,
737 .ep_disconnect = iscsi_iser_ep_disconnect
738};
739
740static int __init iser_init(void)
741{
742 int err;
743
744 iser_dbg("Starting iSER datamover...\n");
745
746 if (iscsi_max_lun < 1) {
747 printk(KERN_ERR "Invalid max_lun value of %u\n", iscsi_max_lun);
748 return -EINVAL;
749 }
750
751 iscsi_iser_transport.max_lun = iscsi_max_lun;
752
753 memset(&ig, 0, sizeof(struct iser_global));
754
755 ig.desc_cache = kmem_cache_create("iser_descriptors",
756 sizeof (struct iser_desc),
757 0, SLAB_HWCACHE_ALIGN,
758 NULL, NULL);
759 if (ig.desc_cache == NULL)
760 return -ENOMEM;
761
762 /* device init is called only after the first addr resolution */
763 mutex_init(&ig.device_list_mutex);
764 INIT_LIST_HEAD(&ig.device_list);
765 mutex_init(&ig.connlist_mutex);
766 INIT_LIST_HEAD(&ig.connlist);
767
768 if (!iscsi_register_transport(&iscsi_iser_transport)) {
769 iser_err("iscsi_register_transport failed\n");
770 err = -EINVAL;
771 goto register_transport_failure;
772 }
773
774 return 0;
775
776register_transport_failure:
777 kmem_cache_destroy(ig.desc_cache);
778
779 return err;
780}
781
782static void __exit iser_exit(void)
783{
784 iser_dbg("Removing iSER datamover...\n");
785 iscsi_unregister_transport(&iscsi_iser_transport);
786 kmem_cache_destroy(ig.desc_cache);
787}
788
789module_init(iser_init);
790module_exit(iser_exit);