bfa_fcs_fcpim.c 21.4 KB
Newer Older
1
/*
K
Krishna Gudipati 已提交
2
 * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
 * All rights reserved
 * www.brocade.com
 *
 * Linux driver for Brocade Fibre Channel Host Bus Adapter.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License (GPL) Version 2 as
 * published by the Free Software Foundation
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 */

J
Jing Huang 已提交
18
/*
19 20 21
 *  fcpim.c - FCP initiator mode i-t nexus state machine
 */

M
Maggie Zhang 已提交
22
#include "bfad_drv.h"
K
Krishna Gudipati 已提交
23 24 25
#include "bfa_fcs.h"
#include "bfa_fcbuild.h"
#include "bfad_im.h"
26 27 28 29 30 31

BFA_TRC_FILE(FCS, FCPIM);

/*
 * forward declarations
 */
K
Krishna Gudipati 已提交
32 33 34
static void	bfa_fcs_itnim_timeout(void *arg);
static void	bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim);
static void	bfa_fcs_itnim_send_prli(void *itnim_cbarg,
35
					struct bfa_fcxp_s *fcxp_alloced);
K
Krishna Gudipati 已提交
36 37 38 39
static void	bfa_fcs_itnim_prli_response(void *fcsarg,
			 struct bfa_fcxp_s *fcxp, void *cbarg,
			    bfa_status_t req_status, u32 rsp_len,
			    u32 resid_len, struct fchs_s *rsp_fchs);
40 41
static void	bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim,
			enum bfa_itnim_aen_event event);
42

J
Jing Huang 已提交
43
/*
44 45 46 47 48 49 50 51 52 53
 *  fcs_itnim_sm FCS itnim state machine events
 */

enum bfa_fcs_itnim_event {
	BFA_FCS_ITNIM_SM_ONLINE = 1,	/*  rport online event */
	BFA_FCS_ITNIM_SM_OFFLINE = 2,	/*  rport offline */
	BFA_FCS_ITNIM_SM_FRMSENT = 3,	/*  prli frame is sent */
	BFA_FCS_ITNIM_SM_RSP_OK = 4,	/*  good response */
	BFA_FCS_ITNIM_SM_RSP_ERROR = 5,	/*  error response */
	BFA_FCS_ITNIM_SM_TIMEOUT = 6,	/*  delay timeout */
K
Krishna Gudipati 已提交
54 55
	BFA_FCS_ITNIM_SM_HCB_OFFLINE = 7, /*  BFA online callback */
	BFA_FCS_ITNIM_SM_HCB_ONLINE = 8, /*  BFA offline callback */
56 57 58
	BFA_FCS_ITNIM_SM_INITIATOR = 9,	/*  rport is initiator */
	BFA_FCS_ITNIM_SM_DELETE = 10,	/*  delete event from rport */
	BFA_FCS_ITNIM_SM_PRLO = 11,	/*  delete event from rport */
K
Krishna Gudipati 已提交
59
	BFA_FCS_ITNIM_SM_RSP_NOT_SUPP = 12, /* cmd not supported rsp */
60 61
};

K
Krishna Gudipati 已提交
62
static void	bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim,
63
					 enum bfa_fcs_itnim_event event);
K
Krishna Gudipati 已提交
64
static void	bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim,
65
					   enum bfa_fcs_itnim_event event);
K
Krishna Gudipati 已提交
66
static void	bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim,
67
				      enum bfa_fcs_itnim_event event);
K
Krishna Gudipati 已提交
68
static void	bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim,
69
					    enum bfa_fcs_itnim_event event);
K
Krishna Gudipati 已提交
70
static void	bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim,
71
					    enum bfa_fcs_itnim_event event);
K
Krishna Gudipati 已提交
72
static void	bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
73
					enum bfa_fcs_itnim_event event);
K
Krishna Gudipati 已提交
74
static void	bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim,
75
					     enum bfa_fcs_itnim_event event);
K
Krishna Gudipati 已提交
76
static void	bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim,
77 78 79 80 81 82 83 84 85 86 87 88 89
					   enum bfa_fcs_itnim_event event);

