1/**
2 * Copyright (C) 2005 - 2011 Emulex
3 * All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation.  The full GNU General
8 * Public License is included in this distribution in the file called COPYING.
9 *
10 * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com)
11 *
12 * Contact Information:
13 * linux-drivers@emulex.com
14 *
15 * Emulex
16 * 3333 Susan Street
17 * Costa Mesa, CA 92626
18 */
19
20#include <scsi/libiscsi.h>
21#include <scsi/scsi_transport_iscsi.h>
22#include <scsi/scsi_transport.h>
23#include <scsi/scsi_cmnd.h>
24#include <scsi/scsi_device.h>
25#include <scsi/scsi_host.h>
26#include <scsi/scsi.h>
27
28#include "be_iscsi.h"
29
30extern struct iscsi_transport beiscsi_iscsi_transport;
31
32/**
33 * beiscsi_session_create - creates a new iscsi session
34 * @cmds_max: max commands supported
35 * @qdepth: max queue depth supported
36 * @initial_cmdsn: initial iscsi CMDSN
37 */
38struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep,
39						 u16 cmds_max,
40						 u16 qdepth,
41						 u32 initial_cmdsn)
42{
43	struct Scsi_Host *shost;
44	struct beiscsi_endpoint *beiscsi_ep;
45	struct iscsi_cls_session *cls_session;
46	struct beiscsi_hba *phba;
47	struct iscsi_session *sess;
48	struct beiscsi_session *beiscsi_sess;
49	struct beiscsi_io_task *io_task;
50
51	SE_DEBUG(DBG_LVL_8, "In beiscsi_session_create\n");
52
53	if (!ep) {
54		SE_DEBUG(DBG_LVL_1, "beiscsi_session_create: invalid ep\n");
55		return NULL;
56	}
57	beiscsi_ep = ep->dd_data;
58	phba = beiscsi_ep->phba;
59	shost = phba->shost;
60	if (cmds_max > beiscsi_ep->phba->params.wrbs_per_cxn) {
61		shost_printk(KERN_ERR, shost, "Cannot handle %d cmds."
62			     "Max cmds per session supported is %d. Using %d. "
63			     "\n", cmds_max,
64			      beiscsi_ep->phba->params.wrbs_per_cxn,
65			      beiscsi_ep->phba->params.wrbs_per_cxn);
66		cmds_max = beiscsi_ep->phba->params.wrbs_per_cxn;
67	}
68
69	cls_session = iscsi_session_setup(&beiscsi_iscsi_transport,
70					  shost, cmds_max,
71					  sizeof(*beiscsi_sess),
72					  sizeof(*io_task),
73					  initial_cmdsn, ISCSI_MAX_TARGET);
74	if (!cls_session)
75		return NULL;
76	sess = cls_session->dd_data;
77	beiscsi_sess = sess->dd_data;
78	beiscsi_sess->bhs_pool =  pci_pool_create("beiscsi_bhs_pool",
79						   phba->pcidev,
80						   sizeof(struct be_cmd_bhs),
81						   64, 0);
82	if (!beiscsi_sess->bhs_pool)
83		goto destroy_sess;
84
85	return cls_session;
86destroy_sess:
87	iscsi_session_teardown(cls_session);
88	return NULL;
89}
90
91/**
92 * beiscsi_session_destroy - destroys iscsi session
93 * @cls_session:	pointer to iscsi cls session
94 *
95 * Destroys iSCSI session instance and releases
96 * resources allocated for it.
97 */
98void beiscsi_session_destroy(struct iscsi_cls_session *cls_session)
99{
100	struct iscsi_session *sess = cls_session->dd_data;
101	struct beiscsi_session *beiscsi_sess = sess->dd_data;
102
103	SE_DEBUG(DBG_LVL_8, "In beiscsi_session_destroy\n");
104	pci_pool_destroy(beiscsi_sess->bhs_pool);
105	iscsi_session_teardown(cls_session);
106}
107
108/**
109 * beiscsi_conn_create - create an instance of iscsi connection
110 * @cls_session: ptr to iscsi_cls_session
111 * @cid: iscsi cid
112 */
113struct iscsi_cls_conn *
114beiscsi_conn_create(struct iscsi_cls_session *cls_session, u32 cid)
115{
116	struct beiscsi_hba *phba;
117	struct Scsi_Host *shost;
118	struct iscsi_cls_conn *cls_conn;
119	struct beiscsi_conn *beiscsi_conn;
120	struct iscsi_conn *conn;
121	struct iscsi_session *sess;
122	struct beiscsi_session *beiscsi_sess;
123
124	SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_create ,cid"
125		 "from iscsi layer=%d\n", cid);
126	shost = iscsi_session_to_shost(cls_session);
127	phba = iscsi_host_priv(shost);
128
129	cls_conn = iscsi_conn_setup(cls_session, sizeof(*beiscsi_conn), cid);
130	if (!cls_conn)
131		return NULL;
132
133	conn = cls_conn->dd_data;
134	beiscsi_conn = conn->dd_data;
135	beiscsi_conn->ep = NULL;
136	beiscsi_conn->phba = phba;
137	beiscsi_conn->conn = conn;
138	sess = cls_session->dd_data;
139	beiscsi_sess = sess->dd_data;
140	beiscsi_conn->beiscsi_sess = beiscsi_sess;
141	return cls_conn;
142}
143
144/**
145 * beiscsi_bindconn_cid - Bind the beiscsi_conn with phba connection table
146 * @beiscsi_conn: The pointer to  beiscsi_conn structure
147 * @phba: The phba instance
148 * @cid: The cid to free
149 */
150static int beiscsi_bindconn_cid(struct beiscsi_hba *phba,
151				struct beiscsi_conn *beiscsi_conn,
152				unsigned int cid)
153{
154	if (phba->conn_table[cid]) {
155		SE_DEBUG(DBG_LVL_1,
156			 "Connection table already occupied. Detected clash\n");
157		return -EINVAL;
158	} else {
159		SE_DEBUG(DBG_LVL_8, "phba->conn_table[%d]=%p(beiscsi_conn)\n",
160			 cid, beiscsi_conn);
161		phba->conn_table[cid] = beiscsi_conn;
162	}
163	return 0;
164}
165
166/**
167 * beiscsi_conn_bind - Binds iscsi session/connection with TCP connection
168 * @cls_session: pointer to iscsi cls session
169 * @cls_conn: pointer to iscsi cls conn
170 * @transport_fd: EP handle(64 bit)
171 *
172 * This function binds the TCP Conn with iSCSI Connection and Session.
173 */
174int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
175		      struct iscsi_cls_conn *cls_conn,
176		      u64 transport_fd, int is_leading)
177{
178	struct iscsi_conn *conn = cls_conn->dd_data;
179	struct beiscsi_conn *beiscsi_conn = conn->dd_data;
180	struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
181	struct beiscsi_hba *phba = iscsi_host_priv(shost);
182	struct beiscsi_endpoint *beiscsi_ep;
183	struct iscsi_endpoint *ep;
184
185	SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_bind\n");
186	ep = iscsi_lookup_endpoint(transport_fd);
187	if (!ep)
188		return -EINVAL;
189
190	beiscsi_ep = ep->dd_data;
191
192	if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
193		return -EINVAL;
194
195	if (beiscsi_ep->phba != phba) {
196		SE_DEBUG(DBG_LVL_8,
197			 "beiscsi_ep->hba=%p not equal to phba=%p\n",
198			 beiscsi_ep->phba, phba);
199		return -EEXIST;
200	}
201
202	beiscsi_conn->beiscsi_conn_cid = beiscsi_ep->ep_cid;
203	beiscsi_conn->ep = beiscsi_ep;
204	beiscsi_ep->conn = beiscsi_conn;
205	SE_DEBUG(DBG_LVL_8, "beiscsi_conn=%p conn=%p ep_cid=%d\n",
206		 beiscsi_conn, conn, beiscsi_ep->ep_cid);
207	return beiscsi_bindconn_cid(phba, beiscsi_conn, beiscsi_ep->ep_cid);
208}
209
210/**
211 * beiscsi_ep_get_param - get the iscsi parameter
212 * @ep: pointer to iscsi ep
213 * @param: parameter type identifier
214 * @buf: buffer pointer
215 *
216 * returns iscsi parameter
217 */
218int beiscsi_ep_get_param(struct iscsi_endpoint *ep,
219			   enum iscsi_param param, char *buf)
220{
221	struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
222	int len = 0;
223
224	SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_get_param, param= %d\n", param);
225
226	switch (param) {
227	case ISCSI_PARAM_CONN_PORT:
228		len = sprintf(buf, "%hu\n", beiscsi_ep->dst_tcpport);
229		break;
230	case ISCSI_PARAM_CONN_ADDRESS:
231		if (beiscsi_ep->ip_type == BE2_IPV4)
232			len = sprintf(buf, "%pI4\n", &beiscsi_ep->dst_addr);
233		else
234			len = sprintf(buf, "%pI6\n", &beiscsi_ep->dst6_addr);
235		break;
236	default:
237		return -ENOSYS;
238	}
239	return len;
240}
241
242int beiscsi_set_param(struct iscsi_cls_conn *cls_conn,
243		      enum iscsi_param param, char *buf, int buflen)
244{
245	struct iscsi_conn *conn = cls_conn->dd_data;
246	struct iscsi_session *session = conn->session;
247	int ret;
248
249	SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_set_param, param= %d\n", param);
250	ret = iscsi_set_param(cls_conn, param, buf, buflen);
251	if (ret)
252		return ret;
253	/*
254	 * If userspace tried to set the value to higher than we can
255	 * support override here.
256	 */
257	switch (param) {
258	case ISCSI_PARAM_FIRST_BURST:
259		if (session->first_burst > 8192)
260			session->first_burst = 8192;
261		break;
262	case ISCSI_PARAM_MAX_RECV_DLENGTH:
263		if (conn->max_recv_dlength > 65536)
264			conn->max_recv_dlength = 65536;
265		break;
266	case ISCSI_PARAM_MAX_BURST:
267		if (session->max_burst > 262144)
268			session->max_burst = 262144;
269		break;
270	case ISCSI_PARAM_MAX_XMIT_DLENGTH:
271		if ((conn->max_xmit_dlength > 65536) ||
272		    (conn->max_xmit_dlength == 0))
273			conn->max_xmit_dlength = 65536;
274	default:
275		return 0;
276	}
277
278	return 0;
279}
280
281/**
282 * beiscsi_get_host_param - get the iscsi parameter
283 * @shost: pointer to scsi_host structure
284 * @param: parameter type identifier
285 * @buf: buffer pointer
286 *
287 * returns host parameter
288 */
289int beiscsi_get_host_param(struct Scsi_Host *shost,
290			   enum iscsi_host_param param, char *buf)
291{
292	struct beiscsi_hba *phba = iscsi_host_priv(shost);
293	int status = 0;
294
295	SE_DEBUG(DBG_LVL_8, "In beiscsi_get_host_param, param= %d\n", param);
296	switch (param) {
297	case ISCSI_HOST_PARAM_HWADDRESS:
298		status = beiscsi_get_macaddr(buf, phba);
299		if (status < 0) {
300			SE_DEBUG(DBG_LVL_1, "beiscsi_get_macaddr Failed\n");
301			return status;
302		}
303		break;
304	default:
305		return iscsi_host_get_param(shost, param, buf);
306	}
307	return status;
308}
309
310int beiscsi_get_macaddr(char *buf, struct beiscsi_hba *phba)
311{
312	struct be_cmd_resp_get_mac_addr *resp;
313	struct be_mcc_wrb *wrb;
314	unsigned int tag, wrb_num;
315	unsigned short status, extd_status;
316	struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
317	int rc;
318
319	if (phba->read_mac_address)
320		return sysfs_format_mac(buf, phba->mac_address,
321					ETH_ALEN);
322
323	tag = be_cmd_get_mac_addr(phba);
324	if (!tag) {
325		SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed\n");
326		return -EBUSY;
327	} else
328		wait_event_interruptible(phba->ctrl.mcc_wait[tag],
329					 phba->ctrl.mcc_numtag[tag]);
330
331	wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16;
332	extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
333	status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
334	if (status || extd_status) {
335		SE_DEBUG(DBG_LVL_1, "Failed to get be_cmd_get_mac_addr"
336				    " status = %d extd_status = %d\n",
337				    status, extd_status);
338		free_mcc_tag(&phba->ctrl, tag);
339		return -EAGAIN;
340	}
341	wrb = queue_get_wrb(mccq, wrb_num);
342	free_mcc_tag(&phba->ctrl, tag);
343	resp = embedded_payload(wrb);
344	memcpy(phba->mac_address, resp->mac_address, ETH_ALEN);
345	rc = sysfs_format_mac(buf, phba->mac_address,
346			       ETH_ALEN);
347	phba->read_mac_address = 1;
348	return rc;
349}
350
351
352/**
353 * beiscsi_conn_get_stats - get the iscsi stats
354 * @cls_conn: pointer to iscsi cls conn
355 * @stats: pointer to iscsi_stats structure
356 *
357 * returns iscsi stats
358 */
359void beiscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn,
360			    struct iscsi_stats *stats)
361{
362	struct iscsi_conn *conn = cls_conn->dd_data;
363
364	SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_get_stats\n");
365	stats->txdata_octets = conn->txdata_octets;
366	stats->rxdata_octets = conn->rxdata_octets;
367	stats->dataout_pdus = conn->dataout_pdus_cnt;
368	stats->scsirsp_pdus = conn->scsirsp_pdus_cnt;
369	stats->scsicmd_pdus = conn->scsicmd_pdus_cnt;
370	stats->datain_pdus = conn->datain_pdus_cnt;
371	stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt;
372	stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt;
373	stats->r2t_pdus = conn->r2t_pdus_cnt;
374	stats->digest_err = 0;
375	stats->timeout_err = 0;
376	stats->custom_length = 0;
377	strcpy(stats->custom[0].desc, "eh_abort_cnt");
378	stats->custom[0].value = conn->eh_abort_cnt;
379}
380
381/**
382 * beiscsi_set_params_for_offld - get the parameters for offload
383 * @beiscsi_conn: pointer to beiscsi_conn
384 * @params: pointer to offload_params structure
385 */
386static void  beiscsi_set_params_for_offld(struct beiscsi_conn *beiscsi_conn,
387					  struct beiscsi_offload_params *params)
388{
389	struct iscsi_conn *conn = beiscsi_conn->conn;
390	struct iscsi_session *session = conn->session;
391
392	AMAP_SET_BITS(struct amap_beiscsi_offload_params, max_burst_length,
393		      params, session->max_burst);
394	AMAP_SET_BITS(struct amap_beiscsi_offload_params,
395		      max_send_data_segment_length, params,
396		      conn->max_xmit_dlength);
397	AMAP_SET_BITS(struct amap_beiscsi_offload_params, first_burst_length,
398		      params, session->first_burst);
399	AMAP_SET_BITS(struct amap_beiscsi_offload_params, erl, params,
400		      session->erl);
401	AMAP_SET_BITS(struct amap_beiscsi_offload_params, dde, params,
402		      conn->datadgst_en);
403	AMAP_SET_BITS(struct amap_beiscsi_offload_params, hde, params,
404		      conn->hdrdgst_en);
405	AMAP_SET_BITS(struct amap_beiscsi_offload_params, ir2t, params,
406		      session->initial_r2t_en);
407	AMAP_SET_BITS(struct amap_beiscsi_offload_params, imd, params,
408		      session->imm_data_en);
409	AMAP_SET_BITS(struct amap_beiscsi_offload_params, exp_statsn, params,
410		      (conn->exp_statsn - 1));
411}
412
413/**
414 * beiscsi_conn_start - offload of session to chip
415 * @cls_conn: pointer to beiscsi_conn
416 */
417int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn)
418{
419	struct iscsi_conn *conn = cls_conn->dd_data;
420	struct beiscsi_conn *beiscsi_conn = conn->dd_data;
421	struct beiscsi_endpoint *beiscsi_ep;
422	struct beiscsi_offload_params params;
423
424	SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_start\n");
425	memset(&params, 0, sizeof(struct beiscsi_offload_params));
426	beiscsi_ep = beiscsi_conn->ep;
427	if (!beiscsi_ep)
428		SE_DEBUG(DBG_LVL_1, "In beiscsi_conn_start , no beiscsi_ep\n");
429
430	beiscsi_conn->login_in_progress = 0;
431	beiscsi_set_params_for_offld(beiscsi_conn, &params);
432	beiscsi_offload_connection(beiscsi_conn, &params);
433	iscsi_conn_start(cls_conn);
434	return 0;
435}
436
437/**
438 * beiscsi_get_cid - Allocate a cid
439 * @phba: The phba instance
440 */
441static int beiscsi_get_cid(struct beiscsi_hba *phba)
442{
443	unsigned short cid = 0xFFFF;
444
445	if (!phba->avlbl_cids)
446		return cid;
447
448	cid = phba->cid_array[phba->cid_alloc++];
449	if (phba->cid_alloc == phba->params.cxns_per_ctrl)
450		phba->cid_alloc = 0;
451	phba->avlbl_cids--;
452	return cid;
453}
454
455/**
456 * beiscsi_put_cid - Free the cid
457 * @phba: The phba for which the cid is being freed
458 * @cid: The cid to free
459 */
460static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid)
461{
462	phba->avlbl_cids++;
463	phba->cid_array[phba->cid_free++] = cid;
464	if (phba->cid_free == phba->params.cxns_per_ctrl)
465		phba->cid_free = 0;
466}
467
468/**
469 * beiscsi_free_ep - free endpoint
470 * @ep:	pointer to iscsi endpoint structure
471 */
472static void beiscsi_free_ep(struct beiscsi_endpoint *beiscsi_ep)
473{
474	struct beiscsi_hba *phba = beiscsi_ep->phba;
475
476	beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
477	beiscsi_ep->phba = NULL;
478}
479
480/**
481 * beiscsi_open_conn - Ask FW to open a TCP connection
482 * @ep:	endpoint to be used
483 * @src_addr: The source IP address
484 * @dst_addr: The Destination  IP address
485 *
486 * Asks the FW to open a TCP connection
487 */
488static int beiscsi_open_conn(struct iscsi_endpoint *ep,
489			     struct sockaddr *src_addr,
490			     struct sockaddr *dst_addr, int non_blocking)
491{
492	struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
493	struct beiscsi_hba *phba = beiscsi_ep->phba;
494	struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
495	struct be_mcc_wrb *wrb;
496	struct tcp_connect_and_offload_out *ptcpcnct_out;
497	unsigned short status, extd_status;
498	struct be_dma_mem nonemb_cmd;
499	unsigned int tag, wrb_num;
500	int ret = -ENOMEM;
501
502	SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn\n");
503	beiscsi_ep->ep_cid = beiscsi_get_cid(phba);
504	if (beiscsi_ep->ep_cid == 0xFFFF) {
505		SE_DEBUG(DBG_LVL_1, "No free cid available\n");
506		return ret;
507	}
508	SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn, ep_cid=%d\n",
509		 beiscsi_ep->ep_cid);
510	phba->ep_array[beiscsi_ep->ep_cid -
511		       phba->fw_config.iscsi_cid_start] = ep;
512	if (beiscsi_ep->ep_cid > (phba->fw_config.iscsi_cid_start +
513				  phba->params.cxns_per_ctrl * 2)) {
514		SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n");
515		goto free_ep;
516	}
517
518	beiscsi_ep->cid_vld = 0;
519	nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev,
520				sizeof(struct tcp_connect_and_offload_in),
521				&nonemb_cmd.dma);
522	if (nonemb_cmd.va == NULL) {
523		SE_DEBUG(DBG_LVL_1,
524			 "Failed to allocate memory for mgmt_open_connection"
525			 "\n");
526		beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
527		return -ENOMEM;
528	}
529	nonemb_cmd.size = sizeof(struct tcp_connect_and_offload_in);
530	memset(nonemb_cmd.va, 0, nonemb_cmd.size);
531	tag = mgmt_open_connection(phba, dst_addr, beiscsi_ep, &nonemb_cmd);
532	if (!tag) {
533		SE_DEBUG(DBG_LVL_1,
534			 "mgmt_open_connection Failed for cid=%d\n",
535			 beiscsi_ep->ep_cid);
536		beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
537		pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
538				    nonemb_cmd.va, nonemb_cmd.dma);
539		return -EAGAIN;
540	} else {
541		wait_event_interruptible(phba->ctrl.mcc_wait[tag],
542					 phba->ctrl.mcc_numtag[tag]);
543	}
544	wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16;
545	extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
546	status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
547	if (status || extd_status) {
548		SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed"
549				    " status = %d extd_status = %d\n",
550				    status, extd_status);
551		free_mcc_tag(&phba->ctrl, tag);
552		pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
553			    nonemb_cmd.va, nonemb_cmd.dma);
554		goto free_ep;
555	} else {
556		wrb = queue_get_wrb(mccq, wrb_num);
557		free_mcc_tag(&phba->ctrl, tag);
558
559		ptcpcnct_out = embedded_payload(wrb);
560		beiscsi_ep = ep->dd_data;
561		beiscsi_ep->fw_handle = ptcpcnct_out->connection_handle;
562		beiscsi_ep->cid_vld = 1;
563		SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n");
564	}
565	pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
566			    nonemb_cmd.va, nonemb_cmd.dma);
567	return 0;
568
569free_ep:
570	beiscsi_free_ep(beiscsi_ep);
571	return -EBUSY;
572}
573
574/**
575 * beiscsi_ep_connect - Ask chip to create TCP Conn
576 * @scsi_host: Pointer to scsi_host structure
577 * @dst_addr: The IP address of Target
578 * @non_blocking: blocking or non-blocking call
579 *
580 * This routines first asks chip to create a connection and then allocates an EP
581 */
582struct iscsi_endpoint *
583beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
584		   int non_blocking)
585{
586	struct beiscsi_hba *phba;
587	struct beiscsi_endpoint *beiscsi_ep;
588	struct iscsi_endpoint *ep;
589	int ret;
590
591	SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_connect\n");
592	if (shost)
593		phba = iscsi_host_priv(shost);
594	else {
595		ret = -ENXIO;
596		SE_DEBUG(DBG_LVL_1, "shost is NULL\n");
597		return ERR_PTR(ret);
598	}
599
600	if (phba->state != BE_ADAPTER_UP) {
601		ret = -EBUSY;
602		SE_DEBUG(DBG_LVL_1, "The Adapter state is Not UP\n");
603		return ERR_PTR(ret);
604	}
605
606	ep = iscsi_create_endpoint(sizeof(struct beiscsi_endpoint));
607	if (!ep) {
608		ret = -ENOMEM;
609		return ERR_PTR(ret);
610	}
611
612	beiscsi_ep = ep->dd_data;
613	beiscsi_ep->phba = phba;
614	beiscsi_ep->openiscsi_ep = ep;
615	ret = beiscsi_open_conn(ep, NULL, dst_addr, non_blocking);
616	if (ret) {
617		SE_DEBUG(DBG_LVL_1, "Failed in beiscsi_open_conn\n");
618		goto free_ep;
619	}
620
621	return ep;
622
623free_ep:
624	iscsi_destroy_endpoint(ep);
625	return ERR_PTR(ret);
626}
627
628/**
629 * beiscsi_ep_poll - Poll to see if connection is established
630 * @ep:	endpoint to be used
631 * @timeout_ms: timeout specified in millisecs
632 *
633 * Poll to see if TCP connection established
634 */
635int beiscsi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)
636{
637	struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
638
639	SE_DEBUG(DBG_LVL_8, "In  beiscsi_ep_poll\n");
640	if (beiscsi_ep->cid_vld == 1)
641		return 1;
642	else
643		return 0;
644}
645
646/**
647 * beiscsi_close_conn - Upload the  connection
648 * @ep: The iscsi endpoint
649 * @flag: The type of connection closure
650 */
651static int beiscsi_close_conn(struct  beiscsi_endpoint *beiscsi_ep, int flag)
652{
653	int ret = 0;
654	unsigned int tag;
655	struct beiscsi_hba *phba = beiscsi_ep->phba;
656
657	tag = mgmt_upload_connection(phba, beiscsi_ep->ep_cid, flag);
658	if (!tag) {
659		SE_DEBUG(DBG_LVL_8, "upload failed for cid 0x%x\n",
660			 beiscsi_ep->ep_cid);
661		ret = -EAGAIN;
662	} else {
663		wait_event_interruptible(phba->ctrl.mcc_wait[tag],
664					 phba->ctrl.mcc_numtag[tag]);
665		free_mcc_tag(&phba->ctrl, tag);
666	}
667	return ret;
668}
669
670/**
671 * beiscsi_unbind_conn_to_cid - Unbind the beiscsi_conn from phba conn table
672 * @phba: The phba instance
673 * @cid: The cid to free
674 */
675static int beiscsi_unbind_conn_to_cid(struct beiscsi_hba *phba,
676				      unsigned int cid)
677{
678	if (phba->conn_table[cid])
679		phba->conn_table[cid] = NULL;
680	else {
681		SE_DEBUG(DBG_LVL_8, "Connection table Not occupied.\n");
682		return -EINVAL;
683	}
684	return 0;
685}
686
687/**
688 * beiscsi_ep_disconnect - Tears down the TCP connection
689 * @ep:	endpoint to be used
690 *
691 * Tears down the TCP connection
692 */
693void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
694{
695	struct beiscsi_conn *beiscsi_conn;
696	struct beiscsi_endpoint *beiscsi_ep;
697	struct beiscsi_hba *phba;
698	unsigned int tag;
699	unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH;
700
701	beiscsi_ep = ep->dd_data;
702	phba = beiscsi_ep->phba;
703	SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect for ep_cid = %d\n",
704			     beiscsi_ep->ep_cid);
705
706	if (!beiscsi_ep->conn) {
707		SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect, no "
708			 "beiscsi_ep\n");
709		return;
710	}
711	beiscsi_conn = beiscsi_ep->conn;
712	iscsi_suspend_queue(beiscsi_conn->conn);
713
714	SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect ep_cid = %d\n",
715		 beiscsi_ep->ep_cid);
716
717	tag = mgmt_invalidate_connection(phba, beiscsi_ep,
718					    beiscsi_ep->ep_cid, 1,
719					    savecfg_flag);
720	if (!tag) {
721		SE_DEBUG(DBG_LVL_1,
722			 "mgmt_invalidate_connection Failed for cid=%d\n",
723			  beiscsi_ep->ep_cid);
724	} else {
725		wait_event_interruptible(phba->ctrl.mcc_wait[tag],
726					 phba->ctrl.mcc_numtag[tag]);
727		free_mcc_tag(&phba->ctrl, tag);
728	}
729
730	beiscsi_close_conn(beiscsi_ep, CONNECTION_UPLOAD_GRACEFUL);
731	beiscsi_free_ep(beiscsi_ep);
732	beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid);
733	iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep);
734}
735
736umode_t be2iscsi_attr_is_visible(int param_type, int param)
737{
738	switch (param_type) {
739	case ISCSI_HOST_PARAM:
740		switch (param) {
741		case ISCSI_HOST_PARAM_HWADDRESS:
742		case ISCSI_HOST_PARAM_IPADDRESS:
743		case ISCSI_HOST_PARAM_INITIATOR_NAME:
744			return S_IRUGO;
745		default:
746			return 0;
747		}
748	case ISCSI_PARAM:
749		switch (param) {
750		case ISCSI_PARAM_MAX_RECV_DLENGTH:
751		case ISCSI_PARAM_MAX_XMIT_DLENGTH:
752		case ISCSI_PARAM_HDRDGST_EN:
753		case ISCSI_PARAM_DATADGST_EN:
754		case ISCSI_PARAM_CONN_ADDRESS:
755		case ISCSI_PARAM_CONN_PORT:
756		case ISCSI_PARAM_EXP_STATSN:
757		case ISCSI_PARAM_PERSISTENT_ADDRESS:
758		case ISCSI_PARAM_PERSISTENT_PORT:
759		case ISCSI_PARAM_PING_TMO:
760		case ISCSI_PARAM_RECV_TMO:
761		case ISCSI_PARAM_INITIAL_R2T_EN:
762		case ISCSI_PARAM_MAX_R2T:
763		case ISCSI_PARAM_IMM_DATA_EN:
764		case ISCSI_PARAM_FIRST_BURST:
765		case ISCSI_PARAM_MAX_BURST:
766		case ISCSI_PARAM_PDU_INORDER_EN:
767		case ISCSI_PARAM_DATASEQ_INORDER_EN:
768		case ISCSI_PARAM_ERL:
769		case ISCSI_PARAM_TARGET_NAME:
770		case ISCSI_PARAM_TPGT:
771		case ISCSI_PARAM_USERNAME:
772		case ISCSI_PARAM_PASSWORD:
773		case ISCSI_PARAM_USERNAME_IN:
774		case ISCSI_PARAM_PASSWORD_IN:
775		case ISCSI_PARAM_FAST_ABORT:
776		case ISCSI_PARAM_ABORT_TMO:
777		case ISCSI_PARAM_LU_RESET_TMO:
778		case ISCSI_PARAM_IFACE_NAME:
779		case ISCSI_PARAM_INITIATOR_NAME:
780			return S_IRUGO;
781		default:
782			return 0;
783		}
784	}
785
786	return 0;
787}
788