- patches.suse/slab-handle-memoryless-nodes-v2a.patch: Refresh.
[linux-flexiantxendom0-3.2.10.git] / drivers / scsi / bfa / scn.c
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
28 BFA_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  */
36 static void     bfa_fcs_port_scn_send_scr(void *scn_cbarg,
37                                           struct bfa_fcxp_s *fcxp_alloced);
38 static 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);
45 static void     bfa_fcs_port_scn_send_ls_acc(struct bfa_fcs_port_s *port,
46                                              struct fchs_s *rx_fchs);
47 static 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  */
56 enum 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
65 static void     bfa_fcs_port_scn_sm_offline(struct bfa_fcs_port_scn_s *scn,
66                                             enum port_scn_event event);
67 static void     bfa_fcs_port_scn_sm_sending_scr(struct bfa_fcs_port_scn_s *scn,
68                                                 enum port_scn_event event);
69 static void     bfa_fcs_port_scn_sm_scr(struct bfa_fcs_port_scn_s *scn,
70                                         enum port_scn_event event);
71 static void     bfa_fcs_port_scn_sm_scr_retry(struct bfa_fcs_port_scn_s *scn,
72                                               enum port_scn_event event);
73 static 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  */
79 static void
80 bfa_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_assert(0);
94         }
95 }
96
97 static void
98 bfa_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_assert(0);
113         }
114 }
115
116 static void
117 bfa_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_assert(0);
141         }
142 }
143
144 static void
145 bfa_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_assert(0);
161         }
162 }
163
164 static void
165 bfa_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_assert(0);
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  */
187 static void
188 bfa_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_RA_TOV);
222
223         bfa_sm_send_event(scn, SCNSM_EVENT_SCR_SENT);
224 }
225
226 static void
227 bfa_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  */
274 static void
275 bfa_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  */
310 static void
311 bfa_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  */
327 void
328 bfa_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
336 void
337 bfa_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
345 void
346 bfa_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
354 static void
355 bfa_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
389 static void
390 bfa_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
410 void
411 bfa_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
482