static struct bfa_sm_table_s itnim_sm_table[] = {
	{BFA_SM(bfa_fcs_itnim_sm_offline), BFA_ITNIM_OFFLINE},
	{BFA_SM(bfa_fcs_itnim_sm_prli_send), BFA_ITNIM_PRLI_SEND},
	{BFA_SM(bfa_fcs_itnim_sm_prli), BFA_ITNIM_PRLI_SENT},
	{BFA_SM(bfa_fcs_itnim_sm_prli_retry), BFA_ITNIM_PRLI_RETRY},
	{BFA_SM(bfa_fcs_itnim_sm_hcb_online), BFA_ITNIM_HCB_ONLINE},
	{BFA_SM(bfa_fcs_itnim_sm_online), BFA_ITNIM_ONLINE},
	{BFA_SM(bfa_fcs_itnim_sm_hcb_offline), BFA_ITNIM_HCB_OFFLINE},
	{BFA_SM(bfa_fcs_itnim_sm_initiator), BFA_ITNIM_INITIATIOR},
};

J
Jing Huang 已提交
90
/*
91 92 93 94 95
 *  fcs_itnim_sm FCS itnim state machine
 */

static void
bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim,
K
Krishna Gudipati 已提交
96
		 enum bfa_fcs_itnim_event event)
97 98 99 100 101 102 103
{
	bfa_trc(itnim->fcs, itnim->rport->pwwn);
	bfa_trc(itnim->fcs, event);

	switch (event) {
	case BFA_FCS_ITNIM_SM_ONLINE:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send);
J
Jing Huang 已提交
104
		itnim->prli_retries = 0;
105 106 107 108
		bfa_fcs_itnim_send_prli(itnim, NULL);
		break;

	case BFA_FCS_ITNIM_SM_OFFLINE:
109
		bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
110 111 112 113 114 115 116 117 118 119 120
		break;

	case BFA_FCS_ITNIM_SM_INITIATOR:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
		break;

	case BFA_FCS_ITNIM_SM_DELETE:
		bfa_fcs_itnim_free(itnim);
		break;

	default:
121
		bfa_sm_fault(itnim->fcs, event);
122 123 124 125 126 127
	}

}

static void
bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim,
K
Krishna Gudipati 已提交
128
		 enum bfa_fcs_itnim_event event)
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
{
	bfa_trc(itnim->fcs, itnim->rport->pwwn);
	bfa_trc(itnim->fcs, event);

	switch (event) {
	case BFA_FCS_ITNIM_SM_FRMSENT:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli);
		break;

	case BFA_FCS_ITNIM_SM_INITIATOR:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
		bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe);
		break;

	case BFA_FCS_ITNIM_SM_OFFLINE:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
		bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe);
146
		bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
147 148 149 150 151 152 153 154 155
		break;

	case BFA_FCS_ITNIM_SM_DELETE:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
		bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe);
		bfa_fcs_itnim_free(itnim);
		break;

	default:
156
		bfa_sm_fault(itnim->fcs, event);
157 158 159 160 161
	}
}

static void
bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim,
K
Krishna Gudipati 已提交
162
		 enum bfa_fcs_itnim_event event)
163 164 165 166 167 168
{
	bfa_trc(itnim->fcs, itnim->rport->pwwn);
	bfa_trc(itnim->fcs, event);

	switch (event) {
	case BFA_FCS_ITNIM_SM_RSP_OK:
169 170 171 172 173 174
		if (itnim->rport->scsi_function == BFA_RPORT_INITIATOR) {
			bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
		} else {
			bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_online);
			bfa_itnim_online(itnim->bfa_itnim, itnim->seq_rec);
		}
175 176 177 178 179 180 181 182 183
		break;

	case BFA_FCS_ITNIM_SM_RSP_ERROR:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_retry);
		bfa_timer_start(itnim->fcs->bfa, &itnim->timer,
				bfa_fcs_itnim_timeout, itnim,
				BFA_FCS_RETRY_TIMEOUT);
		break;

