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

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

J
Jing Huang 已提交
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
					   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 已提交
87
/*
88 89 90 91 92
 *  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

	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 已提交
497
/*
498 499 500
 *  itnim_public FCS ITNIM public interfaces
 */

J
Jing Huang 已提交
501
/*
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
	itnim->task_retry_id = BFA_FALSE;

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

	return itnim;
}

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

J
Jing Huang 已提交
589
/*
590 591 592 593 594 595 596 597 598
 * 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 已提交
599
/*
600 601 602 603 604 605 606 607 608 609 610
 * 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 已提交
611
/*
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
 * 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 已提交
628
/*
629 630 631 632 633
 * 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

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

J
Jing Huang 已提交
640
/*
641 642 643 644 645
 * 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

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

J
Jing Huang 已提交
652
/*
653 654 655 656 657 658
 * 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

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

J
Jing Huang 已提交
664
/*
665 666 667 668 669
 * 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
}

J
Jing Huang 已提交
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);
	}
}