bfa_fcs_fcpim.c 19.8 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 18 19 20 21
 * 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.
 */

/**
 *  fcpim.c - FCP initiator mode i-t nexus state machine
 */

K
Krishna Gudipati 已提交
22 23 24 25
#include "bfa_fcs.h"
#include "bfa_fcbuild.h"
#include "bfad_drv.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 42 43 44 45 46 47 48 49 50 51

/**
 *  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 已提交
52 53
	BFA_FCS_ITNIM_SM_HCB_OFFLINE = 7, /*  BFA online callback */
	BFA_FCS_ITNIM_SM_HCB_ONLINE = 8, /*  BFA offline callback */
54 55 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
static void	bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim,
60
					 enum bfa_fcs_itnim_event event);
K
Krishna Gudipati 已提交
61
static void	bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim,
62
					   enum bfa_fcs_itnim_event event);
K
Krishna Gudipati 已提交
63
static void	bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim,
64
				      enum bfa_fcs_itnim_event event);
K
Krishna Gudipati 已提交
65
static void	bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim,
66
					    enum bfa_fcs_itnim_event event);
K
Krishna Gudipati 已提交
67
static void	bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim,
68
					    enum bfa_fcs_itnim_event event);
K
Krishna Gudipati 已提交
69
static void	bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
70
					enum bfa_fcs_itnim_event event);
K
Krishna Gudipati 已提交
71
static void	bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim,
72
					     enum bfa_fcs_itnim_event event);
K
Krishna Gudipati 已提交
73
static void	bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim,
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
					   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},
};

/**
 *  fcs_itnim_sm FCS itnim state machine
 */

static void
bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim,
K
Krishna Gudipati 已提交
93
		 enum bfa_fcs_itnim_event event)
94 95 96 97 98 99 100
{
	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 已提交
101
		itnim->prli_retries = 0;
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
		bfa_fcs_itnim_send_prli(itnim, NULL);
		break;

	case BFA_FCS_ITNIM_SM_OFFLINE:
		bfa_fcs_rport_itnim_ack(itnim->rport);
		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:
118
		bfa_sm_fault(itnim->fcs, event);
119 120 121 122 123 124
	}

}

static void
bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim,
K
Krishna Gudipati 已提交
125
		 enum bfa_fcs_itnim_event event)
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
{
	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);
		bfa_fcs_rport_itnim_ack(itnim->rport);
		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:
153
		bfa_sm_fault(itnim->fcs, event);
154 155 156 157 158
	}
}

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

	switch (event) {
	case BFA_FCS_ITNIM_SM_RSP_OK:
166 167 168 169 170 171
		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);
		}
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
		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;

	case BFA_FCS_ITNIM_SM_OFFLINE:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
		bfa_fcxp_discard(itnim->fcxp);
		bfa_fcs_rport_itnim_ack(itnim->rport);
		break;

	case BFA_FCS_ITNIM_SM_INITIATOR:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
189
		bfa_fcxp_discard(itnim->fcxp);
190 191 192 193 194 195 196 197 198
		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:
199
		bfa_sm_fault(itnim->fcs, event);
200 201 202 203 204 205 206 207 208 209 210 211
	}
}

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 已提交
212 213 214 215 216 217 218 219 220 221
		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);
			bfa_fcs_rport_logo_imp(itnim->rport);
		}
222 223
		break;

K
Krishna Gudipati 已提交
224

225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
	case BFA_FCS_ITNIM_SM_OFFLINE:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
		bfa_timer_stop(&itnim->timer);
		bfa_fcs_rport_itnim_ack(itnim->rport);
		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:
243
		bfa_sm_fault(itnim->fcs, event);
244 245 246 247 248 249 250
	}
}

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

255 256 257 258 259 260 261
	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 已提交
262 263 264 265 266
		wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port));
		wwn2str(rpwwn_buf, itnim->rport->pwwn);
		BFA_LOG(KERN_INFO, bfad, log_level,
		"Target (WWN = %s) is online for initiator (WWN = %s)\n",
		rpwwn_buf, lpwwn_buf);
267 268 269 270 271 272 273 274 275 276 277 278 279 280
		break;

	case BFA_FCS_ITNIM_SM_OFFLINE:
		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
		bfa_itnim_offline(itnim->bfa_itnim);
		bfa_fcs_rport_itnim_ack(itnim->rport);
		break;

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

	default:
281
		bfa_sm_fault(itnim->fcs, event);
282 283 284 285 286
	}
}

static void
bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
K
Krishna Gudipati 已提交
287
		 enum bfa_fcs_itnim_event event)