K
Krishna Gudipati 已提交
184 185 186 187
	case BFA_FCS_ITNIM_SM_RSP_NOT_SUPP:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
		break;

188 189 190
	case BFA_FCS_ITNIM_SM_OFFLINE:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
		bfa_fcxp_discard(itnim->fcxp);
191
		bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
192 193 194 195
		break;

	case BFA_FCS_ITNIM_SM_INITIATOR:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
196
		bfa_fcxp_discard(itnim->fcxp);
197 198 199 200 201 202 203 204 205
		break;

	case BFA_FCS_ITNIM_SM_DELETE:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
		bfa_fcxp_discard(itnim->fcxp);
		bfa_fcs_itnim_free(itnim);
		break;

	default:
206
		bfa_sm_fault(itnim->fcs, event);
207 208 209 210 211 212 213 214 215 216 217 218
	}
}

static void
bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim,
			    enum bfa_fcs_itnim_event event)
{
	bfa_trc(itnim->fcs, itnim->rport->pwwn);
	bfa_trc(itnim->fcs, event);

	switch (event) {
	case BFA_FCS_ITNIM_SM_TIMEOUT:
J
Jing Huang 已提交
219 220 221 222 223 224 225 226
		if (itnim->prli_retries < BFA_FCS_RPORT_MAX_RETRIES) {
			itnim->prli_retries++;
			bfa_trc(itnim->fcs, itnim->prli_retries);
			bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send);
			bfa_fcs_itnim_send_prli(itnim, NULL);
		} else {
			/* invoke target offline */
			bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
227
			bfa_sm_send_event(itnim->rport, RPSM_EVENT_LOGO_IMP);
J
Jing Huang 已提交
228
		}
229 230
		break;

K
Krishna Gudipati 已提交
231

232 233 234
	case BFA_FCS_ITNIM_SM_OFFLINE:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
		bfa_timer_stop(&itnim->timer);
235
		bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
236 237 238 239 240 241 242 243 244 245 246 247 248 249
		break;

	case BFA_FCS_ITNIM_SM_INITIATOR:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
		bfa_timer_stop(&itnim->timer);
		break;

	case BFA_FCS_ITNIM_SM_DELETE:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
		bfa_timer_stop(&itnim->timer);
		bfa_fcs_itnim_free(itnim);
		break;

	default:
250
		bfa_sm_fault(itnim->fcs, event);
251 252 253 254 255 256 257
	}
}

static void
bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim,
			    enum bfa_fcs_itnim_event event)
{
K
Krishna Gudipati 已提交
258 259 260 261
	struct bfad_s *bfad = (struct bfad_s *)itnim->fcs->bfad;
	char	lpwwn_buf[BFA_STRING_32];
	char	rpwwn_buf[BFA_STRING_32];

262 263 264 265 266 267 268
	bfa_trc(itnim->fcs, itnim->rport->pwwn);
	bfa_trc(itnim->fcs, event);

	switch (event) {
	case BFA_FCS_ITNIM_SM_HCB_ONLINE:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_online);
		bfa_fcb_itnim_online(itnim->itnim_drv);
K
Krishna Gudipati 已提交
269 270
		wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port));
		wwn2str(rpwwn_buf, itnim->rport->pwwn);
271
		BFA_LOG(KERN_INFO, bfad, bfa_log_level,
K
Krishna Gudipati 已提交
272 273
		"Target (WWN = %s) is online for initiator (WWN = %s)\n",
		rpwwn_buf, lpwwn_buf);
274
		bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_ONLINE);
275 276 277 278 279
		break;

	case BFA_FCS_ITNIM_SM_OFFLINE:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
		bfa_itnim_offline(itnim->bfa_itnim);
280
		bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
281 282 283 284 285 286 287 288
		break;

	case BFA_FCS_ITNIM_SM_DELETE:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
		bfa_fcs_itnim_free(itnim);
		break;

	default:
289
		bfa_sm_fault(itnim->fcs, event);
290 291 292 293 294
	}
}

static void
bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
K
Krishna Gudipati 已提交
295
		 enum bfa_fcs_itnim_event event)
