xref: /openbmc/linux/drivers/scsi/bfa/bfa_fcs_lport.c (revision a09d2831)
1 /*
2  * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
3  * All rights reserved
4  * www.brocade.com
5  *
6  * Linux driver for Brocade Fibre Channel Host Bus Adapter.
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License (GPL) Version 2 as
10  * published by the Free Software Foundation
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  */
17 
18 /**
19  *  bfa_fcs_port.c BFA FCS port
20  */
21 
22 #include <fcs/bfa_fcs.h>
23 #include <fcs/bfa_fcs_lport.h>
24 #include <fcs/bfa_fcs_rport.h>
25 #include <fcb/bfa_fcb_port.h>
26 #include <bfa_svc.h>
27 #include <log/bfa_log_fcs.h>
28 #include "fcs.h"
29 #include "fcs_lport.h"
30 #include "fcs_vport.h"
31 #include "fcs_rport.h"
32 #include "fcs_fcxp.h"
33 #include "fcs_trcmod.h"
34 #include "lport_priv.h"
35 #include <aen/bfa_aen_lport.h>
36 
37 BFA_TRC_FILE(FCS, PORT);
38 
39 /**
40  * Forward declarations
41  */
42 
43 static void     bfa_fcs_port_aen_post(struct bfa_fcs_port_s *port,
44 				      enum bfa_lport_aen_event event);
45 static void     bfa_fcs_port_send_ls_rjt(struct bfa_fcs_port_s *port,
46 			struct fchs_s *rx_fchs, u8 reason_code,
47 			u8 reason_code_expl);
48 static void     bfa_fcs_port_plogi(struct bfa_fcs_port_s *port,
49 			struct fchs_s *rx_fchs,
50 			struct fc_logi_s *plogi);
51 static void     bfa_fcs_port_online_actions(struct bfa_fcs_port_s *port);
52 static void     bfa_fcs_port_offline_actions(struct bfa_fcs_port_s *port);
53 static void     bfa_fcs_port_unknown_init(struct bfa_fcs_port_s *port);
54 static void     bfa_fcs_port_unknown_online(struct bfa_fcs_port_s *port);
55 static void     bfa_fcs_port_unknown_offline(struct bfa_fcs_port_s *port);
56 static void     bfa_fcs_port_deleted(struct bfa_fcs_port_s *port);
57 static void     bfa_fcs_port_echo(struct bfa_fcs_port_s *port,
58 			struct fchs_s *rx_fchs,
59 			struct fc_echo_s *echo, u16 len);
60 static void     bfa_fcs_port_rnid(struct bfa_fcs_port_s *port,
61 			struct fchs_s *rx_fchs,
62 			struct fc_rnid_cmd_s *rnid, u16 len);
63 static void     bfa_fs_port_get_gen_topo_data(struct bfa_fcs_port_s *port,
64 			struct fc_rnid_general_topology_data_s *gen_topo_data);
65 
66 static struct {
67 	void            (*init) (struct bfa_fcs_port_s *port);
68 	void            (*online) (struct bfa_fcs_port_s *port);
69 	void            (*offline) (struct bfa_fcs_port_s *port);
70 } __port_action[] = {
71 	{
72 	bfa_fcs_port_unknown_init, bfa_fcs_port_unknown_online,
73 			bfa_fcs_port_unknown_offline}, {
74 	bfa_fcs_port_fab_init, bfa_fcs_port_fab_online,
75 			bfa_fcs_port_fab_offline}, {
76 	bfa_fcs_port_loop_init, bfa_fcs_port_loop_online,
77 			bfa_fcs_port_loop_offline}, {
78 bfa_fcs_port_n2n_init, bfa_fcs_port_n2n_online,
79 			bfa_fcs_port_n2n_offline},};
80 
81 /**
82  *  fcs_port_sm FCS logical port state machine
83  */
84 
85 enum bfa_fcs_port_event {
86 	BFA_FCS_PORT_SM_CREATE = 1,
87 	BFA_FCS_PORT_SM_ONLINE = 2,
88 	BFA_FCS_PORT_SM_OFFLINE = 3,
89 	BFA_FCS_PORT_SM_DELETE = 4,
90 	BFA_FCS_PORT_SM_DELRPORT = 5,
91 };
92 
93 static void     bfa_fcs_port_sm_uninit(struct bfa_fcs_port_s *port,
94 				       enum bfa_fcs_port_event event);
95 static void     bfa_fcs_port_sm_init(struct bfa_fcs_port_s *port,
96 				     enum bfa_fcs_port_event event);
97 static void     bfa_fcs_port_sm_online(struct bfa_fcs_port_s *port,
98 				       enum bfa_fcs_port_event event);
99 static void     bfa_fcs_port_sm_offline(struct bfa_fcs_port_s *port,
100 					enum bfa_fcs_port_event event);
101 static void     bfa_fcs_port_sm_deleting(struct bfa_fcs_port_s *port,
102 					 enum bfa_fcs_port_event event);
103 
104 static void
105 bfa_fcs_port_sm_uninit(struct bfa_fcs_port_s *port,
106 			enum bfa_fcs_port_event event)
107 {
108 	bfa_trc(port->fcs, port->port_cfg.pwwn);
109 	bfa_trc(port->fcs, event);
110 
111 	switch (event) {
112 	case BFA_FCS_PORT_SM_CREATE:
113 		bfa_sm_set_state(port, bfa_fcs_port_sm_init);
114 		break;
115 
116 	default:
117 		bfa_assert(0);
118 	}
119 }
120 
121 static void
122 bfa_fcs_port_sm_init(struct bfa_fcs_port_s *port, enum bfa_fcs_port_event event)
123 {
124 	bfa_trc(port->fcs, port->port_cfg.pwwn);
125 	bfa_trc(port->fcs, event);
126 
127 	switch (event) {
128 	case BFA_FCS_PORT_SM_ONLINE:
129 		bfa_sm_set_state(port, bfa_fcs_port_sm_online);
130 		bfa_fcs_port_online_actions(port);
131 		break;
132 
133 	case BFA_FCS_PORT_SM_DELETE:
134 		bfa_sm_set_state(port, bfa_fcs_port_sm_uninit);
135 		bfa_fcs_port_deleted(port);
136 		break;
137 
138 	default:
139 		bfa_assert(0);
140 	}
141 }
142 
143 static void
144 bfa_fcs_port_sm_online(struct bfa_fcs_port_s *port,
145 			enum bfa_fcs_port_event event)
146 {
147 	struct bfa_fcs_rport_s *rport;
148 	struct list_head *qe, *qen;
149 
150 	bfa_trc(port->fcs, port->port_cfg.pwwn);
151 	bfa_trc(port->fcs, event);
152 
153 	switch (event) {
154 	case BFA_FCS_PORT_SM_OFFLINE:
155 		bfa_sm_set_state(port, bfa_fcs_port_sm_offline);
156 		bfa_fcs_port_offline_actions(port);
157 		break;
158 
159 	case BFA_FCS_PORT_SM_DELETE:
160 
161 		__port_action[port->fabric->fab_type].offline(port);
162 
163 		if (port->num_rports == 0) {
164 			bfa_sm_set_state(port, bfa_fcs_port_sm_uninit);
165 			bfa_fcs_port_deleted(port);
166 		} else {
167 			bfa_sm_set_state(port, bfa_fcs_port_sm_deleting);
168 			list_for_each_safe(qe, qen, &port->rport_q) {
169 				rport = (struct bfa_fcs_rport_s *)qe;
170 				bfa_fcs_rport_delete(rport);
171 			}
172 		}
173 		break;
174 
175 	case BFA_FCS_PORT_SM_DELRPORT:
176 		break;
177 
178 	default:
179 		bfa_assert(0);
180 	}
181 }
182 
183 static void
184 bfa_fcs_port_sm_offline(struct bfa_fcs_port_s *port,
185 			enum bfa_fcs_port_event event)
186 {
187 	struct bfa_fcs_rport_s *rport;
188 	struct list_head *qe, *qen;
189 
190 	bfa_trc(port->fcs, port->port_cfg.pwwn);
191 	bfa_trc(port->fcs, event);
192 
193 	switch (event) {
194 	case BFA_FCS_PORT_SM_ONLINE:
195 		bfa_sm_set_state(port, bfa_fcs_port_sm_online);
196 		bfa_fcs_port_online_actions(port);
197 		break;
198 
199 	case BFA_FCS_PORT_SM_DELETE:
200 		if (port->num_rports == 0) {
201 			bfa_sm_set_state(port, bfa_fcs_port_sm_uninit);
202 			bfa_fcs_port_deleted(port);
203 		} else {
204 			bfa_sm_set_state(port, bfa_fcs_port_sm_deleting);
205 			list_for_each_safe(qe, qen, &port->rport_q) {
206 				rport = (struct bfa_fcs_rport_s *)qe;
207 				bfa_fcs_rport_delete(rport);
208 			}
209 		}
210 		break;
211 
212 	case BFA_FCS_PORT_SM_DELRPORT:
213 	case BFA_FCS_PORT_SM_OFFLINE:
214 		break;
215 
216 	default:
217 		bfa_assert(0);
218 	}
219 }
220 
221 static void
222 bfa_fcs_port_sm_deleting(struct bfa_fcs_port_s *port,
223 			 enum bfa_fcs_port_event event)
224 {
225 	bfa_trc(port->fcs, port->port_cfg.pwwn);
226 	bfa_trc(port->fcs, event);
227 
228 	switch (event) {
229 	case BFA_FCS_PORT_SM_DELRPORT:
230 		if (port->num_rports == 0) {
231 			bfa_sm_set_state(port, bfa_fcs_port_sm_uninit);
232 			bfa_fcs_port_deleted(port);
233 		}
234 		break;
235 
236 	default:
237 		bfa_assert(0);
238 	}
239 }
240 
241 
242 
243 /**
244  *  fcs_port_pvt
245  */
246 
247 /**
248  * Send AEN notification
249  */
250 static void
251 bfa_fcs_port_aen_post(struct bfa_fcs_port_s *port,
252 		      enum bfa_lport_aen_event event)
253 {
254 	union bfa_aen_data_u aen_data;
255 	struct bfa_log_mod_s *logmod = port->fcs->logm;
256 	enum bfa_port_role role = port->port_cfg.roles;
257 	wwn_t           lpwwn = bfa_fcs_port_get_pwwn(port);
258 	char            lpwwn_ptr[BFA_STRING_32];
259 	char           *role_str[BFA_PORT_ROLE_FCP_MAX / 2 + 1] =
260 		{ "Initiator", "Target", "IPFC" };
261 
262 	wwn2str(lpwwn_ptr, lpwwn);
263 
264 	bfa_assert(role <= BFA_PORT_ROLE_FCP_MAX);
265 
266 	switch (event) {
267 	case BFA_LPORT_AEN_ONLINE:
268 		bfa_log(logmod, BFA_AEN_LPORT_ONLINE, lpwwn_ptr,
269 			role_str[role / 2]);
270 		break;
271 	case BFA_LPORT_AEN_OFFLINE:
272 		bfa_log(logmod, BFA_AEN_LPORT_OFFLINE, lpwwn_ptr,
273 			role_str[role / 2]);
274 		break;
275 	case BFA_LPORT_AEN_NEW:
276 		bfa_log(logmod, BFA_AEN_LPORT_NEW, lpwwn_ptr,
277 			role_str[role / 2]);
278 		break;
279 	case BFA_LPORT_AEN_DELETE:
280 		bfa_log(logmod, BFA_AEN_LPORT_DELETE, lpwwn_ptr,
281 			role_str[role / 2]);
282 		break;
283 	case BFA_LPORT_AEN_DISCONNECT:
284 		bfa_log(logmod, BFA_AEN_LPORT_DISCONNECT, lpwwn_ptr,
285 			role_str[role / 2]);
286 		break;
287 	default:
288 		break;
289 	}
290 
291 	aen_data.lport.vf_id = port->fabric->vf_id;
292 	aen_data.lport.roles = role;
293 	aen_data.lport.ppwwn =
294 		bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(port->fcs));
295 	aen_data.lport.lpwwn = lpwwn;
296 }
297 
298 /*
299  * Send a LS reject
300  */
301 static void
302 bfa_fcs_port_send_ls_rjt(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs,
303 			 u8 reason_code, u8 reason_code_expl)
304 {
305 	struct fchs_s          fchs;
306 	struct bfa_fcxp_s *fcxp;
307 	struct bfa_rport_s *bfa_rport = NULL;
308 	int             len;
309 
310 	bfa_trc(port->fcs, rx_fchs->s_id);
311 
312 	fcxp = bfa_fcs_fcxp_alloc(port->fcs);
313 	if (!fcxp)
314 		return;
315 
316 	len = fc_ls_rjt_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
317 			      bfa_fcs_port_get_fcid(port), rx_fchs->ox_id,
318 			      reason_code, reason_code_expl);
319 
320 	bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
321 		      BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL,
322 		      FC_MAX_PDUSZ, 0);
323 }
324 
325 /**
326  * Process incoming plogi from a remote port.
327  */
328 static void
329 bfa_fcs_port_plogi(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs,
330 			struct fc_logi_s *plogi)
331 {
332 	struct bfa_fcs_rport_s *rport;
333 
334 	bfa_trc(port->fcs, rx_fchs->d_id);
335 	bfa_trc(port->fcs, rx_fchs->s_id);
336 
337 	/*
338 	 * If min cfg mode is enabled, drop any incoming PLOGIs
339 	 */
340 	if (__fcs_min_cfg(port->fcs)) {
341 		bfa_trc(port->fcs, rx_fchs->s_id);
342 		return;
343 	}
344 
345 	if (fc_plogi_parse(rx_fchs) != FC_PARSE_OK) {
346 		bfa_trc(port->fcs, rx_fchs->s_id);
347 		/*
348 		 * send a LS reject
349 		 */
350 		bfa_fcs_port_send_ls_rjt(port, rx_fchs,
351 					 FC_LS_RJT_RSN_PROTOCOL_ERROR,
352 					 FC_LS_RJT_EXP_SPARMS_ERR_OPTIONS);
353 		return;
354 	}
355 
356 	/**
357 * Direct Attach P2P mode : verify address assigned by the r-port.
358 	 */
359 	if ((!bfa_fcs_fabric_is_switched(port->fabric))
360 	    &&
361 	    (memcmp
362 	     ((void *)&bfa_fcs_port_get_pwwn(port), (void *)&plogi->port_name,
363 	      sizeof(wwn_t)) < 0)) {
364 		if (BFA_FCS_PID_IS_WKA(rx_fchs->d_id)) {
365 			/*
366 			 * Address assigned to us cannot be a WKA
367 			 */
368 			bfa_fcs_port_send_ls_rjt(port, rx_fchs,
369 					FC_LS_RJT_RSN_PROTOCOL_ERROR,
370 					FC_LS_RJT_EXP_INVALID_NPORT_ID);
371 			return;
372 		}
373 		port->pid = rx_fchs->d_id;
374 	}
375 
376 	/**
377 	 * First, check if we know the device by pwwn.
378 	 */
379 	rport = bfa_fcs_port_get_rport_by_pwwn(port, plogi->port_name);
380 	if (rport) {
381 		/**
382 		 * Direct Attach P2P mode: handle address assigned by the rport.
383 		 */
384 		if ((!bfa_fcs_fabric_is_switched(port->fabric))
385 		    &&
386 		    (memcmp
387 		     ((void *)&bfa_fcs_port_get_pwwn(port),
388 		      (void *)&plogi->port_name, sizeof(wwn_t)) < 0)) {
389 			port->pid = rx_fchs->d_id;
390 			rport->pid = rx_fchs->s_id;
391 		}
392 		bfa_fcs_rport_plogi(rport, rx_fchs, plogi);
393 		return;
394 	}
395 
396 	/**
397 	 * Next, lookup rport by PID.
398 	 */
399 	rport = bfa_fcs_port_get_rport_by_pid(port, rx_fchs->s_id);
400 	if (!rport) {
401 		/**
402 		 * Inbound PLOGI from a new device.
403 		 */
404 		bfa_fcs_rport_plogi_create(port, rx_fchs, plogi);
405 		return;
406 	}
407 
408 	/**
409 	 * Rport is known only by PID.
410 	 */
411 	if (rport->pwwn) {
412 		/**
413 		 * This is a different device with the same pid. Old device
414 		 * disappeared. Send implicit LOGO to old device.
415 		 */
416 		bfa_assert(rport->pwwn != plogi->port_name);
417 		bfa_fcs_rport_logo_imp(rport);
418 
419 		/**
420 		 * Inbound PLOGI from a new device (with old PID).
421 		 */
422 		bfa_fcs_rport_plogi_create(port, rx_fchs, plogi);
423 		return;
424 	}
425 
426 	/**
427 	 * PLOGI crossing each other.
428 	 */
429 	bfa_assert(rport->pwwn == WWN_NULL);
430 	bfa_fcs_rport_plogi(rport, rx_fchs, plogi);
431 }
432 
433 /*
434  * Process incoming ECHO.
435  * Since it does not require a login, it is processed here.
436  */
437 static void
438 bfa_fcs_port_echo(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs,
439 			struct fc_echo_s *echo, u16 rx_len)
440 {
441 	struct fchs_s          fchs;
442 	struct bfa_fcxp_s *fcxp;
443 	struct bfa_rport_s *bfa_rport = NULL;
444 	int             len, pyld_len;
445 
446 	bfa_trc(port->fcs, rx_fchs->s_id);
447 	bfa_trc(port->fcs, rx_fchs->d_id);
448 	bfa_trc(port->fcs, rx_len);
449 
450 	fcxp = bfa_fcs_fcxp_alloc(port->fcs);
451 	if (!fcxp)
452 		return;
453 
454 	len = fc_ls_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
455 			      bfa_fcs_port_get_fcid(port), rx_fchs->ox_id);
456 
457 	/*
458 	 * Copy the payload (if any) from the echo frame
459 	 */
460 	pyld_len = rx_len - sizeof(struct fchs_s);
461 	bfa_trc(port->fcs, pyld_len);
462 
463 	if (pyld_len > len)
464 		memcpy(((u8 *) bfa_fcxp_get_reqbuf(fcxp)) +
465 		       sizeof(struct fc_echo_s), (echo + 1),
466 		       (pyld_len - sizeof(struct fc_echo_s)));
467 
468 	bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
469 		      BFA_FALSE, FC_CLASS_3, pyld_len, &fchs, NULL, NULL,
470 		      FC_MAX_PDUSZ, 0);
471 }
472 
473 /*
474  * Process incoming RNID.
475  * Since it does not require a login, it is processed here.
476  */
477 static void
478 bfa_fcs_port_rnid(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs,
479 			struct fc_rnid_cmd_s *rnid, u16 rx_len)
480 {
481 	struct fc_rnid_common_id_data_s common_id_data;
482 	struct fc_rnid_general_topology_data_s gen_topo_data;
483 	struct fchs_s          fchs;
484 	struct bfa_fcxp_s *fcxp;
485 	struct bfa_rport_s *bfa_rport = NULL;
486 	u16        len;
487 	u32        data_format;
488 
489 	bfa_trc(port->fcs, rx_fchs->s_id);
490 	bfa_trc(port->fcs, rx_fchs->d_id);
491 	bfa_trc(port->fcs, rx_len);
492 
493 	fcxp = bfa_fcs_fcxp_alloc(port->fcs);
494 	if (!fcxp)
495 		return;
496 
497 	/*
498 	 * Check Node Indentification Data Format
499 	 * We only support General Topology Discovery Format.
500 	 * For any other requested Data Formats, we return Common Node Id Data
501 	 * only, as per FC-LS.
502 	 */
503 	bfa_trc(port->fcs, rnid->node_id_data_format);
504 	if (rnid->node_id_data_format == RNID_NODEID_DATA_FORMAT_DISCOVERY) {
505 		data_format = RNID_NODEID_DATA_FORMAT_DISCOVERY;
506 		/*
507 		 * Get General topology data for this port
508 		 */
509 		bfa_fs_port_get_gen_topo_data(port, &gen_topo_data);
510 	} else {
511 		data_format = RNID_NODEID_DATA_FORMAT_COMMON;
512 	}
513 
514 	/*
515 	 * Copy the Node Id Info
516 	 */
517 	common_id_data.port_name = bfa_fcs_port_get_pwwn(port);
518 	common_id_data.node_name = bfa_fcs_port_get_nwwn(port);
519 
520 	len = fc_rnid_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
521 				bfa_fcs_port_get_fcid(port), rx_fchs->ox_id,
522 				data_format, &common_id_data, &gen_topo_data);
523 
524 	bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
525 		      BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL,
526 		      FC_MAX_PDUSZ, 0);
527 
528 	return;
529 }
530 
531 /*
532  *  Fill out General Topolpgy Discovery Data for RNID ELS.
533  */
534 static void
535 bfa_fs_port_get_gen_topo_data(struct bfa_fcs_port_s *port,
536 			struct fc_rnid_general_topology_data_s *gen_topo_data)
537 {
538 
539 	bfa_os_memset(gen_topo_data, 0,
540 		      sizeof(struct fc_rnid_general_topology_data_s));
541 
542 	gen_topo_data->asso_type = bfa_os_htonl(RNID_ASSOCIATED_TYPE_HOST);
543 	gen_topo_data->phy_port_num = 0;	/* @todo */
544 	gen_topo_data->num_attached_nodes = bfa_os_htonl(1);
545 }
546 
547 static void
548 bfa_fcs_port_online_actions(struct bfa_fcs_port_s *port)
549 {
550 	bfa_trc(port->fcs, port->fabric->oper_type);
551 
552 	__port_action[port->fabric->fab_type].init(port);
553 	__port_action[port->fabric->fab_type].online(port);
554 
555 	bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_ONLINE);
556 	bfa_fcb_port_online(port->fcs->bfad, port->port_cfg.roles,
557 			port->fabric->vf_drv, (port->vport == NULL) ?
558 			NULL : port->vport->vport_drv);
559 }
560 
561 static void
562 bfa_fcs_port_offline_actions(struct bfa_fcs_port_s *port)
563 {
564 	struct list_head *qe, *qen;
565 	struct bfa_fcs_rport_s *rport;
566 
567 	bfa_trc(port->fcs, port->fabric->oper_type);
568 
569 	__port_action[port->fabric->fab_type].offline(port);
570 
571 	if (bfa_fcs_fabric_is_online(port->fabric) == BFA_TRUE)
572 		bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_DISCONNECT);
573 	else
574 		bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_OFFLINE);
575 	bfa_fcb_port_offline(port->fcs->bfad, port->port_cfg.roles,
576 			port->fabric->vf_drv,
577 			(port->vport == NULL) ? NULL : port->vport->vport_drv);
578 
579 	list_for_each_safe(qe, qen, &port->rport_q) {
580 		rport = (struct bfa_fcs_rport_s *)qe;
581 		bfa_fcs_rport_offline(rport);
582 	}
583 }
584 
585 static void
586 bfa_fcs_port_unknown_init(struct bfa_fcs_port_s *port)
587 {
588 	bfa_assert(0);
589 }
590 
591 static void
592 bfa_fcs_port_unknown_online(struct bfa_fcs_port_s *port)
593 {
594 	bfa_assert(0);
595 }
596 
597 static void
598 bfa_fcs_port_unknown_offline(struct bfa_fcs_port_s *port)
599 {
600 	bfa_assert(0);
601 }
602 
603 static void
604 bfa_fcs_port_deleted(struct bfa_fcs_port_s *port)
605 {
606 	bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_DELETE);
607 
608 	/*
609 	 * Base port will be deleted by the OS driver
610 	 */
611 	if (port->vport) {
612 		bfa_fcb_port_delete(port->fcs->bfad, port->port_cfg.roles,
613 			port->fabric->vf_drv,
614 			port->vport ? port->vport->vport_drv : NULL);
615 		bfa_fcs_vport_delete_comp(port->vport);
616 	} else {
617 		bfa_fcs_fabric_port_delete_comp(port->fabric);
618 	}
619 }
620 
621 
622 
623 /**
624  *  fcs_lport_api BFA FCS port API
625  */
626 /**
627  *   Module initialization
628  */
629 void
630 bfa_fcs_port_modinit(struct bfa_fcs_s *fcs)
631 {
632 
633 }
634 
635 /**
636  *   Module cleanup
637  */
638 void
639 bfa_fcs_port_modexit(struct bfa_fcs_s *fcs)
640 {
641 	bfa_fcs_modexit_comp(fcs);
642 }
643 
644 /**
645  * 		Unsolicited frame receive handling.
646  */
647 void
648 bfa_fcs_port_uf_recv(struct bfa_fcs_port_s *lport, struct fchs_s *fchs,
649 			u16 len)
650 {
651 	u32        pid = fchs->s_id;
652 	struct bfa_fcs_rport_s *rport = NULL;
653 	struct fc_els_cmd_s   *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
654 
655 	bfa_stats(lport, uf_recvs);
656 
657 	if (!bfa_fcs_port_is_online(lport)) {
658 		bfa_stats(lport, uf_recv_drops);
659 		return;
660 	}
661 
662 	/**
663 	 * First, handle ELSs that donot require a login.
664 	 */
665 	/*
666 	 * Handle PLOGI first
667 	 */
668 	if ((fchs->type == FC_TYPE_ELS) &&
669 		(els_cmd->els_code == FC_ELS_PLOGI)) {
670 		bfa_fcs_port_plogi(lport, fchs, (struct fc_logi_s *) els_cmd);
671 		return;
672 	}
673 
674 	/*
675 	 * Handle ECHO separately.
676 	 */
677 	if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_ECHO)) {
678 		bfa_fcs_port_echo(lport, fchs,
679 			(struct fc_echo_s *) els_cmd, len);
680 		return;
681 	}
682 
683 	/*
684 	 * Handle RNID separately.
685 	 */
686 	if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_RNID)) {
687 		bfa_fcs_port_rnid(lport, fchs,
688 			(struct fc_rnid_cmd_s *) els_cmd, len);
689 		return;
690 	}
691 
692 	/**
693 	 * look for a matching remote port ID
694 	 */
695 	rport = bfa_fcs_port_get_rport_by_pid(lport, pid);
696 	if (rport) {
697 		bfa_trc(rport->fcs, fchs->s_id);
698 		bfa_trc(rport->fcs, fchs->d_id);
699 		bfa_trc(rport->fcs, fchs->type);
700 
701 		bfa_fcs_rport_uf_recv(rport, fchs, len);
702 		return;
703 	}
704 
705 	/**
706 	 * Only handles ELS frames for now.
707 	 */
708 	if (fchs->type != FC_TYPE_ELS) {
709 		bfa_trc(lport->fcs, fchs->type);
710 		bfa_assert(0);
711 		return;
712 	}
713 
714 	bfa_trc(lport->fcs, els_cmd->els_code);
715 	if (els_cmd->els_code == FC_ELS_RSCN) {
716 		bfa_fcs_port_scn_process_rscn(lport, fchs, len);
717 		return;
718 	}
719 
720 	if (els_cmd->els_code == FC_ELS_LOGO) {
721 		/**
722 		 * @todo Handle LOGO frames received.
723 		 */
724 		bfa_trc(lport->fcs, els_cmd->els_code);
725 		return;
726 	}
727 
728 	if (els_cmd->els_code == FC_ELS_PRLI) {
729 		/**
730 		 * @todo Handle PRLI frames received.
731 		 */
732 		bfa_trc(lport->fcs, els_cmd->els_code);
733 		return;
734 	}
735 
736 	/**
737 	 * Unhandled ELS frames. Send a LS_RJT.
738 	 */
739 	bfa_fcs_port_send_ls_rjt(lport, fchs, FC_LS_RJT_RSN_CMD_NOT_SUPP,
740 				 FC_LS_RJT_EXP_NO_ADDL_INFO);
741 
742 }
743 
744 /**
745  *   PID based Lookup for a R-Port in the Port R-Port Queue
746  */
747 struct bfa_fcs_rport_s *
748 bfa_fcs_port_get_rport_by_pid(struct bfa_fcs_port_s *port, u32 pid)
749 {
750 	struct bfa_fcs_rport_s *rport;
751 	struct list_head *qe;
752 
753 	list_for_each(qe, &port->rport_q) {
754 		rport = (struct bfa_fcs_rport_s *)qe;
755 		if (rport->pid == pid)
756 			return rport;
757 	}
758 
759 	bfa_trc(port->fcs, pid);
760 	return NULL;
761 }
762 
763 /**
764  *   PWWN based Lookup for a R-Port in the Port R-Port Queue
765  */
766 struct bfa_fcs_rport_s *
767 bfa_fcs_port_get_rport_by_pwwn(struct bfa_fcs_port_s *port, wwn_t pwwn)
768 {
769 	struct bfa_fcs_rport_s *rport;
770 	struct list_head *qe;
771 
772 	list_for_each(qe, &port->rport_q) {
773 		rport = (struct bfa_fcs_rport_s *)qe;
774 		if (wwn_is_equal(rport->pwwn, pwwn))
775 			return rport;
776 	}
777 
778 	bfa_trc(port->fcs, pwwn);
779 	return NULL;
780 }
781 
782 /**
783  *   NWWN based Lookup for a R-Port in the Port R-Port Queue
784  */
785 struct bfa_fcs_rport_s *
786 bfa_fcs_port_get_rport_by_nwwn(struct bfa_fcs_port_s *port, wwn_t nwwn)
787 {
788 	struct bfa_fcs_rport_s *rport;
789 	struct list_head *qe;
790 
791 	list_for_each(qe, &port->rport_q) {
792 		rport = (struct bfa_fcs_rport_s *)qe;
793 		if (wwn_is_equal(rport->nwwn, nwwn))
794 			return rport;
795 	}
796 
797 	bfa_trc(port->fcs, nwwn);
798 	return NULL;
799 }
800 
801 /**
802  * Called by rport module when new rports are discovered.
803  */
804 void
805 bfa_fcs_port_add_rport(struct bfa_fcs_port_s *port,
806 		       struct bfa_fcs_rport_s *rport)
807 {
808 	list_add_tail(&rport->qe, &port->rport_q);
809 	port->num_rports++;
810 }
811 
812 /**
813  * Called by rport module to when rports are deleted.
814  */
815 void
816 bfa_fcs_port_del_rport(struct bfa_fcs_port_s *port,
817 		       struct bfa_fcs_rport_s *rport)
818 {
819 	bfa_assert(bfa_q_is_on_q(&port->rport_q, rport));
820 	list_del(&rport->qe);
821 	port->num_rports--;
822 
823 	bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELRPORT);
824 }
825 
826 /**
827  * Called by fabric for base port when fabric login is complete.
828  * Called by vport for virtual ports when FDISC is complete.
829  */
830 void
831 bfa_fcs_port_online(struct bfa_fcs_port_s *port)
832 {
833 	bfa_sm_send_event(port, BFA_FCS_PORT_SM_ONLINE);
834 }
835 
836 /**
837  * Called by fabric for base port when fabric goes offline.
838  * Called by vport for virtual ports when virtual port becomes offline.
839  */
840 void
841 bfa_fcs_port_offline(struct bfa_fcs_port_s *port)
842 {
843 	bfa_sm_send_event(port, BFA_FCS_PORT_SM_OFFLINE);
844 }
845 
846 /**
847  * Called by fabric to delete base lport and associated resources.
848  *
849  * Called by vport to delete lport and associated resources. Should call
850  * bfa_fcs_vport_delete_comp() for vports on completion.
851  */
852 void
853 bfa_fcs_port_delete(struct bfa_fcs_port_s *port)
854 {
855 	bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELETE);
856 }
857 
858 /**
859  * Called by fabric in private loop topology to process LIP event.
860  */
861 void
862 bfa_fcs_port_lip(struct bfa_fcs_port_s *port)
863 {
864 }
865 
866 /**
867  * Return TRUE if port is online, else return FALSE
868  */
869 bfa_boolean_t
870 bfa_fcs_port_is_online(struct bfa_fcs_port_s *port)
871 {
872 	return bfa_sm_cmp_state(port, bfa_fcs_port_sm_online);
873 }
874 
875 /**
876  * Logical port initialization of base or virtual port.
877  * Called by fabric for base port or by vport for virtual ports.
878  */
879 void
880 bfa_fcs_lport_init(struct bfa_fcs_port_s *lport, struct bfa_fcs_s *fcs,
881 		   u16 vf_id, struct bfa_port_cfg_s *port_cfg,
882 		   struct bfa_fcs_vport_s *vport)
883 {
884 	lport->fcs = fcs;
885 	lport->fabric = bfa_fcs_vf_lookup(fcs, vf_id);
886 	bfa_os_assign(lport->port_cfg, *port_cfg);
887 	lport->vport = vport;
888 	lport->lp_tag = (vport) ? bfa_lps_get_tag(vport->lps) :
889 			 bfa_lps_get_tag(lport->fabric->lps);
890 
891 	INIT_LIST_HEAD(&lport->rport_q);
892 	lport->num_rports = 0;
893 
894 	lport->bfad_port =
895 		bfa_fcb_port_new(fcs->bfad, lport, lport->port_cfg.roles,
896 				lport->fabric->vf_drv,
897 				vport ? vport->vport_drv : NULL);
898 	bfa_fcs_port_aen_post(lport, BFA_LPORT_AEN_NEW);
899 
900 	bfa_sm_set_state(lport, bfa_fcs_port_sm_uninit);
901 	bfa_sm_send_event(lport, BFA_FCS_PORT_SM_CREATE);
902 }
903 
904 
905 
906 /**
907  *  fcs_lport_api
908  */
909 
910 void
911 bfa_fcs_port_get_attr(struct bfa_fcs_port_s *port,
912 		      struct bfa_port_attr_s *port_attr)
913 {
914 	if (bfa_sm_cmp_state(port, bfa_fcs_port_sm_online))
915 		port_attr->pid = port->pid;
916 	else
917 		port_attr->pid = 0;
918 
919 	port_attr->port_cfg = port->port_cfg;
920 
921 	if (port->fabric) {
922 		port_attr->port_type = bfa_fcs_fabric_port_type(port->fabric);
923 		port_attr->loopback = bfa_fcs_fabric_is_loopback(port->fabric);
924 		port_attr->fabric_name = bfa_fcs_port_get_fabric_name(port);
925 		memcpy(port_attr->fabric_ip_addr,
926 		       bfa_fcs_port_get_fabric_ipaddr(port),
927 		       BFA_FCS_FABRIC_IPADDR_SZ);
928 
929 		if (port->vport != NULL)
930 			port_attr->port_type = BFA_PPORT_TYPE_VPORT;
931 
932 	} else {
933 		port_attr->port_type = BFA_PPORT_TYPE_UNKNOWN;
934 		port_attr->state = BFA_PORT_UNINIT;
935 	}
936 
937 }
938 
939 
940