288
{
K
Krishna Gudipati 已提交
289 290 291 292
	struct bfad_s *bfad = (struct bfad_s *)itnim->fcs->bfad;
	char	lpwwn_buf[BFA_STRING_32];
	char	rpwwn_buf[BFA_STRING_32];

293 294 295 296 297 298 299 300
	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 已提交
301 302 303 304 305 306
		wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port));
		wwn2str(rpwwn_buf, itnim->rport->pwwn);
		if (bfa_fcs_lport_is_online(itnim->rport->port) == BFA_TRUE)
			BFA_LOG(KERN_ERR, bfad, log_level,
			"Target (WWN = %s) connectivity lost for "
			"initiator (WWN = %s)\n", rpwwn_buf, lpwwn_buf);
307
		else
K
Krishna Gudipati 已提交
308 309 310
			BFA_LOG(KERN_INFO, bfad, log_level,
			"Target (WWN = %s) offlined by initiator (WWN = %s)\n",
			rpwwn_buf, lpwwn_buf);
311 312 313 314 315 316 317 318
		break;

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

	default:
319
		bfa_sm_fault(itnim->fcs, event);
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
	}
}

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);
		bfa_fcs_rport_itnim_ack(itnim->rport);
		break;

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

	default:
342
		bfa_sm_fault(itnim->fcs, event);
343 344 345 346 347 348 349 350 351 352
	}
}

/*
 * 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 已提交
353
		 enum bfa_fcs_itnim_event event)
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
{
	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);
		bfa_fcs_rport_itnim_ack(itnim->rport);
		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:
375
		bfa_sm_fault(itnim->fcs, event);
376 377 378 379 380 381 382 383
	}
}

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 已提交
384 385
	struct bfa_fcs_lport_s *port = rport->port;
	struct fchs_s	fchs;
386
	struct bfa_fcxp_s *fcxp;
K
Krishna Gudipati 已提交
387
	int		len;
388 389 390 391 392 393

	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 已提交
394
		bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &itnim->fcxp_wqe,
395 396 397 398 399
				    bfa_fcs_itnim_send_prli, itnim);
		return;
	}
	itnim->fcxp = fcxp;

K
Krishna Gudipati 已提交
400 401
	len = fc_prli_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
			    itnim->rport->pid, bfa_fcs_lport_get_fcid(port), 0);
402 403 404

	bfa_fcxp_send(fcxp, rport->bfa_rport, port->fabric->vf_id, port->lp_tag,
		      BFA_FALSE, FC_CLASS_3, len, &fchs,
K
Krishna Gudipati 已提交
405 406
		      bfa_fcs_itnim_prli_response, (void *)itnim,
		      FC_MAX_PDUSZ, FC_ELS_TOV);
407 408 409 410 411 412 413 414 415 416

	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 已提交
417 418 419 420
	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;
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
	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 已提交
448
					 BFA_RPORT_INITIATOR;
449 450
				itnim->stats.prli_rsp_acc++;
				bfa_sm_send_event(itnim,
451
						  BFA_FCS_ITNIM_SM_RSP_OK);
452 453 454 455 456 457 458 459 460
				return;
			}

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

		sparams = &prli_resp->parampage.servparams;
K
Krishna Gudipati 已提交
461 462
		itnim->seq_rec	     = sparams->retry;
		itnim->rec_support   = sparams->rec_support;
463
		itnim->task_retry_id = sparams->task_retry_id;
K
Krishna Gudipati 已提交
464
		itnim->conf_comp     = sparams->confirm;
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481

		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++;
		bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR);
	}
}

static void
bfa_fcs_itnim_timeout(void *arg)
{
K
Krishna Gudipati 已提交
482
	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) arg;
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501

	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);
}



/**
 *  itnim_public FCS ITNIM public interfaces
 */

/**
K
Krishna Gudipati 已提交
502
 *	Called by rport when a new rport is created.
503 504 505 506 507 508
 *
 * @param[in] rport	-  remote port.
 */
struct bfa_fcs_itnim_s *
bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport)
{
K
Krishna Gudipati 已提交
509
	struct bfa_fcs_lport_s *port = rport->port;
510
	struct bfa_fcs_itnim_s *itnim;
K
Krishna Gudipati 已提交
511
	struct bfad_itnim_s   *itnim_drv;
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
	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 已提交
533 534
	bfa_itnim =
		bfa_itnim_create(port->fcs->bfa, rport->bfa_rport, itnim);
535 536 537 538 539 540 541 542

	if (bfa_itnim == NULL) {
		bfa_trc(port->fcs, rport->pwwn);
		bfa_fcb_itnim_free(port->fcs->bfad, itnim_drv);
		bfa_assert(0);
		return NULL;
	}

K
Krishna Gudipati 已提交
543 544 545 546
	itnim->bfa_itnim     = bfa_itnim;
	itnim->seq_rec	     = BFA_FALSE;
	itnim->rec_support   = BFA_FALSE;
	itnim->conf_comp     = BFA_FALSE;
547 548 549 550 551 552 553 554 555 556 557
	itnim->task_retry_id = BFA_FALSE;

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

	return itnim;
}