296
{
K
Krishna Gudipati 已提交
297 298 299 300
	struct bfad_s *bfad = (struct bfad_s *)itnim->fcs->bfad;
	char	lpwwn_buf[BFA_STRING_32];
	char	rpwwn_buf[BFA_STRING_32];

301 302 303 304 305 306 307 308
	bfa_trc(itnim->fcs, itnim->rport->pwwn);
	bfa_trc(itnim->fcs, event);

	switch (event) {
	case BFA_FCS_ITNIM_SM_OFFLINE:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_offline);
		bfa_fcb_itnim_offline(itnim->itnim_drv);
		bfa_itnim_offline(itnim->bfa_itnim);
K
Krishna Gudipati 已提交
309 310
		wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port));
		wwn2str(rpwwn_buf, itnim->rport->pwwn);
311
		if (bfa_fcs_lport_is_online(itnim->rport->port) == BFA_TRUE) {
312
			BFA_LOG(KERN_ERR, bfad, bfa_log_level,
K
Krishna Gudipati 已提交
313 314
			"Target (WWN = %s) connectivity lost for "
			"initiator (WWN = %s)\n", rpwwn_buf, lpwwn_buf);
315 316
			bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_DISCONNECT);
		} else {
317
			BFA_LOG(KERN_INFO, bfad, bfa_log_level,
K
Krishna Gudipati 已提交
318 319
			"Target (WWN = %s) offlined by initiator (WWN = %s)\n",
			rpwwn_buf, lpwwn_buf);
320 321
			bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_OFFLINE);
		}
322 323 324 325 326 327 328 329
		break;

	case BFA_FCS_ITNIM_SM_DELETE:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
		bfa_fcs_itnim_free(itnim);
		break;

	default:
330
		bfa_sm_fault(itnim->fcs, event);
331 332 333 334 335 336 337 338 339 340 341 342 343
	}
}

static void
bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim,
			     enum bfa_fcs_itnim_event event)
{
	bfa_trc(itnim->fcs, itnim->rport->pwwn);
	bfa_trc(itnim->fcs, event);

	switch (event) {
	case BFA_FCS_ITNIM_SM_HCB_OFFLINE:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
344
		bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
345 346 347 348 349 350 351 352
		break;

	case BFA_FCS_ITNIM_SM_DELETE:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
		bfa_fcs_itnim_free(itnim);
		break;

	default:
353
		bfa_sm_fault(itnim->fcs, event);
354 355 356 357 358 359 360 361 362 363
	}
}

/*
 * This state is set when a discovered rport is also in intiator mode.
 * This ITN is marked as no_op and is not active and will not be truned into
 * online state.
 */
static void
bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim,
K
Krishna Gudipati 已提交
364
		 enum bfa_fcs_itnim_event event)
365 366 367 368 369 370 371
{
	bfa_trc(itnim->fcs, itnim->rport->pwwn);
	bfa_trc(itnim->fcs, event);

	switch (event) {
	case BFA_FCS_ITNIM_SM_OFFLINE:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
372
		bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
373 374 375 376 377 378 379 380 381 382 383 384 385
		break;

	case BFA_FCS_ITNIM_SM_RSP_ERROR:
	case BFA_FCS_ITNIM_SM_ONLINE:
	case BFA_FCS_ITNIM_SM_INITIATOR:
		break;

	case BFA_FCS_ITNIM_SM_DELETE:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
		bfa_fcs_itnim_free(itnim);
		break;

	default:
386
		bfa_sm_fault(itnim->fcs, event);
387 388 389
	}
}

390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
static void
bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim,
			enum bfa_itnim_aen_event event)
{
	struct bfa_fcs_rport_s *rport = itnim->rport;
	struct bfad_s *bfad = (struct bfad_s *)itnim->fcs->bfad;
	struct bfa_aen_entry_s	*aen_entry;

	/* Don't post events for well known addresses */
	if (BFA_FCS_PID_IS_WKA(rport->pid))
		return;

	bfad_get_aen_entry(bfad, aen_entry);
	if (!aen_entry)
		return;

