diff options
Diffstat (limited to 'drivers/scsi/bfa/rport_ftrs.c')
-rw-r--r-- | drivers/scsi/bfa/rport_ftrs.c | 379 |
1 files changed, 0 insertions, 379 deletions
diff --git a/drivers/scsi/bfa/rport_ftrs.c b/drivers/scsi/bfa/rport_ftrs.c deleted file mode 100644 index f2a9361ce9a4..000000000000 --- a/drivers/scsi/bfa/rport_ftrs.c +++ /dev/null | |||
@@ -1,379 +0,0 @@ | |||
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 | |||
31 | BFA_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 | |||
36 | static void bfa_fcs_rpf_send_rpsc2(void *rport_cbarg, | ||
37 | struct bfa_fcxp_s *fcxp_alloced); | ||
38 | static 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); | ||
43 | static void bfa_fcs_rpf_timeout(void *arg); | ||
44 | |||
45 | /** | ||
46 | * fcs_rport_ftrs_sm FCS rport state machine events | ||
47 | */ | ||
48 | |||
49 | enum 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 | |||
59 | static void bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, | ||
60 | enum rpf_event event); | ||
61 | static void bfa_fcs_rpf_sm_rpsc_sending(struct bfa_fcs_rpf_s *rpf, | ||
62 | enum rpf_event event); | ||
63 | static void bfa_fcs_rpf_sm_rpsc(struct bfa_fcs_rpf_s *rpf, | ||
64 | enum rpf_event event); | ||
65 | static void bfa_fcs_rpf_sm_rpsc_retry(struct bfa_fcs_rpf_s *rpf, | ||
66 | enum rpf_event event); | ||
67 | static void bfa_fcs_rpf_sm_offline(struct bfa_fcs_rpf_s *rpf, | ||
68 | enum rpf_event event); | ||
69 | static void bfa_fcs_rpf_sm_online(struct bfa_fcs_rpf_s *rpf, | ||
70 | enum rpf_event event); | ||
71 | |||
72 | static void | ||
73 | bfa_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 | |||
103 | static void | ||
104 | bfa_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 | |||
126 | static void | ||
127 | bfa_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 | |||
172 | static void | ||
173 | bfa_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 | |||
198 | static void | ||
199 | bfa_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 | |||
218 | static void | ||
219 | bfa_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 | */ | ||
243 | void 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 | */ | ||
256 | void 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 | */ | ||
270 | void 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 | |||
281 | static void | ||
282 | bfa_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 | |||
291 | static void | ||
292 | bfa_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 | |||
322 | static void | ||
323 | bfa_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 | } | ||