1/*
2 * This file is part of the Chelsio FCoE driver for Linux.
3 *
4 * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
5 *
6 * This software is available to you under a choice of one of two
7 * licenses.  You may choose to be licensed under the terms of the GNU
8 * General Public License (GPL) Version 2, available from the file
9 * COPYING in the main directory of this source tree, or the
10 * OpenIB.org BSD license below:
11 *
12 *     Redistribution and use in source and binary forms, with or
13 *     without modification, are permitted provided that the following
14 *     conditions are met:
15 *
16 *      - Redistributions of source code must retain the above
17 *        copyright notice, this list of conditions and the following
18 *        disclaimer.
19 *
20 *      - Redistributions in binary form must reproduce the above
21 *        copyright notice, this list of conditions and the following
22 *        disclaimer in the documentation and/or other materials
23 *        provided with the distribution.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 * SOFTWARE.
33 */
34
35#include <linux/string.h>
36#include <scsi/scsi_device.h>
37#include <scsi/scsi_transport_fc.h>
38#include <scsi/fc/fc_els.h>
39#include <scsi/fc/fc_fs.h>
40
41#include "csio_hw.h"
42#include "csio_lnode.h"
43#include "csio_rnode.h"
44
45static int csio_rnode_init(struct csio_rnode *, struct csio_lnode *);
46static void csio_rnode_exit(struct csio_rnode *);
47
48/* Static machine forward declarations */
49static void csio_rns_uninit(struct csio_rnode *, enum csio_rn_ev);
50static void csio_rns_ready(struct csio_rnode *, enum csio_rn_ev);
51static void csio_rns_offline(struct csio_rnode *, enum csio_rn_ev);
52static void csio_rns_disappeared(struct csio_rnode *, enum csio_rn_ev);
53
54/* RNF event mapping */
55static enum csio_rn_ev fwevt_to_rnevt[] = {
56	CSIO_RNFE_NONE,		/* None */
57	CSIO_RNFE_LOGGED_IN,	/* PLOGI_ACC_RCVD  */
58	CSIO_RNFE_NONE,		/* PLOGI_RJT_RCVD  */
59	CSIO_RNFE_PLOGI_RECV,	/* PLOGI_RCVD	   */
60	CSIO_RNFE_LOGO_RECV,	/* PLOGO_RCVD	   */
61	CSIO_RNFE_PRLI_DONE,	/* PRLI_ACC_RCVD   */
62	CSIO_RNFE_NONE,		/* PRLI_RJT_RCVD   */
63	CSIO_RNFE_PRLI_RECV,	/* PRLI_RCVD	   */
64	CSIO_RNFE_PRLO_RECV,	/* PRLO_RCVD	   */
65	CSIO_RNFE_NONE,		/* NPORT_ID_CHGD   */
66	CSIO_RNFE_LOGO_RECV,	/* FLOGO_RCVD	   */
67	CSIO_RNFE_NONE,		/* CLR_VIRT_LNK_RCVD */
68	CSIO_RNFE_LOGGED_IN,	/* FLOGI_ACC_RCVD   */
69	CSIO_RNFE_NONE,		/* FLOGI_RJT_RCVD   */
70	CSIO_RNFE_LOGGED_IN,	/* FDISC_ACC_RCVD   */
71	CSIO_RNFE_NONE,		/* FDISC_RJT_RCVD   */
72	CSIO_RNFE_NONE,		/* FLOGI_TMO_MAX_RETRY */
73	CSIO_RNFE_NONE,		/* IMPL_LOGO_ADISC_ACC */
74	CSIO_RNFE_NONE,		/* IMPL_LOGO_ADISC_RJT */
75	CSIO_RNFE_NONE,		/* IMPL_LOGO_ADISC_CNFLT */
76	CSIO_RNFE_NONE,		/* PRLI_TMO		*/
77	CSIO_RNFE_NONE,		/* ADISC_TMO		*/
78	CSIO_RNFE_NAME_MISSING,	/* RSCN_DEV_LOST  */
79	CSIO_RNFE_NONE,		/* SCR_ACC_RCVD	*/
80	CSIO_RNFE_NONE,		/* ADISC_RJT_RCVD */
81	CSIO_RNFE_NONE,		/* LOGO_SNT */
82	CSIO_RNFE_LOGO_RECV,	/* PROTO_ERR_IMPL_LOGO */
83};
84
85#define CSIO_FWE_TO_RNFE(_evt)	((_evt > PROTO_ERR_IMPL_LOGO) ?		\
86						CSIO_RNFE_NONE :	\
87						fwevt_to_rnevt[_evt])
88int
89csio_is_rnode_ready(struct csio_rnode *rn)
90{
91	return csio_match_state(rn, csio_rns_ready);
92}
93
94static int
95csio_is_rnode_uninit(struct csio_rnode *rn)
96{
97	return csio_match_state(rn, csio_rns_uninit);
98}
99
100static int
101csio_is_rnode_wka(uint8_t rport_type)
102{
103	if ((rport_type == FLOGI_VFPORT) ||
104	    (rport_type == FDISC_VFPORT) ||
105	    (rport_type == NS_VNPORT) ||
106	    (rport_type == FDMI_VNPORT))
107		return 1;
108
109	return 0;
110}
111
112/*
113 * csio_rn_lookup - Finds the rnode with the given flowid
114 * @ln - lnode
115 * @flowid - flowid.
116 *
117 * Does the rnode lookup on the given lnode and flowid.If no matching entry
118 * found, NULL is returned.
119 */
120static struct csio_rnode *
121csio_rn_lookup(struct csio_lnode *ln, uint32_t flowid)
122{
123	struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead;
124	struct list_head *tmp;
125	struct csio_rnode *rn;
126
127	list_for_each(tmp, &rnhead->sm.sm_list) {
128		rn = (struct csio_rnode *) tmp;
129		if (rn->flowid == flowid)
130			return rn;
131	}
132
133	return NULL;
134}
135
136/*
137 * csio_rn_lookup_wwpn - Finds the rnode with the given wwpn
138 * @ln: lnode
139 * @wwpn: wwpn
140 *
141 * Does the rnode lookup on the given lnode and wwpn. If no matching entry
142 * found, NULL is returned.
143 */
144static struct csio_rnode *
145csio_rn_lookup_wwpn(struct csio_lnode *ln, uint8_t *wwpn)
146{
147	struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead;
148	struct list_head *tmp;
149	struct csio_rnode *rn;
150
151	list_for_each(tmp, &rnhead->sm.sm_list) {
152		rn = (struct csio_rnode *) tmp;
153		if (!memcmp(csio_rn_wwpn(rn), wwpn, 8))
154			return rn;
155	}
156
157	return NULL;
158}
159
160/**
161 * csio_rnode_lookup_portid - Finds the rnode with the given portid
162 * @ln:		lnode
163 * @portid:	port id
164 *
165 * Lookup the rnode list for a given portid. If no matching entry
166 * found, NULL is returned.
167 */
168struct csio_rnode *
169csio_rnode_lookup_portid(struct csio_lnode *ln, uint32_t portid)
170{
171	struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead;
172	struct list_head *tmp;
173	struct csio_rnode *rn;
174
175	list_for_each(tmp, &rnhead->sm.sm_list) {
176		rn = (struct csio_rnode *) tmp;
177		if (rn->nport_id == portid)
178			return rn;
179	}
180
181	return NULL;
182}
183
184static int
185csio_rn_dup_flowid(struct csio_lnode *ln, uint32_t rdev_flowid,
186		    uint32_t *vnp_flowid)
187{
188	struct csio_rnode *rnhead;
189	struct list_head *tmp, *tmp1;
190	struct csio_rnode *rn;
191	struct csio_lnode *ln_tmp;
192	struct csio_hw *hw = csio_lnode_to_hw(ln);
193
194	list_for_each(tmp1, &hw->sln_head) {
195		ln_tmp = (struct csio_lnode *) tmp1;
196		if (ln_tmp == ln)
197			continue;
198
199		rnhead = (struct csio_rnode *)&ln_tmp->rnhead;
200		list_for_each(tmp, &rnhead->sm.sm_list) {
201
202			rn = (struct csio_rnode *) tmp;
203			if (csio_is_rnode_ready(rn)) {
204				if (rn->flowid == rdev_flowid) {
205					*vnp_flowid = csio_ln_flowid(ln_tmp);
206					return 1;
207				}
208			}
209		}
210	}
211
212	return 0;
213}
214
215static struct csio_rnode *
216csio_alloc_rnode(struct csio_lnode *ln)
217{
218	struct csio_hw *hw = csio_lnode_to_hw(ln);
219
220	struct csio_rnode *rn = mempool_alloc(hw->rnode_mempool, GFP_ATOMIC);
221	if (!rn)
222		goto err;
223
224	memset(rn, 0, sizeof(struct csio_rnode));
225	if (csio_rnode_init(rn, ln))
226		goto err_free;
227
228	CSIO_INC_STATS(ln, n_rnode_alloc);
229
230	return rn;
231
232err_free:
233	mempool_free(rn, hw->rnode_mempool);
234err:
235	CSIO_INC_STATS(ln, n_rnode_nomem);
236	return NULL;
237}
238
239static void
240csio_free_rnode(struct csio_rnode *rn)
241{
242	struct csio_hw *hw = csio_lnode_to_hw(csio_rnode_to_lnode(rn));
243
244	csio_rnode_exit(rn);
245	CSIO_INC_STATS(rn->lnp, n_rnode_free);
246	mempool_free(rn, hw->rnode_mempool);
247}
248
249/*
250 * csio_get_rnode - Gets rnode with the given flowid
251 * @ln - lnode
252 * @flowid - flow id.
253 *
254 * Does the rnode lookup on the given lnode and flowid. If no matching
255 * rnode found, then new rnode with given npid is allocated and returned.
256 */
257static struct csio_rnode *
258csio_get_rnode(struct csio_lnode *ln, uint32_t flowid)
259{
260	struct csio_rnode *rn;
261
262	rn = csio_rn_lookup(ln, flowid);
263	if (!rn) {
264		rn = csio_alloc_rnode(ln);
265		if (!rn)
266			return NULL;
267
268		rn->flowid = flowid;
269	}
270
271	return rn;
272}
273
274/*
275 * csio_put_rnode - Frees the given rnode
276 * @ln - lnode
277 * @flowid - flow id.
278 *
279 * Does the rnode lookup on the given lnode and flowid. If no matching
280 * rnode found, then new rnode with given npid is allocated and returned.
281 */
282void
283csio_put_rnode(struct csio_lnode *ln, struct csio_rnode *rn)
284{
285	CSIO_DB_ASSERT(csio_is_rnode_uninit(rn) != 0);
286	csio_free_rnode(rn);
287}
288
289/*
290 * csio_confirm_rnode - confirms rnode based on wwpn.
291 * @ln: lnode
292 * @rdev_flowid: remote device flowid
293 * @rdevp: remote device params
294 * This routines searches other rnode in list having same wwpn of new rnode.
295 * If there is a match, then matched rnode is returned and otherwise new rnode
296 * is returned.
297 * returns rnode.
298 */
299struct csio_rnode *
300csio_confirm_rnode(struct csio_lnode *ln, uint32_t rdev_flowid,
301		   struct fcoe_rdev_entry *rdevp)
302{
303	uint8_t rport_type;
304	struct csio_rnode *rn, *match_rn;
305	uint32_t vnp_flowid = 0;
306	__be32 *port_id;
307
308	port_id = (__be32 *)&rdevp->r_id[0];
309	rport_type =
310		FW_RDEV_WR_RPORT_TYPE_GET(rdevp->rd_xfer_rdy_to_rport_type);
311
312	/* Drop rdev event for cntrl port */
313	if (rport_type == FAB_CTLR_VNPORT) {
314		csio_ln_dbg(ln,
315			    "Unhandled rport_type:%d recv in rdev evt "
316			    "ssni:x%x\n", rport_type, rdev_flowid);
317		return NULL;
318	}
319
320	/* Lookup on flowid */
321	rn = csio_rn_lookup(ln, rdev_flowid);
322	if (!rn) {
323
324		/* Drop events with duplicate flowid */
325		if (csio_rn_dup_flowid(ln, rdev_flowid, &vnp_flowid)) {
326			csio_ln_warn(ln,
327				     "ssni:%x already active on vnpi:%x",
328				     rdev_flowid, vnp_flowid);
329			return NULL;
330		}
331
332		/* Lookup on wwpn for NPORTs */
333		rn = csio_rn_lookup_wwpn(ln, rdevp->wwpn);
334		if (!rn)
335			goto alloc_rnode;
336
337	} else {
338		/* Lookup well-known ports with nport id */
339		if (csio_is_rnode_wka(rport_type)) {
340			match_rn = csio_rnode_lookup_portid(ln,
341				      ((ntohl(*port_id) >> 8) & CSIO_DID_MASK));
342			if (match_rn == NULL) {
343				csio_rn_flowid(rn) = CSIO_INVALID_IDX;
344				goto alloc_rnode;
345			}
346
347			/*
348			 * Now compare the wwpn to confirm that
349			 * same port relogged in. If so update the matched rn.
350			 * Else, go ahead and alloc a new rnode.
351			 */
352			if (!memcmp(csio_rn_wwpn(match_rn), rdevp->wwpn, 8)) {
353				if (rn == match_rn)
354					goto found_rnode;
355				csio_ln_dbg(ln,
356					    "nport_id:x%x and wwpn:%llx"
357					    " match for ssni:x%x\n",
358					    rn->nport_id,
359					    wwn_to_u64(rdevp->wwpn),
360					    rdev_flowid);
361				if (csio_is_rnode_ready(rn)) {
362					csio_ln_warn(ln,
363						     "rnode is already"
364						     "active ssni:x%x\n",
365						     rdev_flowid);
366					CSIO_ASSERT(0);
367				}
368				csio_rn_flowid(rn) = CSIO_INVALID_IDX;
369				rn = match_rn;
370
371				/* Update rn */
372				goto found_rnode;
373			}
374			csio_rn_flowid(rn) = CSIO_INVALID_IDX;
375			goto alloc_rnode;
376		}
377
378		/* wwpn match */
379		if (!memcmp(csio_rn_wwpn(rn), rdevp->wwpn, 8))
380			goto found_rnode;
381
382		/* Search for rnode that have same wwpn */
383		match_rn = csio_rn_lookup_wwpn(ln, rdevp->wwpn);
384		if (match_rn != NULL) {
385			csio_ln_dbg(ln,
386				"ssni:x%x changed for rport name(wwpn):%llx "
387				"did:x%x\n", rdev_flowid,
388				wwn_to_u64(rdevp->wwpn),
389				match_rn->nport_id);
390			csio_rn_flowid(rn) = CSIO_INVALID_IDX;
391			rn = match_rn;
392		} else {
393			csio_ln_dbg(ln,
394				"rnode wwpn mismatch found ssni:x%x "
395				"name(wwpn):%llx\n",
396				rdev_flowid,
397				wwn_to_u64(csio_rn_wwpn(rn)));
398			if (csio_is_rnode_ready(rn)) {
399				csio_ln_warn(ln,
400					     "rnode is already active "
401					     "wwpn:%llx ssni:x%x\n",
402					     wwn_to_u64(csio_rn_wwpn(rn)),
403					     rdev_flowid);
404				CSIO_ASSERT(0);
405			}
406			csio_rn_flowid(rn) = CSIO_INVALID_IDX;
407			goto alloc_rnode;
408		}
409	}
410
411found_rnode:
412	csio_ln_dbg(ln, "found rnode:%p ssni:x%x name(wwpn):%llx\n",
413		rn, rdev_flowid, wwn_to_u64(rdevp->wwpn));
414
415	/* Update flowid */
416	csio_rn_flowid(rn) = rdev_flowid;
417
418	/* update rdev entry */
419	rn->rdev_entry = rdevp;
420	CSIO_INC_STATS(ln, n_rnode_match);
421	return rn;
422
423alloc_rnode:
424	rn = csio_get_rnode(ln, rdev_flowid);
425	if (!rn)
426		return NULL;
427
428	csio_ln_dbg(ln, "alloc rnode:%p ssni:x%x name(wwpn):%llx\n",
429		rn, rdev_flowid, wwn_to_u64(rdevp->wwpn));
430
431	/* update rdev entry */
432	rn->rdev_entry = rdevp;
433	return rn;
434}
435
436/*
437 * csio_rn_verify_rparams - verify rparams.
438 * @ln: lnode
439 * @rn: rnode
440 * @rdevp: remote device params
441 * returns success if rparams are verified.
442 */
443static int
444csio_rn_verify_rparams(struct csio_lnode *ln, struct csio_rnode *rn,
445			struct fcoe_rdev_entry *rdevp)
446{
447	uint8_t null[8];
448	uint8_t rport_type;
449	uint8_t fc_class;
450	__be32 *did;
451
452	did = (__be32 *) &rdevp->r_id[0];
453	rport_type =
454		FW_RDEV_WR_RPORT_TYPE_GET(rdevp->rd_xfer_rdy_to_rport_type);
455	switch (rport_type) {
456	case FLOGI_VFPORT:
457		rn->role = CSIO_RNFR_FABRIC;
458		if (((ntohl(*did) >> 8) & CSIO_DID_MASK) != FC_FID_FLOGI) {
459			csio_ln_err(ln, "ssni:x%x invalid fabric portid\n",
460				csio_rn_flowid(rn));
461			return -EINVAL;
462		}
463		/* NPIV support */
464		if (FW_RDEV_WR_NPIV_GET(rdevp->vft_to_qos))
465			ln->flags |= CSIO_LNF_NPIVSUPP;
466
467		break;
468
469	case NS_VNPORT:
470		rn->role = CSIO_RNFR_NS;
471		if (((ntohl(*did) >> 8) & CSIO_DID_MASK) != FC_FID_DIR_SERV) {
472			csio_ln_err(ln, "ssni:x%x invalid fabric portid\n",
473				csio_rn_flowid(rn));
474			return -EINVAL;
475		}
476		break;
477
478	case REG_FC4_VNPORT:
479	case REG_VNPORT:
480		rn->role = CSIO_RNFR_NPORT;
481		if (rdevp->event_cause == PRLI_ACC_RCVD ||
482			rdevp->event_cause == PRLI_RCVD) {
483			if (FW_RDEV_WR_TASK_RETRY_ID_GET(
484							rdevp->enh_disc_to_tgt))
485				rn->fcp_flags |= FCP_SPPF_OVLY_ALLOW;
486
487			if (FW_RDEV_WR_RETRY_GET(rdevp->enh_disc_to_tgt))
488				rn->fcp_flags |= FCP_SPPF_RETRY;
489
490			if (FW_RDEV_WR_CONF_CMPL_GET(rdevp->enh_disc_to_tgt))
491				rn->fcp_flags |= FCP_SPPF_CONF_COMPL;
492
493			if (FW_RDEV_WR_TGT_GET(rdevp->enh_disc_to_tgt))
494				rn->role |= CSIO_RNFR_TARGET;
495
496			if (FW_RDEV_WR_INI_GET(rdevp->enh_disc_to_tgt))
497				rn->role |= CSIO_RNFR_INITIATOR;
498		}
499
500		break;
501
502	case FDMI_VNPORT:
503	case FAB_CTLR_VNPORT:
504		rn->role = 0;
505		break;
506
507	default:
508		csio_ln_err(ln, "ssni:x%x invalid rport type recv x%x\n",
509			csio_rn_flowid(rn), rport_type);
510		return -EINVAL;
511	}
512
513	/* validate wwpn/wwnn for Name server/remote port */
514	if (rport_type == REG_VNPORT || rport_type == NS_VNPORT) {
515		memset(null, 0, 8);
516		if (!memcmp(rdevp->wwnn, null, 8)) {
517			csio_ln_err(ln,
518				    "ssni:x%x invalid wwnn received from"
519				    " rport did:x%x\n",
520				    csio_rn_flowid(rn),
521				    (ntohl(*did) & CSIO_DID_MASK));
522			return -EINVAL;
523		}
524
525		if (!memcmp(rdevp->wwpn, null, 8)) {
526			csio_ln_err(ln,
527				    "ssni:x%x invalid wwpn received from"
528				    " rport did:x%x\n",
529				    csio_rn_flowid(rn),
530				    (ntohl(*did) & CSIO_DID_MASK));
531			return -EINVAL;
532		}
533
534	}
535
536	/* Copy wwnn, wwpn and nport id */
537	rn->nport_id = (ntohl(*did) >> 8) & CSIO_DID_MASK;
538	memcpy(csio_rn_wwnn(rn), rdevp->wwnn, 8);
539	memcpy(csio_rn_wwpn(rn), rdevp->wwpn, 8);
540	rn->rn_sparm.csp.sp_bb_data = rdevp->rcv_fr_sz;
541	fc_class = FW_RDEV_WR_CLASS_GET(rdevp->vft_to_qos);
542	rn->rn_sparm.clsp[fc_class - 1].cp_class = htons(FC_CPC_VALID);
543
544	return 0;
545}
546
547static void
548__csio_reg_rnode(struct csio_rnode *rn)
549{
550	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
551	struct csio_hw *hw = csio_lnode_to_hw(ln);
552
553	spin_unlock_irq(&hw->lock);
554	csio_reg_rnode(rn);
555	spin_lock_irq(&hw->lock);
556
557	if (rn->role & CSIO_RNFR_TARGET)
558		ln->n_scsi_tgts++;
559
560	if (rn->nport_id == FC_FID_MGMT_SERV)
561		csio_ln_fdmi_start(ln, (void *) rn);
562}
563
564static void
565__csio_unreg_rnode(struct csio_rnode *rn)
566{
567	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
568	struct csio_hw *hw = csio_lnode_to_hw(ln);
569	LIST_HEAD(tmp_q);
570	int cmpl = 0;
571
572	if (!list_empty(&rn->host_cmpl_q)) {
573		csio_dbg(hw, "Returning completion queue I/Os\n");
574		list_splice_tail_init(&rn->host_cmpl_q, &tmp_q);
575		cmpl = 1;
576	}
577
578	if (rn->role & CSIO_RNFR_TARGET) {
579		ln->n_scsi_tgts--;
580		ln->last_scan_ntgts--;
581	}
582
583	spin_unlock_irq(&hw->lock);
584	csio_unreg_rnode(rn);
585	spin_lock_irq(&hw->lock);
586
587	/* Cleanup I/Os that were waiting for rnode to unregister */
588	if (cmpl)
589		csio_scsi_cleanup_io_q(csio_hw_to_scsim(hw), &tmp_q);
590
591}
592
593/*****************************************************************************/
594/* START: Rnode SM                                                           */
595/*****************************************************************************/
596
597/*
598 * csio_rns_uninit -
599 * @rn - rnode
600 * @evt - SM event.
601 *
602 */
603static void
604csio_rns_uninit(struct csio_rnode *rn, enum csio_rn_ev evt)
605{
606	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
607	int ret = 0;
608
609	CSIO_INC_STATS(rn, n_evt_sm[evt]);
610
611	switch (evt) {
612	case CSIO_RNFE_LOGGED_IN:
613	case CSIO_RNFE_PLOGI_RECV:
614		ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
615		if (!ret) {
616			csio_set_state(&rn->sm, csio_rns_ready);
617			__csio_reg_rnode(rn);
618		} else {
619			CSIO_INC_STATS(rn, n_err_inval);
620		}
621		break;
622	case CSIO_RNFE_LOGO_RECV:
623		csio_ln_dbg(ln,
624			    "ssni:x%x Ignoring event %d recv "
625			    "in rn state[uninit]\n", csio_rn_flowid(rn), evt);
626		CSIO_INC_STATS(rn, n_evt_drop);
627		break;
628	default:
629		csio_ln_dbg(ln,
630			    "ssni:x%x unexp event %d recv "
631			    "in rn state[uninit]\n", csio_rn_flowid(rn), evt);
632		CSIO_INC_STATS(rn, n_evt_unexp);
633		break;
634	}
635}
636
637/*
638 * csio_rns_ready -
639 * @rn - rnode
640 * @evt - SM event.
641 *
642 */
643static void
644csio_rns_ready(struct csio_rnode *rn, enum csio_rn_ev evt)
645{
646	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
647	int ret = 0;
648
649	CSIO_INC_STATS(rn, n_evt_sm[evt]);
650
651	switch (evt) {
652	case CSIO_RNFE_LOGGED_IN:
653	case CSIO_RNFE_PLOGI_RECV:
654		csio_ln_dbg(ln,
655			"ssni:x%x Ignoring event %d recv from did:x%x "
656			"in rn state[ready]\n", csio_rn_flowid(rn), evt,
657			rn->nport_id);
658		CSIO_INC_STATS(rn, n_evt_drop);
659		break;
660
661	case CSIO_RNFE_PRLI_DONE:
662	case CSIO_RNFE_PRLI_RECV:
663		ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
664		if (!ret)
665			__csio_reg_rnode(rn);
666		else
667			CSIO_INC_STATS(rn, n_err_inval);
668
669		break;
670	case CSIO_RNFE_DOWN:
671		csio_set_state(&rn->sm, csio_rns_offline);
672		__csio_unreg_rnode(rn);
673
674		/* FW expected to internally aborted outstanding SCSI WRs
675		 * and return all SCSI WRs to host with status "ABORTED".
676		 */
677		break;
678
679	case CSIO_RNFE_LOGO_RECV:
680		csio_set_state(&rn->sm, csio_rns_offline);
681
682		__csio_unreg_rnode(rn);
683
684		/* FW expected to internally aborted outstanding SCSI WRs
685		 * and return all SCSI WRs to host with status "ABORTED".
686		 */
687		break;
688
689	case CSIO_RNFE_CLOSE:
690		/*
691		 * Each rnode receives CLOSE event when driver is removed or
692		 * device is reset
693		 * Note: All outstanding IOs on remote port need to returned
694		 * to uppper layer with appropriate error before sending
695		 * CLOSE event
696		 */
697		csio_set_state(&rn->sm, csio_rns_uninit);
698		__csio_unreg_rnode(rn);
699		break;
700
701	case CSIO_RNFE_NAME_MISSING:
702		csio_set_state(&rn->sm, csio_rns_disappeared);
703		__csio_unreg_rnode(rn);
704
705		/*
706		 * FW expected to internally aborted outstanding SCSI WRs
707		 * and return all SCSI WRs to host with status "ABORTED".
708		 */
709
710		break;
711
712	default:
713		csio_ln_dbg(ln,
714			"ssni:x%x unexp event %d recv from did:x%x "
715			"in rn state[uninit]\n", csio_rn_flowid(rn), evt,
716			rn->nport_id);
717		CSIO_INC_STATS(rn, n_evt_unexp);
718		break;
719	}
720}
721
722/*
723 * csio_rns_offline -
724 * @rn - rnode
725 * @evt - SM event.
726 *
727 */
728static void
729csio_rns_offline(struct csio_rnode *rn, enum csio_rn_ev evt)
730{
731	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
732	int ret = 0;
733
734	CSIO_INC_STATS(rn, n_evt_sm[evt]);
735
736	switch (evt) {
737	case CSIO_RNFE_LOGGED_IN:
738	case CSIO_RNFE_PLOGI_RECV:
739		ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
740		if (!ret) {
741			csio_set_state(&rn->sm, csio_rns_ready);
742			__csio_reg_rnode(rn);
743		} else {
744			CSIO_INC_STATS(rn, n_err_inval);
745			csio_post_event(&rn->sm, CSIO_RNFE_CLOSE);
746		}
747		break;
748
749	case CSIO_RNFE_DOWN:
750		csio_ln_dbg(ln,
751			"ssni:x%x Ignoring event %d recv from did:x%x "
752			"in rn state[offline]\n", csio_rn_flowid(rn), evt,
753			rn->nport_id);
754		CSIO_INC_STATS(rn, n_evt_drop);
755		break;
756
757	case CSIO_RNFE_CLOSE:
758		/* Each rnode receives CLOSE event when driver is removed or
759		 * device is reset
760		 * Note: All outstanding IOs on remote port need to returned
761		 * to uppper layer with appropriate error before sending
762		 * CLOSE event
763		 */
764		csio_set_state(&rn->sm, csio_rns_uninit);
765		break;
766
767	case CSIO_RNFE_NAME_MISSING:
768		csio_set_state(&rn->sm, csio_rns_disappeared);
769		break;
770
771	default:
772		csio_ln_dbg(ln,
773			"ssni:x%x unexp event %d recv from did:x%x "
774			"in rn state[offline]\n", csio_rn_flowid(rn), evt,
775			rn->nport_id);
776		CSIO_INC_STATS(rn, n_evt_unexp);
777		break;
778	}
779}
780
781/*
782 * csio_rns_disappeared -
783 * @rn - rnode
784 * @evt - SM event.
785 *
786 */
787static void
788csio_rns_disappeared(struct csio_rnode *rn, enum csio_rn_ev evt)
789{
790	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
791	int ret = 0;
792
793	CSIO_INC_STATS(rn, n_evt_sm[evt]);
794
795	switch (evt) {
796	case CSIO_RNFE_LOGGED_IN:
797	case CSIO_RNFE_PLOGI_RECV:
798		ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
799		if (!ret) {
800			csio_set_state(&rn->sm, csio_rns_ready);
801			__csio_reg_rnode(rn);
802		} else {
803			CSIO_INC_STATS(rn, n_err_inval);
804			csio_post_event(&rn->sm, CSIO_RNFE_CLOSE);
805		}
806		break;
807
808	case CSIO_RNFE_CLOSE:
809		/* Each rnode receives CLOSE event when driver is removed or
810		 * device is reset.
811		 * Note: All outstanding IOs on remote port need to returned
812		 * to uppper layer with appropriate error before sending
813		 * CLOSE event
814		 */
815		csio_set_state(&rn->sm, csio_rns_uninit);
816		break;
817
818	case CSIO_RNFE_DOWN:
819	case CSIO_RNFE_NAME_MISSING:
820		csio_ln_dbg(ln,
821			"ssni:x%x Ignoring event %d recv from did x%x"
822			"in rn state[disappeared]\n", csio_rn_flowid(rn),
823			evt, rn->nport_id);
824		break;
825
826	default:
827		csio_ln_dbg(ln,
828			"ssni:x%x unexp event %d recv from did x%x"
829			"in rn state[disappeared]\n", csio_rn_flowid(rn),
830			evt, rn->nport_id);
831		CSIO_INC_STATS(rn, n_evt_unexp);
832		break;
833	}
834}
835
836/*****************************************************************************/
837/* END: Rnode SM                                                             */
838/*****************************************************************************/
839
840/*
841 * csio_rnode_devloss_handler - Device loss event handler
842 * @rn: rnode
843 *
844 * Post event to close rnode SM and free rnode.
845 */
846void
847csio_rnode_devloss_handler(struct csio_rnode *rn)
848{
849	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
850
851	/* ignore if same rnode came back as online */
852	if (csio_is_rnode_ready(rn))
853		return;
854
855	csio_post_event(&rn->sm, CSIO_RNFE_CLOSE);
856
857	/* Free rn if in uninit state */
858	if (csio_is_rnode_uninit(rn))
859		csio_put_rnode(ln, rn);
860}
861
862/**
863 * csio_rnode_fwevt_handler - Event handler for firmware rnode events.
864 * @rn:		rnode
865 * @fwevt:	firmware event to handle
866 */
867void
868csio_rnode_fwevt_handler(struct csio_rnode *rn, uint8_t fwevt)
869{
870	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
871	enum csio_rn_ev evt;
872
873	evt = CSIO_FWE_TO_RNFE(fwevt);
874	if (!evt) {
875		csio_ln_err(ln, "ssni:x%x Unhandled FW Rdev event: %d\n",
876			    csio_rn_flowid(rn), fwevt);
877		CSIO_INC_STATS(rn, n_evt_unexp);
878		return;
879	}
880	CSIO_INC_STATS(rn, n_evt_fw[fwevt]);
881
882	/* Track previous & current events for debugging */
883	rn->prev_evt = rn->cur_evt;
884	rn->cur_evt = fwevt;
885
886	/* Post event to rnode SM */
887	csio_post_event(&rn->sm, evt);
888
889	/* Free rn if in uninit state */
890	if (csio_is_rnode_uninit(rn))
891		csio_put_rnode(ln, rn);
892}
893
894/*
895 * csio_rnode_init - Initialize rnode.
896 * @rn: RNode
897 * @ln: Associated lnode
898 *
899 * Caller is responsible for holding the lock. The lock is required
900 * to be held for inserting the rnode in ln->rnhead list.
901 */
902static int
903csio_rnode_init(struct csio_rnode *rn, struct csio_lnode *ln)
904{
905	csio_rnode_to_lnode(rn) = ln;
906	csio_init_state(&rn->sm, csio_rns_uninit);
907	INIT_LIST_HEAD(&rn->host_cmpl_q);
908	csio_rn_flowid(rn) = CSIO_INVALID_IDX;
909
910	/* Add rnode to list of lnodes->rnhead */
911	list_add_tail(&rn->sm.sm_list, &ln->rnhead);
912
913	return 0;
914}
915
916static void
917csio_rnode_exit(struct csio_rnode *rn)
918{
919	list_del_init(&rn->sm.sm_list);
920	CSIO_DB_ASSERT(list_empty(&rn->host_cmpl_q));
921}
922