	aen_entry->aen_data.itnim.vf_id = rport->port->fabric->vf_id;
	aen_entry->aen_data.itnim.ppwwn = bfa_fcs_lport_get_pwwn(
					bfa_fcs_get_base_port(itnim->fcs));
	aen_entry->aen_data.itnim.lpwwn = bfa_fcs_lport_get_pwwn(rport->port);
	aen_entry->aen_data.itnim.rpwwn = rport->pwwn;

	/* Send the AEN notification */
	bfad_im_post_vendor_event(aen_entry, bfad, ++rport->fcs->fcs_aen_seq,
				  BFA_AEN_CAT_ITNIM, event);
}

417 418 419 420 421
static void
bfa_fcs_itnim_send_prli(void *itnim_cbarg, struct bfa_fcxp_s *fcxp_alloced)
{
	struct bfa_fcs_itnim_s *itnim = itnim_cbarg;
	struct bfa_fcs_rport_s *rport = itnim->rport;
K
Krishna Gudipati 已提交
422 423
	struct bfa_fcs_lport_s *port = rport->port;
	struct fchs_s	fchs;
424
	struct bfa_fcxp_s *fcxp;
K
Krishna Gudipati 已提交
425
	int		len;
426 427 428 429 430 431

	bfa_trc(itnim->fcs, itnim->rport->pwwn);

	fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
	if (!fcxp) {
		itnim->stats.fcxp_alloc_wait++;
K
Krishna Gudipati 已提交
432
		bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &itnim->fcxp_wqe,
433 434 435 436 437
				    bfa_fcs_itnim_send_prli, itnim);
		return;
	}
	itnim->fcxp = fcxp;

K
Krishna Gudipati 已提交
438 439
	len = fc_prli_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
			    itnim->rport->pid, bfa_fcs_lport_get_fcid(port), 0);
440 441 442

	bfa_fcxp_send(fcxp, rport->bfa_rport, port->fabric->vf_id, port->lp_tag,
		      BFA_FALSE, FC_CLASS_3, len, &fchs,
K
Krishna Gudipati 已提交
443 444
		      bfa_fcs_itnim_prli_response, (void *)itnim,
		      FC_MAX_PDUSZ, FC_ELS_TOV);
445 446 447 448 449 450 451 452 453 454

	itnim->stats.prli_sent++;
	bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_FRMSENT);
}

static void
bfa_fcs_itnim_prli_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
			    bfa_status_t req_status, u32 rsp_len,
			    u32 resid_len, struct fchs_s *rsp_fchs)
{
K
Krishna Gudipati 已提交
455 456 457 458
	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cbarg;
	struct fc_els_cmd_s *els_cmd;
	struct fc_prli_s *prli_resp;
	struct fc_ls_rjt_s *ls_rjt;
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
	struct fc_prli_params_s *sparams;

	bfa_trc(itnim->fcs, req_status);

	/*
	 * Sanity Checks
	 */
	if (req_status != BFA_STATUS_OK) {
		itnim->stats.prli_rsp_err++;
		bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR);
		return;
	}

	els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);

	if (els_cmd->els_code == FC_ELS_ACC) {
		prli_resp = (struct fc_prli_s *) els_cmd;

		if (fc_prli_rsp_parse(prli_resp, rsp_len) != FC_PARSE_OK) {
			bfa_trc(itnim->fcs, rsp_len);
			/*
			 * Check if this  r-port is also in Initiator mode.
			 * If so, we need to set this ITN as a no-op.
			 */
			if (prli_resp->parampage.servparams.initiator) {
				bfa_trc(itnim->fcs, prli_resp->parampage.type);
				itnim->rport->scsi_function =
K
Krishna Gudipati 已提交
486
					 BFA_RPORT_INITIATOR;
487
				itnim->stats.prli_rsp_acc++;
K
Krishna Gudipati 已提交
488
				itnim->stats.initiator++;
489
				bfa_sm_send_event(itnim,
490
						  BFA_FCS_ITNIM_SM_RSP_OK);
491 492 493 494 495 496 497 498 499
				return;
			}

			itnim->stats.prli_rsp_parse_err++;
			return;
		}
		itnim->rport->scsi_function = BFA_RPORT_TARGET;

		sparams = &prli_resp->parampage.servparams;
K
Krishna Gudipati 已提交
500 501
		itnim->seq_rec	     = sparams->retry;
		itnim->rec_support   = sparams->rec_support;
502
		itnim->task_retry_id = sparams->task_retry_id;
K
Krishna Gudipati 已提交
503
		itnim->conf_comp     = sparams->confirm;
504 505 506 507 508 509 510 511 512 513

		itnim->stats.prli_rsp_acc++;
		bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_OK);
	} else {
		ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp);

		bfa_trc(itnim->fcs, ls_rjt->reason_code);
		bfa_trc(itnim->fcs, ls_rjt->reason_code_expl);

		itnim->stats.prli_rsp_rjt++;
