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