[SCSI] libiscsi: iscsi_session_setup to allow for private space
[linux-2.6-block.git] / drivers / scsi / be2iscsi / be_iscsi.c
CommitLineData
6733b39a
JK
1/**
2 * Copyright (C) 2005 - 2009 ServerEngines
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 (jayamohank@serverengines.com)
11 *
12 * Contact Information:
13 * linux-drivers@serverengines.com
14 *
15 * ServerEngines
16 * 209 N. Fair Oaks Ave
17 * Sunnyvale, CA 94085
18 *
19 */
20
21#include <scsi/libiscsi.h>
22#include <scsi/scsi_transport_iscsi.h>
23#include <scsi/scsi_transport.h>
24#include <scsi/scsi_cmnd.h>
25#include <scsi/scsi_device.h>
26#include <scsi/scsi_host.h>
27#include <scsi/scsi.h>
28
29#include "be_iscsi.h"
30
31extern struct iscsi_transport beiscsi_iscsi_transport;
32
33/**
34 * beiscsi_session_create - creates a new iscsi session
35 * @cmds_max: max commands supported
36 * @qdepth: max queue depth supported
37 * @initial_cmdsn: initial iscsi CMDSN
38 */
39struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep,
40 u16 cmds_max,
41 u16 qdepth,
42 u32 initial_cmdsn)
43{
44 struct Scsi_Host *shost;
45 struct beiscsi_endpoint *beiscsi_ep;
46 struct iscsi_cls_session *cls_session;
6733b39a
JK
47 struct beiscsi_hba *phba;
48 struct iscsi_task *task;
b8b9e1b8
JK
49 struct iscsi_session *sess;
50 struct beiscsi_session *beiscsi_sess;
6733b39a
JK
51 struct beiscsi_io_task *io_task;
52 unsigned int max_size, num_cmd;
53 dma_addr_t bus_add;
54 u64 pa_addr;
55 void *vaddr;
56
57 SE_DEBUG(DBG_LVL_8, "In beiscsi_session_create\n");
58
59 if (!ep) {
60 SE_DEBUG(DBG_LVL_1, "beiscsi_session_create: invalid ep \n");
61 return NULL;
62 }
63 beiscsi_ep = ep->dd_data;
64 phba = beiscsi_ep->phba;
65 shost = phba->shost;
66 if (cmds_max > beiscsi_ep->phba->params.wrbs_per_cxn) {
67 shost_printk(KERN_ERR, shost, "Cannot handle %d cmds."
68 "Max cmds per session supported is %d. Using %d. "
69 "\n", cmds_max,
70 beiscsi_ep->phba->params.wrbs_per_cxn,
71 beiscsi_ep->phba->params.wrbs_per_cxn);
72 cmds_max = beiscsi_ep->phba->params.wrbs_per_cxn;
73 }
74
75 cls_session = iscsi_session_setup(&beiscsi_iscsi_transport,
76 shost, cmds_max,
b8b9e1b8
JK
77 sizeof(*beiscsi_sess),
78 sizeof(*io_task),
6733b39a
JK
79 initial_cmdsn, ISCSI_MAX_TARGET);
80 if (!cls_session)
81 return NULL;
82 sess = cls_session->dd_data;
83 max_size = ALIGN(sizeof(struct be_cmd_bhs), 64) * sess->cmds_max;
84 vaddr = pci_alloc_consistent(phba->pcidev, max_size, &bus_add);
85 pa_addr = (__u64) bus_add;
86
87 for (num_cmd = 0; num_cmd < sess->cmds_max; num_cmd++) {
88 task = sess->cmds[num_cmd];
89 io_task = task->dd_data;
90 io_task->cmd_bhs = vaddr;
91 io_task->bhs_pa.u.a64.address = pa_addr;
92 io_task->alloc_size = max_size;
93 vaddr += ALIGN(sizeof(struct be_cmd_bhs), 64);
94 pa_addr += ALIGN(sizeof(struct be_cmd_bhs), 64);
95 }
96 return cls_session;
97}
98
99/**
100 * beiscsi_session_destroy - destroys iscsi session
101 * @cls_session: pointer to iscsi cls session
102 *
103 * Destroys iSCSI session instance and releases
104 * resources allocated for it.
105 */
106void beiscsi_session_destroy(struct iscsi_cls_session *cls_session)
107{
108 struct iscsi_task *task;
109 struct beiscsi_io_task *io_task;
110 struct iscsi_session *sess = cls_session->dd_data;
111 struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
112 struct beiscsi_hba *phba = iscsi_host_priv(shost);
113
114 task = sess->cmds[0];
115 io_task = task->dd_data;
116 pci_free_consistent(phba->pcidev,
117 io_task->alloc_size,
118 io_task->cmd_bhs,
119 io_task->bhs_pa.u.a64.address);
120 iscsi_session_teardown(cls_session);
121}
122
123/**
124 * beiscsi_conn_create - create an instance of iscsi connection
125 * @cls_session: ptr to iscsi_cls_session
126 * @cid: iscsi cid
127 */
128struct iscsi_cls_conn *
129beiscsi_conn_create(struct iscsi_cls_session *cls_session, u32 cid)
130{
131 struct beiscsi_hba *phba;
132 struct Scsi_Host *shost;
133 struct iscsi_cls_conn *cls_conn;
134 struct beiscsi_conn *beiscsi_conn;
135 struct iscsi_conn *conn;
136
137 SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_create ,cid"
138 "from iscsi layer=%d\n", cid);
139 shost = iscsi_session_to_shost(cls_session);
140 phba = iscsi_host_priv(shost);
141
142 cls_conn = iscsi_conn_setup(cls_session, sizeof(*beiscsi_conn), cid);
143 if (!cls_conn)
144 return NULL;
145
146 conn = cls_conn->dd_data;
147 beiscsi_conn = conn->dd_data;
148 beiscsi_conn->ep = NULL;
149 beiscsi_conn->phba = phba;
150 beiscsi_conn->conn = conn;
151 return cls_conn;
152}
153
154/**
155 * beiscsi_bindconn_cid - Bind the beiscsi_conn with phba connection table
156 * @beiscsi_conn: The pointer to beiscsi_conn structure
157 * @phba: The phba instance
158 * @cid: The cid to free
159 */
160static int beiscsi_bindconn_cid(struct beiscsi_hba *phba,
161 struct beiscsi_conn *beiscsi_conn,
162 unsigned int cid)
163{
164 if (phba->conn_table[cid]) {
165 SE_DEBUG(DBG_LVL_1,
166 "Connection table already occupied. Detected clash\n");
167 return -EINVAL;
168 } else {
169 SE_DEBUG(DBG_LVL_8, "phba->conn_table[%d]=%p(beiscsi_conn) \n",
170 cid, beiscsi_conn);
171 phba->conn_table[cid] = beiscsi_conn;
172 }
173 return 0;
174}
175
176/**
177 * beiscsi_conn_bind - Binds iscsi session/connection with TCP connection
178 * @cls_session: pointer to iscsi cls session
179 * @cls_conn: pointer to iscsi cls conn
180 * @transport_fd: EP handle(64 bit)
181 *
182 * This function binds the TCP Conn with iSCSI Connection and Session.
183 */
184int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
185 struct iscsi_cls_conn *cls_conn,
186 u64 transport_fd, int is_leading)
187{
188 struct iscsi_conn *conn = cls_conn->dd_data;
189 struct beiscsi_conn *beiscsi_conn = conn->dd_data;
190 struct Scsi_Host *shost =
191 (struct Scsi_Host *)iscsi_session_to_shost(cls_session);
192 struct beiscsi_hba *phba = (struct beiscsi_hba *)iscsi_host_priv(shost);
193 struct beiscsi_endpoint *beiscsi_ep;
194 struct iscsi_endpoint *ep;
195
196 SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_bind\n");
197 ep = iscsi_lookup_endpoint(transport_fd);
198 if (!ep)
199 return -EINVAL;
200
201 beiscsi_ep = ep->dd_data;
202
203 if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
204 return -EINVAL;
205
206 if (beiscsi_ep->phba != phba) {
207 SE_DEBUG(DBG_LVL_8,
208 "beiscsi_ep->hba=%p not equal to phba=%p \n",
209 beiscsi_ep->phba, phba);
210 return -EEXIST;
211 }
212
213 beiscsi_conn->beiscsi_conn_cid = beiscsi_ep->ep_cid;
214 beiscsi_conn->ep = beiscsi_ep;
215 beiscsi_ep->conn = beiscsi_conn;
216 SE_DEBUG(DBG_LVL_8, "beiscsi_conn=%p conn=%p ep_cid=%d \n",
217 beiscsi_conn, conn, beiscsi_ep->ep_cid);
218 return beiscsi_bindconn_cid(phba, beiscsi_conn, beiscsi_ep->ep_cid);
219}
220
221/**
222 * beiscsi_conn_get_param - get the iscsi parameter
223 * @cls_conn: pointer to iscsi cls conn
224 * @param: parameter type identifier
225 * @buf: buffer pointer
226 *
227 * returns iscsi parameter
228 */
229int beiscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
230 enum iscsi_param param, char *buf)
231{
232 struct beiscsi_endpoint *beiscsi_ep;
233 struct iscsi_conn *conn = cls_conn->dd_data;
234 struct beiscsi_conn *beiscsi_conn = conn->dd_data;
235 int len = 0;
236
237 beiscsi_ep = beiscsi_conn->ep;
238 if (!beiscsi_ep) {
239 SE_DEBUG(DBG_LVL_1,
240 "In beiscsi_conn_get_param , no beiscsi_ep\n");
241 return -1;
242 }
243
244 switch (param) {
245 case ISCSI_PARAM_CONN_PORT:
246 len = sprintf(buf, "%hu\n", beiscsi_ep->dst_tcpport);
247 break;
248 case ISCSI_PARAM_CONN_ADDRESS:
249 if (beiscsi_ep->ip_type == BE2_IPV4)
250 len = sprintf(buf, "%pI4\n", &beiscsi_ep->dst_addr);
251 else
252 len = sprintf(buf, "%pI6\n", &beiscsi_ep->dst6_addr);
253 break;
254 default:
255 return iscsi_conn_get_param(cls_conn, param, buf);
256 }
257 return len;
258}
259
260int beiscsi_set_param(struct iscsi_cls_conn *cls_conn,
261 enum iscsi_param param, char *buf, int buflen)
262{
263 struct iscsi_conn *conn = cls_conn->dd_data;
264 struct iscsi_session *session = conn->session;
265 int ret;
266
267 ret = iscsi_set_param(cls_conn, param, buf, buflen);
268 if (ret)
269 return ret;
270 /*
271 * If userspace tried to set the value to higher than we can
272 * support override here.
273 */
274 switch (param) {
275 case ISCSI_PARAM_FIRST_BURST:
276 if (session->first_burst > 8192)
277 session->first_burst = 8192;
278 break;
279 case ISCSI_PARAM_MAX_RECV_DLENGTH:
280 if (conn->max_recv_dlength > 65536)
281 conn->max_recv_dlength = 65536;
282 break;
283 case ISCSI_PARAM_MAX_BURST:
284 if (session->first_burst > 262144)
285 session->first_burst = 262144;
286 break;
287 default:
288 return 0;
289 }
290
291 return 0;
292}
293
294/**
295 * beiscsi_get_host_param - get the iscsi parameter
296 * @shost: pointer to scsi_host structure
297 * @param: parameter type identifier
298 * @buf: buffer pointer
299 *
300 * returns host parameter
301 */
302int beiscsi_get_host_param(struct Scsi_Host *shost,
303 enum iscsi_host_param param, char *buf)
304{
305 struct beiscsi_hba *phba = (struct beiscsi_hba *)iscsi_host_priv(shost);
306 int len = 0;
307
308 switch (param) {
309 case ISCSI_HOST_PARAM_HWADDRESS:
310 be_cmd_get_mac_addr(&phba->ctrl, phba->mac_address);
311 len = sysfs_format_mac(buf, phba->mac_address, ETH_ALEN);
312 break;
313 default:
314 return iscsi_host_get_param(shost, param, buf);
315 }
316 return len;
317}
318
319/**
320 * beiscsi_conn_get_stats - get the iscsi stats
321 * @cls_conn: pointer to iscsi cls conn
322 * @stats: pointer to iscsi_stats structure
323 *
324 * returns iscsi stats
325 */
326void beiscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn,
327 struct iscsi_stats *stats)
328{
329 struct iscsi_conn *conn = cls_conn->dd_data;
330
331 SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_get_stats\n");
332 stats->txdata_octets = conn->txdata_octets;
333 stats->rxdata_octets = conn->rxdata_octets;
334 stats->dataout_pdus = conn->dataout_pdus_cnt;
335 stats->scsirsp_pdus = conn->scsirsp_pdus_cnt;
336 stats->scsicmd_pdus = conn->scsicmd_pdus_cnt;
337 stats->datain_pdus = conn->datain_pdus_cnt;
338 stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt;
339 stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt;
340 stats->r2t_pdus = conn->r2t_pdus_cnt;
341 stats->digest_err = 0;
342 stats->timeout_err = 0;
343 stats->custom_length = 0;
344 strcpy(stats->custom[0].desc, "eh_abort_cnt");
345 stats->custom[0].value = conn->eh_abort_cnt;
346}
347
348/**
349 * beiscsi_set_params_for_offld - get the parameters for offload
350 * @beiscsi_conn: pointer to beiscsi_conn
351 * @params: pointer to offload_params structure
352 */
353static void beiscsi_set_params_for_offld(struct beiscsi_conn *beiscsi_conn,
354 struct beiscsi_offload_params *params)
355{
356 struct iscsi_conn *conn = beiscsi_conn->conn;
357 struct iscsi_session *session = conn->session;
358
359 AMAP_SET_BITS(struct amap_beiscsi_offload_params, max_burst_length,
360 params, session->max_burst);
361 AMAP_SET_BITS(struct amap_beiscsi_offload_params,
362 max_send_data_segment_length, params,
363 conn->max_xmit_dlength);
364 AMAP_SET_BITS(struct amap_beiscsi_offload_params, first_burst_length,
365 params, session->first_burst);
366 AMAP_SET_BITS(struct amap_beiscsi_offload_params, erl, params,
367 session->erl);
368 AMAP_SET_BITS(struct amap_beiscsi_offload_params, dde, params,
369 conn->datadgst_en);
370 AMAP_SET_BITS(struct amap_beiscsi_offload_params, hde, params,
371 conn->hdrdgst_en);
372 AMAP_SET_BITS(struct amap_beiscsi_offload_params, ir2t, params,
373 session->initial_r2t_en);
374 AMAP_SET_BITS(struct amap_beiscsi_offload_params, imd, params,
375 session->imm_data_en);
376 AMAP_SET_BITS(struct amap_beiscsi_offload_params, exp_statsn, params,
377 (conn->exp_statsn - 1));
378}
379
380/**
381 * beiscsi_conn_start - offload of session to chip
382 * @cls_conn: pointer to beiscsi_conn
383 */
384int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn)
385{
386 struct iscsi_conn *conn = cls_conn->dd_data;
387 struct beiscsi_conn *beiscsi_conn = conn->dd_data;
388 struct beiscsi_endpoint *beiscsi_ep;
389 struct beiscsi_offload_params params;
390 struct iscsi_session *session = conn->session;
391 struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session);
392 struct beiscsi_hba *phba = iscsi_host_priv(shost);
393
394 memset(&params, 0, sizeof(struct beiscsi_offload_params));
395 beiscsi_ep = beiscsi_conn->ep;
396 if (!beiscsi_ep)
397 SE_DEBUG(DBG_LVL_1, "In beiscsi_conn_start , no beiscsi_ep\n");
398
399 free_mgmt_sgl_handle(phba, beiscsi_conn->plogin_sgl_handle);
400 beiscsi_conn->login_in_progress = 0;
401 beiscsi_set_params_for_offld(beiscsi_conn, &params);
402 beiscsi_offload_connection(beiscsi_conn, &params);
403 iscsi_conn_start(cls_conn);
404 return 0;
405}
406
407/**
408 * beiscsi_get_cid - Allocate a cid
409 * @phba: The phba instance
410 */
411static int beiscsi_get_cid(struct beiscsi_hba *phba)
412{
413 unsigned short cid = 0xFFFF;
414
415 if (!phba->avlbl_cids)
416 return cid;
417
418 cid = phba->cid_array[phba->cid_alloc++];
419 if (phba->cid_alloc == phba->params.cxns_per_ctrl)
420 phba->cid_alloc = 0;
421 phba->avlbl_cids--;
422 return cid;
423}
424
425/**
426 * beiscsi_open_conn - Ask FW to open a TCP connection
427 * @ep: endpoint to be used
428 * @src_addr: The source IP address
429 * @dst_addr: The Destination IP address
430 *
431 * Asks the FW to open a TCP connection
432 */
433static int beiscsi_open_conn(struct iscsi_endpoint *ep,
434 struct sockaddr *src_addr,
435 struct sockaddr *dst_addr, int non_blocking)
436{
437 struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
438 struct beiscsi_hba *phba = beiscsi_ep->phba;
439 int ret = -1;
440
441 beiscsi_ep->ep_cid = beiscsi_get_cid(phba);
442 if (beiscsi_ep->ep_cid == 0xFFFF) {
443 SE_DEBUG(DBG_LVL_1, "No free cid available\n");
444 return ret;
445 }
446 SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn, ep_cid=%d ",
447 beiscsi_ep->ep_cid);
448 phba->ep_array[beiscsi_ep->ep_cid] = ep;
449 if (beiscsi_ep->ep_cid >
450 (phba->fw_config.iscsi_cid_start + phba->params.cxns_per_ctrl)) {
451 SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n");
452 return ret;
453 }
454
455 beiscsi_ep->cid_vld = 0;
456 return mgmt_open_connection(phba, dst_addr, beiscsi_ep);
457}
458
459/**
460 * beiscsi_put_cid - Free the cid
461 * @phba: The phba for which the cid is being freed
462 * @cid: The cid to free
463 */
464static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid)
465{
466 phba->avlbl_cids++;
467 phba->cid_array[phba->cid_free++] = cid;
468 if (phba->cid_free == phba->params.cxns_per_ctrl)
469 phba->cid_free = 0;
470}
471
472/**
473 * beiscsi_free_ep - free endpoint
474 * @ep: pointer to iscsi endpoint structure
475 */
476static void beiscsi_free_ep(struct iscsi_endpoint *ep)
477{
478 struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
479 struct beiscsi_hba *phba = beiscsi_ep->phba;
480
481 beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
482 beiscsi_ep->phba = NULL;
483 iscsi_destroy_endpoint(ep);
484}
485
486/**
487 * beiscsi_ep_connect - Ask chip to create TCP Conn
488 * @scsi_host: Pointer to scsi_host structure
489 * @dst_addr: The IP address of Target
490 * @non_blocking: blocking or non-blocking call
491 *
492 * This routines first asks chip to create a connection and then allocates an EP
493 */
494struct iscsi_endpoint *
495beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
496 int non_blocking)
497{
498 struct beiscsi_hba *phba;
499 struct beiscsi_endpoint *beiscsi_ep;
500 struct iscsi_endpoint *ep;
501 int ret;
502
503 SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_connect \n");
504 if (shost)
505 phba = iscsi_host_priv(shost);
506 else {
507 ret = -ENXIO;
508 SE_DEBUG(DBG_LVL_1, "shost is NULL \n");
509 return ERR_PTR(ret);
510 }
511 ep = iscsi_create_endpoint(sizeof(struct beiscsi_endpoint));
512 if (!ep) {
513 ret = -ENOMEM;
514 return ERR_PTR(ret);
515 }
516
517 beiscsi_ep = ep->dd_data;
518 beiscsi_ep->phba = phba;
519
520 if (beiscsi_open_conn(ep, NULL, dst_addr, non_blocking)) {
521 SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n");
522 ret = -ENOMEM;
523 goto free_ep;
524 }
525
526 return ep;
527
528free_ep:
529 beiscsi_free_ep(ep);
530 return ERR_PTR(ret);
531}
532
533/**
534 * beiscsi_ep_poll - Poll to see if connection is established
535 * @ep: endpoint to be used
536 * @timeout_ms: timeout specified in millisecs
537 *
538 * Poll to see if TCP connection established
539 */
540int beiscsi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)
541{
542 struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
543
544 SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_poll\n");
545 if (beiscsi_ep->cid_vld == 1)
546 return 1;
547 else
548 return 0;
549}
550
551/**
552 * beiscsi_close_conn - Upload the connection
553 * @ep: The iscsi endpoint
554 * @flag: The type of connection closure
555 */
556static int beiscsi_close_conn(struct iscsi_endpoint *ep, int flag)
557{
558 int ret = 0;
559 struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
560 struct beiscsi_hba *phba = beiscsi_ep->phba;
561
562 if (MGMT_STATUS_SUCCESS !=
563 mgmt_upload_connection(phba, beiscsi_ep->ep_cid,
564 CONNECTION_UPLOAD_GRACEFUL)) {
565 SE_DEBUG(DBG_LVL_8, "upload failed for cid 0x%x",
566 beiscsi_ep->ep_cid);
567 ret = -1;
568 }
569
570 return ret;
571}
572
573/**
574 * beiscsi_ep_disconnect - Tears down the TCP connection
575 * @ep: endpoint to be used
576 *
577 * Tears down the TCP connection
578 */
579void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
580{
581 struct beiscsi_conn *beiscsi_conn;
582 struct beiscsi_endpoint *beiscsi_ep;
583 struct beiscsi_hba *phba;
584 int flag = 0;
585
586 beiscsi_ep = ep->dd_data;
587 phba = beiscsi_ep->phba;
588 SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect\n");
589
590 if (beiscsi_ep->conn) {
591 beiscsi_conn = beiscsi_ep->conn;
592 iscsi_suspend_queue(beiscsi_conn->conn);
593 beiscsi_close_conn(ep, flag);
594 }
595
596 beiscsi_free_ep(ep);
597}
598
599/**
600 * beiscsi_unbind_conn_to_cid - Unbind the beiscsi_conn from phba conn table
601 * @phba: The phba instance
602 * @cid: The cid to free
603 */
604static int beiscsi_unbind_conn_to_cid(struct beiscsi_hba *phba,
605 unsigned int cid)
606{
607 if (phba->conn_table[cid])
608 phba->conn_table[cid] = NULL;
609 else {
610 SE_DEBUG(DBG_LVL_8, "Connection table Not occupied. \n");
611 return -EINVAL;
612 }
613 return 0;
614}
615
616/**
617 * beiscsi_conn_stop - Invalidate and stop the connection
618 * @cls_conn: pointer to get iscsi_conn
619 * @flag: The type of connection closure
620 */
621void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
622{
623 struct iscsi_conn *conn = cls_conn->dd_data;
624 struct beiscsi_conn *beiscsi_conn = conn->dd_data;
625 struct beiscsi_endpoint *beiscsi_ep;
626 struct iscsi_session *session = conn->session;
627 struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session);
628 struct beiscsi_hba *phba = iscsi_host_priv(shost);
629 unsigned int status;
630 unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH;
631
632 SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop\n");
633 beiscsi_ep = beiscsi_conn->ep;
634 if (!beiscsi_ep) {
635 SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop , no beiscsi_ep\n");
636 return;
637 }
638 status = mgmt_invalidate_connection(phba, beiscsi_ep,
639 beiscsi_ep->ep_cid, 1,
640 savecfg_flag);
641 if (status != MGMT_STATUS_SUCCESS) {
642 SE_DEBUG(DBG_LVL_1,
643 "mgmt_invalidate_connection Failed for cid=%d \n",
644 beiscsi_ep->ep_cid);
645 }
646 beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid);
647 iscsi_conn_stop(cls_conn, flag);
648}