K
Krishna Gudipati 已提交
514 515 516 517
		if (ls_rjt->reason_code == FC_LS_RJT_RSN_CMD_NOT_SUPP) {
			bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_NOT_SUPP);
			return;
		}
518 519 520 521 522 523 524
		bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR);
	}
}

static void
bfa_fcs_itnim_timeout(void *arg)
{
K
Krishna Gudipati 已提交
525
	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) arg;
526 527 528 529 530 531 532 533 534 535 536 537 538 539

	itnim->stats.timeout++;
	bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_TIMEOUT);
}

static void
bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim)
{
	bfa_itnim_delete(itnim->bfa_itnim);
	bfa_fcb_itnim_free(itnim->fcs->bfad, itnim->itnim_drv);
}



J
Jing Huang 已提交
540
/*
541 542 543
 *  itnim_public FCS ITNIM public interfaces
 */

J
Jing Huang 已提交
544
/*
K
Krishna Gudipati 已提交
545
 *	Called by rport when a new rport is created.
546 547 548 549 550 551
 *
 * @param[in] rport	-  remote port.
 */
struct bfa_fcs_itnim_s *
bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport)
{
K
Krishna Gudipati 已提交
552
	struct bfa_fcs_lport_s *port = rport->port;
553
	struct bfa_fcs_itnim_s *itnim;
K
Krishna Gudipati 已提交
554
	struct bfad_itnim_s   *itnim_drv;
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
	struct bfa_itnim_s *bfa_itnim;

	/*
	 * call bfad to allocate the itnim
	 */
	bfa_fcb_itnim_alloc(port->fcs->bfad, &itnim, &itnim_drv);
	if (itnim == NULL) {
		bfa_trc(port->fcs, rport->pwwn);
		return NULL;
	}

	/*
	 * Initialize itnim
	 */
	itnim->rport = rport;
	itnim->fcs = rport->fcs;
	itnim->itnim_drv = itnim_drv;

	/*
	 * call BFA to create the itnim
	 */
K
Krishna Gudipati 已提交
576 577
	bfa_itnim =
		bfa_itnim_create(port->fcs->bfa, rport->bfa_rport, itnim);
578 579 580 581

	if (bfa_itnim == NULL) {
		bfa_trc(port->fcs, rport->pwwn);
		bfa_fcb_itnim_free(port->fcs->bfad, itnim_drv);
582
		WARN_ON(1);
583 584 585
		return NULL;
	}

K
Krishna Gudipati 已提交
586 587 588 589
	itnim->bfa_itnim     = bfa_itnim;
	itnim->seq_rec	     = BFA_FALSE;
	itnim->rec_support   = BFA_FALSE;
	itnim->conf_comp     = BFA_FALSE;
590 591 592 593 594 595 596 597 598 599
	itnim->task_retry_id = BFA_FALSE;

	/*
	 * Set State machine
	 */
	bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);

	return itnim;
}

J
Jing Huang 已提交
600
/*
K
Krishna Gudipati 已提交
601
 *	Called by rport to delete  the instance of FCPIM.
602 603 604 605 606 607 608 609 610 611
 *
 * @param[in] rport	-  remote port.
 */
