• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/scsi/bfa/
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#include <bfa.h>
19#include <bfa_svc.h>
20#include "fcs_lport.h"
21#include "fcs_rport.h"
22#include "fcs_ms.h"
23#include "fcs_trcmod.h"
24#include "fcs_fcxp.h"
25#include "fcs.h"
26#include "lport_priv.h"
27
28BFA_TRC_FILE(FCS, SCN);
29
30#define FC_QOS_RSCN_EVENT		0x0c
31#define FC_FABRIC_NAME_RSCN_EVENT	0x0d
32
33/*
34 * forward declarations
35 */
36static void     bfa_fcs_port_scn_send_scr(void *scn_cbarg,
37					  struct bfa_fcxp_s *fcxp_alloced);
38static void     bfa_fcs_port_scn_scr_response(void *fcsarg,
39					      struct bfa_fcxp_s *fcxp,
40					      void *cbarg,
41					      bfa_status_t req_status,
42					      u32 rsp_len,
43					      u32 resid_len,
44					      struct fchs_s *rsp_fchs);
45static void     bfa_fcs_port_scn_send_ls_acc(struct bfa_fcs_port_s *port,
46					     struct fchs_s *rx_fchs);
47static void     bfa_fcs_port_scn_timeout(void *arg);
48
49/**
50 *  fcs_scm_sm FCS SCN state machine
51 */
52
53/**
54 * VPort SCN State Machine events
55 */
56enum port_scn_event {
57	SCNSM_EVENT_PORT_ONLINE = 1,
58	SCNSM_EVENT_PORT_OFFLINE = 2,
59	SCNSM_EVENT_RSP_OK = 3,
60	SCNSM_EVENT_RSP_ERROR = 4,
61	SCNSM_EVENT_TIMEOUT = 5,
62	SCNSM_EVENT_SCR_SENT = 6,
63};
64
65static void     bfa_fcs_port_scn_sm_offline(struct bfa_fcs_port_scn_s *scn,
66					    enum port_scn_event event);
67static void     bfa_fcs_port_scn_sm_sending_scr(struct bfa_fcs_port_scn_s *scn,
68						enum port_scn_event event);
69static void     bfa_fcs_port_scn_sm_scr(struct bfa_fcs_port_scn_s *scn,
70					enum port_scn_event event);
71static void     bfa_fcs_port_scn_sm_scr_retry(struct bfa_fcs_port_scn_s *scn,
72					      enum port_scn_event event);
73static void     bfa_fcs_port_scn_sm_online(struct bfa_fcs_port_scn_s *scn,
74					   enum port_scn_event event);
75
76/**
77 * 		Starting state - awaiting link up.
78 */
79static void
80bfa_fcs_port_scn_sm_offline(struct bfa_fcs_port_scn_s *scn,
81			    enum port_scn_event event)
82{
83	switch (event) {
84	case SCNSM_EVENT_PORT_ONLINE:
85		bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_sending_scr);
86		bfa_fcs_port_scn_send_scr(scn, NULL);
87		break;
88
89	case SCNSM_EVENT_PORT_OFFLINE:
90		break;
91
92	default:
93		bfa_sm_fault(scn->port->fcs, event);
94	}
95}
96
97static void
98bfa_fcs_port_scn_sm_sending_scr(struct bfa_fcs_port_scn_s *scn,
99				enum port_scn_event event)
100{
101	switch (event) {
102	case SCNSM_EVENT_SCR_SENT:
103		bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_scr);
104		break;
105
106	case SCNSM_EVENT_PORT_OFFLINE:
107		bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline);
108		bfa_fcxp_walloc_cancel(scn->port->fcs->bfa, &scn->fcxp_wqe);
109		break;
110
111	default:
112		bfa_sm_fault(scn->port->fcs, event);
113	}
114}
115
116static void
117bfa_fcs_port_scn_sm_scr(struct bfa_fcs_port_scn_s *scn,
118			enum port_scn_event event)
119{
120	struct bfa_fcs_port_s *port = scn->port;
121
122	switch (event) {
123	case SCNSM_EVENT_RSP_OK:
124		bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_online);
125		break;
126
127	case SCNSM_EVENT_RSP_ERROR:
128		bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_scr_retry);
129		bfa_timer_start(port->fcs->bfa, &scn->timer,
130				bfa_fcs_port_scn_timeout, scn,
131				BFA_FCS_RETRY_TIMEOUT);
132		break;
133
134	case SCNSM_EVENT_PORT_OFFLINE:
135		bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline);
136		bfa_fcxp_discard(scn->fcxp);
137		break;
138
139	default:
140		bfa_sm_fault(scn->port->fcs, event);
141	}
142}
143
144static void
145bfa_fcs_port_scn_sm_scr_retry(struct bfa_fcs_port_scn_s *scn,
146			      enum port_scn_event event)
147{
148	switch (event) {
149	case SCNSM_EVENT_TIMEOUT:
150		bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_sending_scr);
151		bfa_fcs_port_scn_send_scr(scn, NULL);
152		break;
153
154	case SCNSM_EVENT_PORT_OFFLINE:
155		bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline);
156		bfa_timer_stop(&scn->timer);
157		break;
158
159	default:
160		bfa_sm_fault(scn->port->fcs, event);
161	}
162}
163
164static void
165bfa_fcs_port_scn_sm_online(struct bfa_fcs_port_scn_s *scn,
166			   enum port_scn_event event)
167{
168	switch (event) {
169	case SCNSM_EVENT_PORT_OFFLINE:
170		bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline);
171		break;
172
173	default:
174		bfa_sm_fault(scn->port->fcs, event);
175	}
176}
177
178
179
180/**
181 *  fcs_scn_private FCS SCN private functions
182 */
183
184/**
185 * This routine will be called to send a SCR command.
186 */
187static void
188bfa_fcs_port_scn_send_scr(void *scn_cbarg, struct bfa_fcxp_s *fcxp_alloced)
189{
190	struct bfa_fcs_port_scn_s *scn = scn_cbarg;
191	struct bfa_fcs_port_s *port = scn->port;
192	struct fchs_s          fchs;
193	int             len;
194	struct bfa_fcxp_s *fcxp;
195
196	bfa_trc(port->fcs, port->pid);
197	bfa_trc(port->fcs, port->port_cfg.pwwn);
198
199	fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
200	if (!fcxp) {
201		bfa_fcxp_alloc_wait(port->fcs->bfa, &scn->fcxp_wqe,
202				    bfa_fcs_port_scn_send_scr, scn);
203		return;
204	}
205	scn->fcxp = fcxp;
206
207	/*
208	 * Handle VU registrations for Base port only
209	 */
210	if ((!port->vport) && bfa_ioc_get_fcmode(&port->fcs->bfa->ioc)) {
211		len = fc_scr_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
212				   bfa_lps_is_brcd_fabric(port->fabric->lps),
213				   port->pid, 0);
214	} else {
215		len = fc_scr_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), BFA_FALSE,
216				   port->pid, 0);
217	}
218
219	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
220		      FC_CLASS_3, len, &fchs, bfa_fcs_port_scn_scr_response,
221		      (void *)scn, FC_MAX_PDUSZ, FC_ELS_TOV);
222
223	bfa_sm_send_event(scn, SCNSM_EVENT_SCR_SENT);
224}
225
226static void
227bfa_fcs_port_scn_scr_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
228			      void *cbarg, bfa_status_t req_status,
229			      u32 rsp_len, u32 resid_len,
230			      struct fchs_s *rsp_fchs)
231{
232	struct bfa_fcs_port_scn_s *scn = (struct bfa_fcs_port_scn_s *)cbarg;
233	struct bfa_fcs_port_s *port = scn->port;
234	struct fc_els_cmd_s   *els_cmd;
235	struct fc_ls_rjt_s    *ls_rjt;
236
237	bfa_trc(port->fcs, port->port_cfg.pwwn);
238
239	/*
240	 * Sanity Checks
241	 */
242	if (req_status != BFA_STATUS_OK) {
243		bfa_trc(port->fcs, req_status);
244		bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR);
245		return;
246	}
247
248	els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);
249
250	switch (els_cmd->els_code) {
251
252	case FC_ELS_ACC:
253		bfa_sm_send_event(scn, SCNSM_EVENT_RSP_OK);
254		break;
255
256	case FC_ELS_LS_RJT:
257
258		ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp);
259
260		bfa_trc(port->fcs, ls_rjt->reason_code);
261		bfa_trc(port->fcs, ls_rjt->reason_code_expl);
262
263		bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR);
264		break;
265
266	default:
267		bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR);
268	}
269}
270
271/*
272 * Send a LS Accept
273 */
274static void
275bfa_fcs_port_scn_send_ls_acc(struct bfa_fcs_port_s *port,
276			struct fchs_s *rx_fchs)
277{
278	struct fchs_s          fchs;
279	struct bfa_fcxp_s *fcxp;
280	struct bfa_rport_s *bfa_rport = NULL;
281	int             len;
282
283	bfa_trc(port->fcs, rx_fchs->s_id);
284
285	fcxp = bfa_fcs_fcxp_alloc(port->fcs);
286	if (!fcxp)
287		return;
288
289	len = fc_ls_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
290			      bfa_fcs_port_get_fcid(port), rx_fchs->ox_id);
291
292	bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
293		      BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL,
294		      FC_MAX_PDUSZ, 0);
295}
296
297/**
298 *     This routine will be called by bfa_timer on timer timeouts.
299 *
300 * 	param[in] 	vport 			- pointer to bfa_fcs_port_t.
301 * 	param[out]	vport_status 	- pointer to return vport status in
302 *
303 * 	return
304 * 		void
305 *
306*  	Special Considerations:
307 *
308 * 	note
309 */
310static void
311bfa_fcs_port_scn_timeout(void *arg)
312{
313	struct bfa_fcs_port_scn_s *scn = (struct bfa_fcs_port_scn_s *)arg;
314
315	bfa_sm_send_event(scn, SCNSM_EVENT_TIMEOUT);
316}
317
318
319
320/**
321 *  fcs_scn_public FCS state change notification public interfaces
322 */
323
324/*
325 * Functions called by port/fab
326 */
327void
328bfa_fcs_port_scn_init(struct bfa_fcs_port_s *port)
329{
330	struct bfa_fcs_port_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port);
331
332	scn->port = port;
333	bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline);
334}
335
336void
337bfa_fcs_port_scn_offline(struct bfa_fcs_port_s *port)
338{
339	struct bfa_fcs_port_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port);
340
341	scn->port = port;
342	bfa_sm_send_event(scn, SCNSM_EVENT_PORT_OFFLINE);
343}
344
345void
346bfa_fcs_port_scn_online(struct bfa_fcs_port_s *port)
347{
348	struct bfa_fcs_port_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port);
349
350	scn->port = port;
351	bfa_sm_send_event(scn, SCNSM_EVENT_PORT_ONLINE);
352}
353
354static void
355bfa_fcs_port_scn_portid_rscn(struct bfa_fcs_port_s *port, u32 rpid)
356{
357	struct bfa_fcs_rport_s *rport;
358
359	bfa_trc(port->fcs, rpid);
360
361	/**
362	 * If this is an unknown device, then it just came online.
363	 * Otherwise let rport handle the RSCN event.
364	 */
365	rport = bfa_fcs_port_get_rport_by_pid(port, rpid);
366	if (rport == NULL) {
367		/*
368		 * If min cfg mode is enabled, we donot need to
369		 * discover any new rports.
370		 */
371		if (!__fcs_min_cfg(port->fcs))
372			rport = bfa_fcs_rport_create(port, rpid);
373	} else {
374		bfa_fcs_rport_scn(rport);
375	}
376}
377
378/**
379 * rscn format based PID comparison
380 */
381#define __fc_pid_match(__c0, __c1, __fmt)		\
382	(((__fmt) == FC_RSCN_FORMAT_FABRIC) ||		\
383	 (((__fmt) == FC_RSCN_FORMAT_DOMAIN) &&		\
384	  ((__c0)[0] == (__c1)[0])) ||			\
385	 (((__fmt) == FC_RSCN_FORMAT_AREA) &&		\
386	  ((__c0)[0] == (__c1)[0]) &&			\
387	  ((__c0)[1] == (__c1)[1])))
388
389static void
390bfa_fcs_port_scn_multiport_rscn(struct bfa_fcs_port_s *port,
391			enum fc_rscn_format format, u32 rscn_pid)
392{
393	struct bfa_fcs_rport_s *rport;
394	struct list_head *qe, *qe_next;
395	u8        *c0, *c1;
396
397	bfa_trc(port->fcs, format);
398	bfa_trc(port->fcs, rscn_pid);
399
400	c0 = (u8 *) &rscn_pid;
401
402	list_for_each_safe(qe, qe_next, &port->rport_q) {
403		rport = (struct bfa_fcs_rport_s *)qe;
404		c1 = (u8 *) &rport->pid;
405		if (__fc_pid_match(c0, c1, format))
406			bfa_fcs_rport_scn(rport);
407	}
408}
409
410void
411bfa_fcs_port_scn_process_rscn(struct bfa_fcs_port_s *port, struct fchs_s *fchs,
412			      u32 len)
413{
414	struct fc_rscn_pl_s   *rscn = (struct fc_rscn_pl_s *) (fchs + 1);
415	int             num_entries;
416	u32        rscn_pid;
417	bfa_boolean_t   nsquery = BFA_FALSE;
418	int             i = 0;
419
420	num_entries =
421		(bfa_os_ntohs(rscn->payldlen) -
422		 sizeof(u32)) / sizeof(rscn->event[0]);
423
424	bfa_trc(port->fcs, num_entries);
425
426	port->stats.num_rscn++;
427
428	bfa_fcs_port_scn_send_ls_acc(port, fchs);
429
430	for (i = 0; i < num_entries; i++) {
431		rscn_pid = rscn->event[i].portid;
432
433		bfa_trc(port->fcs, rscn->event[i].format);
434		bfa_trc(port->fcs, rscn_pid);
435
436		switch (rscn->event[i].format) {
437		case FC_RSCN_FORMAT_PORTID:
438			if (rscn->event[i].qualifier == FC_QOS_RSCN_EVENT) {
439				/*
440				 * Ignore this event. f/w would have processed
441				 * it
442				 */
443				bfa_trc(port->fcs, rscn_pid);
444			} else {
445				port->stats.num_portid_rscn++;
446				bfa_fcs_port_scn_portid_rscn(port, rscn_pid);
447			}
448			break;
449
450		case FC_RSCN_FORMAT_FABRIC:
451			if (rscn->event[i].qualifier ==
452			    FC_FABRIC_NAME_RSCN_EVENT) {
453				bfa_fcs_port_ms_fabric_rscn(port);
454				break;
455			}
456			/*
457			 * !!!!!!!!! Fall Through !!!!!!!!!!!!!
458			 */
459
460		case FC_RSCN_FORMAT_AREA:
461		case FC_RSCN_FORMAT_DOMAIN:
462			nsquery = BFA_TRUE;
463			bfa_fcs_port_scn_multiport_rscn(port,
464							rscn->event[i].format,
465							rscn_pid);
466			break;
467
468		default:
469			bfa_assert(0);
470			nsquery = BFA_TRUE;
471		}
472	}
473
474	/**
475	 * If any of area, domain or fabric RSCN is received, do a fresh discovery
476	 * to find new devices.
477	 */
478	if (nsquery)
479		bfa_fcs_port_ns_query(port);
480}
481