• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/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/**
19 *  rport_ftrs.c Remote port features (RPF) implementation.
20 */
21
22#include <bfa.h>
23#include <bfa_svc.h>
24#include "fcbuild.h"
25#include "fcs_rport.h"
26#include "fcs_lport.h"
27#include "fcs_trcmod.h"
28#include "fcs_fcxp.h"
29#include "fcs.h"
30
31BFA_TRC_FILE(FCS, RPORT_FTRS);
32
33#define BFA_FCS_RPF_RETRIES	(3)
34#define BFA_FCS_RPF_RETRY_TIMEOUT  (1000) /* 1 sec (In millisecs) */
35
36static void     bfa_fcs_rpf_send_rpsc2(void *rport_cbarg,
37			struct bfa_fcxp_s *fcxp_alloced);
38static void     bfa_fcs_rpf_rpsc2_response(void *fcsarg,
39			struct bfa_fcxp_s *fcxp, void *cbarg,
40			bfa_status_t req_status, u32 rsp_len,
41			u32 resid_len,
42			struct fchs_s *rsp_fchs);
43static void     bfa_fcs_rpf_timeout(void *arg);
44
45/**
46 *  fcs_rport_ftrs_sm FCS rport state machine events
47 */
48
49enum rpf_event {
50	RPFSM_EVENT_RPORT_OFFLINE  = 1,     /*  Rport offline            */
51	RPFSM_EVENT_RPORT_ONLINE   = 2,     /*  Rport online            */
52	RPFSM_EVENT_FCXP_SENT      = 3,    /*  Frame from has been sent */
53	RPFSM_EVENT_TIMEOUT  	   = 4,    /*  Rport SM timeout event   */
54	RPFSM_EVENT_RPSC_COMP      = 5,
55	RPFSM_EVENT_RPSC_FAIL      = 6,
56	RPFSM_EVENT_RPSC_ERROR     = 7,
57};
58
59static void	bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf,
60					enum rpf_event event);
61static void     bfa_fcs_rpf_sm_rpsc_sending(struct bfa_fcs_rpf_s *rpf,
62					       enum rpf_event event);
63static void     bfa_fcs_rpf_sm_rpsc(struct bfa_fcs_rpf_s *rpf,
64					       enum rpf_event event);
65static void 	bfa_fcs_rpf_sm_rpsc_retry(struct bfa_fcs_rpf_s *rpf,
66							enum rpf_event event);
67static void     bfa_fcs_rpf_sm_offline(struct bfa_fcs_rpf_s *rpf,
68							enum rpf_event event);
69static void     bfa_fcs_rpf_sm_online(struct bfa_fcs_rpf_s *rpf,
70							enum rpf_event event);
71
72static void
73bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
74{
75	struct bfa_fcs_rport_s *rport = rpf->rport;
76	struct bfa_fcs_fabric_s *fabric = &rport->fcs->fabric;
77
78	bfa_trc(rport->fcs, rport->pwwn);
79	bfa_trc(rport->fcs, rport->pid);
80	bfa_trc(rport->fcs, event);
81
82	switch (event) {
83	case RPFSM_EVENT_RPORT_ONLINE:
84		/* Send RPSC2 to a Brocade fabric only. */
85		if ((!BFA_FCS_PID_IS_WKA(rport->pid)) &&
86			((bfa_lps_is_brcd_fabric(rport->port->fabric->lps)) ||
87			(bfa_fcs_fabric_get_switch_oui(fabric) ==
88						BFA_FCS_BRCD_SWITCH_OUI))) {
89			bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending);
90			rpf->rpsc_retries = 0;
91			bfa_fcs_rpf_send_rpsc2(rpf, NULL);
92		}
93		break;
94
95	case RPFSM_EVENT_RPORT_OFFLINE:
96		break;
97
98	default:
99		bfa_sm_fault(rport->fcs, event);
100	}
101}
102
103static void
104bfa_fcs_rpf_sm_rpsc_sending(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
105{
106	struct bfa_fcs_rport_s *rport = rpf->rport;
107
108	bfa_trc(rport->fcs, event);
109
110	switch (event) {
111	case RPFSM_EVENT_FCXP_SENT:
112		bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc);
113		break;
114
115	case RPFSM_EVENT_RPORT_OFFLINE:
116		bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline);
117		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rpf->fcxp_wqe);
118		rpf->rpsc_retries = 0;
119		break;
120
121	default:
122		bfa_sm_fault(rport->fcs, event);
123	}
124}
125
126static void
127bfa_fcs_rpf_sm_rpsc(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
128{
129	struct bfa_fcs_rport_s *rport = rpf->rport;
130
131	bfa_trc(rport->fcs, rport->pid);
132	bfa_trc(rport->fcs, event);
133
134	switch (event) {
135	case RPFSM_EVENT_RPSC_COMP:
136		bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_online);
137		/* Update speed info in f/w via BFA */
138		if (rpf->rpsc_speed != BFA_PPORT_SPEED_UNKNOWN)
139			bfa_rport_speed(rport->bfa_rport, rpf->rpsc_speed);
140		else if (rpf->assigned_speed != BFA_PPORT_SPEED_UNKNOWN)
141			bfa_rport_speed(rport->bfa_rport, rpf->assigned_speed);
142		break;
143
144	case RPFSM_EVENT_RPSC_FAIL:
145		/* RPSC not supported by rport */
146		bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_online);
147		break;
148
149	case RPFSM_EVENT_RPSC_ERROR:
150		/* need to retry...delayed a bit. */
151		if (rpf->rpsc_retries++ < BFA_FCS_RPF_RETRIES) {
152			bfa_timer_start(rport->fcs->bfa, &rpf->timer,
153				    bfa_fcs_rpf_timeout, rpf,
154				    BFA_FCS_RPF_RETRY_TIMEOUT);
155			bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_retry);
156		} else {
157			bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_online);
158		}
159		break;
160
161	case RPFSM_EVENT_RPORT_OFFLINE:
162		bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline);
163		bfa_fcxp_discard(rpf->fcxp);
164		rpf->rpsc_retries = 0;
165		break;
166
167	default:
168		bfa_sm_fault(rport->fcs, event);
169	}
170}
171
172static void
173bfa_fcs_rpf_sm_rpsc_retry(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
174{
175	struct bfa_fcs_rport_s *rport = rpf->rport;
176
177	bfa_trc(rport->fcs, rport->pid);
178	bfa_trc(rport->fcs, event);
179
180	switch (event) {
181	case RPFSM_EVENT_TIMEOUT:
182		/* re-send the RPSC */
183		bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending);
184		bfa_fcs_rpf_send_rpsc2(rpf, NULL);
185		break;
186
187	case RPFSM_EVENT_RPORT_OFFLINE:
188		bfa_timer_stop(&rpf->timer);
189		bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline);
190		rpf->rpsc_retries = 0;
191		break;
192
193	default:
194		bfa_sm_fault(rport->fcs, event);
195	}
196}
197
198static void
199bfa_fcs_rpf_sm_online(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
200{
201	struct bfa_fcs_rport_s *rport = rpf->rport;
202
203	bfa_trc(rport->fcs, rport->pwwn);
204	bfa_trc(rport->fcs, rport->pid);
205	bfa_trc(rport->fcs, event);
206
207	switch (event) {
208	case RPFSM_EVENT_RPORT_OFFLINE:
209		bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline);
210		rpf->rpsc_retries = 0;
211		break;
212
213	default:
214		bfa_sm_fault(rport->fcs, event);
215	}
216}
217
218static void
219bfa_fcs_rpf_sm_offline(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
220{
221	struct bfa_fcs_rport_s *rport = rpf->rport;
222
223	bfa_trc(rport->fcs, rport->pwwn);
224	bfa_trc(rport->fcs, rport->pid);
225	bfa_trc(rport->fcs, event);
226
227	switch (event) {
228	case RPFSM_EVENT_RPORT_ONLINE:
229		bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending);
230		bfa_fcs_rpf_send_rpsc2(rpf, NULL);
231		break;
232
233	case RPFSM_EVENT_RPORT_OFFLINE:
234		break;
235
236	default:
237		bfa_sm_fault(rport->fcs, event);
238	}
239}
240/**
241 * Called when Rport is created.
242 */
243void  bfa_fcs_rpf_init(struct bfa_fcs_rport_s *rport)
244{
245	struct bfa_fcs_rpf_s *rpf = &rport->rpf;
246
247	bfa_trc(rport->fcs, rport->pid);
248	rpf->rport = rport;
249
250	bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_uninit);
251}
252
253/**
254 * Called when Rport becomes online
255 */
256void  bfa_fcs_rpf_rport_online(struct bfa_fcs_rport_s *rport)
257{
258	bfa_trc(rport->fcs, rport->pid);
259
260	if (__fcs_min_cfg(rport->port->fcs))
261		return;
262
263	if (bfa_fcs_fabric_is_switched(rport->port->fabric))
264		bfa_sm_send_event(&rport->rpf, RPFSM_EVENT_RPORT_ONLINE);
265}
266
267/**
268 * Called when Rport becomes offline
269 */
270void  bfa_fcs_rpf_rport_offline(struct bfa_fcs_rport_s *rport)
271{
272	bfa_trc(rport->fcs, rport->pid);
273
274	if (__fcs_min_cfg(rport->port->fcs))
275		return;
276
277	rport->rpf.rpsc_speed = 0;
278	bfa_sm_send_event(&rport->rpf, RPFSM_EVENT_RPORT_OFFLINE);
279}
280
281static void
282bfa_fcs_rpf_timeout(void *arg)
283{
284	struct bfa_fcs_rpf_s *rpf = (struct bfa_fcs_rpf_s *) arg;
285	struct bfa_fcs_rport_s *rport = rpf->rport;
286
287	bfa_trc(rport->fcs, rport->pid);
288	bfa_sm_send_event(rpf, RPFSM_EVENT_TIMEOUT);
289}
290
291static void
292bfa_fcs_rpf_send_rpsc2(void *rpf_cbarg, struct bfa_fcxp_s *fcxp_alloced)
293{
294	struct bfa_fcs_rpf_s *rpf 	= (struct bfa_fcs_rpf_s *)rpf_cbarg;
295	struct bfa_fcs_rport_s *rport = rpf->rport;
296	struct bfa_fcs_port_s *port = rport->port;
297	struct fchs_s          fchs;
298	int             len;
299	struct bfa_fcxp_s *fcxp;
300
301	bfa_trc(rport->fcs, rport->pwwn);
302
303	fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
304	if (!fcxp) {
305		bfa_fcxp_alloc_wait(port->fcs->bfa, &rpf->fcxp_wqe,
306					bfa_fcs_rpf_send_rpsc2, rpf);
307		return;
308	}
309	rpf->fcxp = fcxp;
310
311	len = fc_rpsc2_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid,
312			    bfa_fcs_port_get_fcid(port), &rport->pid, 1);
313
314	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
315			  FC_CLASS_3, len, &fchs, bfa_fcs_rpf_rpsc2_response,
316			  rpf, FC_MAX_PDUSZ, FC_ELS_TOV);
317	rport->stats.rpsc_sent++;
318	bfa_sm_send_event(rpf, RPFSM_EVENT_FCXP_SENT);
319
320}
321
322static void
323bfa_fcs_rpf_rpsc2_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
324			    bfa_status_t req_status, u32 rsp_len,
325			    u32 resid_len, struct fchs_s *rsp_fchs)
326{
327	struct bfa_fcs_rpf_s *rpf = (struct bfa_fcs_rpf_s *) cbarg;
328	struct bfa_fcs_rport_s *rport = rpf->rport;
329	struct fc_ls_rjt_s    *ls_rjt;
330	struct fc_rpsc2_acc_s  *rpsc2_acc;
331	u16        num_ents;
332
333	bfa_trc(rport->fcs, req_status);
334
335	if (req_status != BFA_STATUS_OK) {
336		bfa_trc(rport->fcs, req_status);
337		if (req_status == BFA_STATUS_ETIMER)
338			rport->stats.rpsc_failed++;
339		bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR);
340		return;
341	}
342
343	rpsc2_acc = (struct fc_rpsc2_acc_s *) BFA_FCXP_RSP_PLD(fcxp);
344	if (rpsc2_acc->els_cmd == FC_ELS_ACC) {
345		rport->stats.rpsc_accs++;
346		num_ents = bfa_os_ntohs(rpsc2_acc->num_pids);
347		bfa_trc(rport->fcs, num_ents);
348		if (num_ents > 0) {
349			bfa_assert(rpsc2_acc->port_info[0].pid != rport->pid);
350			bfa_trc(rport->fcs,
351				bfa_os_ntohs(rpsc2_acc->port_info[0].pid));
352			bfa_trc(rport->fcs,
353				bfa_os_ntohs(rpsc2_acc->port_info[0].speed));
354			bfa_trc(rport->fcs,
355				bfa_os_ntohs(rpsc2_acc->port_info[0].index));
356			bfa_trc(rport->fcs,
357				rpsc2_acc->port_info[0].type);
358
359			if (rpsc2_acc->port_info[0].speed == 0) {
360				bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR);
361				return;
362			}
363
364			rpf->rpsc_speed = fc_rpsc_operspeed_to_bfa_speed(
365				bfa_os_ntohs(rpsc2_acc->port_info[0].speed));
366
367			bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_COMP);
368		}
369	} else {
370		ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp);
371		bfa_trc(rport->fcs, ls_rjt->reason_code);
372		bfa_trc(rport->fcs, ls_rjt->reason_code_expl);
373		rport->stats.rpsc_rejects++;
374		if (ls_rjt->reason_code == FC_LS_RJT_RSN_CMD_NOT_SUPP)
375			bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_FAIL);
376		else
377			bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR);
378	}
379}
380