void
bfa_fcs_itnim_delete(struct bfa_fcs_itnim_s *itnim)
{
	bfa_trc(itnim->fcs, itnim->rport->pid);
	bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_DELETE);
}

J
Jing Huang 已提交
612
/*
613 614 615 616 617 618 619 620 621 622 623
 * Notification from rport that PLOGI is complete to initiate FC-4 session.
 */
void
bfa_fcs_itnim_rport_online(struct bfa_fcs_itnim_s *itnim)
{
	itnim->stats.onlines++;

	if (!BFA_FCS_PID_IS_WKA(itnim->rport->pid)) {
		bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_ONLINE);
	} else {
		/*
K
Krishna Gudipati 已提交
624 625
		 *  For well known addresses, we set the itnim to initiator
		 *  state
626 627 628 629 630 631
		 */
		itnim->stats.initiator++;
		bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR);
	}
}

J
Jing Huang 已提交
632
/*
633 634 635 636 637 638 639 640 641
 * Called by rport to handle a remote device offline.
 */
void
bfa_fcs_itnim_rport_offline(struct bfa_fcs_itnim_s *itnim)
{
	itnim->stats.offlines++;
	bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_OFFLINE);
}

J
Jing Huang 已提交
642
/*
643 644 645 646 647 648 649 650 651 652 653
 * Called by rport when remote port is known to be an initiator from
 * PRLI received.
 */
void
bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim)
{
	bfa_trc(itnim->fcs, itnim->rport->pid);
	itnim->stats.initiator++;
	bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR);
}

J
Jing Huang 已提交
654
/*
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
 * Called by rport to check if the itnim is online.
 */
bfa_status_t
bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim)
{
	bfa_trc(itnim->fcs, itnim->rport->pid);
	switch (bfa_sm_to_state(itnim_sm_table, itnim->sm)) {
	case BFA_ITNIM_ONLINE:
	case BFA_ITNIM_INITIATIOR:
		return BFA_STATUS_OK;

	default:
		return BFA_STATUS_NO_FCPIM_NEXUS;
	}
}

J
Jing Huang 已提交
671
/*
672 673 674 675 676
 * BFA completion callback for bfa_itnim_online().
 */
void
bfa_cb_itnim_online(void *cbarg)
{
K
Krishna Gudipati 已提交
677
	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cbarg;
678 679 680 681 682

	bfa_trc(itnim->fcs, itnim->rport->pwwn);
	bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_ONLINE);
}

J
Jing Huang 已提交
683
/*
684 685 686 687 688
 * BFA completion callback for bfa_itnim_offline().
 */
void
bfa_cb_itnim_offline(void *cb_arg)
{
K
Krishna Gudipati 已提交
689
	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
690 691 692 693 694

	bfa_trc(itnim->fcs, itnim->rport->pwwn);
	bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_OFFLINE);
}

J
Jing Huang 已提交
695
/*
696 697 698 699 700 701
 * Mark the beginning of PATH TOV handling. IO completion callbacks
 * are still pending.
 */
void
bfa_cb_itnim_tov_begin(void *cb_arg)
{
K
Krishna Gudipati 已提交
702
	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
703 704 705 706

	bfa_trc(itnim->fcs, itnim->rport->pwwn);
}

J
Jing Huang 已提交
707
/*
708 709 710 711 712
 * Mark the end of PATH TOV handling. All pending IOs are already cleaned up.
 */
void
bfa_cb_itnim_tov(void *cb_arg)
{
K
Krishna Gudipati 已提交
713 714
	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
	struct bfad_itnim_s *itnim_drv = itnim->itnim_drv;
715 716

	bfa_trc(itnim->fcs, itnim->rport->pwwn);
K
Krishna Gudipati 已提交
717
	itnim_drv->state = ITNIM_STATE_TIMEOUT;
718 719
}

J
Jing Huang 已提交
720
/*
K
Krishna Gudipati 已提交
721
 *		BFA notification to FCS/driver for second level error recovery.
722 723 724 725 726 727 728 729
 *
 * Atleast one I/O request has timedout and target is unresponsive to
 * repeated abort requests. Second level error recovery should be initiated
 * by starting implicit logout and recovery procedures.
 */