/**
K
Krishna Gudipati 已提交
558
 *	Called by rport to delete  the instance of FCPIM.
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
 *
 * @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);
}

/**
 * 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 已提交
581 582
		 *  For well known addresses, we set the itnim to initiator
		 *  state
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633
		 */
		itnim->stats.initiator++;
		bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR);
	}
}

/**
 * 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);
}

/**
 * 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);
}

/**
 * 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;
	}
}

/**
 * BFA completion callback for bfa_itnim_online().
 */
void
bfa_cb_itnim_online(void *cbarg)
{
K
Krishna Gudipati 已提交
634
	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cbarg;
635 636 637 638 639 640 641 642 643 644 645

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

/**
 * BFA completion callback for bfa_itnim_offline().
 */
void
bfa_cb_itnim_offline(void *cb_arg)
{
K
Krishna Gudipati 已提交
646
	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
647 648 649 650 651 652 653 654 655 656 657 658

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

/**
 * 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 已提交
659
	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
660 661 662 663 664 665 666 667 668 669

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

/**
 * 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 已提交
670 671
	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
	struct bfad_itnim_s *itnim_drv = itnim->itnim_drv;
672 673

	bfa_trc(itnim->fcs, itnim->rport->pwwn);
K
Krishna Gudipati 已提交
674
	itnim_drv->state = ITNIM_STATE_TIMEOUT;
675 676 677
}

/**
K
Krishna Gudipati 已提交
678
 *		BFA notification to FCS/driver for second level error recovery.
679 680 681 682 683 684 685 686
 *
 * 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 已提交
687
	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
688 689 690 691 692 693 694

	itnim->stats.sler++;
	bfa_trc(itnim->fcs, itnim->rport->pwwn);
	bfa_fcs_rport_logo_imp(itnim->rport);
}

struct bfa_fcs_itnim_s *
K
Krishna Gudipati 已提交
695
bfa_fcs_itnim_lookup(struct bfa_fcs_lport_s *port, wwn_t rpwwn)
696 697 698 699 700 701 702 703
{
	struct bfa_fcs_rport_s *rport;
	rport = bfa_fcs_rport_lookup(port, rpwwn);

	if (!rport)
		return NULL;

	bfa_assert(rport->itnim != NULL);
704
	return rport->itnim;
705 706 707
}

bfa_status_t
K
Krishna Gudipati 已提交
708
bfa_fcs_itnim_attr_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn,
709 710 711 712 713 714 715 716 717
		       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 已提交
718 719 720 721
	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;
722 723 724 725 726
	attr->task_retry_id = itnim->task_retry_id;
	return BFA_STATUS_OK;
}

bfa_status_t
K
Krishna Gudipati 已提交
727
bfa_fcs_itnim_stats_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn,
728 729 730 731 732 733 734 735 736 737 738
			struct bfa_itnim_stats_s *stats)
{
	struct bfa_fcs_itnim_s *itnim = NULL;

	bfa_assert(port != NULL);

	itnim = bfa_fcs_itnim_lookup(port, rpwwn);

	if (itnim == NULL)
		return BFA_STATUS_NO_FCPIM_NEXUS;

739
	memcpy(stats, &itnim->stats, sizeof(struct bfa_itnim_stats_s));
740 741 742 743 744

	return BFA_STATUS_OK;
}

bfa_status_t
K
Krishna Gudipati 已提交
745
bfa_fcs_itnim_stats_clear(struct bfa_fcs_lport_s *port, wwn_t rpwwn)
746 747 748 749 750 751 752 753 754 755
{
	struct bfa_fcs_itnim_s *itnim = NULL;

	bfa_assert(port != NULL);

	itnim = bfa_fcs_itnim_lookup(port, rpwwn);

	if (itnim == NULL)
		return BFA_STATUS_NO_FCPIM_NEXUS;

756
	memset(&itnim->stats, 0, sizeof(struct bfa_itnim_stats_s));
757 758 759 760
	return BFA_STATUS_OK;
}

void
K
Krishna Gudipati 已提交
761 762
bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim,
			struct fchs_s *fchs, u16 len)
763
{
K
Krishna Gudipati 已提交
764
	struct fc_els_cmd_s *els_cmd;
765 766 767 768 769 770 771 772 773 774 775 776

	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:
777
		bfa_fcs_rport_prlo(itnim->rport, fchs->ox_id);
778 779 780 781 782 783
		break;

	default:
		bfa_assert(0);
	}
}