xref: /openbmc/linux/drivers/scsi/bnx2i/bnx2i_iscsi.c (revision db5ed4dfd5dd0142ec36ff7b335e0ec3b836b3e6)
1cf4e6363SMichael Chan /*
2f39a7757SVikas Chaudhary  * bnx2i_iscsi.c: QLogic NetXtreme II iSCSI driver.
3cf4e6363SMichael Chan  *
40b3bf387SEddie Wai  * Copyright (c) 2006 - 2013 Broadcom Corporation
5cf4e6363SMichael Chan  * Copyright (c) 2007, 2008 Red Hat, Inc.  All rights reserved.
6cf4e6363SMichael Chan  * Copyright (c) 2007, 2008 Mike Christie
7f39a7757SVikas Chaudhary  * Copyright (c) 2014, QLogic Corporation
8cf4e6363SMichael Chan  *
9cf4e6363SMichael Chan  * This program is free software; you can redistribute it and/or modify
10cf4e6363SMichael Chan  * it under the terms of the GNU General Public License as published by
11cf4e6363SMichael Chan  * the Free Software Foundation.
12cf4e6363SMichael Chan  *
13cf4e6363SMichael Chan  * Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
14f39a7757SVikas Chaudhary  * Previously Maintained by: Eddie Wai (eddie.wai@broadcom.com)
15f39a7757SVikas Chaudhary  * Maintained by: QLogic-Storage-Upstream@qlogic.com
16cf4e6363SMichael Chan  */
17cf4e6363SMichael Chan 
185a0e3ad6STejun Heo #include <linux/slab.h>
19cf4e6363SMichael Chan #include <scsi/scsi_tcq.h>
20cf4e6363SMichael Chan #include <scsi/libiscsi.h>
21cf4e6363SMichael Chan #include "bnx2i.h"
22cf4e6363SMichael Chan 
23cf4e6363SMichael Chan struct scsi_transport_template *bnx2i_scsi_xport_template;
24cf4e6363SMichael Chan struct iscsi_transport bnx2i_iscsi_transport;
25cf4e6363SMichael Chan static struct scsi_host_template bnx2i_host_template;
26cf4e6363SMichael Chan 
27cf4e6363SMichael Chan /*
28cf4e6363SMichael Chan  * Global endpoint resource info
29cf4e6363SMichael Chan  */
30cf4e6363SMichael Chan static DEFINE_SPINLOCK(bnx2i_resc_lock); /* protects global resources */
31cf4e6363SMichael Chan 
32b5cf6b63SEddie Wai DECLARE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu);
33cf4e6363SMichael Chan 
34cf4e6363SMichael Chan static int bnx2i_adapter_ready(struct bnx2i_hba *hba)
35cf4e6363SMichael Chan {
36cf4e6363SMichael Chan 	int retval = 0;
37cf4e6363SMichael Chan 
38cf4e6363SMichael Chan 	if (!hba || !test_bit(ADAPTER_STATE_UP, &hba->adapter_state) ||
39cf4e6363SMichael Chan 	    test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state) ||
40cf4e6363SMichael Chan 	    test_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state))
41cf4e6363SMichael Chan 		retval = -EPERM;
42cf4e6363SMichael Chan 	return retval;
43cf4e6363SMichael Chan }
44cf4e6363SMichael Chan 
45cf4e6363SMichael Chan /**
46cf4e6363SMichael Chan  * bnx2i_get_write_cmd_bd_idx - identifies various BD bookmarks
47cf4e6363SMichael Chan  * @cmd:		iscsi cmd struct pointer
48cf4e6363SMichael Chan  * @buf_off:		absolute buffer offset
49cf4e6363SMichael Chan  * @start_bd_off:	u32 pointer to return the offset within the BD
50cf4e6363SMichael Chan  *			indicated by 'start_bd_idx' on which 'buf_off' falls
51cf4e6363SMichael Chan  * @start_bd_idx:	index of the BD on which 'buf_off' falls
52cf4e6363SMichael Chan  *
53cf4e6363SMichael Chan  * identifies & marks various bd info for scsi command's imm data,
54cf4e6363SMichael Chan  * unsolicited data and the first solicited data seq.
55cf4e6363SMichael Chan  */
56cf4e6363SMichael Chan static void bnx2i_get_write_cmd_bd_idx(struct bnx2i_cmd *cmd, u32 buf_off,
57cf4e6363SMichael Chan 				       u32 *start_bd_off, u32 *start_bd_idx)
58cf4e6363SMichael Chan {
59cf4e6363SMichael Chan 	struct iscsi_bd *bd_tbl = cmd->io_tbl.bd_tbl;
60cf4e6363SMichael Chan 	u32 cur_offset = 0;
61cf4e6363SMichael Chan 	u32 cur_bd_idx = 0;
62cf4e6363SMichael Chan 
63cf4e6363SMichael Chan 	if (buf_off) {
64cf4e6363SMichael Chan 		while (buf_off >= (cur_offset + bd_tbl->buffer_length)) {
65cf4e6363SMichael Chan 			cur_offset += bd_tbl->buffer_length;
66cf4e6363SMichael Chan 			cur_bd_idx++;
67cf4e6363SMichael Chan 			bd_tbl++;
68cf4e6363SMichael Chan 		}
69cf4e6363SMichael Chan 	}
70cf4e6363SMichael Chan 
71cf4e6363SMichael Chan 	*start_bd_off = buf_off - cur_offset;
72cf4e6363SMichael Chan 	*start_bd_idx = cur_bd_idx;
73cf4e6363SMichael Chan }
74cf4e6363SMichael Chan 
75cf4e6363SMichael Chan /**
76cf4e6363SMichael Chan  * bnx2i_setup_write_cmd_bd_info - sets up BD various information
77cf4e6363SMichael Chan  * @task:	transport layer's cmd struct pointer
78cf4e6363SMichael Chan  *
79cf4e6363SMichael Chan  * identifies & marks various bd info for scsi command's immediate data,
80cf4e6363SMichael Chan  * unsolicited data and first solicited data seq which includes BD start
81cf4e6363SMichael Chan  * index & BD buf off. his function takes into account iscsi parameter such
82cf4e6363SMichael Chan  * as immediate data and unsolicited data is support on this connection.
83cf4e6363SMichael Chan  */
84cf4e6363SMichael Chan static void bnx2i_setup_write_cmd_bd_info(struct iscsi_task *task)
85cf4e6363SMichael Chan {
86cf4e6363SMichael Chan 	struct bnx2i_cmd *cmd = task->dd_data;
87cf4e6363SMichael Chan 	u32 start_bd_offset;
88cf4e6363SMichael Chan 	u32 start_bd_idx;
89cf4e6363SMichael Chan 	u32 buffer_offset = 0;
90cf4e6363SMichael Chan 	u32 cmd_len = cmd->req.total_data_transfer_length;
91cf4e6363SMichael Chan 
92cf4e6363SMichael Chan 	/* if ImmediateData is turned off & IntialR2T is turned on,
93cf4e6363SMichael Chan 	 * there will be no immediate or unsolicited data, just return.
94cf4e6363SMichael Chan 	 */
95cf4e6363SMichael Chan 	if (!iscsi_task_has_unsol_data(task) && !task->imm_count)
96cf4e6363SMichael Chan 		return;
97cf4e6363SMichael Chan 
98cf4e6363SMichael Chan 	/* Immediate data */
99cf4e6363SMichael Chan 	buffer_offset += task->imm_count;
100cf4e6363SMichael Chan 	if (task->imm_count == cmd_len)
101cf4e6363SMichael Chan 		return;
102cf4e6363SMichael Chan 
103cf4e6363SMichael Chan 	if (iscsi_task_has_unsol_data(task)) {
104cf4e6363SMichael Chan 		bnx2i_get_write_cmd_bd_idx(cmd, buffer_offset,
105cf4e6363SMichael Chan 					   &start_bd_offset, &start_bd_idx);
106cf4e6363SMichael Chan 		cmd->req.ud_buffer_offset = start_bd_offset;
107cf4e6363SMichael Chan 		cmd->req.ud_start_bd_index = start_bd_idx;
108cf4e6363SMichael Chan 		buffer_offset += task->unsol_r2t.data_length;
109cf4e6363SMichael Chan 	}
110cf4e6363SMichael Chan 
111cf4e6363SMichael Chan 	if (buffer_offset != cmd_len) {
112cf4e6363SMichael Chan 		bnx2i_get_write_cmd_bd_idx(cmd, buffer_offset,
113cf4e6363SMichael Chan 					   &start_bd_offset, &start_bd_idx);
114cf4e6363SMichael Chan 		if ((start_bd_offset > task->conn->session->first_burst) ||
115cf4e6363SMichael Chan 		    (start_bd_idx > scsi_sg_count(cmd->scsi_cmd))) {
116cf4e6363SMichael Chan 			int i = 0;
117cf4e6363SMichael Chan 
118cf4e6363SMichael Chan 			iscsi_conn_printk(KERN_ALERT, task->conn,
119cf4e6363SMichael Chan 					  "bnx2i- error, buf offset 0x%x "
120cf4e6363SMichael Chan 					  "bd_valid %d use_sg %d\n",
121cf4e6363SMichael Chan 					  buffer_offset, cmd->io_tbl.bd_valid,
122cf4e6363SMichael Chan 					  scsi_sg_count(cmd->scsi_cmd));
123cf4e6363SMichael Chan 			for (i = 0; i < cmd->io_tbl.bd_valid; i++)
124cf4e6363SMichael Chan 				iscsi_conn_printk(KERN_ALERT, task->conn,
125cf4e6363SMichael Chan 						  "bnx2i err, bd[%d]: len %x\n",
126cf4e6363SMichael Chan 						  i, cmd->io_tbl.bd_tbl[i].\
127cf4e6363SMichael Chan 						  buffer_length);
128cf4e6363SMichael Chan 		}
129cf4e6363SMichael Chan 		cmd->req.sd_buffer_offset = start_bd_offset;
130cf4e6363SMichael Chan 		cmd->req.sd_start_bd_index = start_bd_idx;
131cf4e6363SMichael Chan 	}
132cf4e6363SMichael Chan }
133cf4e6363SMichael Chan 
134cf4e6363SMichael Chan 
135cf4e6363SMichael Chan 
136cf4e6363SMichael Chan /**
137cf4e6363SMichael Chan  * bnx2i_map_scsi_sg - maps IO buffer and prepares the BD table
138cf4e6363SMichael Chan  * @hba:	adapter instance
139cf4e6363SMichael Chan  * @cmd:	iscsi cmd struct pointer
140cf4e6363SMichael Chan  *
141cf4e6363SMichael Chan  * map SG list
142cf4e6363SMichael Chan  */
143cf4e6363SMichael Chan static int bnx2i_map_scsi_sg(struct bnx2i_hba *hba, struct bnx2i_cmd *cmd)
144cf4e6363SMichael Chan {
145cf4e6363SMichael Chan 	struct scsi_cmnd *sc = cmd->scsi_cmd;
146cf4e6363SMichael Chan 	struct iscsi_bd *bd = cmd->io_tbl.bd_tbl;
147cf4e6363SMichael Chan 	struct scatterlist *sg;
148cf4e6363SMichael Chan 	int byte_count = 0;
149cf4e6363SMichael Chan 	int bd_count = 0;
150cf4e6363SMichael Chan 	int sg_count;
151cf4e6363SMichael Chan 	int sg_len;
152cf4e6363SMichael Chan 	u64 addr;
153cf4e6363SMichael Chan 	int i;
154cf4e6363SMichael Chan 
155cf4e6363SMichael Chan 	BUG_ON(scsi_sg_count(sc) > ISCSI_MAX_BDS_PER_CMD);
156cf4e6363SMichael Chan 
157cf4e6363SMichael Chan 	sg_count = scsi_dma_map(sc);
158cf4e6363SMichael Chan 
159cf4e6363SMichael Chan 	scsi_for_each_sg(sc, sg, sg_count, i) {
160cf4e6363SMichael Chan 		sg_len = sg_dma_len(sg);
161cf4e6363SMichael Chan 		addr = (u64) sg_dma_address(sg);
162cf4e6363SMichael Chan 		bd[bd_count].buffer_addr_lo = addr & 0xffffffff;
163cf4e6363SMichael Chan 		bd[bd_count].buffer_addr_hi = addr >> 32;
164cf4e6363SMichael Chan 		bd[bd_count].buffer_length = sg_len;
165cf4e6363SMichael Chan 		bd[bd_count].flags = 0;
166cf4e6363SMichael Chan 		if (bd_count == 0)
167cf4e6363SMichael Chan 			bd[bd_count].flags = ISCSI_BD_FIRST_IN_BD_CHAIN;
168cf4e6363SMichael Chan 
169cf4e6363SMichael Chan 		byte_count += sg_len;
170cf4e6363SMichael Chan 		bd_count++;
171cf4e6363SMichael Chan 	}
172cf4e6363SMichael Chan 
173cf4e6363SMichael Chan 	if (bd_count)
174cf4e6363SMichael Chan 		bd[bd_count - 1].flags |= ISCSI_BD_LAST_IN_BD_CHAIN;
175cf4e6363SMichael Chan 
176cf4e6363SMichael Chan 	BUG_ON(byte_count != scsi_bufflen(sc));
177cf4e6363SMichael Chan 	return bd_count;
178cf4e6363SMichael Chan }
179cf4e6363SMichael Chan 
180cf4e6363SMichael Chan /**
181cf4e6363SMichael Chan  * bnx2i_iscsi_map_sg_list - maps SG list
182cf4e6363SMichael Chan  * @cmd:	iscsi cmd struct pointer
183cf4e6363SMichael Chan  *
184cf4e6363SMichael Chan  * creates BD list table for the command
185cf4e6363SMichael Chan  */
186cf4e6363SMichael Chan static void bnx2i_iscsi_map_sg_list(struct bnx2i_cmd *cmd)
187cf4e6363SMichael Chan {
188cf4e6363SMichael Chan 	int bd_count;
189cf4e6363SMichael Chan 
190cf4e6363SMichael Chan 	bd_count  = bnx2i_map_scsi_sg(cmd->conn->hba, cmd);
191cf4e6363SMichael Chan 	if (!bd_count) {
192cf4e6363SMichael Chan 		struct iscsi_bd *bd = cmd->io_tbl.bd_tbl;
193cf4e6363SMichael Chan 
194cf4e6363SMichael Chan 		bd[0].buffer_addr_lo = bd[0].buffer_addr_hi = 0;
195cf4e6363SMichael Chan 		bd[0].buffer_length = bd[0].flags = 0;
196cf4e6363SMichael Chan 	}
197cf4e6363SMichael Chan 	cmd->io_tbl.bd_valid = bd_count;
198cf4e6363SMichael Chan }
199cf4e6363SMichael Chan 
200cf4e6363SMichael Chan 
201cf4e6363SMichael Chan /**
202cf4e6363SMichael Chan  * bnx2i_iscsi_unmap_sg_list - unmaps SG list
203cf4e6363SMichael Chan  * @cmd:	iscsi cmd struct pointer
204cf4e6363SMichael Chan  *
205cf4e6363SMichael Chan  * unmap IO buffers and invalidate the BD table
206cf4e6363SMichael Chan  */
207cf4e6363SMichael Chan void bnx2i_iscsi_unmap_sg_list(struct bnx2i_cmd *cmd)
208cf4e6363SMichael Chan {
209cf4e6363SMichael Chan 	struct scsi_cmnd *sc = cmd->scsi_cmd;
210cf4e6363SMichael Chan 
211cf4e6363SMichael Chan 	if (cmd->io_tbl.bd_valid && sc) {
212cf4e6363SMichael Chan 		scsi_dma_unmap(sc);
213cf4e6363SMichael Chan 		cmd->io_tbl.bd_valid = 0;
214cf4e6363SMichael Chan 	}
215cf4e6363SMichael Chan }
216cf4e6363SMichael Chan 
217cf4e6363SMichael Chan static void bnx2i_setup_cmd_wqe_template(struct bnx2i_cmd *cmd)
218cf4e6363SMichael Chan {
219cf4e6363SMichael Chan 	memset(&cmd->req, 0x00, sizeof(cmd->req));
220cf4e6363SMichael Chan 	cmd->req.op_code = 0xFF;
221cf4e6363SMichael Chan 	cmd->req.bd_list_addr_lo = (u32) cmd->io_tbl.bd_tbl_dma;
222cf4e6363SMichael Chan 	cmd->req.bd_list_addr_hi =
223cf4e6363SMichael Chan 		(u32) ((u64) cmd->io_tbl.bd_tbl_dma >> 32);
224cf4e6363SMichael Chan 
225cf4e6363SMichael Chan }
226cf4e6363SMichael Chan 
227cf4e6363SMichael Chan 
228cf4e6363SMichael Chan /**
229cf4e6363SMichael Chan  * bnx2i_bind_conn_to_iscsi_cid - bind conn structure to 'iscsi_cid'
230cf4e6363SMichael Chan  * @hba:	pointer to adapter instance
231cf4e6363SMichael Chan  * @conn:	pointer to iscsi connection
232cf4e6363SMichael Chan  * @iscsi_cid:	iscsi context ID, range 0 - (MAX_CONN - 1)
233cf4e6363SMichael Chan  *
234cf4e6363SMichael Chan  * update iscsi cid table entry with connection pointer. This enables
235cf4e6363SMichael Chan  *	driver to quickly get hold of connection structure pointer in
236cf4e6363SMichael Chan  *	completion/interrupt thread using iscsi context ID
237cf4e6363SMichael Chan  */
238cf4e6363SMichael Chan static int bnx2i_bind_conn_to_iscsi_cid(struct bnx2i_hba *hba,
239cf4e6363SMichael Chan 					struct bnx2i_conn *bnx2i_conn,
240cf4e6363SMichael Chan 					u32 iscsi_cid)
241cf4e6363SMichael Chan {
242cf4e6363SMichael Chan 	if (hba && hba->cid_que.conn_cid_tbl[iscsi_cid]) {
243cf4e6363SMichael Chan 		iscsi_conn_printk(KERN_ALERT, bnx2i_conn->cls_conn->dd_data,
244cf4e6363SMichael Chan 				 "conn bind - entry #%d not free\n", iscsi_cid);
245cf4e6363SMichael Chan 		return -EBUSY;
246cf4e6363SMichael Chan 	}
247cf4e6363SMichael Chan 
248cf4e6363SMichael Chan 	hba->cid_que.conn_cid_tbl[iscsi_cid] = bnx2i_conn;
249cf4e6363SMichael Chan 	return 0;
250cf4e6363SMichael Chan }
251cf4e6363SMichael Chan 
252cf4e6363SMichael Chan 
253cf4e6363SMichael Chan /**
254cf4e6363SMichael Chan  * bnx2i_get_conn_from_id - maps an iscsi cid to corresponding conn ptr
255cf4e6363SMichael Chan  * @hba:	pointer to adapter instance
256cf4e6363SMichael Chan  * @iscsi_cid:	iscsi context ID, range 0 - (MAX_CONN - 1)
257cf4e6363SMichael Chan  */
258cf4e6363SMichael Chan struct bnx2i_conn *bnx2i_get_conn_from_id(struct bnx2i_hba *hba,
259cf4e6363SMichael Chan 					  u16 iscsi_cid)
260cf4e6363SMichael Chan {
261cf4e6363SMichael Chan 	if (!hba->cid_que.conn_cid_tbl) {
262cf4e6363SMichael Chan 		printk(KERN_ERR "bnx2i: ERROR - missing conn<->cid table\n");
263cf4e6363SMichael Chan 		return NULL;
264cf4e6363SMichael Chan 
265cf4e6363SMichael Chan 	} else if (iscsi_cid >= hba->max_active_conns) {
266cf4e6363SMichael Chan 		printk(KERN_ERR "bnx2i: wrong cid #%d\n", iscsi_cid);
267cf4e6363SMichael Chan 		return NULL;
268cf4e6363SMichael Chan 	}
269cf4e6363SMichael Chan 	return hba->cid_que.conn_cid_tbl[iscsi_cid];
270cf4e6363SMichael Chan }
271cf4e6363SMichael Chan 
272cf4e6363SMichael Chan 
273cf4e6363SMichael Chan /**
274cf4e6363SMichael Chan  * bnx2i_alloc_iscsi_cid - allocates a iscsi_cid from free pool
275cf4e6363SMichael Chan  * @hba:	pointer to adapter instance
276cf4e6363SMichael Chan  */
277cf4e6363SMichael Chan static u32 bnx2i_alloc_iscsi_cid(struct bnx2i_hba *hba)
278cf4e6363SMichael Chan {
279cf4e6363SMichael Chan 	int idx;
280cf4e6363SMichael Chan 
281cf4e6363SMichael Chan 	if (!hba->cid_que.cid_free_cnt)
282cf4e6363SMichael Chan 		return -1;
283cf4e6363SMichael Chan 
284cf4e6363SMichael Chan 	idx = hba->cid_que.cid_q_cons_idx;
285cf4e6363SMichael Chan 	hba->cid_que.cid_q_cons_idx++;
286cf4e6363SMichael Chan 	if (hba->cid_que.cid_q_cons_idx == hba->cid_que.cid_q_max_idx)
287cf4e6363SMichael Chan 		hba->cid_que.cid_q_cons_idx = 0;
288cf4e6363SMichael Chan 
289cf4e6363SMichael Chan 	hba->cid_que.cid_free_cnt--;
290cf4e6363SMichael Chan 	return hba->cid_que.cid_que[idx];
291cf4e6363SMichael Chan }
292cf4e6363SMichael Chan 
293cf4e6363SMichael Chan 
294cf4e6363SMichael Chan /**
295cf4e6363SMichael Chan  * bnx2i_free_iscsi_cid - returns tcp port to free list
296cf4e6363SMichael Chan  * @hba: 		pointer to adapter instance
297cf4e6363SMichael Chan  * @iscsi_cid:		iscsi context ID to free
298cf4e6363SMichael Chan  */
299cf4e6363SMichael Chan static void bnx2i_free_iscsi_cid(struct bnx2i_hba *hba, u16 iscsi_cid)
300cf4e6363SMichael Chan {
301cf4e6363SMichael Chan 	int idx;
302cf4e6363SMichael Chan 
303cf4e6363SMichael Chan 	if (iscsi_cid == (u16) -1)
304cf4e6363SMichael Chan 		return;
305cf4e6363SMichael Chan 
306cf4e6363SMichael Chan 	hba->cid_que.cid_free_cnt++;
307cf4e6363SMichael Chan 
308cf4e6363SMichael Chan 	idx = hba->cid_que.cid_q_prod_idx;
309cf4e6363SMichael Chan 	hba->cid_que.cid_que[idx] = iscsi_cid;
310cf4e6363SMichael Chan 	hba->cid_que.conn_cid_tbl[iscsi_cid] = NULL;
311cf4e6363SMichael Chan 	hba->cid_que.cid_q_prod_idx++;
312cf4e6363SMichael Chan 	if (hba->cid_que.cid_q_prod_idx == hba->cid_que.cid_q_max_idx)
313cf4e6363SMichael Chan 		hba->cid_que.cid_q_prod_idx = 0;
314cf4e6363SMichael Chan }
315cf4e6363SMichael Chan 
316cf4e6363SMichael Chan 
317cf4e6363SMichael Chan /**
318cf4e6363SMichael Chan  * bnx2i_setup_free_cid_que - sets up free iscsi cid queue
319cf4e6363SMichael Chan  * @hba:	pointer to adapter instance
320cf4e6363SMichael Chan  *
321cf4e6363SMichael Chan  * allocates memory for iscsi cid queue & 'cid - conn ptr' mapping table,
322cf4e6363SMichael Chan  * 	and initialize table attributes
323cf4e6363SMichael Chan  */
324cf4e6363SMichael Chan static int bnx2i_setup_free_cid_que(struct bnx2i_hba *hba)
325cf4e6363SMichael Chan {
326cf4e6363SMichael Chan 	int mem_size;
327cf4e6363SMichael Chan 	int i;
328cf4e6363SMichael Chan 
329cf4e6363SMichael Chan 	mem_size = hba->max_active_conns * sizeof(u32);
330cf4e6363SMichael Chan 	mem_size = (mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
331cf4e6363SMichael Chan 
332cf4e6363SMichael Chan 	hba->cid_que.cid_que_base = kmalloc(mem_size, GFP_KERNEL);
333cf4e6363SMichael Chan 	if (!hba->cid_que.cid_que_base)
334cf4e6363SMichael Chan 		return -ENOMEM;
335cf4e6363SMichael Chan 
336cf4e6363SMichael Chan 	mem_size = hba->max_active_conns * sizeof(struct bnx2i_conn *);
337cf4e6363SMichael Chan 	mem_size = (mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
338cf4e6363SMichael Chan 	hba->cid_que.conn_cid_tbl = kmalloc(mem_size, GFP_KERNEL);
339cf4e6363SMichael Chan 	if (!hba->cid_que.conn_cid_tbl) {
340cf4e6363SMichael Chan 		kfree(hba->cid_que.cid_que_base);
341cf4e6363SMichael Chan 		hba->cid_que.cid_que_base = NULL;
342cf4e6363SMichael Chan 		return -ENOMEM;
343cf4e6363SMichael Chan 	}
344cf4e6363SMichael Chan 
345cf4e6363SMichael Chan 	hba->cid_que.cid_que = (u32 *)hba->cid_que.cid_que_base;
346cf4e6363SMichael Chan 	hba->cid_que.cid_q_prod_idx = 0;
347cf4e6363SMichael Chan 	hba->cid_que.cid_q_cons_idx = 0;
348cf4e6363SMichael Chan 	hba->cid_que.cid_q_max_idx = hba->max_active_conns;
349cf4e6363SMichael Chan 	hba->cid_que.cid_free_cnt = hba->max_active_conns;
350cf4e6363SMichael Chan 
351cf4e6363SMichael Chan 	for (i = 0; i < hba->max_active_conns; i++) {
352cf4e6363SMichael Chan 		hba->cid_que.cid_que[i] = i;
353cf4e6363SMichael Chan 		hba->cid_que.conn_cid_tbl[i] = NULL;
354cf4e6363SMichael Chan 	}
355cf4e6363SMichael Chan 	return 0;
356cf4e6363SMichael Chan }
357cf4e6363SMichael Chan 
358cf4e6363SMichael Chan 
359cf4e6363SMichael Chan /**
360cf4e6363SMichael Chan  * bnx2i_release_free_cid_que - releases 'iscsi_cid' queue resources
361cf4e6363SMichael Chan  * @hba:	pointer to adapter instance
362cf4e6363SMichael Chan  */
363cf4e6363SMichael Chan static void bnx2i_release_free_cid_que(struct bnx2i_hba *hba)
364cf4e6363SMichael Chan {
365cf4e6363SMichael Chan 	kfree(hba->cid_que.cid_que_base);
366cf4e6363SMichael Chan 	hba->cid_que.cid_que_base = NULL;
367cf4e6363SMichael Chan 
368cf4e6363SMichael Chan 	kfree(hba->cid_que.conn_cid_tbl);
369cf4e6363SMichael Chan 	hba->cid_que.conn_cid_tbl = NULL;
370cf4e6363SMichael Chan }
371cf4e6363SMichael Chan 
372cf4e6363SMichael Chan 
373cf4e6363SMichael Chan /**
374cf4e6363SMichael Chan  * bnx2i_alloc_ep - allocates ep structure from global pool
375cf4e6363SMichael Chan  * @hba:	pointer to adapter instance
376cf4e6363SMichael Chan  *
377cf4e6363SMichael Chan  * routine allocates a free endpoint structure from global pool and
378cf4e6363SMichael Chan  *	a tcp port to be used for this connection.  Global resource lock,
379cf4e6363SMichael Chan  *	'bnx2i_resc_lock' is held while accessing shared global data structures
380cf4e6363SMichael Chan  */
381cf4e6363SMichael Chan static struct iscsi_endpoint *bnx2i_alloc_ep(struct bnx2i_hba *hba)
382cf4e6363SMichael Chan {
383cf4e6363SMichael Chan 	struct iscsi_endpoint *ep;
384cf4e6363SMichael Chan 	struct bnx2i_endpoint *bnx2i_ep;
3859ae58e14SEddie Wai 	u32 ec_div;
386cf4e6363SMichael Chan 
387cf4e6363SMichael Chan 	ep = iscsi_create_endpoint(sizeof(*bnx2i_ep));
388cf4e6363SMichael Chan 	if (!ep) {
389cf4e6363SMichael Chan 		printk(KERN_ERR "bnx2i: Could not allocate ep\n");
390cf4e6363SMichael Chan 		return NULL;
391cf4e6363SMichael Chan 	}
392cf4e6363SMichael Chan 
393cf4e6363SMichael Chan 	bnx2i_ep = ep->dd_data;
39446012e8bSEddie Wai 	bnx2i_ep->cls_ep = ep;
395cf4e6363SMichael Chan 	INIT_LIST_HEAD(&bnx2i_ep->link);
396cf4e6363SMichael Chan 	bnx2i_ep->state = EP_STATE_IDLE;
397c19dcd01SAnil Veerabhadrappa 	bnx2i_ep->ep_iscsi_cid = (u16) -1;
398cf4e6363SMichael Chan 	bnx2i_ep->hba = hba;
399cf4e6363SMichael Chan 	bnx2i_ep->hba_age = hba->age;
4009ae58e14SEddie Wai 
4019ae58e14SEddie Wai 	ec_div = event_coal_div;
4029ae58e14SEddie Wai 	while (ec_div >>= 1)
4039ae58e14SEddie Wai 		bnx2i_ep->ec_shift += 1;
4049ae58e14SEddie Wai 
405cf4e6363SMichael Chan 	hba->ofld_conns_active++;
406cf4e6363SMichael Chan 	init_waitqueue_head(&bnx2i_ep->ofld_wait);
407cf4e6363SMichael Chan 	return ep;
408cf4e6363SMichael Chan }
409cf4e6363SMichael Chan 
410cf4e6363SMichael Chan 
411cf4e6363SMichael Chan /**
412cf4e6363SMichael Chan  * bnx2i_free_ep - free endpoint
413cf4e6363SMichael Chan  * @ep:		pointer to iscsi endpoint structure
414cf4e6363SMichael Chan  */
415cf4e6363SMichael Chan static void bnx2i_free_ep(struct iscsi_endpoint *ep)
416cf4e6363SMichael Chan {
417cf4e6363SMichael Chan 	struct bnx2i_endpoint *bnx2i_ep = ep->dd_data;
418cf4e6363SMichael Chan 	unsigned long flags;
419cf4e6363SMichael Chan 
420cf4e6363SMichael Chan 	spin_lock_irqsave(&bnx2i_resc_lock, flags);
421cf4e6363SMichael Chan 	bnx2i_ep->state = EP_STATE_IDLE;
422cf4e6363SMichael Chan 	bnx2i_ep->hba->ofld_conns_active--;
423cf4e6363SMichael Chan 
424a91031a6SEddie Wai 	if (bnx2i_ep->ep_iscsi_cid != (u16) -1)
425cf4e6363SMichael Chan 		bnx2i_free_iscsi_cid(bnx2i_ep->hba, bnx2i_ep->ep_iscsi_cid);
426a91031a6SEddie Wai 
427cf4e6363SMichael Chan 	if (bnx2i_ep->conn) {
428cf4e6363SMichael Chan 		bnx2i_ep->conn->ep = NULL;
429cf4e6363SMichael Chan 		bnx2i_ep->conn = NULL;
430cf4e6363SMichael Chan 	}
431cf4e6363SMichael Chan 
432cf4e6363SMichael Chan 	bnx2i_ep->hba = NULL;
433cf4e6363SMichael Chan 	spin_unlock_irqrestore(&bnx2i_resc_lock, flags);
434cf4e6363SMichael Chan 	iscsi_destroy_endpoint(ep);
435cf4e6363SMichael Chan }
436cf4e6363SMichael Chan 
437cf4e6363SMichael Chan 
438cf4e6363SMichael Chan /**
439cf4e6363SMichael Chan  * bnx2i_alloc_bdt - allocates buffer descriptor (BD) table for the command
440cf4e6363SMichael Chan  * @hba:	adapter instance pointer
441cf4e6363SMichael Chan  * @session:	iscsi session pointer
442cf4e6363SMichael Chan  * @cmd:	iscsi command structure
443cf4e6363SMichael Chan  */
444cf4e6363SMichael Chan static int bnx2i_alloc_bdt(struct bnx2i_hba *hba, struct iscsi_session *session,
445cf4e6363SMichael Chan 			   struct bnx2i_cmd *cmd)
446cf4e6363SMichael Chan {
447cf4e6363SMichael Chan 	struct io_bdt *io = &cmd->io_tbl;
448cf4e6363SMichael Chan 	struct iscsi_bd *bd;
449cf4e6363SMichael Chan 
450cf4e6363SMichael Chan 	io->bd_tbl = dma_alloc_coherent(&hba->pcidev->dev,
451cf4e6363SMichael Chan 					ISCSI_MAX_BDS_PER_CMD * sizeof(*bd),
452cf4e6363SMichael Chan 					&io->bd_tbl_dma, GFP_KERNEL);
453cf4e6363SMichael Chan 	if (!io->bd_tbl) {
454cf4e6363SMichael Chan 		iscsi_session_printk(KERN_ERR, session, "Could not "
455cf4e6363SMichael Chan 				     "allocate bdt.\n");
456cf4e6363SMichael Chan 		return -ENOMEM;
457cf4e6363SMichael Chan 	}
458cf4e6363SMichael Chan 	io->bd_valid = 0;
459cf4e6363SMichael Chan 	return 0;
460cf4e6363SMichael Chan }
461cf4e6363SMichael Chan 
462cf4e6363SMichael Chan /**
463cf4e6363SMichael Chan  * bnx2i_destroy_cmd_pool - destroys iscsi command pool and release BD table
464cf4e6363SMichael Chan  * @hba:	adapter instance pointer
465cf4e6363SMichael Chan  * @session:	iscsi session pointer
466cf4e6363SMichael Chan  * @cmd:	iscsi command structure
467cf4e6363SMichael Chan  */
468cf4e6363SMichael Chan static void bnx2i_destroy_cmd_pool(struct bnx2i_hba *hba,
469cf4e6363SMichael Chan 				   struct iscsi_session *session)
470cf4e6363SMichael Chan {
471cf4e6363SMichael Chan 	int i;
472cf4e6363SMichael Chan 
473cf4e6363SMichael Chan 	for (i = 0; i < session->cmds_max; i++) {
474cf4e6363SMichael Chan 		struct iscsi_task *task = session->cmds[i];
475cf4e6363SMichael Chan 		struct bnx2i_cmd *cmd = task->dd_data;
476cf4e6363SMichael Chan 
477cf4e6363SMichael Chan 		if (cmd->io_tbl.bd_tbl)
478cf4e6363SMichael Chan 			dma_free_coherent(&hba->pcidev->dev,
479cf4e6363SMichael Chan 					  ISCSI_MAX_BDS_PER_CMD *
480cf4e6363SMichael Chan 					  sizeof(struct iscsi_bd),
481cf4e6363SMichael Chan 					  cmd->io_tbl.bd_tbl,
482cf4e6363SMichael Chan 					  cmd->io_tbl.bd_tbl_dma);
483cf4e6363SMichael Chan 	}
484cf4e6363SMichael Chan 
485cf4e6363SMichael Chan }
486cf4e6363SMichael Chan 
487cf4e6363SMichael Chan 
488cf4e6363SMichael Chan /**
489cf4e6363SMichael Chan  * bnx2i_setup_cmd_pool - sets up iscsi command pool for the session
490cf4e6363SMichael Chan  * @hba:	adapter instance pointer
491cf4e6363SMichael Chan  * @session:	iscsi session pointer
492cf4e6363SMichael Chan  */
493cf4e6363SMichael Chan static int bnx2i_setup_cmd_pool(struct bnx2i_hba *hba,
494cf4e6363SMichael Chan 				struct iscsi_session *session)
495cf4e6363SMichael Chan {
496cf4e6363SMichael Chan 	int i;
497cf4e6363SMichael Chan 
498cf4e6363SMichael Chan 	for (i = 0; i < session->cmds_max; i++) {
499cf4e6363SMichael Chan 		struct iscsi_task *task = session->cmds[i];
500cf4e6363SMichael Chan 		struct bnx2i_cmd *cmd = task->dd_data;
501cf4e6363SMichael Chan 
502cf4e6363SMichael Chan 		task->hdr = &cmd->hdr;
503cf4e6363SMichael Chan 		task->hdr_max = sizeof(struct iscsi_hdr);
504cf4e6363SMichael Chan 
505cf4e6363SMichael Chan 		if (bnx2i_alloc_bdt(hba, session, cmd))
506cf4e6363SMichael Chan 			goto free_bdts;
507cf4e6363SMichael Chan 	}
508cf4e6363SMichael Chan 
509cf4e6363SMichael Chan 	return 0;
510cf4e6363SMichael Chan 
511cf4e6363SMichael Chan free_bdts:
512cf4e6363SMichael Chan 	bnx2i_destroy_cmd_pool(hba, session);
513cf4e6363SMichael Chan 	return -ENOMEM;
514cf4e6363SMichael Chan }
515cf4e6363SMichael Chan 
516cf4e6363SMichael Chan 
517cf4e6363SMichael Chan /**
518cf4e6363SMichael Chan  * bnx2i_setup_mp_bdt - allocate BD table resources
519cf4e6363SMichael Chan  * @hba:	pointer to adapter structure
520cf4e6363SMichael Chan  *
521cf4e6363SMichael Chan  * Allocate memory for dummy buffer and associated BD
522cf4e6363SMichael Chan  * table to be used by middle path (MP) requests
523cf4e6363SMichael Chan  */
524cf4e6363SMichael Chan static int bnx2i_setup_mp_bdt(struct bnx2i_hba *hba)
525cf4e6363SMichael Chan {
526cf4e6363SMichael Chan 	int rc = 0;
527cf4e6363SMichael Chan 	struct iscsi_bd *mp_bdt;
528cf4e6363SMichael Chan 	u64 addr;
529cf4e6363SMichael Chan 
530be1fefc2SMichael Chan 	hba->mp_bd_tbl = dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
531cf4e6363SMichael Chan 					    &hba->mp_bd_dma, GFP_KERNEL);
532cf4e6363SMichael Chan 	if (!hba->mp_bd_tbl) {
533cf4e6363SMichael Chan 		printk(KERN_ERR "unable to allocate Middle Path BDT\n");
534cf4e6363SMichael Chan 		rc = -1;
535cf4e6363SMichael Chan 		goto out;
536cf4e6363SMichael Chan 	}
537cf4e6363SMichael Chan 
538be1fefc2SMichael Chan 	hba->dummy_buffer = dma_alloc_coherent(&hba->pcidev->dev,
539be1fefc2SMichael Chan 					       CNIC_PAGE_SIZE,
540cf4e6363SMichael Chan 					       &hba->dummy_buf_dma, GFP_KERNEL);
541cf4e6363SMichael Chan 	if (!hba->dummy_buffer) {
542cf4e6363SMichael Chan 		printk(KERN_ERR "unable to alloc Middle Path Dummy Buffer\n");
543be1fefc2SMichael Chan 		dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
544cf4e6363SMichael Chan 				  hba->mp_bd_tbl, hba->mp_bd_dma);
545cf4e6363SMichael Chan 		hba->mp_bd_tbl = NULL;
546cf4e6363SMichael Chan 		rc = -1;
547cf4e6363SMichael Chan 		goto out;
548cf4e6363SMichael Chan 	}
549cf4e6363SMichael Chan 
550cf4e6363SMichael Chan 	mp_bdt = (struct iscsi_bd *) hba->mp_bd_tbl;
551cf4e6363SMichael Chan 	addr = (unsigned long) hba->dummy_buf_dma;
552cf4e6363SMichael Chan 	mp_bdt->buffer_addr_lo = addr & 0xffffffff;
553cf4e6363SMichael Chan 	mp_bdt->buffer_addr_hi = addr >> 32;
554be1fefc2SMichael Chan 	mp_bdt->buffer_length = CNIC_PAGE_SIZE;
555cf4e6363SMichael Chan 	mp_bdt->flags = ISCSI_BD_LAST_IN_BD_CHAIN |
556cf4e6363SMichael Chan 			ISCSI_BD_FIRST_IN_BD_CHAIN;
557cf4e6363SMichael Chan out:
558cf4e6363SMichael Chan 	return rc;
559cf4e6363SMichael Chan }
560cf4e6363SMichael Chan 
561cf4e6363SMichael Chan 
562cf4e6363SMichael Chan /**
563cf4e6363SMichael Chan  * bnx2i_free_mp_bdt - releases ITT back to free pool
564cf4e6363SMichael Chan  * @hba:	pointer to adapter instance
565cf4e6363SMichael Chan  *
566cf4e6363SMichael Chan  * free MP dummy buffer and associated BD table
567cf4e6363SMichael Chan  */
568cf4e6363SMichael Chan static void bnx2i_free_mp_bdt(struct bnx2i_hba *hba)
569cf4e6363SMichael Chan {
570cf4e6363SMichael Chan 	if (hba->mp_bd_tbl) {
571be1fefc2SMichael Chan 		dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
572cf4e6363SMichael Chan 				  hba->mp_bd_tbl, hba->mp_bd_dma);
573cf4e6363SMichael Chan 		hba->mp_bd_tbl = NULL;
574cf4e6363SMichael Chan 	}
575cf4e6363SMichael Chan 	if (hba->dummy_buffer) {
576be1fefc2SMichael Chan 		dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
577cf4e6363SMichael Chan 				  hba->dummy_buffer, hba->dummy_buf_dma);
578cf4e6363SMichael Chan 		hba->dummy_buffer = NULL;
579cf4e6363SMichael Chan 	}
580cf4e6363SMichael Chan 		return;
581cf4e6363SMichael Chan }
582cf4e6363SMichael Chan 
583cf4e6363SMichael Chan /**
584cf4e6363SMichael Chan  * bnx2i_drop_session - notifies iscsid of connection error.
585cf4e6363SMichael Chan  * @hba:	adapter instance pointer
586cf4e6363SMichael Chan  * @session:	iscsi session pointer
587cf4e6363SMichael Chan  *
588cf4e6363SMichael Chan  * This notifies iscsid that there is a error, so it can initiate
589cf4e6363SMichael Chan  * recovery.
590cf4e6363SMichael Chan  *
591cf4e6363SMichael Chan  * This relies on caller using the iscsi class iterator so the object
592cf4e6363SMichael Chan  * is refcounted and does not disapper from under us.
593cf4e6363SMichael Chan  */
594cf4e6363SMichael Chan void bnx2i_drop_session(struct iscsi_cls_session *cls_session)
595cf4e6363SMichael Chan {
596cf4e6363SMichael Chan 	iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED);
597cf4e6363SMichael Chan }
598cf4e6363SMichael Chan 
599cf4e6363SMichael Chan /**
600cf4e6363SMichael Chan  * bnx2i_ep_destroy_list_add - add an entry to EP destroy list
601cf4e6363SMichael Chan  * @hba:	pointer to adapter instance
6023f79410cSMaxime Jayat  * @ep:		pointer to endpoint (transport identifier) structure
603cf4e6363SMichael Chan  *
604cf4e6363SMichael Chan  * EP destroy queue manager
605cf4e6363SMichael Chan  */
606cf4e6363SMichael Chan static int bnx2i_ep_destroy_list_add(struct bnx2i_hba *hba,
607cf4e6363SMichael Chan 				     struct bnx2i_endpoint *ep)
608cf4e6363SMichael Chan {
609cf4e6363SMichael Chan 	write_lock_bh(&hba->ep_rdwr_lock);
610cf4e6363SMichael Chan 	list_add_tail(&ep->link, &hba->ep_destroy_list);
611cf4e6363SMichael Chan 	write_unlock_bh(&hba->ep_rdwr_lock);
612cf4e6363SMichael Chan 	return 0;
613cf4e6363SMichael Chan }
614cf4e6363SMichael Chan 
615cf4e6363SMichael Chan /**
616cf4e6363SMichael Chan  * bnx2i_ep_destroy_list_del - add an entry to EP destroy list
617cf4e6363SMichael Chan  *
618cf4e6363SMichael Chan  * @hba: 		pointer to adapter instance
6193f79410cSMaxime Jayat  * @ep: 		pointer to endpoint (transport identifier) structure
620cf4e6363SMichael Chan  *
621cf4e6363SMichael Chan  * EP destroy queue manager
622cf4e6363SMichael Chan  */
623cf4e6363SMichael Chan static int bnx2i_ep_destroy_list_del(struct bnx2i_hba *hba,
624cf4e6363SMichael Chan 				     struct bnx2i_endpoint *ep)
625cf4e6363SMichael Chan {
626cf4e6363SMichael Chan 	write_lock_bh(&hba->ep_rdwr_lock);
627cf4e6363SMichael Chan 	list_del_init(&ep->link);
628cf4e6363SMichael Chan 	write_unlock_bh(&hba->ep_rdwr_lock);
629cf4e6363SMichael Chan 
630cf4e6363SMichael Chan 	return 0;
631cf4e6363SMichael Chan }
632cf4e6363SMichael Chan 
633cf4e6363SMichael Chan /**
634cf4e6363SMichael Chan  * bnx2i_ep_ofld_list_add - add an entry to ep offload pending list
635cf4e6363SMichael Chan  * @hba:	pointer to adapter instance
6363f79410cSMaxime Jayat  * @ep:		pointer to endpoint (transport identifier) structure
637cf4e6363SMichael Chan  *
638cf4e6363SMichael Chan  * pending conn offload completion queue manager
639cf4e6363SMichael Chan  */
640cf4e6363SMichael Chan static int bnx2i_ep_ofld_list_add(struct bnx2i_hba *hba,
641cf4e6363SMichael Chan 				  struct bnx2i_endpoint *ep)
642cf4e6363SMichael Chan {
643cf4e6363SMichael Chan 	write_lock_bh(&hba->ep_rdwr_lock);
644cf4e6363SMichael Chan 	list_add_tail(&ep->link, &hba->ep_ofld_list);
645cf4e6363SMichael Chan 	write_unlock_bh(&hba->ep_rdwr_lock);
646cf4e6363SMichael Chan 	return 0;
647cf4e6363SMichael Chan }
648cf4e6363SMichael Chan 
649cf4e6363SMichael Chan /**
650cf4e6363SMichael Chan  * bnx2i_ep_ofld_list_del - add an entry to ep offload pending list
651cf4e6363SMichael Chan  * @hba: 		pointer to adapter instance
6523f79410cSMaxime Jayat  * @ep: 		pointer to endpoint (transport identifier) structure
653cf4e6363SMichael Chan  *
654cf4e6363SMichael Chan  * pending conn offload completion queue manager
655cf4e6363SMichael Chan  */
656cf4e6363SMichael Chan static int bnx2i_ep_ofld_list_del(struct bnx2i_hba *hba,
657cf4e6363SMichael Chan 				  struct bnx2i_endpoint *ep)
658cf4e6363SMichael Chan {
659cf4e6363SMichael Chan 	write_lock_bh(&hba->ep_rdwr_lock);
660cf4e6363SMichael Chan 	list_del_init(&ep->link);
661cf4e6363SMichael Chan 	write_unlock_bh(&hba->ep_rdwr_lock);
662cf4e6363SMichael Chan 	return 0;
663cf4e6363SMichael Chan }
664cf4e6363SMichael Chan 
665cf4e6363SMichael Chan 
666cf4e6363SMichael Chan /**
667cf4e6363SMichael Chan  * bnx2i_find_ep_in_ofld_list - find iscsi_cid in pending list of endpoints
668cf4e6363SMichael Chan  *
669cf4e6363SMichael Chan  * @hba: 		pointer to adapter instance
670cf4e6363SMichael Chan  * @iscsi_cid:		iscsi context ID to find
671cf4e6363SMichael Chan  *
672cf4e6363SMichael Chan  */
673cf4e6363SMichael Chan struct bnx2i_endpoint *
674cf4e6363SMichael Chan bnx2i_find_ep_in_ofld_list(struct bnx2i_hba *hba, u32 iscsi_cid)
675cf4e6363SMichael Chan {
676cf4e6363SMichael Chan 	struct list_head *list;
677cf4e6363SMichael Chan 	struct list_head *tmp;
678cf4e6363SMichael Chan 	struct bnx2i_endpoint *ep;
679cf4e6363SMichael Chan 
680cf4e6363SMichael Chan 	read_lock_bh(&hba->ep_rdwr_lock);
681cf4e6363SMichael Chan 	list_for_each_safe(list, tmp, &hba->ep_ofld_list) {
682cf4e6363SMichael Chan 		ep = (struct bnx2i_endpoint *)list;
683cf4e6363SMichael Chan 
684cf4e6363SMichael Chan 		if (ep->ep_iscsi_cid == iscsi_cid)
685cf4e6363SMichael Chan 			break;
686cf4e6363SMichael Chan 		ep = NULL;
687cf4e6363SMichael Chan 	}
688cf4e6363SMichael Chan 	read_unlock_bh(&hba->ep_rdwr_lock);
689cf4e6363SMichael Chan 
690cf4e6363SMichael Chan 	if (!ep)
691cf4e6363SMichael Chan 		printk(KERN_ERR "l5 cid %d not found\n", iscsi_cid);
692cf4e6363SMichael Chan 	return ep;
693cf4e6363SMichael Chan }
694cf4e6363SMichael Chan 
695cf4e6363SMichael Chan /**
696cf4e6363SMichael Chan  * bnx2i_find_ep_in_destroy_list - find iscsi_cid in destroy list
697cf4e6363SMichael Chan  * @hba: 		pointer to adapter instance
698cf4e6363SMichael Chan  * @iscsi_cid:		iscsi context ID to find
699cf4e6363SMichael Chan  *
700cf4e6363SMichael Chan  */
701cf4e6363SMichael Chan struct bnx2i_endpoint *
702cf4e6363SMichael Chan bnx2i_find_ep_in_destroy_list(struct bnx2i_hba *hba, u32 iscsi_cid)
703cf4e6363SMichael Chan {
704cf4e6363SMichael Chan 	struct list_head *list;
705cf4e6363SMichael Chan 	struct list_head *tmp;
706cf4e6363SMichael Chan 	struct bnx2i_endpoint *ep;
707cf4e6363SMichael Chan 
708cf4e6363SMichael Chan 	read_lock_bh(&hba->ep_rdwr_lock);
709cf4e6363SMichael Chan 	list_for_each_safe(list, tmp, &hba->ep_destroy_list) {
710cf4e6363SMichael Chan 		ep = (struct bnx2i_endpoint *)list;
711cf4e6363SMichael Chan 
712cf4e6363SMichael Chan 		if (ep->ep_iscsi_cid == iscsi_cid)
713cf4e6363SMichael Chan 			break;
714cf4e6363SMichael Chan 		ep = NULL;
715cf4e6363SMichael Chan 	}
716cf4e6363SMichael Chan 	read_unlock_bh(&hba->ep_rdwr_lock);
717cf4e6363SMichael Chan 
718cf4e6363SMichael Chan 	if (!ep)
719cf4e6363SMichael Chan 		printk(KERN_ERR "l5 cid %d not found\n", iscsi_cid);
720cf4e6363SMichael Chan 
721cf4e6363SMichael Chan 	return ep;
722cf4e6363SMichael Chan }
723cf4e6363SMichael Chan 
72446012e8bSEddie Wai /**
72546012e8bSEddie Wai  * bnx2i_ep_active_list_add - add an entry to ep active list
72646012e8bSEddie Wai  * @hba:	pointer to adapter instance
7273f79410cSMaxime Jayat  * @ep:		pointer to endpoint (transport identifier) structure
72846012e8bSEddie Wai  *
72946012e8bSEddie Wai  * current active conn queue manager
73046012e8bSEddie Wai  */
73146012e8bSEddie Wai static void bnx2i_ep_active_list_add(struct bnx2i_hba *hba,
73246012e8bSEddie Wai 				     struct bnx2i_endpoint *ep)
73346012e8bSEddie Wai {
73446012e8bSEddie Wai 	write_lock_bh(&hba->ep_rdwr_lock);
73546012e8bSEddie Wai 	list_add_tail(&ep->link, &hba->ep_active_list);
73646012e8bSEddie Wai 	write_unlock_bh(&hba->ep_rdwr_lock);
73746012e8bSEddie Wai }
73846012e8bSEddie Wai 
73946012e8bSEddie Wai 
74046012e8bSEddie Wai /**
74146012e8bSEddie Wai  * bnx2i_ep_active_list_del - deletes an entry to ep active list
74246012e8bSEddie Wai  * @hba:	pointer to adapter instance
7433f79410cSMaxime Jayat  * @ep:		pointer to endpoint (transport identifier) structure
74446012e8bSEddie Wai  *
74546012e8bSEddie Wai  * current active conn queue manager
74646012e8bSEddie Wai  */
74746012e8bSEddie Wai static void bnx2i_ep_active_list_del(struct bnx2i_hba *hba,
74846012e8bSEddie Wai 				     struct bnx2i_endpoint *ep)
74946012e8bSEddie Wai {
75046012e8bSEddie Wai 	write_lock_bh(&hba->ep_rdwr_lock);
75146012e8bSEddie Wai 	list_del_init(&ep->link);
75246012e8bSEddie Wai 	write_unlock_bh(&hba->ep_rdwr_lock);
75346012e8bSEddie Wai }
75446012e8bSEddie Wai 
75546012e8bSEddie Wai 
756cf4e6363SMichael Chan /**
757cf4e6363SMichael Chan  * bnx2i_setup_host_queue_size - assigns shost->can_queue param
758cf4e6363SMichael Chan  * @hba:	pointer to adapter instance
759cf4e6363SMichael Chan  * @shost:	scsi host pointer
760cf4e6363SMichael Chan  *
761cf4e6363SMichael Chan  * Initializes 'can_queue' parameter based on how many outstanding commands
762cf4e6363SMichael Chan  * 	the device can handle. Each device 5708/5709/57710 has different
763cf4e6363SMichael Chan  *	capabilities
764cf4e6363SMichael Chan  */
765cf4e6363SMichael Chan static void bnx2i_setup_host_queue_size(struct bnx2i_hba *hba,
766cf4e6363SMichael Chan 					struct Scsi_Host *shost)
767cf4e6363SMichael Chan {
768cf4e6363SMichael Chan 	if (test_bit(BNX2I_NX2_DEV_5708, &hba->cnic_dev_type))
769cf4e6363SMichael Chan 		shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_5708;
770cf4e6363SMichael Chan 	else if (test_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type))
771cf4e6363SMichael Chan 		shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_5709;
772cf4e6363SMichael Chan 	else if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type))
773cf4e6363SMichael Chan 		shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_57710;
774cf4e6363SMichael Chan 	else
775cf4e6363SMichael Chan 		shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_5708;
776cf4e6363SMichael Chan }
777cf4e6363SMichael Chan 
778cf4e6363SMichael Chan 
779cf4e6363SMichael Chan /**
780cf4e6363SMichael Chan  * bnx2i_alloc_hba - allocate and init adapter instance
781cf4e6363SMichael Chan  * @cnic:	cnic device pointer
782cf4e6363SMichael Chan  *
783cf4e6363SMichael Chan  * allocate & initialize adapter structure and call other
784cf4e6363SMichael Chan  *	support routines to do per adapter initialization
785cf4e6363SMichael Chan  */
786cf4e6363SMichael Chan struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic)
787cf4e6363SMichael Chan {
788cf4e6363SMichael Chan 	struct Scsi_Host *shost;
789cf4e6363SMichael Chan 	struct bnx2i_hba *hba;
790cf4e6363SMichael Chan 
791cf4e6363SMichael Chan 	shost = iscsi_host_alloc(&bnx2i_host_template, sizeof(*hba), 0);
792cf4e6363SMichael Chan 	if (!shost)
793cf4e6363SMichael Chan 		return NULL;
794cf4e6363SMichael Chan 	shost->dma_boundary = cnic->pcidev->dma_mask;
795cf4e6363SMichael Chan 	shost->transportt = bnx2i_scsi_xport_template;
796cf4e6363SMichael Chan 	shost->max_id = ISCSI_MAX_CONNS_PER_HBA;
797cf4e6363SMichael Chan 	shost->max_channel = 0;
798cf4e6363SMichael Chan 	shost->max_lun = 512;
799cf4e6363SMichael Chan 	shost->max_cmd_len = 16;
800cf4e6363SMichael Chan 
801cf4e6363SMichael Chan 	hba = iscsi_host_priv(shost);
802cf4e6363SMichael Chan 	hba->shost = shost;
803cf4e6363SMichael Chan 	hba->netdev = cnic->netdev;
804cf4e6363SMichael Chan 	/* Get PCI related information and update hba struct members */
805cf4e6363SMichael Chan 	hba->pcidev = cnic->pcidev;
806cf4e6363SMichael Chan 	pci_dev_get(hba->pcidev);
807cf4e6363SMichael Chan 	hba->pci_did = hba->pcidev->device;
808cf4e6363SMichael Chan 	hba->pci_vid = hba->pcidev->vendor;
809cf4e6363SMichael Chan 	hba->pci_sdid = hba->pcidev->subsystem_device;
810cf4e6363SMichael Chan 	hba->pci_svid = hba->pcidev->subsystem_vendor;
811cf4e6363SMichael Chan 	hba->pci_func = PCI_FUNC(hba->pcidev->devfn);
812cf4e6363SMichael Chan 	hba->pci_devno = PCI_SLOT(hba->pcidev->devfn);
813cf4e6363SMichael Chan 
814b83908ceSEddie Wai 	bnx2i_identify_device(hba, cnic);
815cf4e6363SMichael Chan 	bnx2i_setup_host_queue_size(hba, shost);
816cf4e6363SMichael Chan 
817a7717180SEddie Wai 	hba->reg_base = pci_resource_start(hba->pcidev, 0);
818cf4e6363SMichael Chan 	if (test_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type)) {
819a7717180SEddie Wai 		hba->regview = pci_iomap(hba->pcidev, 0, BNX2_MQ_CONFIG2);
820cf4e6363SMichael Chan 		if (!hba->regview)
821cf4e6363SMichael Chan 			goto ioreg_map_err;
822cf4e6363SMichael Chan 	} else if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) {
823a7717180SEddie Wai 		hba->regview = pci_iomap(hba->pcidev, 0, 4096);
824cf4e6363SMichael Chan 		if (!hba->regview)
825cf4e6363SMichael Chan 			goto ioreg_map_err;
826cf4e6363SMichael Chan 	}
827cf4e6363SMichael Chan 
828cf4e6363SMichael Chan 	if (bnx2i_setup_mp_bdt(hba))
829cf4e6363SMichael Chan 		goto mp_bdt_mem_err;
830cf4e6363SMichael Chan 
831cf4e6363SMichael Chan 	INIT_LIST_HEAD(&hba->ep_ofld_list);
83246012e8bSEddie Wai 	INIT_LIST_HEAD(&hba->ep_active_list);
833cf4e6363SMichael Chan 	INIT_LIST_HEAD(&hba->ep_destroy_list);
834cf4e6363SMichael Chan 	rwlock_init(&hba->ep_rdwr_lock);
835cf4e6363SMichael Chan 
836cf4e6363SMichael Chan 	hba->mtu_supported = BNX2I_MAX_MTU_SUPPORTED;
837cf4e6363SMichael Chan 
838cf4e6363SMichael Chan 	/* different values for 5708/5709/57710 */
839cf4e6363SMichael Chan 	hba->max_active_conns = ISCSI_MAX_CONNS_PER_HBA;
840cf4e6363SMichael Chan 
841cf4e6363SMichael Chan 	if (bnx2i_setup_free_cid_que(hba))
842cf4e6363SMichael Chan 		goto cid_que_err;
843cf4e6363SMichael Chan 
844cf4e6363SMichael Chan 	/* SQ/RQ/CQ size can be changed via sysfx interface */
845cf4e6363SMichael Chan 	if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) {
846cf4e6363SMichael Chan 		if (sq_size && sq_size <= BNX2I_5770X_SQ_WQES_MAX)
847cf4e6363SMichael Chan 			hba->max_sqes = sq_size;
848cf4e6363SMichael Chan 		else
849cf4e6363SMichael Chan 			hba->max_sqes = BNX2I_5770X_SQ_WQES_DEFAULT;
850cf4e6363SMichael Chan 	} else {	/* 5706/5708/5709 */
851cf4e6363SMichael Chan 		if (sq_size && sq_size <= BNX2I_570X_SQ_WQES_MAX)
852cf4e6363SMichael Chan 			hba->max_sqes = sq_size;
853cf4e6363SMichael Chan 		else
854cf4e6363SMichael Chan 			hba->max_sqes = BNX2I_570X_SQ_WQES_DEFAULT;
855cf4e6363SMichael Chan 	}
856cf4e6363SMichael Chan 
857cf4e6363SMichael Chan 	hba->max_rqes = rq_size;
858cf4e6363SMichael Chan 	hba->max_cqes = hba->max_sqes + rq_size;
859cf4e6363SMichael Chan 	if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) {
860cf4e6363SMichael Chan 		if (hba->max_cqes > BNX2I_5770X_CQ_WQES_MAX)
861cf4e6363SMichael Chan 			hba->max_cqes = BNX2I_5770X_CQ_WQES_MAX;
862cf4e6363SMichael Chan 	} else if (hba->max_cqes > BNX2I_570X_CQ_WQES_MAX)
863cf4e6363SMichael Chan 		hba->max_cqes = BNX2I_570X_CQ_WQES_MAX;
864cf4e6363SMichael Chan 
865cf4e6363SMichael Chan 	hba->num_ccell = hba->max_sqes / 2;
866cf4e6363SMichael Chan 
867cf4e6363SMichael Chan 	spin_lock_init(&hba->lock);
868cf4e6363SMichael Chan 	mutex_init(&hba->net_dev_lock);
869490475a9SAnil Veerabhadrappa 	init_waitqueue_head(&hba->eh_wait);
870e37d2c47SEddie Wai 	if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) {
871d5307a07SEddie Wai 		hba->hba_shutdown_tmo = 30 * HZ;
872e37d2c47SEddie Wai 		hba->conn_teardown_tmo = 20 * HZ;
873e37d2c47SEddie Wai 		hba->conn_ctx_destroy_tmo = 6 * HZ;
874e37d2c47SEddie Wai 	} else {	/* 5706/5708/5709 */
87555e15c97SEddie Wai 		hba->hba_shutdown_tmo = 20 * HZ;
876e37d2c47SEddie Wai 		hba->conn_teardown_tmo = 10 * HZ;
877e37d2c47SEddie Wai 		hba->conn_ctx_destroy_tmo = 2 * HZ;
878e37d2c47SEddie Wai 	}
879cf4e6363SMichael Chan 
8802e499d3cSBarak Witkowski #ifdef CONFIG_32BIT
8812e499d3cSBarak Witkowski 	spin_lock_init(&hba->stat_lock);
8822e499d3cSBarak Witkowski #endif
8832e499d3cSBarak Witkowski 	memset(&hba->stats, 0, sizeof(struct iscsi_stats_info));
8842e499d3cSBarak Witkowski 
885cf4e6363SMichael Chan 	if (iscsi_host_add(shost, &hba->pcidev->dev))
886cf4e6363SMichael Chan 		goto free_dump_mem;
887cf4e6363SMichael Chan 	return hba;
888cf4e6363SMichael Chan 
889cf4e6363SMichael Chan free_dump_mem:
890cf4e6363SMichael Chan 	bnx2i_release_free_cid_que(hba);
891cf4e6363SMichael Chan cid_que_err:
892cf4e6363SMichael Chan 	bnx2i_free_mp_bdt(hba);
893cf4e6363SMichael Chan mp_bdt_mem_err:
894cf4e6363SMichael Chan 	if (hba->regview) {
895a7717180SEddie Wai 		pci_iounmap(hba->pcidev, hba->regview);
896cf4e6363SMichael Chan 		hba->regview = NULL;
897cf4e6363SMichael Chan 	}
898cf4e6363SMichael Chan ioreg_map_err:
899cf4e6363SMichael Chan 	pci_dev_put(hba->pcidev);
900cf4e6363SMichael Chan 	scsi_host_put(shost);
901cf4e6363SMichael Chan 	return NULL;
902cf4e6363SMichael Chan }
903cf4e6363SMichael Chan 
904cf4e6363SMichael Chan /**
905cf4e6363SMichael Chan  * bnx2i_free_hba- releases hba structure and resources held by the adapter
906cf4e6363SMichael Chan  * @hba:	pointer to adapter instance
907cf4e6363SMichael Chan  *
908cf4e6363SMichael Chan  * free adapter structure and call various cleanup routines.
909cf4e6363SMichael Chan  */
910cf4e6363SMichael Chan void bnx2i_free_hba(struct bnx2i_hba *hba)
911cf4e6363SMichael Chan {
912cf4e6363SMichael Chan 	struct Scsi_Host *shost = hba->shost;
913cf4e6363SMichael Chan 
914cf4e6363SMichael Chan 	iscsi_host_remove(shost);
915cf4e6363SMichael Chan 	INIT_LIST_HEAD(&hba->ep_ofld_list);
91646012e8bSEddie Wai 	INIT_LIST_HEAD(&hba->ep_active_list);
917cf4e6363SMichael Chan 	INIT_LIST_HEAD(&hba->ep_destroy_list);
918cf4e6363SMichael Chan 	pci_dev_put(hba->pcidev);
919cf4e6363SMichael Chan 
920cf4e6363SMichael Chan 	if (hba->regview) {
921a7717180SEddie Wai 		pci_iounmap(hba->pcidev, hba->regview);
922cf4e6363SMichael Chan 		hba->regview = NULL;
923cf4e6363SMichael Chan 	}
924cf4e6363SMichael Chan 	bnx2i_free_mp_bdt(hba);
925cf4e6363SMichael Chan 	bnx2i_release_free_cid_que(hba);
926cf4e6363SMichael Chan 	iscsi_host_free(shost);
927cf4e6363SMichael Chan }
928cf4e6363SMichael Chan 
929cf4e6363SMichael Chan /**
930cf4e6363SMichael Chan  * bnx2i_conn_free_login_resources - free DMA resources used for login process
931cf4e6363SMichael Chan  * @hba:		pointer to adapter instance
932cf4e6363SMichael Chan  * @bnx2i_conn:		iscsi connection pointer
933cf4e6363SMichael Chan  *
934cf4e6363SMichael Chan  * Login related resources, mostly BDT & payload DMA memory is freed
935cf4e6363SMichael Chan  */
936cf4e6363SMichael Chan static void bnx2i_conn_free_login_resources(struct bnx2i_hba *hba,
937cf4e6363SMichael Chan 					    struct bnx2i_conn *bnx2i_conn)
938cf4e6363SMichael Chan {
939cf4e6363SMichael Chan 	if (bnx2i_conn->gen_pdu.resp_bd_tbl) {
940be1fefc2SMichael Chan 		dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
941cf4e6363SMichael Chan 				  bnx2i_conn->gen_pdu.resp_bd_tbl,
942cf4e6363SMichael Chan 				  bnx2i_conn->gen_pdu.resp_bd_dma);
943cf4e6363SMichael Chan 		bnx2i_conn->gen_pdu.resp_bd_tbl = NULL;
944cf4e6363SMichael Chan 	}
945cf4e6363SMichael Chan 
946cf4e6363SMichael Chan 	if (bnx2i_conn->gen_pdu.req_bd_tbl) {
947be1fefc2SMichael Chan 		dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
948cf4e6363SMichael Chan 				  bnx2i_conn->gen_pdu.req_bd_tbl,
949cf4e6363SMichael Chan 				  bnx2i_conn->gen_pdu.req_bd_dma);
950cf4e6363SMichael Chan 		bnx2i_conn->gen_pdu.req_bd_tbl = NULL;
951cf4e6363SMichael Chan 	}
952cf4e6363SMichael Chan 
953cf4e6363SMichael Chan 	if (bnx2i_conn->gen_pdu.resp_buf) {
954cf4e6363SMichael Chan 		dma_free_coherent(&hba->pcidev->dev,
955cf4e6363SMichael Chan 				  ISCSI_DEF_MAX_RECV_SEG_LEN,
956cf4e6363SMichael Chan 				  bnx2i_conn->gen_pdu.resp_buf,
957cf4e6363SMichael Chan 				  bnx2i_conn->gen_pdu.resp_dma_addr);
958cf4e6363SMichael Chan 		bnx2i_conn->gen_pdu.resp_buf = NULL;
959cf4e6363SMichael Chan 	}
960cf4e6363SMichael Chan 
961cf4e6363SMichael Chan 	if (bnx2i_conn->gen_pdu.req_buf) {
962cf4e6363SMichael Chan 		dma_free_coherent(&hba->pcidev->dev,
963cf4e6363SMichael Chan 				  ISCSI_DEF_MAX_RECV_SEG_LEN,
964cf4e6363SMichael Chan 				  bnx2i_conn->gen_pdu.req_buf,
965cf4e6363SMichael Chan 				  bnx2i_conn->gen_pdu.req_dma_addr);
966cf4e6363SMichael Chan 		bnx2i_conn->gen_pdu.req_buf = NULL;
967cf4e6363SMichael Chan 	}
968cf4e6363SMichael Chan }
969cf4e6363SMichael Chan 
970cf4e6363SMichael Chan /**
971cf4e6363SMichael Chan  * bnx2i_conn_alloc_login_resources - alloc DMA resources for login/nop.
972cf4e6363SMichael Chan  * @hba:		pointer to adapter instance
973cf4e6363SMichael Chan  * @bnx2i_conn:		iscsi connection pointer
974cf4e6363SMichael Chan  *
975cf4e6363SMichael Chan  * Mgmt task DNA resources are allocated in this routine.
976cf4e6363SMichael Chan  */
977cf4e6363SMichael Chan static int bnx2i_conn_alloc_login_resources(struct bnx2i_hba *hba,
978cf4e6363SMichael Chan 					    struct bnx2i_conn *bnx2i_conn)
979cf4e6363SMichael Chan {
980cf4e6363SMichael Chan 	/* Allocate memory for login request/response buffers */
981cf4e6363SMichael Chan 	bnx2i_conn->gen_pdu.req_buf =
982cf4e6363SMichael Chan 		dma_alloc_coherent(&hba->pcidev->dev,
983cf4e6363SMichael Chan 				   ISCSI_DEF_MAX_RECV_SEG_LEN,
984cf4e6363SMichael Chan 				   &bnx2i_conn->gen_pdu.req_dma_addr,
985cf4e6363SMichael Chan 				   GFP_KERNEL);
986cf4e6363SMichael Chan 	if (bnx2i_conn->gen_pdu.req_buf == NULL)
987cf4e6363SMichael Chan 		goto login_req_buf_failure;
988cf4e6363SMichael Chan 
989cf4e6363SMichael Chan 	bnx2i_conn->gen_pdu.req_buf_size = 0;
990cf4e6363SMichael Chan 	bnx2i_conn->gen_pdu.req_wr_ptr = bnx2i_conn->gen_pdu.req_buf;
991cf4e6363SMichael Chan 
992cf4e6363SMichael Chan 	bnx2i_conn->gen_pdu.resp_buf =
993cf4e6363SMichael Chan 		dma_alloc_coherent(&hba->pcidev->dev,
994cf4e6363SMichael Chan 				   ISCSI_DEF_MAX_RECV_SEG_LEN,
995cf4e6363SMichael Chan 				   &bnx2i_conn->gen_pdu.resp_dma_addr,
996cf4e6363SMichael Chan 				   GFP_KERNEL);
997cf4e6363SMichael Chan 	if (bnx2i_conn->gen_pdu.resp_buf == NULL)
998cf4e6363SMichael Chan 		goto login_resp_buf_failure;
999cf4e6363SMichael Chan 
1000cf4e6363SMichael Chan 	bnx2i_conn->gen_pdu.resp_buf_size = ISCSI_DEF_MAX_RECV_SEG_LEN;
1001cf4e6363SMichael Chan 	bnx2i_conn->gen_pdu.resp_wr_ptr = bnx2i_conn->gen_pdu.resp_buf;
1002cf4e6363SMichael Chan 
1003cf4e6363SMichael Chan 	bnx2i_conn->gen_pdu.req_bd_tbl =
1004be1fefc2SMichael Chan 		dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
1005cf4e6363SMichael Chan 				   &bnx2i_conn->gen_pdu.req_bd_dma, GFP_KERNEL);
1006cf4e6363SMichael Chan 	if (bnx2i_conn->gen_pdu.req_bd_tbl == NULL)
1007cf4e6363SMichael Chan 		goto login_req_bd_tbl_failure;
1008cf4e6363SMichael Chan 
1009cf4e6363SMichael Chan 	bnx2i_conn->gen_pdu.resp_bd_tbl =
1010be1fefc2SMichael Chan 		dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
1011cf4e6363SMichael Chan 				   &bnx2i_conn->gen_pdu.resp_bd_dma,
1012cf4e6363SMichael Chan 				   GFP_KERNEL);
1013cf4e6363SMichael Chan 	if (bnx2i_conn->gen_pdu.resp_bd_tbl == NULL)
1014cf4e6363SMichael Chan 		goto login_resp_bd_tbl_failure;
1015cf4e6363SMichael Chan 
1016cf4e6363SMichael Chan 	return 0;
1017cf4e6363SMichael Chan 
1018cf4e6363SMichael Chan login_resp_bd_tbl_failure:
1019be1fefc2SMichael Chan 	dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
1020cf4e6363SMichael Chan 			  bnx2i_conn->gen_pdu.req_bd_tbl,
1021cf4e6363SMichael Chan 			  bnx2i_conn->gen_pdu.req_bd_dma);
1022cf4e6363SMichael Chan 	bnx2i_conn->gen_pdu.req_bd_tbl = NULL;
1023cf4e6363SMichael Chan 
1024cf4e6363SMichael Chan login_req_bd_tbl_failure:
1025cf4e6363SMichael Chan 	dma_free_coherent(&hba->pcidev->dev, ISCSI_DEF_MAX_RECV_SEG_LEN,
1026cf4e6363SMichael Chan 			  bnx2i_conn->gen_pdu.resp_buf,
1027cf4e6363SMichael Chan 			  bnx2i_conn->gen_pdu.resp_dma_addr);
1028cf4e6363SMichael Chan 	bnx2i_conn->gen_pdu.resp_buf = NULL;
1029cf4e6363SMichael Chan login_resp_buf_failure:
1030cf4e6363SMichael Chan 	dma_free_coherent(&hba->pcidev->dev, ISCSI_DEF_MAX_RECV_SEG_LEN,
1031cf4e6363SMichael Chan 			  bnx2i_conn->gen_pdu.req_buf,
1032cf4e6363SMichael Chan 			  bnx2i_conn->gen_pdu.req_dma_addr);
1033cf4e6363SMichael Chan 	bnx2i_conn->gen_pdu.req_buf = NULL;
1034cf4e6363SMichael Chan login_req_buf_failure:
1035cf4e6363SMichael Chan 	iscsi_conn_printk(KERN_ERR, bnx2i_conn->cls_conn->dd_data,
1036cf4e6363SMichael Chan 			  "login resource alloc failed!!\n");
1037cf4e6363SMichael Chan 	return -ENOMEM;
1038cf4e6363SMichael Chan 
1039cf4e6363SMichael Chan }
1040cf4e6363SMichael Chan 
1041cf4e6363SMichael Chan 
1042cf4e6363SMichael Chan /**
1043cf4e6363SMichael Chan  * bnx2i_iscsi_prep_generic_pdu_bd - prepares BD table.
1044cf4e6363SMichael Chan  * @bnx2i_conn:		iscsi connection pointer
1045cf4e6363SMichael Chan  *
1046cf4e6363SMichael Chan  * Allocates buffers and BD tables before shipping requests to cnic
1047cf4e6363SMichael Chan  *	for PDUs prepared by 'iscsid' daemon
1048cf4e6363SMichael Chan  */
1049cf4e6363SMichael Chan static void bnx2i_iscsi_prep_generic_pdu_bd(struct bnx2i_conn *bnx2i_conn)
1050cf4e6363SMichael Chan {
1051cf4e6363SMichael Chan 	struct iscsi_bd *bd_tbl;
1052cf4e6363SMichael Chan 
1053cf4e6363SMichael Chan 	bd_tbl = (struct iscsi_bd *) bnx2i_conn->gen_pdu.req_bd_tbl;
1054cf4e6363SMichael Chan 
1055cf4e6363SMichael Chan 	bd_tbl->buffer_addr_hi =
1056cf4e6363SMichael Chan 		(u32) ((u64) bnx2i_conn->gen_pdu.req_dma_addr >> 32);
1057cf4e6363SMichael Chan 	bd_tbl->buffer_addr_lo = (u32) bnx2i_conn->gen_pdu.req_dma_addr;
1058cf4e6363SMichael Chan 	bd_tbl->buffer_length = bnx2i_conn->gen_pdu.req_wr_ptr -
1059cf4e6363SMichael Chan 				bnx2i_conn->gen_pdu.req_buf;
1060cf4e6363SMichael Chan 	bd_tbl->reserved0 = 0;
1061cf4e6363SMichael Chan 	bd_tbl->flags = ISCSI_BD_LAST_IN_BD_CHAIN |
1062cf4e6363SMichael Chan 			ISCSI_BD_FIRST_IN_BD_CHAIN;
1063cf4e6363SMichael Chan 
1064cf4e6363SMichael Chan 	bd_tbl = (struct iscsi_bd  *) bnx2i_conn->gen_pdu.resp_bd_tbl;
1065cf4e6363SMichael Chan 	bd_tbl->buffer_addr_hi = (u64) bnx2i_conn->gen_pdu.resp_dma_addr >> 32;
1066cf4e6363SMichael Chan 	bd_tbl->buffer_addr_lo = (u32) bnx2i_conn->gen_pdu.resp_dma_addr;
1067cf4e6363SMichael Chan 	bd_tbl->buffer_length = ISCSI_DEF_MAX_RECV_SEG_LEN;
1068cf4e6363SMichael Chan 	bd_tbl->reserved0 = 0;
1069cf4e6363SMichael Chan 	bd_tbl->flags = ISCSI_BD_LAST_IN_BD_CHAIN |
1070cf4e6363SMichael Chan 			ISCSI_BD_FIRST_IN_BD_CHAIN;
1071cf4e6363SMichael Chan }
1072cf4e6363SMichael Chan 
1073cf4e6363SMichael Chan 
1074cf4e6363SMichael Chan /**
1075cf4e6363SMichael Chan  * bnx2i_iscsi_send_generic_request - called to send mgmt tasks.
1076cf4e6363SMichael Chan  * @task:	transport layer task pointer
1077cf4e6363SMichael Chan  *
1078cf4e6363SMichael Chan  * called to transmit PDUs prepared by the 'iscsid' daemon. iSCSI login,
1079cf4e6363SMichael Chan  *	Nop-out and Logout requests flow through this path.
1080cf4e6363SMichael Chan  */
1081cf4e6363SMichael Chan static int bnx2i_iscsi_send_generic_request(struct iscsi_task *task)
1082cf4e6363SMichael Chan {
1083cf4e6363SMichael Chan 	struct bnx2i_cmd *cmd = task->dd_data;
1084cf4e6363SMichael Chan 	struct bnx2i_conn *bnx2i_conn = cmd->conn;
1085cf4e6363SMichael Chan 	int rc = 0;
1086cf4e6363SMichael Chan 	char *buf;
1087cf4e6363SMichael Chan 	int data_len;
1088cf4e6363SMichael Chan 
1089cf4e6363SMichael Chan 	bnx2i_iscsi_prep_generic_pdu_bd(bnx2i_conn);
1090cf4e6363SMichael Chan 	switch (task->hdr->opcode & ISCSI_OPCODE_MASK) {
1091cf4e6363SMichael Chan 	case ISCSI_OP_LOGIN:
1092cf4e6363SMichael Chan 		bnx2i_send_iscsi_login(bnx2i_conn, task);
1093cf4e6363SMichael Chan 		break;
1094cf4e6363SMichael Chan 	case ISCSI_OP_NOOP_OUT:
1095cf4e6363SMichael Chan 		data_len = bnx2i_conn->gen_pdu.req_buf_size;
1096cf4e6363SMichael Chan 		buf = bnx2i_conn->gen_pdu.req_buf;
1097cf4e6363SMichael Chan 		if (data_len)
1098cf4e6363SMichael Chan 			rc = bnx2i_send_iscsi_nopout(bnx2i_conn, task,
1099cf4e6363SMichael Chan 						     buf, data_len, 1);
1100cf4e6363SMichael Chan 		else
1101cf4e6363SMichael Chan 			rc = bnx2i_send_iscsi_nopout(bnx2i_conn, task,
1102cf4e6363SMichael Chan 						     NULL, 0, 1);
1103cf4e6363SMichael Chan 		break;
1104cf4e6363SMichael Chan 	case ISCSI_OP_LOGOUT:
1105cf4e6363SMichael Chan 		rc = bnx2i_send_iscsi_logout(bnx2i_conn, task);
1106cf4e6363SMichael Chan 		break;
1107cf4e6363SMichael Chan 	case ISCSI_OP_SCSI_TMFUNC:
1108cf4e6363SMichael Chan 		rc = bnx2i_send_iscsi_tmf(bnx2i_conn, task);
1109cf4e6363SMichael Chan 		break;
111009813ba5SEddie Wai 	case ISCSI_OP_TEXT:
111109813ba5SEddie Wai 		rc = bnx2i_send_iscsi_text(bnx2i_conn, task);
111209813ba5SEddie Wai 		break;
1113cf4e6363SMichael Chan 	default:
1114cf4e6363SMichael Chan 		iscsi_conn_printk(KERN_ALERT, bnx2i_conn->cls_conn->dd_data,
1115cf4e6363SMichael Chan 				  "send_gen: unsupported op 0x%x\n",
1116cf4e6363SMichael Chan 				  task->hdr->opcode);
1117cf4e6363SMichael Chan 	}
1118cf4e6363SMichael Chan 	return rc;
1119cf4e6363SMichael Chan }
1120cf4e6363SMichael Chan 
1121cf4e6363SMichael Chan 
1122cf4e6363SMichael Chan /**********************************************************************
1123cf4e6363SMichael Chan  *		SCSI-ML Interface
1124cf4e6363SMichael Chan  **********************************************************************/
1125cf4e6363SMichael Chan 
1126cf4e6363SMichael Chan /**
1127cf4e6363SMichael Chan  * bnx2i_cpy_scsi_cdb - copies LUN & CDB fields in required format to sq wqe
1128cf4e6363SMichael Chan  * @sc:		SCSI-ML command pointer
1129cf4e6363SMichael Chan  * @cmd:	iscsi cmd pointer
1130cf4e6363SMichael Chan  */
1131cf4e6363SMichael Chan static void bnx2i_cpy_scsi_cdb(struct scsi_cmnd *sc, struct bnx2i_cmd *cmd)
1132cf4e6363SMichael Chan {
1133cf4e6363SMichael Chan 	u32 dword;
1134cf4e6363SMichael Chan 	int lpcnt;
1135cf4e6363SMichael Chan 	u8 *srcp;
1136cf4e6363SMichael Chan 	u32 *dstp;
1137cf4e6363SMichael Chan 	u32 scsi_lun[2];
1138cf4e6363SMichael Chan 
1139cf4e6363SMichael Chan 	int_to_scsilun(sc->device->lun, (struct scsi_lun *) scsi_lun);
1140cf4e6363SMichael Chan 	cmd->req.lun[0] = be32_to_cpu(scsi_lun[0]);
1141cf4e6363SMichael Chan 	cmd->req.lun[1] = be32_to_cpu(scsi_lun[1]);
1142cf4e6363SMichael Chan 
1143cf4e6363SMichael Chan 	lpcnt = cmd->scsi_cmd->cmd_len / sizeof(dword);
1144cf4e6363SMichael Chan 	srcp = (u8 *) sc->cmnd;
1145cf4e6363SMichael Chan 	dstp = (u32 *) cmd->req.cdb;
1146cf4e6363SMichael Chan 	while (lpcnt--) {
1147cf4e6363SMichael Chan 		memcpy(&dword, (const void *) srcp, 4);
1148cf4e6363SMichael Chan 		*dstp = cpu_to_be32(dword);
1149cf4e6363SMichael Chan 		srcp += 4;
1150cf4e6363SMichael Chan 		dstp++;
1151cf4e6363SMichael Chan 	}
1152cf4e6363SMichael Chan 	if (sc->cmd_len & 0x3) {
1153cf4e6363SMichael Chan 		dword = (u32) srcp[0] | ((u32) srcp[1] << 8);
1154cf4e6363SMichael Chan 		*dstp = cpu_to_be32(dword);
1155cf4e6363SMichael Chan 	}
1156cf4e6363SMichael Chan }
1157cf4e6363SMichael Chan 
1158cf4e6363SMichael Chan static void bnx2i_cleanup_task(struct iscsi_task *task)
1159cf4e6363SMichael Chan {
1160cf4e6363SMichael Chan 	struct iscsi_conn *conn = task->conn;
1161cf4e6363SMichael Chan 	struct bnx2i_conn *bnx2i_conn = conn->dd_data;
1162cf4e6363SMichael Chan 	struct bnx2i_hba *hba = bnx2i_conn->hba;
1163cf4e6363SMichael Chan 
1164cf4e6363SMichael Chan 	/*
1165cf4e6363SMichael Chan 	 * mgmt task or cmd was never sent to us to transmit.
1166cf4e6363SMichael Chan 	 */
1167cf4e6363SMichael Chan 	if (!task->sc || task->state == ISCSI_TASK_PENDING)
1168cf4e6363SMichael Chan 		return;
1169cf4e6363SMichael Chan 	/*
1170cf4e6363SMichael Chan 	 * need to clean-up task context to claim dma buffers
1171cf4e6363SMichael Chan 	 */
1172cf4e6363SMichael Chan 	if (task->state == ISCSI_TASK_ABRT_TMF) {
1173cf4e6363SMichael Chan 		bnx2i_send_cmd_cleanup_req(hba, task->dd_data);
1174cf4e6363SMichael Chan 
1175659743b0SShlomo Pongratz 		spin_unlock_bh(&conn->session->back_lock);
1176cf4e6363SMichael Chan 		wait_for_completion_timeout(&bnx2i_conn->cmd_cleanup_cmpl,
1177cf4e6363SMichael Chan 				msecs_to_jiffies(ISCSI_CMD_CLEANUP_TIMEOUT));
1178659743b0SShlomo Pongratz 		spin_lock_bh(&conn->session->back_lock);
1179cf4e6363SMichael Chan 	}
1180cf4e6363SMichael Chan 	bnx2i_iscsi_unmap_sg_list(task->dd_data);
1181cf4e6363SMichael Chan }
1182cf4e6363SMichael Chan 
1183cf4e6363SMichael Chan /**
1184cf4e6363SMichael Chan  * bnx2i_mtask_xmit - transmit mtask to chip for further processing
1185cf4e6363SMichael Chan  * @conn:	transport layer conn structure pointer
1186cf4e6363SMichael Chan  * @task:	transport layer command structure pointer
1187cf4e6363SMichael Chan  */
1188cf4e6363SMichael Chan static int
1189cf4e6363SMichael Chan bnx2i_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task)
1190cf4e6363SMichael Chan {
1191cf4e6363SMichael Chan 	struct bnx2i_conn *bnx2i_conn = conn->dd_data;
11922e499d3cSBarak Witkowski 	struct bnx2i_hba *hba = bnx2i_conn->hba;
1193cf4e6363SMichael Chan 	struct bnx2i_cmd *cmd = task->dd_data;
1194cf4e6363SMichael Chan 
1195cf4e6363SMichael Chan 	memset(bnx2i_conn->gen_pdu.req_buf, 0, ISCSI_DEF_MAX_RECV_SEG_LEN);
1196cf4e6363SMichael Chan 
1197cf4e6363SMichael Chan 	bnx2i_setup_cmd_wqe_template(cmd);
1198cf4e6363SMichael Chan 	bnx2i_conn->gen_pdu.req_buf_size = task->data_count;
11992e499d3cSBarak Witkowski 
12002e499d3cSBarak Witkowski 	/* Tx PDU/data length count */
12012e499d3cSBarak Witkowski 	ADD_STATS_64(hba, tx_pdus, 1);
12022e499d3cSBarak Witkowski 	ADD_STATS_64(hba, tx_bytes, task->data_count);
12032e499d3cSBarak Witkowski 
1204cf4e6363SMichael Chan 	if (task->data_count) {
1205cf4e6363SMichael Chan 		memcpy(bnx2i_conn->gen_pdu.req_buf, task->data,
1206cf4e6363SMichael Chan 		       task->data_count);
1207cf4e6363SMichael Chan 		bnx2i_conn->gen_pdu.req_wr_ptr =
1208cf4e6363SMichael Chan 			bnx2i_conn->gen_pdu.req_buf + task->data_count;
1209cf4e6363SMichael Chan 	}
1210cf4e6363SMichael Chan 	cmd->conn = conn->dd_data;
1211cf4e6363SMichael Chan 	cmd->scsi_cmd = NULL;
1212cf4e6363SMichael Chan 	return bnx2i_iscsi_send_generic_request(task);
1213cf4e6363SMichael Chan }
1214cf4e6363SMichael Chan 
1215cf4e6363SMichael Chan /**
1216cf4e6363SMichael Chan  * bnx2i_task_xmit - transmit iscsi command to chip for further processing
1217cf4e6363SMichael Chan  * @task:	transport layer command structure pointer
1218cf4e6363SMichael Chan  *
1219cf4e6363SMichael Chan  * maps SG buffers and send request to chip/firmware in the form of SQ WQE
1220cf4e6363SMichael Chan  */
1221cf4e6363SMichael Chan static int bnx2i_task_xmit(struct iscsi_task *task)
1222cf4e6363SMichael Chan {
1223cf4e6363SMichael Chan 	struct iscsi_conn *conn = task->conn;
1224cf4e6363SMichael Chan 	struct iscsi_session *session = conn->session;
1225cf4e6363SMichael Chan 	struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session);
1226cf4e6363SMichael Chan 	struct bnx2i_hba *hba = iscsi_host_priv(shost);
1227cf4e6363SMichael Chan 	struct bnx2i_conn *bnx2i_conn = conn->dd_data;
1228cf4e6363SMichael Chan 	struct scsi_cmnd *sc = task->sc;
1229cf4e6363SMichael Chan 	struct bnx2i_cmd *cmd = task->dd_data;
123012352183SNicholas Bellinger 	struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)task->hdr;
1231cf4e6363SMichael Chan 
1232b5cf6b63SEddie Wai 	if (atomic_read(&bnx2i_conn->ep->num_active_cmds) + 1  >
1233b5cf6b63SEddie Wai 	    hba->max_sqes)
12347287c63eSEddie Wai 		return -ENOMEM;
12357287c63eSEddie Wai 
1236cf4e6363SMichael Chan 	/*
1237cf4e6363SMichael Chan 	 * If there is no scsi_cmnd this must be a mgmt task
1238cf4e6363SMichael Chan 	 */
1239cf4e6363SMichael Chan 	if (!sc)
1240cf4e6363SMichael Chan 		return bnx2i_mtask_xmit(conn, task);
1241cf4e6363SMichael Chan 
1242cf4e6363SMichael Chan 	bnx2i_setup_cmd_wqe_template(cmd);
1243cf4e6363SMichael Chan 	cmd->req.op_code = ISCSI_OP_SCSI_CMD;
1244cf4e6363SMichael Chan 	cmd->conn = bnx2i_conn;
1245cf4e6363SMichael Chan 	cmd->scsi_cmd = sc;
1246cf4e6363SMichael Chan 	cmd->req.total_data_transfer_length = scsi_bufflen(sc);
1247cf4e6363SMichael Chan 	cmd->req.cmd_sn = be32_to_cpu(hdr->cmdsn);
1248cf4e6363SMichael Chan 
1249cf4e6363SMichael Chan 	bnx2i_iscsi_map_sg_list(cmd);
1250cf4e6363SMichael Chan 	bnx2i_cpy_scsi_cdb(sc, cmd);
1251cf4e6363SMichael Chan 
1252cf4e6363SMichael Chan 	cmd->req.op_attr = ISCSI_ATTR_SIMPLE;
1253cf4e6363SMichael Chan 	if (sc->sc_data_direction == DMA_TO_DEVICE) {
1254cf4e6363SMichael Chan 		cmd->req.op_attr |= ISCSI_CMD_REQUEST_WRITE;
1255cf4e6363SMichael Chan 		cmd->req.itt = task->itt |
1256cf4e6363SMichael Chan 			(ISCSI_TASK_TYPE_WRITE << ISCSI_CMD_REQUEST_TYPE_SHIFT);
1257cf4e6363SMichael Chan 		bnx2i_setup_write_cmd_bd_info(task);
1258cf4e6363SMichael Chan 	} else {
1259cf4e6363SMichael Chan 		if (scsi_bufflen(sc))
1260cf4e6363SMichael Chan 			cmd->req.op_attr |= ISCSI_CMD_REQUEST_READ;
1261cf4e6363SMichael Chan 		cmd->req.itt = task->itt |
1262cf4e6363SMichael Chan 			(ISCSI_TASK_TYPE_READ << ISCSI_CMD_REQUEST_TYPE_SHIFT);
1263cf4e6363SMichael Chan 	}
1264cf4e6363SMichael Chan 
1265cf4e6363SMichael Chan 	cmd->req.num_bds = cmd->io_tbl.bd_valid;
1266cf4e6363SMichael Chan 	if (!cmd->io_tbl.bd_valid) {
1267cf4e6363SMichael Chan 		cmd->req.bd_list_addr_lo = (u32) hba->mp_bd_dma;
1268cf4e6363SMichael Chan 		cmd->req.bd_list_addr_hi = (u32) ((u64) hba->mp_bd_dma >> 32);
1269cf4e6363SMichael Chan 		cmd->req.num_bds = 1;
1270cf4e6363SMichael Chan 	}
1271cf4e6363SMichael Chan 
1272cf4e6363SMichael Chan 	bnx2i_send_iscsi_scsicmd(bnx2i_conn, cmd);
1273cf4e6363SMichael Chan 	return 0;
1274cf4e6363SMichael Chan }
1275cf4e6363SMichael Chan 
1276cf4e6363SMichael Chan /**
1277cf4e6363SMichael Chan  * bnx2i_session_create - create a new iscsi session
1278cf4e6363SMichael Chan  * @cmds_max:		max commands supported
1279cf4e6363SMichael Chan  * @qdepth:		scsi queue depth to support
1280cf4e6363SMichael Chan  * @initial_cmdsn:	initial iscsi CMDSN to be used for this session
1281cf4e6363SMichael Chan  *
1282cf4e6363SMichael Chan  * Creates a new iSCSI session instance on given device.
1283cf4e6363SMichael Chan  */
1284cf4e6363SMichael Chan static struct iscsi_cls_session *
1285cf4e6363SMichael Chan bnx2i_session_create(struct iscsi_endpoint *ep,
1286cf4e6363SMichael Chan 		     uint16_t cmds_max, uint16_t qdepth,
1287cf4e6363SMichael Chan 		     uint32_t initial_cmdsn)
1288cf4e6363SMichael Chan {
1289cf4e6363SMichael Chan 	struct Scsi_Host *shost;
1290cf4e6363SMichael Chan 	struct iscsi_cls_session *cls_session;
1291cf4e6363SMichael Chan 	struct bnx2i_hba *hba;
1292cf4e6363SMichael Chan 	struct bnx2i_endpoint *bnx2i_ep;
1293cf4e6363SMichael Chan 
1294cf4e6363SMichael Chan 	if (!ep) {
1295cf4e6363SMichael Chan 		printk(KERN_ERR "bnx2i: missing ep.\n");
1296cf4e6363SMichael Chan 		return NULL;
1297cf4e6363SMichael Chan 	}
1298cf4e6363SMichael Chan 
1299cf4e6363SMichael Chan 	bnx2i_ep = ep->dd_data;
1300cf4e6363SMichael Chan 	shost = bnx2i_ep->hba->shost;
1301cf4e6363SMichael Chan 	hba = iscsi_host_priv(shost);
1302cf4e6363SMichael Chan 	if (bnx2i_adapter_ready(hba))
1303cf4e6363SMichael Chan 		return NULL;
1304cf4e6363SMichael Chan 
1305cf4e6363SMichael Chan 	/*
1306cf4e6363SMichael Chan 	 * user can override hw limit as long as it is within
1307cf4e6363SMichael Chan 	 * the min/max.
1308cf4e6363SMichael Chan 	 */
1309cf4e6363SMichael Chan 	if (cmds_max > hba->max_sqes)
1310cf4e6363SMichael Chan 		cmds_max = hba->max_sqes;
1311cf4e6363SMichael Chan 	else if (cmds_max < BNX2I_SQ_WQES_MIN)
1312cf4e6363SMichael Chan 		cmds_max = BNX2I_SQ_WQES_MIN;
1313cf4e6363SMichael Chan 
1314cf4e6363SMichael Chan 	cls_session = iscsi_session_setup(&bnx2i_iscsi_transport, shost,
1315b8b9e1b8SJayamohan Kallickal 					  cmds_max, 0, sizeof(struct bnx2i_cmd),
1316cf4e6363SMichael Chan 					  initial_cmdsn, ISCSI_MAX_TARGET);
1317cf4e6363SMichael Chan 	if (!cls_session)
1318cf4e6363SMichael Chan 		return NULL;
1319cf4e6363SMichael Chan 
1320cf4e6363SMichael Chan 	if (bnx2i_setup_cmd_pool(hba, cls_session->dd_data))
1321cf4e6363SMichael Chan 		goto session_teardown;
1322cf4e6363SMichael Chan 	return cls_session;
1323cf4e6363SMichael Chan 
1324cf4e6363SMichael Chan session_teardown:
1325cf4e6363SMichael Chan 	iscsi_session_teardown(cls_session);
1326cf4e6363SMichael Chan 	return NULL;
1327cf4e6363SMichael Chan }
1328cf4e6363SMichael Chan 
1329cf4e6363SMichael Chan 
1330cf4e6363SMichael Chan /**
1331cf4e6363SMichael Chan  * bnx2i_session_destroy - destroys iscsi session
1332cf4e6363SMichael Chan  * @cls_session:	pointer to iscsi cls session
1333cf4e6363SMichael Chan  *
1334cf4e6363SMichael Chan  * Destroys previously created iSCSI session instance and releases
1335cf4e6363SMichael Chan  *	all resources held by it
1336cf4e6363SMichael Chan  */
1337cf4e6363SMichael Chan static void bnx2i_session_destroy(struct iscsi_cls_session *cls_session)
1338cf4e6363SMichael Chan {
1339cf4e6363SMichael Chan 	struct iscsi_session *session = cls_session->dd_data;
1340cf4e6363SMichael Chan 	struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
1341cf4e6363SMichael Chan 	struct bnx2i_hba *hba = iscsi_host_priv(shost);
1342cf4e6363SMichael Chan 
1343cf4e6363SMichael Chan 	bnx2i_destroy_cmd_pool(hba, session);
1344cf4e6363SMichael Chan 	iscsi_session_teardown(cls_session);
1345cf4e6363SMichael Chan }
1346cf4e6363SMichael Chan 
1347cf4e6363SMichael Chan 
1348cf4e6363SMichael Chan /**
1349cf4e6363SMichael Chan  * bnx2i_conn_create - create iscsi connection instance
1350cf4e6363SMichael Chan  * @cls_session:	pointer to iscsi cls session
1351cf4e6363SMichael Chan  * @cid:		iscsi cid as per rfc (not NX2's CID terminology)
1352cf4e6363SMichael Chan  *
1353cf4e6363SMichael Chan  * Creates a new iSCSI connection instance for a given session
1354cf4e6363SMichael Chan  */
1355cf4e6363SMichael Chan static struct iscsi_cls_conn *
1356cf4e6363SMichael Chan bnx2i_conn_create(struct iscsi_cls_session *cls_session, uint32_t cid)
1357cf4e6363SMichael Chan {
1358cf4e6363SMichael Chan 	struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
1359cf4e6363SMichael Chan 	struct bnx2i_hba *hba = iscsi_host_priv(shost);
1360cf4e6363SMichael Chan 	struct bnx2i_conn *bnx2i_conn;
1361cf4e6363SMichael Chan 	struct iscsi_cls_conn *cls_conn;
1362cf4e6363SMichael Chan 	struct iscsi_conn *conn;
1363cf4e6363SMichael Chan 
1364cf4e6363SMichael Chan 	cls_conn = iscsi_conn_setup(cls_session, sizeof(*bnx2i_conn),
1365cf4e6363SMichael Chan 				    cid);
1366cf4e6363SMichael Chan 	if (!cls_conn)
1367cf4e6363SMichael Chan 		return NULL;
1368cf4e6363SMichael Chan 	conn = cls_conn->dd_data;
1369cf4e6363SMichael Chan 
1370cf4e6363SMichael Chan 	bnx2i_conn = conn->dd_data;
1371cf4e6363SMichael Chan 	bnx2i_conn->cls_conn = cls_conn;
1372cf4e6363SMichael Chan 	bnx2i_conn->hba = hba;
1373b5cf6b63SEddie Wai 
1374b5cf6b63SEddie Wai 	atomic_set(&bnx2i_conn->work_cnt, 0);
1375b5cf6b63SEddie Wai 
1376cf4e6363SMichael Chan 	/* 'ep' ptr will be assigned in bind() call */
1377cf4e6363SMichael Chan 	bnx2i_conn->ep = NULL;
1378cf4e6363SMichael Chan 	init_completion(&bnx2i_conn->cmd_cleanup_cmpl);
1379cf4e6363SMichael Chan 
1380cf4e6363SMichael Chan 	if (bnx2i_conn_alloc_login_resources(hba, bnx2i_conn)) {
1381cf4e6363SMichael Chan 		iscsi_conn_printk(KERN_ALERT, conn,
1382cf4e6363SMichael Chan 				  "conn_new: login resc alloc failed!!\n");
1383cf4e6363SMichael Chan 		goto free_conn;
1384cf4e6363SMichael Chan 	}
1385cf4e6363SMichael Chan 
1386cf4e6363SMichael Chan 	return cls_conn;
1387cf4e6363SMichael Chan 
1388cf4e6363SMichael Chan free_conn:
1389cf4e6363SMichael Chan 	iscsi_conn_teardown(cls_conn);
1390cf4e6363SMichael Chan 	return NULL;
1391cf4e6363SMichael Chan }
1392cf4e6363SMichael Chan 
1393cf4e6363SMichael Chan /**
1394cf4e6363SMichael Chan  * bnx2i_conn_bind - binds iscsi sess, conn and ep objects together
1395cf4e6363SMichael Chan  * @cls_session:	pointer to iscsi cls session
1396cf4e6363SMichael Chan  * @cls_conn:		pointer to iscsi cls conn
1397cf4e6363SMichael Chan  * @transport_fd:	64-bit EP handle
1398cf4e6363SMichael Chan  * @is_leading:		leading connection on this session?
1399cf4e6363SMichael Chan  *
1400cf4e6363SMichael Chan  * Binds together iSCSI session instance, iSCSI connection instance
1401cf4e6363SMichael Chan  *	and the TCP connection. This routine returns error code if
1402cf4e6363SMichael Chan  *	TCP connection does not belong on the device iSCSI sess/conn
1403cf4e6363SMichael Chan  *	is bound
1404cf4e6363SMichael Chan  */
1405cf4e6363SMichael Chan static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session,
1406cf4e6363SMichael Chan 			   struct iscsi_cls_conn *cls_conn,
1407cf4e6363SMichael Chan 			   uint64_t transport_fd, int is_leading)
1408cf4e6363SMichael Chan {
1409cf4e6363SMichael Chan 	struct iscsi_conn *conn = cls_conn->dd_data;
1410cf4e6363SMichael Chan 	struct bnx2i_conn *bnx2i_conn = conn->dd_data;
1411cf4e6363SMichael Chan 	struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
1412cf4e6363SMichael Chan 	struct bnx2i_hba *hba = iscsi_host_priv(shost);
1413cf4e6363SMichael Chan 	struct bnx2i_endpoint *bnx2i_ep;
1414cf4e6363SMichael Chan 	struct iscsi_endpoint *ep;
1415cf4e6363SMichael Chan 	int ret_code;
1416cf4e6363SMichael Chan 
1417cf4e6363SMichael Chan 	ep = iscsi_lookup_endpoint(transport_fd);
1418cf4e6363SMichael Chan 	if (!ep)
1419cf4e6363SMichael Chan 		return -EINVAL;
1420842158d7SEddie Wai 	/*
1421842158d7SEddie Wai 	 * Forcefully terminate all in progress connection recovery at the
1422842158d7SEddie Wai 	 * earliest, either in bind(), send_pdu(LOGIN), or conn_start()
1423842158d7SEddie Wai 	 */
1424842158d7SEddie Wai 	if (bnx2i_adapter_ready(hba))
1425842158d7SEddie Wai 		return -EIO;
1426cf4e6363SMichael Chan 
1427cf4e6363SMichael Chan 	bnx2i_ep = ep->dd_data;
1428cf4e6363SMichael Chan 	if ((bnx2i_ep->state == EP_STATE_TCP_FIN_RCVD) ||
1429cf4e6363SMichael Chan 	    (bnx2i_ep->state == EP_STATE_TCP_RST_RCVD))
1430cf4e6363SMichael Chan 		/* Peer disconnect via' FIN or RST */
1431cf4e6363SMichael Chan 		return -EINVAL;
1432cf4e6363SMichael Chan 
1433cf4e6363SMichael Chan 	if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
1434cf4e6363SMichael Chan 		return -EINVAL;
1435cf4e6363SMichael Chan 
1436cf4e6363SMichael Chan 	if (bnx2i_ep->hba != hba) {
1437cf4e6363SMichael Chan 		/* Error - TCP connection does not belong to this device
1438cf4e6363SMichael Chan 		 */
1439cf4e6363SMichael Chan 		iscsi_conn_printk(KERN_ALERT, cls_conn->dd_data,
1440cf4e6363SMichael Chan 				  "conn bind, ep=0x%p (%s) does not",
1441cf4e6363SMichael Chan 				  bnx2i_ep, bnx2i_ep->hba->netdev->name);
1442cf4e6363SMichael Chan 		iscsi_conn_printk(KERN_ALERT, cls_conn->dd_data,
1443cf4e6363SMichael Chan 				  "belong to hba (%s)\n",
1444cf4e6363SMichael Chan 				  hba->netdev->name);
1445cf4e6363SMichael Chan 		return -EEXIST;
1446cf4e6363SMichael Chan 	}
1447cf4e6363SMichael Chan 	bnx2i_ep->conn = bnx2i_conn;
1448cf4e6363SMichael Chan 	bnx2i_conn->ep = bnx2i_ep;
1449cf4e6363SMichael Chan 	bnx2i_conn->iscsi_conn_cid = bnx2i_ep->ep_iscsi_cid;
1450cf4e6363SMichael Chan 	bnx2i_conn->fw_cid = bnx2i_ep->ep_cid;
1451cf4e6363SMichael Chan 
1452cf4e6363SMichael Chan 	ret_code = bnx2i_bind_conn_to_iscsi_cid(hba, bnx2i_conn,
1453cf4e6363SMichael Chan 						bnx2i_ep->ep_iscsi_cid);
1454cf4e6363SMichael Chan 
1455cf4e6363SMichael Chan 	/* 5706/5708/5709 FW takes RQ as full when initiated, but for 57710
1456cf4e6363SMichael Chan 	 * driver needs to explicitly replenish RQ index during setup.
1457cf4e6363SMichael Chan 	 */
1458cf4e6363SMichael Chan 	if (test_bit(BNX2I_NX2_DEV_57710, &bnx2i_ep->hba->cnic_dev_type))
1459cf4e6363SMichael Chan 		bnx2i_put_rq_buf(bnx2i_conn, 0);
1460cf4e6363SMichael Chan 
1461cf4e6363SMichael Chan 	bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE);
1462cf4e6363SMichael Chan 	return ret_code;
1463cf4e6363SMichael Chan }
1464cf4e6363SMichael Chan 
1465cf4e6363SMichael Chan 
1466cf4e6363SMichael Chan /**
1467cf4e6363SMichael Chan  * bnx2i_conn_destroy - destroy iscsi connection instance & release resources
1468cf4e6363SMichael Chan  * @cls_conn:	pointer to iscsi cls conn
1469cf4e6363SMichael Chan  *
1470cf4e6363SMichael Chan  * Destroy an iSCSI connection instance and release memory resources held by
1471cf4e6363SMichael Chan  *	this connection
1472cf4e6363SMichael Chan  */
1473cf4e6363SMichael Chan static void bnx2i_conn_destroy(struct iscsi_cls_conn *cls_conn)
1474cf4e6363SMichael Chan {
1475cf4e6363SMichael Chan 	struct iscsi_conn *conn = cls_conn->dd_data;
1476cf4e6363SMichael Chan 	struct bnx2i_conn *bnx2i_conn = conn->dd_data;
1477cf4e6363SMichael Chan 	struct Scsi_Host *shost;
1478cf4e6363SMichael Chan 	struct bnx2i_hba *hba;
1479b5cf6b63SEddie Wai 	struct bnx2i_work *work, *tmp;
1480b5cf6b63SEddie Wai 	unsigned cpu = 0;
1481b5cf6b63SEddie Wai 	struct bnx2i_percpu_s *p;
1482cf4e6363SMichael Chan 
1483cf4e6363SMichael Chan 	shost = iscsi_session_to_shost(iscsi_conn_to_session(cls_conn));
1484cf4e6363SMichael Chan 	hba = iscsi_host_priv(shost);
1485cf4e6363SMichael Chan 
1486cf4e6363SMichael Chan 	bnx2i_conn_free_login_resources(hba, bnx2i_conn);
1487b5cf6b63SEddie Wai 
1488b5cf6b63SEddie Wai 	if (atomic_read(&bnx2i_conn->work_cnt)) {
1489b5cf6b63SEddie Wai 		for_each_online_cpu(cpu) {
1490b5cf6b63SEddie Wai 			p = &per_cpu(bnx2i_percpu, cpu);
1491b5cf6b63SEddie Wai 			spin_lock_bh(&p->p_work_lock);
1492b5cf6b63SEddie Wai 			list_for_each_entry_safe(work, tmp,
1493b5cf6b63SEddie Wai 						 &p->work_list, list) {
1494b5cf6b63SEddie Wai 				if (work->session == conn->session &&
1495b5cf6b63SEddie Wai 				    work->bnx2i_conn == bnx2i_conn) {
1496b5cf6b63SEddie Wai 					list_del_init(&work->list);
1497b5cf6b63SEddie Wai 					kfree(work);
1498b5cf6b63SEddie Wai 					if (!atomic_dec_and_test(
1499b5cf6b63SEddie Wai 							&bnx2i_conn->work_cnt))
1500b5cf6b63SEddie Wai 						break;
1501b5cf6b63SEddie Wai 				}
1502b5cf6b63SEddie Wai 			}
1503b5cf6b63SEddie Wai 			spin_unlock_bh(&p->p_work_lock);
1504b5cf6b63SEddie Wai 		}
1505b5cf6b63SEddie Wai 	}
1506b5cf6b63SEddie Wai 
1507cf4e6363SMichael Chan 	iscsi_conn_teardown(cls_conn);
1508cf4e6363SMichael Chan }
1509cf4e6363SMichael Chan 
1510cf4e6363SMichael Chan 
1511cf4e6363SMichael Chan /**
1512d8585bcdSMike Christie  * bnx2i_ep_get_param - return iscsi ep parameter to caller
1513d8585bcdSMike Christie  * @ep:		pointer to iscsi endpoint
1514cf4e6363SMichael Chan  * @param:	parameter type identifier
1515cf4e6363SMichael Chan  * @buf: 	buffer pointer
1516cf4e6363SMichael Chan  *
1517d8585bcdSMike Christie  * returns iSCSI ep parameters
1518cf4e6363SMichael Chan  */
1519d8585bcdSMike Christie static int bnx2i_ep_get_param(struct iscsi_endpoint *ep,
1520cf4e6363SMichael Chan 			      enum iscsi_param param, char *buf)
1521cf4e6363SMichael Chan {
1522d8585bcdSMike Christie 	struct bnx2i_endpoint *bnx2i_ep = ep->dd_data;
1523d8585bcdSMike Christie 	struct bnx2i_hba *hba = bnx2i_ep->hba;
1524d8585bcdSMike Christie 	int len = -ENOTCONN;
1525cf4e6363SMichael Chan 
1526d8585bcdSMike Christie 	if (!hba)
1527d8585bcdSMike Christie 		return -ENOTCONN;
15287a2962c7SEddie Wai 
1529cf4e6363SMichael Chan 	switch (param) {
1530cf4e6363SMichael Chan 	case ISCSI_PARAM_CONN_PORT:
1531d8585bcdSMike Christie 		mutex_lock(&hba->net_dev_lock);
1532d8585bcdSMike Christie 		if (bnx2i_ep->cm_sk)
1533d8585bcdSMike Christie 			len = sprintf(buf, "%hu\n", bnx2i_ep->cm_sk->dst_port);
1534d8585bcdSMike Christie 		mutex_unlock(&hba->net_dev_lock);
1535cf4e6363SMichael Chan 		break;
1536cf4e6363SMichael Chan 	case ISCSI_PARAM_CONN_ADDRESS:
1537d8585bcdSMike Christie 		mutex_lock(&hba->net_dev_lock);
1538d8585bcdSMike Christie 		if (bnx2i_ep->cm_sk)
1539d8585bcdSMike Christie 			len = sprintf(buf, "%pI4\n", &bnx2i_ep->cm_sk->dst_ip);
1540d8585bcdSMike Christie 		mutex_unlock(&hba->net_dev_lock);
1541cf4e6363SMichael Chan 		break;
1542cf4e6363SMichael Chan 	default:
1543d8585bcdSMike Christie 		return -ENOSYS;
1544cf4e6363SMichael Chan 	}
1545d8585bcdSMike Christie 
1546cf4e6363SMichael Chan 	return len;
1547cf4e6363SMichael Chan }
1548cf4e6363SMichael Chan 
1549cf4e6363SMichael Chan /**
1550cf4e6363SMichael Chan  * bnx2i_host_get_param - returns host (adapter) related parameters
1551cf4e6363SMichael Chan  * @shost:	scsi host pointer
1552cf4e6363SMichael Chan  * @param:	parameter type identifier
1553cf4e6363SMichael Chan  * @buf:	buffer pointer
1554cf4e6363SMichael Chan  */
1555cf4e6363SMichael Chan static int bnx2i_host_get_param(struct Scsi_Host *shost,
1556cf4e6363SMichael Chan 				enum iscsi_host_param param, char *buf)
1557cf4e6363SMichael Chan {
1558cf4e6363SMichael Chan 	struct bnx2i_hba *hba = iscsi_host_priv(shost);
1559cf4e6363SMichael Chan 	int len = 0;
1560cf4e6363SMichael Chan 
1561cf4e6363SMichael Chan 	switch (param) {
1562cf4e6363SMichael Chan 	case ISCSI_HOST_PARAM_HWADDRESS:
1563cf4e6363SMichael Chan 		len = sysfs_format_mac(buf, hba->cnic->mac_addr, 6);
1564cf4e6363SMichael Chan 		break;
1565cf4e6363SMichael Chan 	case ISCSI_HOST_PARAM_NETDEV_NAME:
1566cf4e6363SMichael Chan 		len = sprintf(buf, "%s\n", hba->netdev->name);
1567cf4e6363SMichael Chan 		break;
1568625986c2SMichael Chan 	case ISCSI_HOST_PARAM_IPADDRESS: {
1569625986c2SMichael Chan 		struct list_head *active_list = &hba->ep_active_list;
1570625986c2SMichael Chan 
1571625986c2SMichael Chan 		read_lock_bh(&hba->ep_rdwr_lock);
1572625986c2SMichael Chan 		if (!list_empty(&hba->ep_active_list)) {
1573625986c2SMichael Chan 			struct bnx2i_endpoint *bnx2i_ep;
1574625986c2SMichael Chan 			struct cnic_sock *csk;
1575625986c2SMichael Chan 
1576625986c2SMichael Chan 			bnx2i_ep = list_first_entry(active_list,
1577625986c2SMichael Chan 						    struct bnx2i_endpoint,
1578625986c2SMichael Chan 						    link);
1579625986c2SMichael Chan 			csk = bnx2i_ep->cm_sk;
1580625986c2SMichael Chan 			if (test_bit(SK_F_IPV6, &csk->flags))
1581625986c2SMichael Chan 				len = sprintf(buf, "%pI6\n", csk->src_ip);
1582625986c2SMichael Chan 			else
1583625986c2SMichael Chan 				len = sprintf(buf, "%pI4\n", csk->src_ip);
1584625986c2SMichael Chan 		}
1585625986c2SMichael Chan 		read_unlock_bh(&hba->ep_rdwr_lock);
1586625986c2SMichael Chan 		break;
1587625986c2SMichael Chan 	}
1588cf4e6363SMichael Chan 	default:
1589cf4e6363SMichael Chan 		return iscsi_host_get_param(shost, param, buf);
1590cf4e6363SMichael Chan 	}
1591cf4e6363SMichael Chan 	return len;
1592cf4e6363SMichael Chan }
1593cf4e6363SMichael Chan 
1594cf4e6363SMichael Chan /**
1595cf4e6363SMichael Chan  * bnx2i_conn_start - completes iscsi connection migration to FFP
1596cf4e6363SMichael Chan  * @cls_conn:	pointer to iscsi cls conn
1597cf4e6363SMichael Chan  *
1598cf4e6363SMichael Chan  * last call in FFP migration to handover iscsi conn to the driver
1599cf4e6363SMichael Chan  */
1600cf4e6363SMichael Chan static int bnx2i_conn_start(struct iscsi_cls_conn *cls_conn)
1601cf4e6363SMichael Chan {
1602cf4e6363SMichael Chan 	struct iscsi_conn *conn = cls_conn->dd_data;
1603cf4e6363SMichael Chan 	struct bnx2i_conn *bnx2i_conn = conn->dd_data;
1604cf4e6363SMichael Chan 
1605cf4e6363SMichael Chan 	bnx2i_conn->ep->state = EP_STATE_ULP_UPDATE_START;
1606cf4e6363SMichael Chan 	bnx2i_update_iscsi_conn(conn);
1607cf4e6363SMichael Chan 
1608cf4e6363SMichael Chan 	/*
1609cf4e6363SMichael Chan 	 * this should normally not sleep for a long time so it should
1610cf4e6363SMichael Chan 	 * not disrupt the caller.
1611cf4e6363SMichael Chan 	 */
1612cf4e6363SMichael Chan 	bnx2i_conn->ep->ofld_timer.expires = 1 * HZ + jiffies;
1613cf4e6363SMichael Chan 	bnx2i_conn->ep->ofld_timer.function = bnx2i_ep_ofld_timer;
1614cf4e6363SMichael Chan 	bnx2i_conn->ep->ofld_timer.data = (unsigned long) bnx2i_conn->ep;
1615cf4e6363SMichael Chan 	add_timer(&bnx2i_conn->ep->ofld_timer);
1616cf4e6363SMichael Chan 	/* update iSCSI context for this conn, wait for CNIC to complete */
1617cf4e6363SMichael Chan 	wait_event_interruptible(bnx2i_conn->ep->ofld_wait,
1618cf4e6363SMichael Chan 			bnx2i_conn->ep->state != EP_STATE_ULP_UPDATE_START);
1619cf4e6363SMichael Chan 
1620cf4e6363SMichael Chan 	if (signal_pending(current))
1621cf4e6363SMichael Chan 		flush_signals(current);
1622cf4e6363SMichael Chan 	del_timer_sync(&bnx2i_conn->ep->ofld_timer);
1623cf4e6363SMichael Chan 
1624cf4e6363SMichael Chan 	iscsi_conn_start(cls_conn);
1625cf4e6363SMichael Chan 	return 0;
1626cf4e6363SMichael Chan }
1627cf4e6363SMichael Chan 
1628cf4e6363SMichael Chan 
1629cf4e6363SMichael Chan /**
1630cf4e6363SMichael Chan  * bnx2i_conn_get_stats - returns iSCSI stats
1631cf4e6363SMichael Chan  * @cls_conn:	pointer to iscsi cls conn
1632cf4e6363SMichael Chan  * @stats:	pointer to iscsi statistic struct
1633cf4e6363SMichael Chan  */
1634cf4e6363SMichael Chan static void bnx2i_conn_get_stats(struct iscsi_cls_conn *cls_conn,
1635cf4e6363SMichael Chan 				 struct iscsi_stats *stats)
1636cf4e6363SMichael Chan {
1637cf4e6363SMichael Chan 	struct iscsi_conn *conn = cls_conn->dd_data;
1638cf4e6363SMichael Chan 
1639cf4e6363SMichael Chan 	stats->txdata_octets = conn->txdata_octets;
1640cf4e6363SMichael Chan 	stats->rxdata_octets = conn->rxdata_octets;
1641cf4e6363SMichael Chan 	stats->scsicmd_pdus = conn->scsicmd_pdus_cnt;
1642cf4e6363SMichael Chan 	stats->dataout_pdus = conn->dataout_pdus_cnt;
1643cf4e6363SMichael Chan 	stats->scsirsp_pdus = conn->scsirsp_pdus_cnt;
1644cf4e6363SMichael Chan 	stats->datain_pdus = conn->datain_pdus_cnt;
1645cf4e6363SMichael Chan 	stats->r2t_pdus = conn->r2t_pdus_cnt;
1646cf4e6363SMichael Chan 	stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt;
1647cf4e6363SMichael Chan 	stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt;
1648cf4e6363SMichael Chan 	stats->digest_err = 0;
1649cf4e6363SMichael Chan 	stats->timeout_err = 0;
1650915aafd8SMike Christie 	strcpy(stats->custom[0].desc, "eh_abort_cnt");
1651915aafd8SMike Christie 	stats->custom[0].value = conn->eh_abort_cnt;
1652915aafd8SMike Christie 	stats->custom_length = 1;
1653cf4e6363SMichael Chan }
1654cf4e6363SMichael Chan 
1655cf4e6363SMichael Chan 
1656cf4e6363SMichael Chan /**
1657cf4e6363SMichael Chan  * bnx2i_check_route - checks if target IP route belongs to one of NX2 devices
1658cf4e6363SMichael Chan  * @dst_addr:	target IP address
1659cf4e6363SMichael Chan  *
1660cf4e6363SMichael Chan  * check if route resolves to BNX2 device
1661cf4e6363SMichael Chan  */
1662cf4e6363SMichael Chan static struct bnx2i_hba *bnx2i_check_route(struct sockaddr *dst_addr)
1663cf4e6363SMichael Chan {
1664cf4e6363SMichael Chan 	struct sockaddr_in *desti = (struct sockaddr_in *) dst_addr;
1665cf4e6363SMichael Chan 	struct bnx2i_hba *hba;
1666cf4e6363SMichael Chan 	struct cnic_dev *cnic = NULL;
1667cf4e6363SMichael Chan 
1668cf4e6363SMichael Chan 	hba = get_adapter_list_head();
1669cf4e6363SMichael Chan 	if (hba && hba->cnic)
1670cf4e6363SMichael Chan 		cnic = hba->cnic->cm_select_dev(desti, CNIC_ULP_ISCSI);
1671cf4e6363SMichael Chan 	if (!cnic) {
1672cf4e6363SMichael Chan 		printk(KERN_ALERT "bnx2i: no route,"
1673cf4e6363SMichael Chan 		       "can't connect using cnic\n");
1674cf4e6363SMichael Chan 		goto no_nx2_route;
1675cf4e6363SMichael Chan 	}
1676cf4e6363SMichael Chan 	hba = bnx2i_find_hba_for_cnic(cnic);
1677cf4e6363SMichael Chan 	if (!hba)
1678cf4e6363SMichael Chan 		goto no_nx2_route;
1679cf4e6363SMichael Chan 
1680cf4e6363SMichael Chan 	if (bnx2i_adapter_ready(hba)) {
1681cf4e6363SMichael Chan 		printk(KERN_ALERT "bnx2i: check route, hba not found\n");
1682cf4e6363SMichael Chan 		goto no_nx2_route;
1683cf4e6363SMichael Chan 	}
1684cf4e6363SMichael Chan 	if (hba->netdev->mtu > hba->mtu_supported) {
1685cf4e6363SMichael Chan 		printk(KERN_ALERT "bnx2i: %s network i/f mtu is set to %d\n",
1686cf4e6363SMichael Chan 				  hba->netdev->name, hba->netdev->mtu);
1687cf4e6363SMichael Chan 		printk(KERN_ALERT "bnx2i: iSCSI HBA can support mtu of %d\n",
1688cf4e6363SMichael Chan 				  hba->mtu_supported);
1689cf4e6363SMichael Chan 		goto no_nx2_route;
1690cf4e6363SMichael Chan 	}
1691cf4e6363SMichael Chan 	return hba;
1692cf4e6363SMichael Chan no_nx2_route:
1693cf4e6363SMichael Chan 	return NULL;
1694cf4e6363SMichael Chan }
1695cf4e6363SMichael Chan 
1696cf4e6363SMichael Chan 
1697cf4e6363SMichael Chan /**
1698cf4e6363SMichael Chan  * bnx2i_tear_down_conn - tear down iscsi/tcp connection and free resources
1699cf4e6363SMichael Chan  * @hba:	pointer to adapter instance
17003f79410cSMaxime Jayat  * @ep:		endpoint (transport identifier) structure
1701cf4e6363SMichael Chan  *
1702cf4e6363SMichael Chan  * destroys cm_sock structure and on chip iscsi context
1703cf4e6363SMichael Chan  */
1704cf4e6363SMichael Chan static int bnx2i_tear_down_conn(struct bnx2i_hba *hba,
1705cf4e6363SMichael Chan 				 struct bnx2i_endpoint *ep)
1706cf4e6363SMichael Chan {
17075bf3f39fSEddie Wai 	if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic) && ep->cm_sk)
1708cf4e6363SMichael Chan 		hba->cnic->cm_destroy(ep->cm_sk);
1709cf4e6363SMichael Chan 
1710cf4e6363SMichael Chan 	if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type) &&
1711cf4e6363SMichael Chan 	    ep->state == EP_STATE_DISCONN_TIMEDOUT) {
17125bf3f39fSEddie Wai 		if (ep->conn && ep->conn->cls_conn &&
17135bf3f39fSEddie Wai 		    ep->conn->cls_conn->dd_data) {
17145bf3f39fSEddie Wai 			struct iscsi_conn *conn = ep->conn->cls_conn->dd_data;
17155bf3f39fSEddie Wai 
17165bf3f39fSEddie Wai 			/* Must suspend all rx queue activity for this ep */
17175bf3f39fSEddie Wai 			set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
17185bf3f39fSEddie Wai 		}
17195bf3f39fSEddie Wai 		/* CONN_DISCONNECT timeout may or may not be an issue depending
17205bf3f39fSEddie Wai 		 * on what transcribed in TCP layer, different targets behave
17215bf3f39fSEddie Wai 		 * differently
17225bf3f39fSEddie Wai 		 */
17235bf3f39fSEddie Wai 		printk(KERN_ALERT "bnx2i (%s): - WARN - CONN_DISCON timed out, "
17245bf3f39fSEddie Wai 				  "please submit GRC Dump, NW/PCIe trace, "
17255bf3f39fSEddie Wai 				  "driver msgs to developers for analysis\n",
17265bf3f39fSEddie Wai 				  hba->netdev->name);
1727cf4e6363SMichael Chan 	}
1728cf4e6363SMichael Chan 
1729cf4e6363SMichael Chan 	ep->state = EP_STATE_CLEANUP_START;
1730cf4e6363SMichael Chan 	init_timer(&ep->ofld_timer);
1731e37d2c47SEddie Wai 	ep->ofld_timer.expires = hba->conn_ctx_destroy_tmo + jiffies;
1732cf4e6363SMichael Chan 	ep->ofld_timer.function = bnx2i_ep_ofld_timer;
1733cf4e6363SMichael Chan 	ep->ofld_timer.data = (unsigned long) ep;
1734cf4e6363SMichael Chan 	add_timer(&ep->ofld_timer);
1735cf4e6363SMichael Chan 
1736cf4e6363SMichael Chan 	bnx2i_ep_destroy_list_add(hba, ep);
1737cf4e6363SMichael Chan 
1738cf4e6363SMichael Chan 	/* destroy iSCSI context, wait for it to complete */
1739bee34877SEddie Wai 	if (bnx2i_send_conn_destroy(hba, ep))
1740bee34877SEddie Wai 		ep->state = EP_STATE_CLEANUP_CMPL;
1741bee34877SEddie Wai 
1742cf4e6363SMichael Chan 	wait_event_interruptible(ep->ofld_wait,
1743cf4e6363SMichael Chan 				 (ep->state != EP_STATE_CLEANUP_START));
1744cf4e6363SMichael Chan 
1745cf4e6363SMichael Chan 	if (signal_pending(current))
1746cf4e6363SMichael Chan 		flush_signals(current);
1747cf4e6363SMichael Chan 	del_timer_sync(&ep->ofld_timer);
1748cf4e6363SMichael Chan 
1749cf4e6363SMichael Chan 	bnx2i_ep_destroy_list_del(hba, ep);
1750cf4e6363SMichael Chan 
1751cf4e6363SMichael Chan 	if (ep->state != EP_STATE_CLEANUP_CMPL)
1752cf4e6363SMichael Chan 		/* should never happen */
1753cf4e6363SMichael Chan 		printk(KERN_ALERT "bnx2i - conn destroy failed\n");
1754cf4e6363SMichael Chan 
1755cf4e6363SMichael Chan 	return 0;
1756cf4e6363SMichael Chan }
1757cf4e6363SMichael Chan 
1758cf4e6363SMichael Chan 
1759cf4e6363SMichael Chan /**
1760cf4e6363SMichael Chan  * bnx2i_ep_connect - establish TCP connection to target portal
1761cf4e6363SMichael Chan  * @shost:		scsi host
1762cf4e6363SMichael Chan  * @dst_addr:		target IP address
1763cf4e6363SMichael Chan  * @non_blocking:	blocking or non-blocking call
1764cf4e6363SMichael Chan  *
1765cf4e6363SMichael Chan  * this routine initiates the TCP/IP connection by invoking Option-2 i/f
1766cf4e6363SMichael Chan  *	with l5_core and the CNIC. This is a multi-step process of resolving
1767cf4e6363SMichael Chan  *	route to target, create a iscsi connection context, handshaking with
1768cf4e6363SMichael Chan  *	CNIC module to create/initialize the socket struct and finally
1769cf4e6363SMichael Chan  *	sending down option-2 request to complete TCP 3-way handshake
1770cf4e6363SMichael Chan  */
1771cf4e6363SMichael Chan static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
1772cf4e6363SMichael Chan 					       struct sockaddr *dst_addr,
1773cf4e6363SMichael Chan 					       int non_blocking)
1774cf4e6363SMichael Chan {
1775cf4e6363SMichael Chan 	u32 iscsi_cid = BNX2I_CID_RESERVED;
1776cf4e6363SMichael Chan 	struct sockaddr_in *desti = (struct sockaddr_in *) dst_addr;
1777cf4e6363SMichael Chan 	struct sockaddr_in6 *desti6;
1778cf4e6363SMichael Chan 	struct bnx2i_endpoint *bnx2i_ep;
1779cf4e6363SMichael Chan 	struct bnx2i_hba *hba;
1780cf4e6363SMichael Chan 	struct cnic_dev *cnic;
1781cf4e6363SMichael Chan 	struct cnic_sockaddr saddr;
1782cf4e6363SMichael Chan 	struct iscsi_endpoint *ep;
1783cf4e6363SMichael Chan 	int rc = 0;
1784cf4e6363SMichael Chan 
1785fac3cc45SAnil Veerabhadrappa 	if (shost) {
1786cf4e6363SMichael Chan 		/* driver is given scsi host to work with */
1787cf4e6363SMichael Chan 		hba = iscsi_host_priv(shost);
1788fac3cc45SAnil Veerabhadrappa 	} else
1789cf4e6363SMichael Chan 		/*
1790cf4e6363SMichael Chan 		 * check if the given destination can be reached through
1791cf4e6363SMichael Chan 		 * a iscsi capable NetXtreme2 device
1792cf4e6363SMichael Chan 		 */
1793cf4e6363SMichael Chan 		hba = bnx2i_check_route(dst_addr);
1794fac3cc45SAnil Veerabhadrappa 
1795a91031a6SEddie Wai 	if (!hba) {
1796490475a9SAnil Veerabhadrappa 		rc = -EINVAL;
179755e15c97SEddie Wai 		goto nohba;
1798cf4e6363SMichael Chan 	}
179955e15c97SEddie Wai 	mutex_lock(&hba->net_dev_lock);
1800a91031a6SEddie Wai 
1801a91031a6SEddie Wai 	if (bnx2i_adapter_ready(hba) || !hba->cid_que.cid_free_cnt) {
1802a91031a6SEddie Wai 		rc = -EPERM;
1803a91031a6SEddie Wai 		goto check_busy;
1804a91031a6SEddie Wai 	}
1805a91031a6SEddie Wai 	cnic = hba->cnic;
1806cf4e6363SMichael Chan 	ep = bnx2i_alloc_ep(hba);
1807cf4e6363SMichael Chan 	if (!ep) {
1808cf4e6363SMichael Chan 		rc = -ENOMEM;
1809cf4e6363SMichael Chan 		goto check_busy;
1810cf4e6363SMichael Chan 	}
1811cf4e6363SMichael Chan 	bnx2i_ep = ep->dd_data;
1812cf4e6363SMichael Chan 
1813b5cf6b63SEddie Wai 	atomic_set(&bnx2i_ep->num_active_cmds, 0);
1814cf4e6363SMichael Chan 	iscsi_cid = bnx2i_alloc_iscsi_cid(hba);
1815cf4e6363SMichael Chan 	if (iscsi_cid == -1) {
1816a91031a6SEddie Wai 		printk(KERN_ALERT "bnx2i (%s): alloc_ep - unable to allocate "
1817a91031a6SEddie Wai 			"iscsi cid\n", hba->netdev->name);
1818cf4e6363SMichael Chan 		rc = -ENOMEM;
1819a91031a6SEddie Wai 		bnx2i_free_ep(ep);
1820a91031a6SEddie Wai 		goto check_busy;
1821cf4e6363SMichael Chan 	}
1822cf4e6363SMichael Chan 	bnx2i_ep->hba_age = hba->age;
1823cf4e6363SMichael Chan 
1824cf4e6363SMichael Chan 	rc = bnx2i_alloc_qp_resc(hba, bnx2i_ep);
1825cf4e6363SMichael Chan 	if (rc != 0) {
1826a91031a6SEddie Wai 		printk(KERN_ALERT "bnx2i (%s): ep_conn - alloc QP resc error"
1827a91031a6SEddie Wai 			"\n", hba->netdev->name);
1828cf4e6363SMichael Chan 		rc = -ENOMEM;
1829cf4e6363SMichael Chan 		goto qp_resc_err;
1830cf4e6363SMichael Chan 	}
1831cf4e6363SMichael Chan 
1832cf4e6363SMichael Chan 	bnx2i_ep->ep_iscsi_cid = (u16)iscsi_cid;
1833cf4e6363SMichael Chan 	bnx2i_ep->state = EP_STATE_OFLD_START;
1834cf4e6363SMichael Chan 	bnx2i_ep_ofld_list_add(hba, bnx2i_ep);
1835cf4e6363SMichael Chan 
1836cf4e6363SMichael Chan 	init_timer(&bnx2i_ep->ofld_timer);
1837cf4e6363SMichael Chan 	bnx2i_ep->ofld_timer.expires = 2 * HZ + jiffies;
1838cf4e6363SMichael Chan 	bnx2i_ep->ofld_timer.function = bnx2i_ep_ofld_timer;
1839cf4e6363SMichael Chan 	bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep;
1840cf4e6363SMichael Chan 	add_timer(&bnx2i_ep->ofld_timer);
1841cf4e6363SMichael Chan 
1842bee34877SEddie Wai 	if (bnx2i_send_conn_ofld_req(hba, bnx2i_ep)) {
1843bee34877SEddie Wai 		if (bnx2i_ep->state == EP_STATE_OFLD_FAILED_CID_BUSY) {
1844bee34877SEddie Wai 			printk(KERN_ALERT "bnx2i (%s): iscsi cid %d is busy\n",
1845bee34877SEddie Wai 				hba->netdev->name, bnx2i_ep->ep_iscsi_cid);
1846bee34877SEddie Wai 			rc = -EBUSY;
1847bee34877SEddie Wai 		} else
1848bee34877SEddie Wai 			rc = -ENOSPC;
1849bee34877SEddie Wai 		printk(KERN_ALERT "bnx2i (%s): unable to send conn offld kwqe"
1850bee34877SEddie Wai 			"\n", hba->netdev->name);
1851bee34877SEddie Wai 		bnx2i_ep_ofld_list_del(hba, bnx2i_ep);
1852bee34877SEddie Wai 		goto conn_failed;
1853bee34877SEddie Wai 	}
1854cf4e6363SMichael Chan 
1855cf4e6363SMichael Chan 	/* Wait for CNIC hardware to setup conn context and return 'cid' */
1856cf4e6363SMichael Chan 	wait_event_interruptible(bnx2i_ep->ofld_wait,
1857cf4e6363SMichael Chan 				 bnx2i_ep->state != EP_STATE_OFLD_START);
1858cf4e6363SMichael Chan 
1859cf4e6363SMichael Chan 	if (signal_pending(current))
1860cf4e6363SMichael Chan 		flush_signals(current);
1861cf4e6363SMichael Chan 	del_timer_sync(&bnx2i_ep->ofld_timer);
1862cf4e6363SMichael Chan 
1863cf4e6363SMichael Chan 	bnx2i_ep_ofld_list_del(hba, bnx2i_ep);
1864cf4e6363SMichael Chan 
1865cf4e6363SMichael Chan 	if (bnx2i_ep->state != EP_STATE_OFLD_COMPL) {
1866a91031a6SEddie Wai 		if (bnx2i_ep->state == EP_STATE_OFLD_FAILED_CID_BUSY) {
1867a91031a6SEddie Wai 			printk(KERN_ALERT "bnx2i (%s): iscsi cid %d is busy\n",
1868a91031a6SEddie Wai 				hba->netdev->name, bnx2i_ep->ep_iscsi_cid);
1869a91031a6SEddie Wai 			rc = -EBUSY;
1870a91031a6SEddie Wai 		} else
1871cf4e6363SMichael Chan 			rc = -ENOSPC;
1872cf4e6363SMichael Chan 		goto conn_failed;
1873cf4e6363SMichael Chan 	}
1874cf4e6363SMichael Chan 
1875cf4e6363SMichael Chan 	rc = cnic->cm_create(cnic, CNIC_ULP_ISCSI, bnx2i_ep->ep_cid,
1876cf4e6363SMichael Chan 			     iscsi_cid, &bnx2i_ep->cm_sk, bnx2i_ep);
1877cf4e6363SMichael Chan 	if (rc) {
1878cf4e6363SMichael Chan 		rc = -EINVAL;
1879a91031a6SEddie Wai 		/* Need to terminate and cleanup the connection */
1880a91031a6SEddie Wai 		goto release_ep;
1881cf4e6363SMichael Chan 	}
1882cf4e6363SMichael Chan 
1883cf4e6363SMichael Chan 	bnx2i_ep->cm_sk->rcv_buf = 256 * 1024;
1884cf4e6363SMichael Chan 	bnx2i_ep->cm_sk->snd_buf = 256 * 1024;
1885cf4e6363SMichael Chan 	clear_bit(SK_TCP_TIMESTAMP, &bnx2i_ep->cm_sk->tcp_flags);
1886cf4e6363SMichael Chan 
1887cf4e6363SMichael Chan 	memset(&saddr, 0, sizeof(saddr));
1888cf4e6363SMichael Chan 	if (dst_addr->sa_family == AF_INET) {
1889cf4e6363SMichael Chan 		desti = (struct sockaddr_in *) dst_addr;
1890cf4e6363SMichael Chan 		saddr.remote.v4 = *desti;
1891cf4e6363SMichael Chan 		saddr.local.v4.sin_family = desti->sin_family;
1892cf4e6363SMichael Chan 	} else if (dst_addr->sa_family == AF_INET6) {
1893cf4e6363SMichael Chan 		desti6 = (struct sockaddr_in6 *) dst_addr;
1894cf4e6363SMichael Chan 		saddr.remote.v6 = *desti6;
1895cf4e6363SMichael Chan 		saddr.local.v6.sin6_family = desti6->sin6_family;
1896cf4e6363SMichael Chan 	}
1897cf4e6363SMichael Chan 
1898cf4e6363SMichael Chan 	bnx2i_ep->timestamp = jiffies;
1899cf4e6363SMichael Chan 	bnx2i_ep->state = EP_STATE_CONNECT_START;
1900cf4e6363SMichael Chan 	if (!test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
1901cf4e6363SMichael Chan 		rc = -EINVAL;
1902cf4e6363SMichael Chan 		goto conn_failed;
1903cf4e6363SMichael Chan 	} else
1904cf4e6363SMichael Chan 		rc = cnic->cm_connect(bnx2i_ep->cm_sk, &saddr);
1905cf4e6363SMichael Chan 	if (rc)
1906cf4e6363SMichael Chan 		goto release_ep;
1907cf4e6363SMichael Chan 
190846012e8bSEddie Wai 	bnx2i_ep_active_list_add(hba, bnx2i_ep);
190946012e8bSEddie Wai 
1910cf4e6363SMichael Chan 	if (bnx2i_map_ep_dbell_regs(bnx2i_ep))
191146012e8bSEddie Wai 		goto del_active_ep;
191246012e8bSEddie Wai 
1913cf4e6363SMichael Chan 	mutex_unlock(&hba->net_dev_lock);
1914cf4e6363SMichael Chan 	return ep;
1915cf4e6363SMichael Chan 
191646012e8bSEddie Wai del_active_ep:
191746012e8bSEddie Wai 	bnx2i_ep_active_list_del(hba, bnx2i_ep);
1918cf4e6363SMichael Chan release_ep:
1919cf4e6363SMichael Chan 	if (bnx2i_tear_down_conn(hba, bnx2i_ep)) {
1920cf4e6363SMichael Chan 		mutex_unlock(&hba->net_dev_lock);
1921cf4e6363SMichael Chan 		return ERR_PTR(rc);
1922cf4e6363SMichael Chan 	}
1923cf4e6363SMichael Chan conn_failed:
1924cf4e6363SMichael Chan 	bnx2i_free_qp_resc(hba, bnx2i_ep);
1925cf4e6363SMichael Chan qp_resc_err:
1926cf4e6363SMichael Chan 	bnx2i_free_ep(ep);
1927cf4e6363SMichael Chan check_busy:
192855e15c97SEddie Wai 	mutex_unlock(&hba->net_dev_lock);
192955e15c97SEddie Wai nohba:
1930cf4e6363SMichael Chan 	return ERR_PTR(rc);
1931cf4e6363SMichael Chan }
1932cf4e6363SMichael Chan 
1933cf4e6363SMichael Chan 
1934cf4e6363SMichael Chan /**
1935cf4e6363SMichael Chan  * bnx2i_ep_poll - polls for TCP connection establishement
1936cf4e6363SMichael Chan  * @ep:			TCP connection (endpoint) handle
1937cf4e6363SMichael Chan  * @timeout_ms:		timeout value in milli secs
1938cf4e6363SMichael Chan  *
1939cf4e6363SMichael Chan  * polls for TCP connect request to complete
1940cf4e6363SMichael Chan  */
1941cf4e6363SMichael Chan static int bnx2i_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)
1942cf4e6363SMichael Chan {
1943cf4e6363SMichael Chan 	struct bnx2i_endpoint *bnx2i_ep;
1944cf4e6363SMichael Chan 	int rc = 0;
1945cf4e6363SMichael Chan 
1946cf4e6363SMichael Chan 	bnx2i_ep = ep->dd_data;
1947cf4e6363SMichael Chan 	if ((bnx2i_ep->state == EP_STATE_IDLE) ||
1948cf4e6363SMichael Chan 	    (bnx2i_ep->state == EP_STATE_CONNECT_FAILED) ||
1949cf4e6363SMichael Chan 	    (bnx2i_ep->state == EP_STATE_OFLD_FAILED))
1950cf4e6363SMichael Chan 		return -1;
1951cf4e6363SMichael Chan 	if (bnx2i_ep->state == EP_STATE_CONNECT_COMPL)
1952cf4e6363SMichael Chan 		return 1;
1953cf4e6363SMichael Chan 
1954cf4e6363SMichael Chan 	rc = wait_event_interruptible_timeout(bnx2i_ep->ofld_wait,
1955cf4e6363SMichael Chan 					      ((bnx2i_ep->state ==
1956cf4e6363SMichael Chan 						EP_STATE_OFLD_FAILED) ||
1957cf4e6363SMichael Chan 					       (bnx2i_ep->state ==
1958cf4e6363SMichael Chan 						EP_STATE_CONNECT_FAILED) ||
1959cf4e6363SMichael Chan 					       (bnx2i_ep->state ==
1960cf4e6363SMichael Chan 						EP_STATE_CONNECT_COMPL)),
1961cf4e6363SMichael Chan 					      msecs_to_jiffies(timeout_ms));
1962490475a9SAnil Veerabhadrappa 	if (bnx2i_ep->state == EP_STATE_OFLD_FAILED)
1963cf4e6363SMichael Chan 		rc = -1;
1964cf4e6363SMichael Chan 
1965cf4e6363SMichael Chan 	if (rc > 0)
1966cf4e6363SMichael Chan 		return 1;
1967cf4e6363SMichael Chan 	else if (!rc)
1968cf4e6363SMichael Chan 		return 0;	/* timeout */
1969cf4e6363SMichael Chan 	else
1970cf4e6363SMichael Chan 		return rc;
1971cf4e6363SMichael Chan }
1972cf4e6363SMichael Chan 
1973cf4e6363SMichael Chan 
1974cf4e6363SMichael Chan /**
1975cf4e6363SMichael Chan  * bnx2i_ep_tcp_conn_active - check EP state transition
1976cf4e6363SMichael Chan  * @ep:		endpoint pointer
1977cf4e6363SMichael Chan  *
1978cf4e6363SMichael Chan  * check if underlying TCP connection is active
1979cf4e6363SMichael Chan  */
1980cf4e6363SMichael Chan static int bnx2i_ep_tcp_conn_active(struct bnx2i_endpoint *bnx2i_ep)
1981cf4e6363SMichael Chan {
1982cf4e6363SMichael Chan 	int ret;
1983cf4e6363SMichael Chan 	int cnic_dev_10g = 0;
1984cf4e6363SMichael Chan 
1985cf4e6363SMichael Chan 	if (test_bit(BNX2I_NX2_DEV_57710, &bnx2i_ep->hba->cnic_dev_type))
1986cf4e6363SMichael Chan 		cnic_dev_10g = 1;
1987cf4e6363SMichael Chan 
1988cf4e6363SMichael Chan 	switch (bnx2i_ep->state) {
1989cf4e6363SMichael Chan 	case EP_STATE_CLEANUP_FAILED:
1990cf4e6363SMichael Chan 	case EP_STATE_OFLD_FAILED:
1991cf4e6363SMichael Chan 	case EP_STATE_DISCONN_TIMEDOUT:
1992cf4e6363SMichael Chan 		ret = 0;
1993cf4e6363SMichael Chan 		break;
1994252e4480SEddie Wai 	case EP_STATE_CONNECT_START:
1995ec8933b4SEddie Wai 	case EP_STATE_CONNECT_FAILED:
1996cf4e6363SMichael Chan 	case EP_STATE_CONNECT_COMPL:
1997cf4e6363SMichael Chan 	case EP_STATE_ULP_UPDATE_START:
1998cf4e6363SMichael Chan 	case EP_STATE_ULP_UPDATE_COMPL:
1999cf4e6363SMichael Chan 	case EP_STATE_TCP_FIN_RCVD:
20002eefb20dSEddie Wai 	case EP_STATE_LOGOUT_SENT:
20012eefb20dSEddie Wai 	case EP_STATE_LOGOUT_RESP_RCVD:
2002cf4e6363SMichael Chan 	case EP_STATE_ULP_UPDATE_FAILED:
2003cf4e6363SMichael Chan 		ret = 1;
2004cf4e6363SMichael Chan 		break;
2005cf4e6363SMichael Chan 	case EP_STATE_TCP_RST_RCVD:
2006cf4e6363SMichael Chan 		if (cnic_dev_10g)
2007cf4e6363SMichael Chan 			ret = 0;
200894810e82SEddie Wai 		else
200994810e82SEddie Wai 			ret = 1;
2010cf4e6363SMichael Chan 		break;
2011cf4e6363SMichael Chan 	default:
2012cf4e6363SMichael Chan 		ret = 0;
2013cf4e6363SMichael Chan 	}
2014cf4e6363SMichael Chan 
2015cf4e6363SMichael Chan 	return ret;
2016cf4e6363SMichael Chan }
2017cf4e6363SMichael Chan 
2018cf4e6363SMichael Chan 
20196447f286SEddie Wai /*
20206447f286SEddie Wai  * bnx2i_hw_ep_disconnect - executes TCP connection teardown process in the hw
20216447f286SEddie Wai  * @ep:		TCP connection (bnx2i endpoint) handle
20226447f286SEddie Wai  *
20236447f286SEddie Wai  * executes  TCP connection teardown process
20246447f286SEddie Wai  */
20256447f286SEddie Wai int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep)
20266447f286SEddie Wai {
20276447f286SEddie Wai 	struct bnx2i_hba *hba = bnx2i_ep->hba;
20286447f286SEddie Wai 	struct cnic_dev *cnic;
20296447f286SEddie Wai 	struct iscsi_session *session = NULL;
20306447f286SEddie Wai 	struct iscsi_conn *conn = NULL;
20316447f286SEddie Wai 	int ret = 0;
20322eefb20dSEddie Wai 	int close = 0;
20332eefb20dSEddie Wai 	int close_ret = 0;
20346447f286SEddie Wai 
20356447f286SEddie Wai 	if (!hba)
20366447f286SEddie Wai 		return 0;
20376447f286SEddie Wai 
20386447f286SEddie Wai 	cnic = hba->cnic;
20396447f286SEddie Wai 	if (!cnic)
20406447f286SEddie Wai 		return 0;
20416447f286SEddie Wai 
2042a91031a6SEddie Wai 	if (bnx2i_ep->state == EP_STATE_IDLE ||
2043a91031a6SEddie Wai 	    bnx2i_ep->state == EP_STATE_DISCONN_TIMEDOUT)
2044250ae982SEddie Wai 		return 0;
2045250ae982SEddie Wai 
20466447f286SEddie Wai 	if (!bnx2i_ep_tcp_conn_active(bnx2i_ep))
20476447f286SEddie Wai 		goto destroy_conn;
20486447f286SEddie Wai 
20496447f286SEddie Wai 	if (bnx2i_ep->conn) {
20506447f286SEddie Wai 		conn = bnx2i_ep->conn->cls_conn->dd_data;
20516447f286SEddie Wai 		session = conn->session;
20526447f286SEddie Wai 	}
20536447f286SEddie Wai 
20546447f286SEddie Wai 	init_timer(&bnx2i_ep->ofld_timer);
2055e37d2c47SEddie Wai 	bnx2i_ep->ofld_timer.expires = hba->conn_teardown_tmo + jiffies;
20566447f286SEddie Wai 	bnx2i_ep->ofld_timer.function = bnx2i_ep_ofld_timer;
20576447f286SEddie Wai 	bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep;
20586447f286SEddie Wai 	add_timer(&bnx2i_ep->ofld_timer);
20596447f286SEddie Wai 
20602eefb20dSEddie Wai 	if (!test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic))
20612eefb20dSEddie Wai 		goto out;
20626447f286SEddie Wai 
20636447f286SEddie Wai 	if (session) {
2064659743b0SShlomo Pongratz 		spin_lock_bh(&session->frwd_lock);
20652eefb20dSEddie Wai 		if (bnx2i_ep->state != EP_STATE_TCP_FIN_RCVD) {
20662eefb20dSEddie Wai 			if (session->state == ISCSI_STATE_LOGGING_OUT) {
20672eefb20dSEddie Wai 				if (bnx2i_ep->state == EP_STATE_LOGOUT_SENT) {
20682eefb20dSEddie Wai 					/* Logout sent, but no resp */
2069a91031a6SEddie Wai 					printk(KERN_ALERT "bnx2i (%s): WARNING"
20702eefb20dSEddie Wai 						" logout response was not "
2071a91031a6SEddie Wai 						"received!\n",
2072a91031a6SEddie Wai 						bnx2i_ep->hba->netdev->name);
20732eefb20dSEddie Wai 				} else if (bnx2i_ep->state ==
20742eefb20dSEddie Wai 					   EP_STATE_LOGOUT_RESP_RCVD)
20756447f286SEddie Wai 					close = 1;
20762eefb20dSEddie Wai 			}
20772eefb20dSEddie Wai 		} else
20782eefb20dSEddie Wai 			close = 1;
20792eefb20dSEddie Wai 
2080659743b0SShlomo Pongratz 		spin_unlock_bh(&session->frwd_lock);
20816447f286SEddie Wai 	}
20822eefb20dSEddie Wai 
20832eefb20dSEddie Wai 	bnx2i_ep->state = EP_STATE_DISCONN_START;
20842eefb20dSEddie Wai 
20856447f286SEddie Wai 	if (close)
20866447f286SEddie Wai 		close_ret = cnic->cm_close(bnx2i_ep->cm_sk);
20876447f286SEddie Wai 	else
20886447f286SEddie Wai 		close_ret = cnic->cm_abort(bnx2i_ep->cm_sk);
20892eefb20dSEddie Wai 
20906447f286SEddie Wai 	if (close_ret)
2091a91031a6SEddie Wai 		printk(KERN_ALERT "bnx2i (%s): close/abort(%d) returned %d\n",
20922c2255e0SEddie Wai 			bnx2i_ep->hba->netdev->name, close, close_ret);
20932c2255e0SEddie Wai 	else
20946447f286SEddie Wai 		/* wait for option-2 conn teardown */
20956447f286SEddie Wai 		wait_event_interruptible(bnx2i_ep->ofld_wait,
20966447f286SEddie Wai 				 bnx2i_ep->state != EP_STATE_DISCONN_START);
20976447f286SEddie Wai 
20986447f286SEddie Wai 	if (signal_pending(current))
20996447f286SEddie Wai 		flush_signals(current);
21006447f286SEddie Wai 	del_timer_sync(&bnx2i_ep->ofld_timer);
21016447f286SEddie Wai 
21026447f286SEddie Wai destroy_conn:
210346012e8bSEddie Wai 	bnx2i_ep_active_list_del(hba, bnx2i_ep);
21046447f286SEddie Wai 	if (bnx2i_tear_down_conn(hba, bnx2i_ep))
2105a91031a6SEddie Wai 		return -EINVAL;
21066447f286SEddie Wai out:
21076447f286SEddie Wai 	bnx2i_ep->state = EP_STATE_IDLE;
21086447f286SEddie Wai 	return ret;
21096447f286SEddie Wai }
21106447f286SEddie Wai 
21116447f286SEddie Wai 
2112cf4e6363SMichael Chan /**
2113cf4e6363SMichael Chan  * bnx2i_ep_disconnect - executes TCP connection teardown process
21146447f286SEddie Wai  * @ep:		TCP connection (iscsi endpoint) handle
2115cf4e6363SMichael Chan  *
2116cf4e6363SMichael Chan  * executes  TCP connection teardown process
2117cf4e6363SMichael Chan  */
2118cf4e6363SMichael Chan static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep)
2119cf4e6363SMichael Chan {
2120cf4e6363SMichael Chan 	struct bnx2i_endpoint *bnx2i_ep;
2121cf4e6363SMichael Chan 	struct bnx2i_conn *bnx2i_conn = NULL;
21226447f286SEddie Wai 	struct iscsi_conn *conn = NULL;
2123cf4e6363SMichael Chan 	struct bnx2i_hba *hba;
2124cf4e6363SMichael Chan 
2125cf4e6363SMichael Chan 	bnx2i_ep = ep->dd_data;
2126cf4e6363SMichael Chan 
212794e2bd68SThadeu Lima de Souza Cascardo 	/* driver should not attempt connection cleanup until TCP_CONNECT
2128cf4e6363SMichael Chan 	 * completes either successfully or fails. Timeout is 9-secs, so
2129cf4e6363SMichael Chan 	 * wait for it to complete
2130cf4e6363SMichael Chan 	 */
2131cf4e6363SMichael Chan 	while ((bnx2i_ep->state == EP_STATE_CONNECT_START) &&
2132cf4e6363SMichael Chan 		!time_after(jiffies, bnx2i_ep->timestamp + (12 * HZ)))
2133cf4e6363SMichael Chan 		msleep(250);
2134cf4e6363SMichael Chan 
2135cf4e6363SMichael Chan 	if (bnx2i_ep->conn) {
2136cf4e6363SMichael Chan 		bnx2i_conn = bnx2i_ep->conn;
2137cf4e6363SMichael Chan 		conn = bnx2i_conn->cls_conn->dd_data;
213824246de7SMike Christie 		iscsi_suspend_queue(conn);
2139cf4e6363SMichael Chan 	}
2140cf4e6363SMichael Chan 	hba = bnx2i_ep->hba;
2141cf4e6363SMichael Chan 
2142cf4e6363SMichael Chan 	mutex_lock(&hba->net_dev_lock);
2143cf4e6363SMichael Chan 
2144a91031a6SEddie Wai 	if (bnx2i_ep->state == EP_STATE_DISCONN_TIMEDOUT)
2145a91031a6SEddie Wai 		goto out;
2146a91031a6SEddie Wai 
21476447f286SEddie Wai 	if (bnx2i_ep->state == EP_STATE_IDLE)
2148cf4e6363SMichael Chan 		goto free_resc;
21496447f286SEddie Wai 
2150a91031a6SEddie Wai 	if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) ||
2151a91031a6SEddie Wai 	    (bnx2i_ep->hba_age != hba->age)) {
2152a91031a6SEddie Wai 		bnx2i_ep_active_list_del(hba, bnx2i_ep);
2153cf4e6363SMichael Chan 		goto free_resc;
2154a91031a6SEddie Wai 	}
2155cf4e6363SMichael Chan 
21566447f286SEddie Wai 	/* Do all chip cleanup here */
21576447f286SEddie Wai 	if (bnx2i_hw_ep_disconnect(bnx2i_ep)) {
2158cf4e6363SMichael Chan 		mutex_unlock(&hba->net_dev_lock);
2159cf4e6363SMichael Chan 		return;
2160cf4e6363SMichael Chan 	}
2161cf4e6363SMichael Chan free_resc:
2162cf4e6363SMichael Chan 	bnx2i_free_qp_resc(hba, bnx2i_ep);
2163a91031a6SEddie Wai 
2164cf4e6363SMichael Chan 	if (bnx2i_conn)
2165cf4e6363SMichael Chan 		bnx2i_conn->ep = NULL;
2166cf4e6363SMichael Chan 
2167cf4e6363SMichael Chan 	bnx2i_free_ep(ep);
2168a91031a6SEddie Wai out:
21696447f286SEddie Wai 	mutex_unlock(&hba->net_dev_lock);
2170490475a9SAnil Veerabhadrappa 
2171490475a9SAnil Veerabhadrappa 	wake_up_interruptible(&hba->eh_wait);
2172cf4e6363SMichael Chan }
2173cf4e6363SMichael Chan 
2174cf4e6363SMichael Chan 
2175cf4e6363SMichael Chan /**
2176cf4e6363SMichael Chan  * bnx2i_nl_set_path - ISCSI_UEVENT_PATH_UPDATE user message handler
2177cf4e6363SMichael Chan  * @buf:	pointer to buffer containing iscsi path message
2178cf4e6363SMichael Chan  *
2179cf4e6363SMichael Chan  */
2180cf4e6363SMichael Chan static int bnx2i_nl_set_path(struct Scsi_Host *shost, struct iscsi_path *params)
2181cf4e6363SMichael Chan {
2182cf4e6363SMichael Chan 	struct bnx2i_hba *hba = iscsi_host_priv(shost);
2183cf4e6363SMichael Chan 	char *buf = (char *) params;
2184cf4e6363SMichael Chan 	u16 len = sizeof(*params);
2185cf4e6363SMichael Chan 
2186cf4e6363SMichael Chan 	/* handled by cnic driver */
2187cf4e6363SMichael Chan 	hba->cnic->iscsi_nl_msg_recv(hba->cnic, ISCSI_UEVENT_PATH_UPDATE, buf,
2188cf4e6363SMichael Chan 				     len);
2189cf4e6363SMichael Chan 
2190cf4e6363SMichael Chan 	return 0;
2191cf4e6363SMichael Chan }
2192cf4e6363SMichael Chan 
2193587a1f16SAl Viro static umode_t bnx2i_attr_is_visible(int param_type, int param)
21943128c6c7SMike Christie {
21953128c6c7SMike Christie 	switch (param_type) {
2196f27fb2efSMike Christie 	case ISCSI_HOST_PARAM:
2197f27fb2efSMike Christie 		switch (param) {
2198f27fb2efSMike Christie 		case ISCSI_HOST_PARAM_NETDEV_NAME:
2199f27fb2efSMike Christie 		case ISCSI_HOST_PARAM_HWADDRESS:
2200f27fb2efSMike Christie 		case ISCSI_HOST_PARAM_IPADDRESS:
2201f27fb2efSMike Christie 			return S_IRUGO;
2202f27fb2efSMike Christie 		default:
2203f27fb2efSMike Christie 			return 0;
2204f27fb2efSMike Christie 		}
22053128c6c7SMike Christie 	case ISCSI_PARAM:
22063128c6c7SMike Christie 		switch (param) {
22073128c6c7SMike Christie 		case ISCSI_PARAM_MAX_RECV_DLENGTH:
22083128c6c7SMike Christie 		case ISCSI_PARAM_MAX_XMIT_DLENGTH:
22093128c6c7SMike Christie 		case ISCSI_PARAM_HDRDGST_EN:
22103128c6c7SMike Christie 		case ISCSI_PARAM_DATADGST_EN:
22113128c6c7SMike Christie 		case ISCSI_PARAM_CONN_ADDRESS:
22123128c6c7SMike Christie 		case ISCSI_PARAM_CONN_PORT:
22133128c6c7SMike Christie 		case ISCSI_PARAM_EXP_STATSN:
22143128c6c7SMike Christie 		case ISCSI_PARAM_PERSISTENT_ADDRESS:
22153128c6c7SMike Christie 		case ISCSI_PARAM_PERSISTENT_PORT:
22163128c6c7SMike Christie 		case ISCSI_PARAM_PING_TMO:
22173128c6c7SMike Christie 		case ISCSI_PARAM_RECV_TMO:
22181d063c17SMike Christie 		case ISCSI_PARAM_INITIAL_R2T_EN:
22191d063c17SMike Christie 		case ISCSI_PARAM_MAX_R2T:
22201d063c17SMike Christie 		case ISCSI_PARAM_IMM_DATA_EN:
22211d063c17SMike Christie 		case ISCSI_PARAM_FIRST_BURST:
22221d063c17SMike Christie 		case ISCSI_PARAM_MAX_BURST:
22231d063c17SMike Christie 		case ISCSI_PARAM_PDU_INORDER_EN:
22241d063c17SMike Christie 		case ISCSI_PARAM_DATASEQ_INORDER_EN:
22251d063c17SMike Christie 		case ISCSI_PARAM_ERL:
22261d063c17SMike Christie 		case ISCSI_PARAM_TARGET_NAME:
22271d063c17SMike Christie 		case ISCSI_PARAM_TPGT:
22281d063c17SMike Christie 		case ISCSI_PARAM_USERNAME:
22291d063c17SMike Christie 		case ISCSI_PARAM_PASSWORD:
22301d063c17SMike Christie 		case ISCSI_PARAM_USERNAME_IN:
22311d063c17SMike Christie 		case ISCSI_PARAM_PASSWORD_IN:
22321d063c17SMike Christie 		case ISCSI_PARAM_FAST_ABORT:
22331d063c17SMike Christie 		case ISCSI_PARAM_ABORT_TMO:
22341d063c17SMike Christie 		case ISCSI_PARAM_LU_RESET_TMO:
22351d063c17SMike Christie 		case ISCSI_PARAM_TGT_RESET_TMO:
22361d063c17SMike Christie 		case ISCSI_PARAM_IFACE_NAME:
22371d063c17SMike Christie 		case ISCSI_PARAM_INITIATOR_NAME:
22387c160facSTej Parkash 		case ISCSI_PARAM_BOOT_ROOT:
22397c160facSTej Parkash 		case ISCSI_PARAM_BOOT_NIC:
22407c160facSTej Parkash 		case ISCSI_PARAM_BOOT_TARGET:
22413128c6c7SMike Christie 			return S_IRUGO;
22423128c6c7SMike Christie 		default:
22433128c6c7SMike Christie 			return 0;
22443128c6c7SMike Christie 		}
22453128c6c7SMike Christie 	}
22463128c6c7SMike Christie 
22473128c6c7SMike Christie 	return 0;
22483128c6c7SMike Christie }
2249cf4e6363SMichael Chan 
2250cf4e6363SMichael Chan /*
2251cf4e6363SMichael Chan  * 'Scsi_Host_Template' structure and 'iscsi_tranport' structure template
2252cf4e6363SMichael Chan  * used while registering with the scsi host and iSCSI transport module.
2253cf4e6363SMichael Chan  */
2254cf4e6363SMichael Chan static struct scsi_host_template bnx2i_host_template = {
2255cf4e6363SMichael Chan 	.module			= THIS_MODULE,
2256f39a7757SVikas Chaudhary 	.name			= "QLogic Offload iSCSI Initiator",
2257cf4e6363SMichael Chan 	.proc_name		= "bnx2i",
2258cf4e6363SMichael Chan 	.queuecommand		= iscsi_queuecommand,
2259cf4e6363SMichael Chan 	.eh_abort_handler	= iscsi_eh_abort,
2260cf4e6363SMichael Chan 	.eh_device_reset_handler = iscsi_eh_device_reset,
2261309ce156SJayamohan Kallickal 	.eh_target_reset_handler = iscsi_eh_recover_target,
2262*db5ed4dfSChristoph Hellwig 	.change_queue_depth	= scsi_change_queue_depth,
22636f9c04ffSEddie Wai 	.target_alloc		= iscsi_target_alloc,
2264b5cf6b63SEddie Wai 	.can_queue		= 2048,
2265cf4e6363SMichael Chan 	.max_sectors		= 127,
2266b5cf6b63SEddie Wai 	.cmd_per_lun		= 128,
2267cf4e6363SMichael Chan 	.this_id		= -1,
2268cf4e6363SMichael Chan 	.use_clustering		= ENABLE_CLUSTERING,
2269cf4e6363SMichael Chan 	.sg_tablesize		= ISCSI_MAX_BDS_PER_CMD,
2270cf4e6363SMichael Chan 	.shost_attrs		= bnx2i_dev_attributes,
2271c40ecc12SChristoph Hellwig 	.track_queue_depth	= 1,
2272cf4e6363SMichael Chan };
2273cf4e6363SMichael Chan 
2274cf4e6363SMichael Chan struct iscsi_transport bnx2i_iscsi_transport = {
2275cf4e6363SMichael Chan 	.owner			= THIS_MODULE,
2276cf4e6363SMichael Chan 	.name			= "bnx2i",
2277cf4e6363SMichael Chan 	.caps			= CAP_RECOVERY_L0 | CAP_HDRDGST |
2278cf4e6363SMichael Chan 				  CAP_MULTI_R2T | CAP_DATADGST |
227909813ba5SEddie Wai 				  CAP_DATA_PATH_OFFLOAD |
228009813ba5SEddie Wai 				  CAP_TEXT_NEGO,
2281cf4e6363SMichael Chan 	.create_session		= bnx2i_session_create,
2282cf4e6363SMichael Chan 	.destroy_session	= bnx2i_session_destroy,
2283cf4e6363SMichael Chan 	.create_conn		= bnx2i_conn_create,
2284cf4e6363SMichael Chan 	.bind_conn		= bnx2i_conn_bind,
2285cf4e6363SMichael Chan 	.destroy_conn		= bnx2i_conn_destroy,
22863128c6c7SMike Christie 	.attr_is_visible	= bnx2i_attr_is_visible,
2287cf4e6363SMichael Chan 	.set_param		= iscsi_set_param,
2288d8585bcdSMike Christie 	.get_conn_param		= iscsi_conn_get_param,
2289cf4e6363SMichael Chan 	.get_session_param	= iscsi_session_get_param,
2290cf4e6363SMichael Chan 	.get_host_param		= bnx2i_host_get_param,
2291cf4e6363SMichael Chan 	.start_conn		= bnx2i_conn_start,
2292cf4e6363SMichael Chan 	.stop_conn		= iscsi_conn_stop,
2293cf4e6363SMichael Chan 	.send_pdu		= iscsi_conn_send_pdu,
2294cf4e6363SMichael Chan 	.xmit_task		= bnx2i_task_xmit,
2295cf4e6363SMichael Chan 	.get_stats		= bnx2i_conn_get_stats,
2296cf4e6363SMichael Chan 	/* TCP connect - disconnect - option-2 interface calls */
2297d8585bcdSMike Christie 	.get_ep_param		= bnx2i_ep_get_param,
2298cf4e6363SMichael Chan 	.ep_connect		= bnx2i_ep_connect,
2299cf4e6363SMichael Chan 	.ep_poll		= bnx2i_ep_poll,
2300cf4e6363SMichael Chan 	.ep_disconnect		= bnx2i_ep_disconnect,
2301cf4e6363SMichael Chan 	.set_path		= bnx2i_nl_set_path,
2302cf4e6363SMichael Chan 	/* Error recovery timeout call */
2303cf4e6363SMichael Chan 	.session_recovery_timedout = iscsi_session_recovery_timedout,
2304cf4e6363SMichael Chan 	.cleanup_task		= bnx2i_cleanup_task,
2305cf4e6363SMichael Chan };
2306