void
bfa_cb_itnim_sler(void *cb_arg)
{
K
Krishna Gudipati 已提交
730
	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
731 732 733

	itnim->stats.sler++;
	bfa_trc(itnim->fcs, itnim->rport->pwwn);
734
	bfa_sm_send_event(itnim->rport, RPSM_EVENT_LOGO_IMP);
735 736 737
}

struct bfa_fcs_itnim_s *
K
Krishna Gudipati 已提交
738
bfa_fcs_itnim_lookup(struct bfa_fcs_lport_s *port, wwn_t rpwwn)
739 740 741 742 743 744 745
{
	struct bfa_fcs_rport_s *rport;
	rport = bfa_fcs_rport_lookup(port, rpwwn);

	if (!rport)
		return NULL;

746
	WARN_ON(rport->itnim == NULL);
747
	return rport->itnim;
748 749 750
}

bfa_status_t
K
Krishna Gudipati 已提交
751
bfa_fcs_itnim_attr_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn,
752 753 754 755 756 757 758 759 760
		       struct bfa_itnim_attr_s *attr)
{
	struct bfa_fcs_itnim_s *itnim = NULL;

	itnim = bfa_fcs_itnim_lookup(port, rpwwn);

	if (itnim == NULL)
		return BFA_STATUS_NO_FCPIM_NEXUS;

K
Krishna Gudipati 已提交
761 762 763 764
	attr->state	    = bfa_sm_to_state(itnim_sm_table, itnim->sm);
	attr->retry	    = itnim->seq_rec;
	attr->rec_support   = itnim->rec_support;
	attr->conf_comp	    = itnim->conf_comp;
765 766 767 768 769
	attr->task_retry_id = itnim->task_retry_id;
	return BFA_STATUS_OK;
}

bfa_status_t
K
Krishna Gudipati 已提交
770
bfa_fcs_itnim_stats_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn,
771 772 773 774
			struct bfa_itnim_stats_s *stats)
{
	struct bfa_fcs_itnim_s *itnim = NULL;

775
	WARN_ON(port == NULL);
776 777 778 779 780 781

	itnim = bfa_fcs_itnim_lookup(port, rpwwn);

	if (itnim == NULL)
		return BFA_STATUS_NO_FCPIM_NEXUS;

782
	memcpy(stats, &itnim->stats, sizeof(struct bfa_itnim_stats_s));
783 784 785 786 787

	return BFA_STATUS_OK;
}

bfa_status_t
K
Krishna Gudipati 已提交
788
bfa_fcs_itnim_stats_clear(struct bfa_fcs_lport_s *port, wwn_t rpwwn)
789 790 791
{
	struct bfa_fcs_itnim_s *itnim = NULL;

792
	WARN_ON(port == NULL);
793 794 795 796 797 798

	itnim = bfa_fcs_itnim_lookup(port, rpwwn);

	if (itnim == NULL)
		return BFA_STATUS_NO_FCPIM_NEXUS;

799
	memset(&itnim->stats, 0, sizeof(struct bfa_itnim_stats_s));
800 801 802 803
	return BFA_STATUS_OK;
}

void
K
Krishna Gudipati 已提交
804 805
bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim,
			struct fchs_s *fchs, u16 len)
806
{
K
Krishna Gudipati 已提交
807
	struct fc_els_cmd_s *els_cmd;
808 809 810 811 812 813 814 815 816 817 818 819

	bfa_trc(itnim->fcs, fchs->type);

	if (fchs->type != FC_TYPE_ELS)
		return;

	els_cmd = (struct fc_els_cmd_s *) (fchs + 1);

	bfa_trc(itnim->fcs, els_cmd->els_code);

	switch (els_cmd->els_code) {
	case FC_ELS_PRLO:
820
		bfa_fcs_rport_prlo(itnim->rport, fchs->ox_id);
821 822 823
		break;

	default:
824
		WARN_ON(1);
825 826
	}
}