blob: f2a9361ce9a4335ba97e710014f933030855c16f [file] [log] [blame]
Jing Huang7725ccf2009-09-23 17:46:15 -07001/*
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;
Jing Huang4f1806b2010-07-08 19:50:15 -070076 struct bfa_fcs_fabric_s *fabric = &rport->fcs->fabric;
Jing Huang7725ccf2009-09-23 17:46:15 -070077
78 bfa_trc(rport->fcs, rport->pwwn);
79 bfa_trc(rport->fcs, rport->pid);
80 bfa_trc(rport->fcs, event);
81
82 switch (event) {
Jing Huangf8ceafd2009-09-25 12:29:54 -070083 case RPFSM_EVENT_RPORT_ONLINE:
Jing Huang4f1806b2010-07-08 19:50:15 -070084 /* 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))) {
Jing Huang7725ccf2009-09-23 17:46:15 -070089 bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending);
90 rpf->rpsc_retries = 0;
91 bfa_fcs_rpf_send_rpsc2(rpf, NULL);
Jing Huang4f1806b2010-07-08 19:50:15 -070092 }
93 break;
Jing Huang7725ccf2009-09-23 17:46:15 -070094
Jing Huangf8ceafd2009-09-25 12:29:54 -070095 case RPFSM_EVENT_RPORT_OFFLINE:
Jing Huang7725ccf2009-09-23 17:46:15 -070096 break;
97
98 default:
Krishna Gudipatie641de32010-03-05 19:35:02 -080099 bfa_sm_fault(rport->fcs, event);
Jing Huang7725ccf2009-09-23 17:46:15 -0700100 }
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
Jing Huangf8ceafd2009-09-25 12:29:54 -0700115 case RPFSM_EVENT_RPORT_OFFLINE:
Jing Huang7725ccf2009-09-23 17:46:15 -0700116 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:
Krishna Gudipatie641de32010-03-05 19:35:02 -0800122 bfa_sm_fault(rport->fcs, event);
Jing Huang7725ccf2009-09-23 17:46:15 -0700123 }
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 */
Jing Huangf8ceafd2009-09-25 12:29:54 -0700138 if (rpf->rpsc_speed != BFA_PPORT_SPEED_UNKNOWN)
Jing Huang7725ccf2009-09-23 17:46:15 -0700139 bfa_rport_speed(rport->bfa_rport, rpf->rpsc_speed);
Jing Huangf8ceafd2009-09-25 12:29:54 -0700140 else if (rpf->assigned_speed != BFA_PPORT_SPEED_UNKNOWN)
Jing Huang7725ccf2009-09-23 17:46:15 -0700141 bfa_rport_speed(rport->bfa_rport, rpf->assigned_speed);
Jing Huang7725ccf2009-09-23 17:46:15 -0700142 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
Jing Huangf8ceafd2009-09-25 12:29:54 -0700161 case RPFSM_EVENT_RPORT_OFFLINE:
Jing Huang7725ccf2009-09-23 17:46:15 -0700162 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:
Krishna Gudipatie641de32010-03-05 19:35:02 -0800168 bfa_sm_fault(rport->fcs, event);
Jing Huang7725ccf2009-09-23 17:46:15 -0700169 }
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) {
Jing Huangf8ceafd2009-09-25 12:29:54 -0700181 case RPFSM_EVENT_TIMEOUT:
Jing Huang7725ccf2009-09-23 17:46:15 -0700182 /* 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
Jing Huangf8ceafd2009-09-25 12:29:54 -0700187 case RPFSM_EVENT_RPORT_OFFLINE:
Jing Huang7725ccf2009-09-23 17:46:15 -0700188 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:
Krishna Gudipatie641de32010-03-05 19:35:02 -0800194 bfa_sm_fault(rport->fcs, event);
Jing Huang7725ccf2009-09-23 17:46:15 -0700195 }
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) {
Jing Huangf8ceafd2009-09-25 12:29:54 -0700208 case RPFSM_EVENT_RPORT_OFFLINE:
Jing Huang7725ccf2009-09-23 17:46:15 -0700209 bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline);
210 rpf->rpsc_retries = 0;
211 break;
212
213 default:
Krishna Gudipatie641de32010-03-05 19:35:02 -0800214 bfa_sm_fault(rport->fcs, event);
Jing Huang7725ccf2009-09-23 17:46:15 -0700215 }
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) {
Jing Huangf8ceafd2009-09-25 12:29:54 -0700228 case RPFSM_EVENT_RPORT_ONLINE:
Jing Huang7725ccf2009-09-23 17:46:15 -0700229 bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending);
230 bfa_fcs_rpf_send_rpsc2(rpf, NULL);
231 break;
232
Jing Huangf8ceafd2009-09-25 12:29:54 -0700233 case RPFSM_EVENT_RPORT_OFFLINE:
Jing Huang7725ccf2009-09-23 17:46:15 -0700234 break;
235
236 default:
Krishna Gudipatie641de32010-03-05 19:35:02 -0800237 bfa_sm_fault(rport->fcs, event);
Jing Huang7725ccf2009-09-23 17:46:15 -0700238 }
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
Jing Huangc5073412010-07-08 19:51:28 -0700277 rport->rpf.rpsc_speed = 0;
Jing Huang7725ccf2009-09-23 17:46:15 -0700278 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,
Jing Huang4f1806b2010-07-08 19:50:15 -0700316 rpf, FC_MAX_PDUSZ, FC_ELS_TOV);
Jing Huang7725ccf2009-09-23 17:46:15 -0700317 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++;
Jing Huangf8ceafd2009-09-25 12:29:54 -0700374 if (ls_rjt->reason_code == FC_LS_RJT_RSN_CMD_NOT_SUPP)
Jing Huang7725ccf2009-09-23 17:46:15 -0700375 bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_FAIL);
Jing Huangf8ceafd2009-09-25 12:29:54 -0700376 else
Jing Huang7725ccf2009-09-23 17:46:15 -0700377 bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR);
Jing Huang7725ccf2009-09-23 17:46:15 -0700378 }
379}