lkml.org 
[lkml]   [2009]   [Apr]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH 2/5] bfa: Brocade BFA FC SCSI driver (bfa)
    From: Krishna Chaitanya Gudipati <kgudipat@brocade.com>

    This patch contains code that interfaces with the Brocade Fibre channel HBA
    firmware/hardware and also it acts an interface between the linux driver
    and the firmware/hardware.

    Signed-off-by: Krishna Chaitanya Gudipati <kgudipat@brocade.com>
    ---
    bfa_auth.c | 554 +++++++++++++++
    bfa_auth.h | 94 ++
    bfa_callback_priv.h | 57 +
    bfa_cb_ioim_macros.h | 212 +++++
    bfa_core.c | 410 +++++++++++
    bfa_csdebug.c | 55 +
    bfa_fabric.c | 541 ++++++++++++++
    bfa_fabric.h | 163 ++++
    bfa_fcpim.c | 187 +++++
    bfa_fcpim.h | 409 +++++++++++
    bfa_fcxp.c | 714 +++++++++++++++++++
    bfa_fcxp_priv.h | 137 +++
    bfa_fwimg_priv.h | 31
    bfa_hw_cb.c | 60 +
    bfa_hw_ct.c | 66 +
    bfa_intr.c | 260 +++++++
    bfa_intr_priv.h | 116 +++
    bfa_ioc.c | 1841 +++++++++++++++++++++++++++++++++++++++++++++++++++
    bfa_ioc.h | 249 ++++++
    bfa_iocfc.c | 832 +++++++++++++++++++++++
    bfa_iocfc.h | 117 +++
    bfa_ioim.c | 1292 +++++++++++++++++++++++++++++++++++
    bfa_itnim.c | 1168 ++++++++++++++++++++++++++++++++
    bfa_log.c | 344 +++++++++
    bfa_log_module.c | 448 ++++++++++++
    bfa_lport.c | 585 ++++++++++++++++
    bfa_lport.h | 180 ++++
    bfa_lps.c | 742 ++++++++++++++++++++
    bfa_lps_priv.h | 38 +
    bfa_module.c | 92 ++
    bfa_modules_priv.h | 42 +
    bfa_os_inc.h | 197 +++++
    bfa_port.c | 1659 +++++++++++++++++++++++++++++++++++++++++++++
    bfa_port_priv.h | 89 ++
    bfa_priv.h | 122 +++
    bfa_rport.c | 1142 +++++++++++++++++++++++++++++++
    bfa_rport.h | 210 +++++
    bfa_sgpg.c | 231 ++++++
    bfa_sgpg_priv.h | 79 ++
    bfa_sm.c | 38 +
    bfa_timer.c | 90 ++
    bfa_trcmod_priv.h | 65 +
    bfa_tskim.c | 690 +++++++++++++++++++
    bfa_uf.c | 339 +++++++++
    bfa_uf_priv.h | 47 +
    bfa_vfapi.c | 319 ++++++++
    bfa_vport.c | 327 +++++++++
    bfa_vport.h | 86 ++
    plog.c | 183 +++++
    49 files changed, 17949 insertions(+)

    diff -urpN orig/drivers/scsi/bfa/bfa_auth.c patch/drivers/scsi/bfa/bfa_auth.c
    --- orig/drivers/scsi/bfa/bfa_auth.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_auth.c 2009-04-01 20:08:47.081255000 -0700
    @@ -0,0 +1,554 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +#include <bfa_fabric.h>
    +#include <bfa_lport.h>
    +#include <bfa_vport.h>
    +#include <bfa_auth.h>
    +#include <bfa_priv.h>
    +#include <aen/bfa_aen_audit.h>
    +#include <aen/bfa_aen_port.h>
    +
    +BFA_TRC_FILE(HAL, AUTH);
    +
    +#define BFA_AUTH_RETRY_DELAY (2000) /* milliseconds */
    +
    +#define TEST_PASSWORD "swnewsecret" /* HACK Alert !! HACK for testing */
    +
    +static u32 bfad_auth_power(u32 x, u32 n, u32 len);
    +static void bfad_auth_decrypt_string(char *str, u32 in[], u32 len);
    +static void bfa_auth_aen_audit_post(struct bfa_auth_s *auth,
    + enum bfa_audit_aen_event event);
    +
    +#define GET_AUTH(_bfa) (&_bfa->fabric.auth)
    +
    +/**
    + * bfa_auth_sm auth state machine functions
    + */
    +
    +/**
    + * Auth state machine events
    + */
    +enum bfa_auth_event{
    + BFA_AUTH_SM_START = 1, /* auth start from driver*/
    + BFA_AUTH_SM_STOP = 2, /* auth stop from driver*/
    + BFA_AUTH_SM_SUCCESS = 3, /* auth sucess from FW*/
    + BFA_AUTH_SM_FAIL = 4, /* auth failure from FW*/
    +};
    +
    +bfa_fsm_state_decl(bfa_auth, uninit, struct bfa_auth_s,
    + enum bfa_auth_event)
    +bfa_fsm_state_decl(bfa_auth, success, struct bfa_auth_s,
    + enum bfa_auth_event)
    +bfa_fsm_state_decl(bfa_auth, fail, struct bfa_auth_s,
    + enum bfa_auth_event)
    +bfa_fsm_state_decl(bfa_auth, status_wait, struct bfa_auth_s,
    + enum bfa_auth_event)
    +
    +static void
    +bfa_auth_sm_uninit(struct bfa_auth_s *auth, enum bfa_auth_event evt)
    +{
    + bfa_trc(auth->fabric->bfa, evt);
    +
    + switch (evt) {
    + case BFA_AUTH_SM_START:
    + bfa_fsm_set_state(auth, bfa_auth_sm_status_wait);
    + break;
    + default:
    + bfa_assert(0);
    + }
    +}
    +static void
    +bfa_auth_sm_uninit_entry(struct bfa_auth_s *auth)
    +{
    +}
    +static void
    +bfa_auth_sm_success(struct bfa_auth_s *auth, enum bfa_auth_event evt)
    +{
    + bfa_trc(auth->fabric->bfa, evt);
    + switch (evt) {
    + case BFA_AUTH_SM_START:
    + bfa_fsm_set_state(auth, bfa_auth_sm_status_wait);
    + break;
    + case BFA_AUTH_SM_STOP:
    + bfa_fsm_set_state(auth, bfa_auth_sm_uninit);
    + break;
    + default:
    + bfa_assert(0);
    + }
    +}
    +static void
    +bfa_auth_sm_success_entry(struct bfa_auth_s *auth)
    +{
    +}
    +static void
    +bfa_auth_sm_fail(struct bfa_auth_s *auth, enum bfa_auth_event evt)
    +{
    + switch (evt) {
    + case BFA_AUTH_SM_START:
    + bfa_fsm_set_state(auth, bfa_auth_sm_status_wait);
    + break;
    + case BFA_AUTH_SM_STOP:
    + bfa_fsm_set_state(auth, bfa_auth_sm_uninit);
    + break;
    + default:
    + bfa_assert(0);
    + }
    +}
    +static void
    +bfa_auth_sm_fail_entry(struct bfa_auth_s *auth)
    +{
    +}
    +static void
    +bfa_auth_sm_status_wait(struct bfa_auth_s *auth, enum bfa_auth_event evt)
    +{
    + switch (evt) {
    + case BFA_AUTH_SM_START:
    + bfa_fsm_set_state(auth, bfa_auth_sm_status_wait);
    + break;
    + case BFA_AUTH_SM_STOP:
    + bfa_fsm_set_state(auth, bfa_auth_sm_uninit);
    + break;
    + case BFA_AUTH_SM_SUCCESS:
    + bfa_fsm_set_state(auth, bfa_auth_sm_success);
    + break;
    + case BFA_AUTH_SM_FAIL:
    + bfa_fsm_set_state(auth, bfa_auth_sm_fail);
    + break;
    + default:
    + bfa_assert(0);
    + }
    +}
    +static void
    +bfa_auth_sm_status_wait_entry(struct bfa_auth_s *auth)
    +{
    +}
    +
    +
    +/**
    + * auth internal functions.
    + */
    +
    +
    +/**
    + * @param [in] x - value to be encrypted/decrypted
    + * @param [in] n - pubic[encryption]/private[decryption] key
    + * @param [in] len - key length
    + * @retval output
    + */
    +static u32
    +bfad_auth_power(u32 x, u32 n, u32 len)
    +{
    + long result = 1;
    + while (n) {
    + if (n & 1) {
    + result = (result * x) % len;
    + n = n-1;
    + }
    + x = (x*x) % len;
    + n = n/2;
    + }
    + return result;
    +}
    +
    +/**
    + * @param [out] str - decrypted string
    + * @param [in] in - arry of values encrypted
    + * @param [in] len - length of the array in
    + * @retval none
    + */
    +static void
    +bfad_auth_decrypt_string(char *str, u32 in[], u32 len)
    +{
    + u32 result;
    + size_t i = 0;
    +
    + while (i < len) {
    + result = bfad_auth_power(in[i], PRIVATE_KEY, KEY_LEN);
    + str[i++] = result & 0xff;
    + }
    +
    +}
    +
    +
    +/*
    + * @param[in] auth - auth
    + * @param[in] event - BFA_AUDIT_AEN_AUTH_DISABLE/BFA_AUDIT_AEN_AUTH_ENABLE
    + * @return none
    + */
    +static void
    +bfa_auth_aen_audit_post(struct bfa_auth_s *auth, enum bfa_audit_aen_event event)
    +{
    +
    + union bfa_aen_data_u aen_data;
    +
    + struct bfa_log_mod_s *logmod = auth->fabric->bfa->logm;
    + wwn_t pwwn = auth->fabric->bport.port_cfg.pwwn;
    + char *pwwn_ptr = NULL;
    +
    +
    + bfa_trc(auth->fabric->bfa, event);
    + switch (event) {
    + case BFA_AUDIT_AEN_AUTH_ENABLE:
    + bfa_log(logmod, BFA_AEN_AUDIT_AUTH_ENABLE, pwwn_ptr);
    + break;
    + case BFA_AUDIT_AEN_AUTH_DISABLE:
    + bfa_log(logmod, BFA_AEN_AUDIT_AUTH_DISABLE, pwwn_ptr);
    + break;
    + default:
    + break;
    + }
    +
    + aen_data.audit.pwwn = pwwn;
    +}
    +
    +/*
    + * @param[in] auth - auth
    + * @param[in] event - BFA_PORT_AEN_AUTH_OFF/BFA_PORT_AEN_AUTH_ON
    + * @return none
    + */
    +static void
    +bfa_auth_aen_post(struct bfa_auth_s *auth, enum bfa_port_aen_event event)
    +{
    + union bfa_aen_data_u aen_data;
    + struct bfa_log_mod_s *logmod = auth->fabric->bfa->logm;
    + wwn_t pwwn = auth->fabric->bport.port_cfg.pwwn;
    + char *pwwn_ptr = NULL;
    +
    +
    + switch (event) {
    + case BFA_PORT_AEN_AUTH_ON:
    + bfa_log(logmod, BFA_AEN_PORT_AUTH_ON, pwwn_ptr);
    + break;
    + case BFA_PORT_AEN_AUTH_OFF:
    + bfa_log(logmod, BFA_AEN_PORT_AUTH_OFF, pwwn_ptr);
    + break;
    + default:
    + break;
    + }
    +
    + aen_data.port.pwwn = pwwn;
    +}
    +
    +
    +/**
    + * auth public functions
    + */
    +/**
    + * @param[in] bfa - bfa
    + * @param[in] policy - enable/disable
    + *
    + * @return : BFA_STATUS_OK if successful, else BFA_STATUS_FAILED for failure
    + */
    +bfa_status_t
    +bfa_auth_get_attr(struct bfa_s *bfa, struct bfa_auth_attr_s *attr)
    +{
    + struct bfa_auth_s *auth = GET_AUTH(bfa);
    + bfa_os_memset(attr, 0, sizeof(struct bfa_auth_attr_s));
    +
    + if (auth->algo >= BFA_AUTH_ALGO_MD5 &&
    + auth->algo <= BFA_AUTH_ALGO_SM)
    + attr->algo = auth->algo;
    + else
    + attr->algo = auth->algo = BFA_AUTH_ALGO_MD5;
    +
    + if (auth->group == FC_AUTH_DH_GID_0_DHG_NULL)
    + attr->dh_grp = BFA_AUTH_GROUP_DHNULL;
    + else if (auth->group == FC_AUTH_DH_GID_1_DHG_1024)
    + attr->dh_grp = BFA_AUTH_GROUP_DH1024;
    + else if (auth->group == FC_AUTH_DH_GID_2_DHG_1280)
    + attr->dh_grp = BFA_AUTH_GROUP_DH1280;
    + else if (auth->group == FC_AUTH_DH_GID_3_DHG_1536)
    + attr->dh_grp = BFA_AUTH_GROUP_DH1536;
    + else /* Use the default value as we support only the DHNULL group */
    + attr->dh_grp = BFA_AUTH_GROUP_DHNULL;
    +
    + if (auth->policy == BFA_FALSE)
    + attr->status = BFA_AUTH_STATUS_NONE;
    + else
    + attr->status = auth->status;
    + if (auth->secret_len > 0)
    + attr->secret_set = BFA_TRUE;
    + else
    + attr->secret_set = BFA_FALSE;
    + attr->rjt_code = auth->rjt_code;
    + attr->rjt_code_exp = auth->rjt_code_exp;
    +
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * @param[in] bfa - bfa
    + * @param[in] policy - enable/disable
    + *
    + * @return : BFA_STATUS_OK
    + */
    +bfa_status_t
    +bfa_auth_set_policy(struct bfa_s *bfa, bfa_boolean_t policy)
    +{
    + struct bfa_auth_s *auth = GET_AUTH(bfa);
    + struct bfa_pport_attr_s attr;
    + int status;
    +
    + auth->fabric = &bfa->fabric;
    +
    + if (auth->algo < BFA_AUTH_ALGO_MD5 || auth->algo > BFA_AUTH_ALGO_SM)
    + auth->algo = BFA_AUTH_ALGO_MD5;
    +
    + status = auth->status;
    + if ((status < BFA_AUTH_UNINIT || status > BFA_AUTH_FAILED))
    + //bfa_sm_set_state(auth, bfa_auth_sm_uninit);
    +
    + /*
    + * If the link is already up and authentication is enabled now,
    + * and authentication is not already successful,
    + * then restart authentication process
    + */
    + if (auth->policy == BFA_FALSE && policy == BFA_TRUE &&
    + (auth->status != FC_AUTH_STATE_SUCCESS) &&
    + auth->fabric->is_auth) {
    + bfa_pport_get_attr(bfa, &attr);
    + if (attr.port_state == BFA_PPORT_ST_LINKUP)
    + bfa_auth_reinit(bfa);
    + }
    +
    + auth->policy = policy;
    + bfa->fabric.auth_reqd = policy;
    + bfa_vf_auth_update(&bfa->fabric);
    + bfa_auth_aen_audit_post(auth, (policy == BFA_TRUE) ?
    + BFA_AUDIT_AEN_AUTH_ENABLE : BFA_AUDIT_AEN_AUTH_DISABLE);
    +
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * @param[in] bfa - bfa
    + * @param[in] policy - enable/disable
    + *
    + * @return : enum bfa_auth_status
    + */
    +enum bfa_auth_status
    +bfa_auth_get_status(struct bfa_s *bfa)
    +{
    + if (bfa->fabric.auth.policy == BFA_FALSE)
    + return BFA_AUTH_STATUS_NONE;
    + else
    + return GET_AUTH(bfa)->status;
    +
    +}
    +
    +/**
    + * @param[in] bfa - bfa
    + * @param[in] algo - authentication algorithm
    + *
    + * @return : BFA_STATUS_OK if successful, else BFA_STATUS_FAILED
    + */
    +bfa_status_t
    +bfa_auth_set_algo(struct bfa_s *bfa, enum bfa_auth_algo algo)
    +{
    + struct bfa_auth_s *auth = GET_AUTH(bfa);
    +
    + auth->algo = algo;
    + bfa_vf_auth_update(&bfa->fabric);
    +
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * @param[in] bfa - bfa
    + * @param[out] stats - pointer to the authentication statistics of the bfa
    + *
    + * @return : BFA_STATUS_OK
    + */
    +bfa_status_t
    +bfa_auth_get_stats(struct bfa_s *bfa, struct bfa_auth_stats_s *stats)
    +{
    + struct bfa_auth_s *auth = GET_AUTH(bfa);
    +
    + memcpy(stats, &auth->stats, sizeof(struct bfa_auth_stats_s));
    +
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * @param[in] bfa - bfa
    + * @param[in] group - DH Group
    + *
    + * @return : BFA_TRUE if successful else BFA_FALSE
    + */
    +bfa_status_t
    +bfa_auth_set_dh_group(struct bfa_s *bfa, int group)
    +{
    + if (group == FC_AUTH_DH_GID_0_DHG_NULL) {
    + bfa->fabric.auth.group = group;
    + return BFA_STATUS_OK;
    + }
    + bfa_vf_auth_update(&bfa->fabric);
    +
    + return BFA_STATUS_FAILED;
    +}
    +
    +/**
    + * @param[in] bfa - bfa
    + * @param[in] secret- secret string
    + *
    +* @return : BFA_TRUE
    + */
    +bfa_status_t
    +bfa_auth_set_secretstring(struct bfa_s *bfa, char *secret)
    +{
    + u32 len;
    +
    + len = strlen(secret);
    + strncpy(bfa->fabric.auth.secret, secret, len);
    + bfa->fabric.auth.secret[len] = '\0';
    + bfa->fabric.auth.secret_len = len & 0xff;
    + bfa_vf_auth_update(&bfa->fabric);
    +
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * @param[in] bfa - bfa
    + * @param[in] secret- secret string
    + *
    +* @return : BFA_TRUE
    + */
    +bfa_status_t
    +bfa_auth_set_secretstring_encrypt(struct bfa_s *bfa, u32 secret[],
    + u32 len)
    +{
    + bfad_auth_decrypt_string(bfa->fabric.auth.secret, secret, len);
    + bfa->fabric.auth.secret[len] = '\0';
    + bfa->fabric.auth.secret_len = len & 0xff;
    + bfa_vf_auth_update(&bfa->fabric);
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * @param[in] bfa - bfa
    + * @param[in] src - secret source
    + *
    + * @return : BFA_STATUS_OK if successful, otherwise BFA_STATUS_FAILED
    + */
    +bfa_status_t
    +bfa_auth_set_secretsource(struct bfa_s *bfa, enum bfa_auth_secretsource src)
    +{
    + struct bfa_auth_s *auth = GET_AUTH(bfa);
    +
    + if (src == BFA_AUTH_SECSRC_LOCAL) {
    + auth->source = src;
    + return BFA_STATUS_OK;
    + }
    + bfa_vf_auth_update(&bfa->fabric);
    + return BFA_STATUS_FAILED;
    +}
    +
    +/**
    + * @param[in] bfa - bfa
    + *
    + * @return : BFA_STATUS_OK
    + */
    +bfa_status_t
    +bfa_auth_reset_stats(struct bfa_s *bfa)
    +{
    + struct bfa_auth_s *auth = GET_AUTH(bfa);
    +
    + memset(&auth->stats, 0x00, sizeof(struct bfa_auth_stats_s));
    +
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * @param[in] bfa - bfa
    + *
    + * @return : BFA_STATUS_FAILED
    + */
    +bfa_status_t
    +bfa_auth_reinit(struct bfa_s *bfa)
    +{
    + bfa_auth_start(&bfa->fabric);
    + return BFA_STATUS_OK;
    +}
    +
    +
    +/*
    + * @param[in] fabric - fabric
    + * @return - none
    + */
    +void
    +bfa_auth_start(struct bfa_fabric_s *fabric)
    +{
    + struct bfi_fabric_setauth_req_s req;
    +
    + req.mh.msg_id = BFI_FABRIC_H2I_SETAUTH;
    + req.fw_handle = fabric->vf_id;
    + req.algo = fabric->auth.algo;
    + req.group = fabric->auth.group;
    + req.policy = fabric->auth.policy;
    + memcpy(req.secret, fabric->auth.secret, fabric->auth.secret_len);
    + req.secret_len = fabric->auth.secret_len;
    +
    + bfi_h2i_set(req.mh, BFI_MC_FABRIC, BFI_FABRIC_H2I_AUTH_START,
    + bfa_lpuid(fabric->bfa));
    + /**
    + * queue I/O message to firmware
    + */
    + bfa_reqq_produce(fabric->bfa, fabric->reqq);
    +
    + bfa_fsm_send_event(&fabric->auth, BFA_AUTH_SM_START);
    +
    +}
    +void
    +bfa_auth_start_rsp(struct bfa_fabric_s *fabric)
    +{
    + enum bfa_port_aen_event evt = BFA_PORT_AEN_ONLINE;//TODO
    +
    + bfa_auth_aen_post(&fabric->auth, evt);
    + if (fabric->auth.status) {
    + bfa_trc(fabric->bfa, BFA_AUTH_SM_SUCCESS);
    + bfa_fsm_send_event(&fabric->auth, BFA_AUTH_SM_SUCCESS);
    + } else {
    + bfa_trc(fabric->bfa, BFA_AUTH_SM_FAIL);
    + bfa_fsm_send_event(&fabric->auth, BFA_AUTH_SM_FAIL);
    + }
    +}
    +void
    +bfa_auth_stop(struct bfa_fabric_s *fabric)
    +{
    + struct bfa_auth_s *auth = &fabric->auth;
    +
    + bfa_trc(fabric->bfa, auth->status);
    +
    + if (auth->status >= BFA_AUTH_UNINIT &&
    + auth->status <= BFA_AUTH_FAILED) {
    + //bfa_fabric_sm_send_event(fabric, BFA_AUTH_STOP);
    + }
    +
    + bfa_fsm_send_event(&fabric->auth, BFA_AUTH_SM_STOP);
    +}
    +
    +
    +/* vim:set ts=4 sw=4 noet ff=unix ft=c tw=78 ai: */
    +
    +/*
    + * emacs.Local Variables:
    + * emacs.mode:C
    + * emacs.c-basic-offset:4
    + * emacs.indent-tabs-mode:t
    + * emacs.tab-width:4
    + * emacs.End:
    + */
    diff -urpN orig/drivers/scsi/bfa/bfa_auth.h patch/drivers/scsi/bfa/bfa_auth.h
    --- orig/drivers/scsi/bfa/bfa_auth.h 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_auth.h 2009-04-01 20:08:47.089480000 -0700
    @@ -0,0 +1,94 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +/**
    + * BFA Fabric interfaces
    + */
    +
    +#ifndef __BFA_AUTH_H__
    +#define __BFA_AUTH_H__
    +
    +#include <defs/bfa_defs_vf.h>
    +#include <defs/bfa_defs_status.h>
    +#include <defs/bfa_defs_auth.h>
    +#include <protocol/bfa_protocol.h>
    +
    +
    +/**
    + * P R I V A T E D E F I N I T I O N S
    + * - Used & visible to BFA AUTH module alone (private)
    + */
    +struct bfa_fabric_s;
    +
    +
    +
    +struct bfa_auth_s {
    + bfa_boolean_t policy; /* authentication enabled/disabled */
    + bfa_fsm_t fsm; /* BFA auth state machine */
    + enum bfa_auth_status status; /* authentication status */
    + enum auth_rjt_codes rjt_code; /* auth reject status */
    + enum auth_rjt_code_exps rjt_code_exp; /* auth reject reason */
    + enum bfa_auth_algo algo; /* Authentication algorithm */
    + struct bfa_auth_stats_s stats; /* Statistics */
    + enum auth_dh_gid group; /* DH(diffie-hellman) Group */
    + enum bfa_auth_secretsource source; /* Secret source */
    + char secret[BFA_AUTH_SECRET_STRING_LEN];
    + /* secret string */
    + u8 secret_len;
    + /* secret string length */
    + u8 nretries;
    + /* number of retries */
    + struct bfa_fabric_s *fabric;/* pointer to fabric */
    + u8 sentcode; /* pointer to response data */
    + u8 *response; /* pointer to response data */
    +};
    +/**
    + * P R O T E C T E D D E F I N I T I O N S
    + * - Used & visible to BFA peer modules alone (private)
    + */
    +/**
    + * P U B L I C D E F I N I T I O N S
    + * - Used & visible to driver
    + */
    +
    +/**
    + * bfa fcs authentication public functions
    + */
    +bfa_status_t bfa_auth_get_attr(struct bfa_s *port,
    + struct bfa_auth_attr_s *attr);
    +bfa_status_t bfa_auth_set_policy(struct bfa_s *port,
    + bfa_boolean_t policy);
    +enum bfa_auth_status bfa_auth_get_status(struct bfa_s *port);
    +bfa_status_t bfa_auth_set_algo(struct bfa_s *port,
    + enum bfa_auth_algo algo);
    +bfa_status_t bfa_auth_get_stats(struct bfa_s *port,
    + struct bfa_auth_stats_s *stats);
    +bfa_status_t bfa_auth_set_dh_group(struct bfa_s *port, int group);
    +bfa_status_t bfa_auth_set_secretstring(struct bfa_s *port,
    + char *secret);
    +bfa_status_t bfa_auth_set_secretstring_encrypt(struct bfa_s *port,
    + u32 secret[], u32 len);
    +bfa_status_t bfa_auth_set_secretsource(struct bfa_s *port,
    + enum bfa_auth_secretsource src);
    +bfa_status_t bfa_auth_reset_stats(struct bfa_s *port);
    +bfa_status_t bfa_auth_reinit(struct bfa_s *port);
    +void bfa_auth_stop(struct bfa_fabric_s *fabric);
    +void bfa_auth_start(struct bfa_fabric_s *fabric);
    +void bfa_auth_start_rsp(struct bfa_fabric_s *fabric);
    +#endif //__BFA_AUTH_H__
    +
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_callback_priv.h patch/drivers/scsi/bfa/bfa_callback_priv.h
    --- orig/drivers/scsi/bfa/bfa_callback_priv.h 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_callback_priv.h 2009-04-01 20:08:47.097774000 -0700
    @@ -0,0 +1,57 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#ifndef __BFA_CALLBACK_PRIV_H__
    +#define __BFA_CALLBACK_PRIV_H__
    +
    +#include <cs/bfa_q.h>
    +
    +typedef void (*bfa_cb_cbfn_t) (void *cbarg, bfa_boolean_t complete);
    +
    +/**
    + * Generic BFA callback element.
    + */
    +struct bfa_cb_qe_s {
    + struct list_head qe;
    + bfa_cb_cbfn_t cbfn;
    + bfa_boolean_t once;
    + u32 rsvd;
    + void *cbarg;
    +};
    +
    +#define bfa_cb_queue(__bfa, __hcb_qe, __cbfn, __cbarg) do { \
    + (__hcb_qe)->cbfn = (__cbfn); \
    + (__hcb_qe)->cbarg = (__cbarg); \
    + list_add_tail(&(__hcb_qe)->qe, &(__bfa)->comp_q); \
    +} while (0)
    +
    +#define bfa_cb_dequeue(__hcb_qe) list_del(&(__hcb_qe)->qe)
    +
    +#define bfa_cb_queue_once(__bfa, __hcb_qe, __cbfn, __cbarg) do { \
    + (__hcb_qe)->cbfn = (__cbfn); \
    + (__hcb_qe)->cbarg = (__cbarg); \
    + if (!(__hcb_qe)->once) { \
    + list_add_tail((__hcb_qe), &(__bfa)->comp_q); \
    + (__hcb_qe)->once = BFA_TRUE; \
    + } \
    +} while (0)
    +
    +#define bfa_cb_queue_done(__hcb_qe) do { \
    + (__hcb_qe)->once = BFA_FALSE; \
    +} while (0)
    +
    +#endif /* __BFA_CALLBACK_PRIV_H__ */
    diff -urpN orig/drivers/scsi/bfa/bfa_cb_ioim_macros.h patch/drivers/scsi/bfa/bfa_cb_ioim_macros.h
    --- orig/drivers/scsi/bfa/bfa_cb_ioim_macros.h 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_cb_ioim_macros.h 2009-04-01 20:08:47.105114000 -0700
    @@ -0,0 +1,212 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +/**
    + * bfa_cb_ioim_macros.h BFA IOIM driver interface macros.
    + */
    +
    +#ifndef __BFA_HCB_IOIM_MACROS_H__
    +#define __BFA_HCB_IOIM_MACROS_H__
    +
    +#include <bfa_os_inc.h>
    +/*
    + * #include <linux/dma-mapping.h>
    + *
    + * #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> #include
    + * <scsi/scsi_device.h> #include <scsi/scsi_host.h>
    + */
    +#include "bfad_im_compat.h"
    +
    +/*
    + * task attribute values in FCP-2 FCP_CMND IU
    + */
    +#define SIMPLE_Q 0
    +#define HEAD_OF_Q 1
    +#define ORDERED_Q 2
    +#define ACA_Q 4
    +#define UNTAGGED 5
    +
    +static inline lun_t
    +bfad_int_to_lun(u32 luno)
    +{
    + union {
    + u16 scsi_lun[4];
    + lun_t bfa_lun;
    + } lun;
    +
    + lun.bfa_lun = 0;
    + lun.scsi_lun[0] = bfa_os_htons(luno);
    +
    + return (lun.bfa_lun);
    +}
    +
    +/**
    + * Get LUN for the I/O request
    + */
    +#define bfa_cb_ioim_get_lun(__dio) \
    + bfad_int_to_lun(((struct scsi_cmnd *)__dio)->device->lun)
    +
    +/**
    + * Get CDB for the I/O request
    + */
    +static inline u8 *
    +bfa_cb_ioim_get_cdb(struct bfad_ioim_s *dio)
    +{
    + struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
    +
    + return ((u8 *) cmnd->cmnd);
    +}
    +
    +/**
    + * Get I/O direction (read/write) for the I/O request
    + */
    +static inline enum fcp_iodir
    +bfa_cb_ioim_get_iodir(struct bfad_ioim_s *dio)
    +{
    + struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
    + enum dma_data_direction dmadir;
    +
    + dmadir = cmnd->sc_data_direction;
    + if (dmadir == DMA_TO_DEVICE)
    + return FCP_IODIR_WRITE;
    + else if (dmadir == DMA_FROM_DEVICE)
    + return FCP_IODIR_READ;
    + else
    + return FCP_IODIR_NONE;
    +}
    +
    +/**
    + * Get IO size in bytes for the I/O request
    + */
    +static inline u32
    +bfa_cb_ioim_get_size(struct bfad_ioim_s *dio)
    +{
    + struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
    +
    + return (scsi_bufflen(cmnd));
    +}
    +
    +/**
    + * Get timeout for the I/O request
    + */
    +static inline u8
    +bfa_cb_ioim_get_timeout(struct bfad_ioim_s *dio)
    +{
    + struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
    + /*
    + * TBD: need a timeout for scsi passthru
    + */
    + if (cmnd->device->host == NULL)
    + return 4;
    +
    + return 0;
    +}
    +
    +/**
    + * Get SG element for the I/O request given the SG element index
    + */
    +static inline union bfi_addr_u
    +bfa_cb_ioim_get_sgaddr(struct bfad_ioim_s *dio, int sgeid)
    +{
    + struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
    + struct scatterlist *sge;
    + u64 addr;
    +
    + if (scsi_sg_count(cmnd)) {
    + sge = (struct scatterlist *)scsi_sglist(cmnd) + sgeid;
    + addr = (u64) sg_dma_address(sge);
    + } else
    + addr = (u64) cmnd->SCp.dma_handle;
    +
    + return (*(union bfi_addr_u *) &addr);
    +}
    +
    +static inline u32
    +bfa_cb_ioim_get_sglen(struct bfad_ioim_s *dio, int sgeid)
    +{
    + struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
    + struct scatterlist *sge;
    + u32 len;
    +
    + if (scsi_sg_count(cmnd)) {
    + sge = (struct scatterlist *)scsi_sglist(cmnd) + sgeid;
    + len = sg_dma_len(sge);
    + } else {
    + len = scsi_bufflen(cmnd);
    + }
    +
    + return len;
    +}
    +
    +/**
    + * Get Command Reference Number for the I/O request. 0 if none.
    + */
    +static inline u8
    +bfa_cb_ioim_get_crn(struct bfad_ioim_s *dio)
    +{
    + return 0;
    +}
    +
    +/**
    + * Get SAM-3 priority for the I/O request. 0 is default.
    + */
    +static inline u8
    +bfa_cb_ioim_get_priority(struct bfad_ioim_s *dio)
    +{
    + return 0;
    +}
    +
    +/**
    + * Get task attributes for the I/O request. Default is FCP_TASK_ATTR_SIMPLE(0).
    + */
    +static inline u8
    +bfa_cb_ioim_get_taskattr(struct bfad_ioim_s *dio)
    +{
    + struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
    + u8 task_attr = UNTAGGED;
    +
    + if (cmnd->device->tagged_supported) {
    + switch (cmnd->tag) {
    + case HEAD_OF_QUEUE_TAG:
    + task_attr = HEAD_OF_Q;
    + break;
    + case ORDERED_QUEUE_TAG:
    + task_attr = ORDERED_Q;
    + break;
    + default:
    + task_attr = SIMPLE_Q;
    + break;
    + }
    + }
    +
    + return task_attr;
    +}
    +
    +/**
    + * Get CDB length in bytes for the I/O request. Default is FCP_CMND_CDB_LEN(16).
    + */
    +static inline u8
    +bfa_cb_ioim_get_cdblen(struct bfad_ioim_s *dio)
    +{
    + struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
    +
    + return (cmnd->cmd_len);
    +}
    +
    +
    +
    +#endif /* __BFA_HCB_IOIM_MACROS_H__ */
    diff -urpN orig/drivers/scsi/bfa/bfa_core.c patch/drivers/scsi/bfa/bfa_core.c
    --- orig/drivers/scsi/bfa/bfa_core.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_core.c 2009-04-01 20:08:47.113276000 -0700
    @@ -0,0 +1,410 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#include <bfa.h>
    +#include <defs/bfa_defs_pci.h>
    +#include <cs/bfa_debug.h>
    +#include <bfa_iocfc.h>
    +#include <bfa_fabric.h>
    +
    +#define DEF_CFG_NUM_FABRICS 1
    +#define DEF_CFG_NUM_LPORTS 256
    +#define DEF_CFG_NUM_CQS 4
    +#define DEF_CFG_NUM_IOIM_REQS (512)
    +#define DEF_CFG_NUM_TSKIM_REQS 128
    +#define DEF_CFG_NUM_FCXP_REQS 64
    +#define DEF_CFG_NUM_UF_BUFS 64
    +#define DEF_CFG_NUM_RPORTS 1024
    +#define DEF_CFG_NUM_ITNIMS (DEF_CFG_NUM_RPORTS)
    +#define DEF_CFG_NUM_ITNTMS 256
    +
    +#define DEF_CFG_NUM_SGPGS 512
    +#define DEF_CFG_NUM_REQQ_ELEMS 256
    +#define DEF_CFG_NUM_RSPQ_ELEMS 64
    +#define DEF_CFG_NUM_SBOOT_TGTS 16
    +#define DEF_CFG_NUM_SBOOT_LUNS 16
    +
    +/**
    + * hal_api
    + */
    +
    +/**
    + * Use this function query the memory requirement of the BFA library.
    + * This function needs to be called before bfa_attach() to get the
    + * memory required of the BFA layer for a given driver configuration.
    + *
    + * This call will fail, if the cap is out of range compared to pre-defined
    + * values within the BFA library
    + *
    + * @param[in] cfg - pointer to bfa_ioc_cfg_t. Driver layer should indicate
    + * its configuration in this structure.
    + * The default values for struct bfa_iocfc_cfg_s can be
    + * fetched using bfa_cfg_get_default() API.
    + *
    + * If cap's boundary check fails, the library will use
    + * the default bfa_cap_t values (and log a warning msg).
    + *
    + * @param[out] meminfo - pointer to bfa_meminfo_t. This content
    + * indicates the memory type (see bfa_mem_type_t) and
    + * amount of memory required.
    + *
    + * Driver should allocate the memory, populate the
    + * starting address for each block and provide the same
    + * structure as input parameter to bfa_attach() call.
    + *
    + * @return void
    + *
    + * Special Considerations: @note
    + */
    +void
    +bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo)
    +{
    + int i;
    + u32 km_len = 0, dm_len = 0;
    +
    + bfa_assert((cfg != NULL) && (meminfo != NULL));
    +
    + bfa_os_memset((void *)meminfo, 0, sizeof(struct bfa_meminfo_s));
    + meminfo->meminfo[BFA_MEM_TYPE_KVA - 1].mem_type =
    + BFA_MEM_TYPE_KVA;
    + meminfo->meminfo[BFA_MEM_TYPE_DMA - 1].mem_type =
    + BFA_MEM_TYPE_DMA;
    +
    + bfa_iocfc_meminfo(cfg, &km_len, &dm_len);
    +
    + for (i = 0; hal_mods[i]; i++)
    + hal_mods[i]->meminfo(cfg, &km_len, &dm_len);
    +
    +
    + meminfo->meminfo[BFA_MEM_TYPE_KVA - 1].mem_len = km_len;
    + meminfo->meminfo[BFA_MEM_TYPE_DMA - 1].mem_len = dm_len;
    +}
    +
    +/**
    + * Use this function to do attach the driver instance with the BFA
    + * library. This function will not trigger any HW initialization
    + * process (which will be done in bfa_init() call)
    + *
    + * This call will fail, if the cap is out of range compared to
    + * pre-defined values within the BFA library
    + *
    + * @param[out] bfa Pointer to bfa_t.
    + * @param[in] bfad Opaque handle back to the driver's IOC structure
    + * @param[in] cfg Pointer to bfa_ioc_cfg_t. Should be same structure
    + * that was used in bfa_cfg_get_meminfo().
    + * @param[in] meminfo Pointer to bfa_meminfo_t. The driver should
    + * use the bfa_cfg_get_meminfo() call to
    + * find the memory blocks required, allocate the
    + * required memory and provide the starting addresses.
    + * @param[in] pcidev pointer to struct bfa_pcidev_s
    + *
    + * @return
    + * void
    + *
    + * Special Considerations:
    + *
    + * @note
    + *
    + */
    +void
    +bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
    + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
    +{
    + int i;
    + struct bfa_mem_elem_s *melem;
    +
    + bfa_assert((cfg != NULL) && (meminfo != NULL));
    +
    + /**
    + * initialize all memory pointers for iterative allocation
    + */
    + for (i = 0; i < BFA_MEM_TYPE_MAX; i++) {
    + melem = meminfo->meminfo + i;
    + melem->kva_curp = melem->kva;
    + melem->dma_curp = melem->dma;
    + }
    +
    + bfa_iocfc_attach(bfa, bfad, cfg, meminfo, pcidev);
    +
    + for (i = 0; hal_mods[i]; i++)
    + hal_mods[i]->attach(bfa, bfad, cfg, meminfo, pcidev);
    +
    +}
    +
    +/**
    + * Use this function to delete a BFA IOC. IOC should be stopped (by
    + * calling bfa_stop()) before this function call.
    + *
    + * @param[in] bfa - pointer to bfa_t.
    + *
    + * @return
    + * void
    + *
    + * Special Considerations:
    + *
    + * @note
    + */
    +void
    +bfa_detach(struct bfa_s *bfa)
    +{
    + int i;
    +
    + for (i = 0; hal_mods[i]; i++)
    + hal_mods[i]->detach(bfa);
    +
    + bfa_iocfc_detach(bfa);
    +}
    +
    +
    +void
    +bfa_init_trc(struct bfa_s *bfa, struct bfa_trc_mod_s *trcmod)
    +{
    + bfa->trcmod = trcmod;
    +}
    +
    +
    +void
    +bfa_init_log(struct bfa_s *bfa, struct bfa_log_mod_s *logmod)
    +{
    + bfa->logm = logmod;
    +}
    +
    +
    +void
    +bfa_init_aen(struct bfa_s *bfa, struct bfa_aen_s *aen)
    +{
    + bfa->aen = aen;
    +}
    +
    +void
    +bfa_init_plog(struct bfa_s *bfa, struct bfa_plog_s *plog)
    +{
    + bfa->plog = plog;
    +}
    +
    +/**
    + * Initialize IOC.
    + *
    + * This function will return immediately, when the IOC initialization is
    + * completed, the bfa_cb_init() will be called.
    + *
    + * @param[in] bfa instance
    + *
    + * @return void
    + *
    + * Special Considerations:
    + *
    + * @note
    + * When this function returns, the driver should register the interrupt service
    + * routine(s) and enable the device interrupts. If this is not done,
    + * bfa_cb_init() will never get called
    + */
    +void
    +bfa_init(struct bfa_s *bfa)
    +{
    + bfa_iocfc_init(bfa);
    +}
    +
    +/**
    + * Use this function initiate the IOC configuration setup. This function
    + * will return immediately.
    + *
    + * @param[in] bfa instance
    + *
    + * @return None
    + */
    +void
    +bfa_start(struct bfa_s *bfa)
    +{
    + bfa_iocfc_start(bfa);
    +}
    +void
    +bfa_driver_info_init(struct bfa_s *bfa, struct bfa_driver_info_s *driver_info)
    +{
    + memcpy(&bfa->driver_info, driver_info, sizeof(struct bfa_driver_info_s));
    + bfa->fabric.bfa = bfa;
    + bfa_fabric_psymb_init(&bfa->fabric);
    +}
    +/**
    + * Use this function quiese the IOC. This function will return immediately,
    + * when the IOC is actually stopped, the bfa_cb_stop() will be called.
    + *
    + * @param[in] bfa - pointer to bfa_t.
    + *
    + * @return None
    + *
    + * Special Considerations:
    + * bfa_cb_stop() could be called before or after bfa_stop() returns.
    + *
    + * @note
    + * In case of any failure, we could handle it automatically by doing a
    + * reset and then succeed the bfa_stop() call.
    + */
    +void
    +bfa_stop(struct bfa_s *bfa)
    +{
    + bfa_iocfc_stop(bfa);
    +}
    +
    +void
    +bfa_comp_deq(struct bfa_s *bfa, struct list_head *comp_q)
    +{
    + INIT_LIST_HEAD(comp_q);
    + list_splice_tail_init(&bfa->comp_q, comp_q);
    +}
    +
    +void
    +bfa_comp_process(struct bfa_s *bfa, struct list_head *comp_q)
    +{
    + struct list_head *qe;
    + struct list_head *qen;
    + struct bfa_cb_qe_s *hcb_qe;
    +
    + list_for_each_safe(qe, qen, comp_q) {
    + hcb_qe = (struct bfa_cb_qe_s *) qe;
    + hcb_qe->cbfn(hcb_qe->cbarg, BFA_TRUE);
    + }
    +}
    +
    +void
    +bfa_comp_free(struct bfa_s *bfa, struct list_head *comp_q)
    +{
    + struct list_head *qe;
    + struct bfa_cb_qe_s *hcb_qe;
    +
    + while (!list_empty(comp_q)) {
    + bfa_q_deq(comp_q, &qe);
    + hcb_qe = (struct bfa_cb_qe_s *) qe;
    + hcb_qe->cbfn(hcb_qe->cbarg, BFA_FALSE);
    + }
    +}
    +/**
    + * Periodic timer heart beat from driver
    + */
    +void
    +bfa_timer_tick(struct bfa_s *bfa)
    +{
    + bfa_timer_beat(&bfa->timer_mod);
    +}
    +
    +#ifndef BFA_BIOS_BUILD
    +/**
    + * Return the list of PCI vendor/device id lists supported by this
    + * BFA instance.
    + */
    +void
    +bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids)
    +{
    + static struct bfa_pciid_s __pciids[] = {
    + {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_FC_8G2P},
    + {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_FC_8G1P},
    + {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_CT},
    + };
    +
    + *npciids = sizeof(__pciids) / sizeof(__pciids[0]);
    + *pciids = __pciids;
    +}
    +
    +/**
    + * Use this function query the default struct bfa_iocfc_cfg_s value (compiled
    + * into BFA layer). The OS driver can then turn back and overwrite entries that
    + * have been configured by the user.
    + *
    + * @param[in] cfg - pointer to bfa_ioc_cfg_t
    + *
    + * @return
    + * void
    + *
    + * Special Considerations:
    + * note
    + */
    +void
    +bfa_cfg_get_default(struct bfa_iocfc_cfg_s *cfg)
    +{
    + cfg->fwcfg.num_fabrics = DEF_CFG_NUM_FABRICS;
    + cfg->fwcfg.num_lports = DEF_CFG_NUM_LPORTS;
    + cfg->fwcfg.num_rports = DEF_CFG_NUM_RPORTS;
    + cfg->fwcfg.num_ioim_reqs = DEF_CFG_NUM_IOIM_REQS;
    + cfg->fwcfg.num_tskim_reqs = DEF_CFG_NUM_TSKIM_REQS;
    + cfg->fwcfg.num_fcxp_reqs = DEF_CFG_NUM_FCXP_REQS;
    + cfg->fwcfg.num_uf_bufs = DEF_CFG_NUM_UF_BUFS;
    + cfg->fwcfg.num_cqs = DEF_CFG_NUM_CQS;
    +
    + cfg->drvcfg.num_reqq_elems = DEF_CFG_NUM_REQQ_ELEMS;
    + cfg->drvcfg.num_rspq_elems = DEF_CFG_NUM_RSPQ_ELEMS;
    + cfg->drvcfg.num_sgpgs = DEF_CFG_NUM_SGPGS;
    + cfg->drvcfg.num_sboot_tgts = DEF_CFG_NUM_SBOOT_TGTS;
    + cfg->drvcfg.num_sboot_luns = DEF_CFG_NUM_SBOOT_LUNS;
    + cfg->drvcfg.path_tov = BFA_FCPIM_PATHTOV_DEF;
    + cfg->drvcfg.ioc_recover = BFA_FALSE;
    + cfg->drvcfg.delay_comp = BFA_FALSE;
    + cfg->drvcfg.fw_disc_enabled = BFA_TRUE;
    +
    +}
    +
    +void
    +bfa_cfg_get_min(struct bfa_iocfc_cfg_s *cfg)
    +{
    + bfa_cfg_get_default(cfg);
    + cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MIN;
    + cfg->fwcfg.num_tskim_reqs = BFA_TSKIM_MIN;
    + cfg->fwcfg.num_fcxp_reqs = BFA_FCXP_MIN;
    + cfg->fwcfg.num_uf_bufs = BFA_UF_MIN;
    + cfg->fwcfg.num_rports = BFA_RPORT_MIN;
    +
    + cfg->drvcfg.num_sgpgs = BFA_SGPG_MIN;
    + cfg->drvcfg.num_reqq_elems = BFA_REQQ_NELEMS_MIN;
    + cfg->drvcfg.num_rspq_elems = BFA_RSPQ_NELEMS_MIN;
    + cfg->drvcfg.min_cfg = BFA_TRUE;
    +}
    +
    +void
    +bfa_get_attr(struct bfa_s *bfa, struct bfa_ioc_attr_s *ioc_attr)
    +{
    + bfa_ioc_get_attr(&bfa->ioc, ioc_attr);
    + if (bfa_ioc_get_fcmode(&bfa->ioc))
    + ioc_attr->ioc_type = BFA_IOC_TYPE_FC;
    + else
    + ioc_attr->ioc_type = BFA_IOC_TYPE_FCoE;
    +}
    +
    +/**
    + * Retrieve firmware trace information on IOC failure.
    + */
    +bfa_status_t
    +bfa_debug_fwsave(struct bfa_s *bfa, void *trcdata, int *trclen)
    +{
    + return bfa_ioc_debug_fwsave(&bfa->ioc, trcdata, trclen);
    +}
    +
    +/**
    + * Fetch firmware trace data.
    + *
    + * @param[in] bfa BFA instance
    + * @param[out] trcdata Firmware trace buffer
    + * @param[in,out] trclen Firmware trace buffer len
    + *
    + * @retval BFA_STATUS_OK Firmware trace is fetched.
    + * @retval BFA_STATUS_INPROGRESS Firmware trace fetch is in progress.
    + */
    +bfa_status_t
    +bfa_debug_fwtrc(struct bfa_s *bfa, void *trcdata, int *trclen)
    +{
    + return bfa_ioc_debug_fwtrc(&bfa->ioc, trcdata, trclen);
    +}
    +#endif
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_csdebug.c patch/drivers/scsi/bfa/bfa_csdebug.c
    --- orig/drivers/scsi/bfa/bfa_csdebug.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_csdebug.c 2009-04-01 20:08:47.122084000 -0700
    @@ -0,0 +1,55 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +/**
    + * pbind.c BFA FC Persistent target binding
    + */
    +
    +#include <cs/bfa_debug.h>
    +#include <bfa_os_inc.h>
    +#include <cs/bfa_q.h>
    +#include <log/bfa_log_hal.h>
    +
    +/**
    + * cs_debug_api
    + */
    +
    +
    +void
    +bfa_panic(int line, char *file, char *panicstr)
    +{
    + bfa_log(NULL, BFA_LOG_HAL_ASSERT, file, line, panicstr);
    + bfa_os_panic();
    +}
    +
    +int
    +bfa_q_is_on_q_func(struct list_head *q, struct list_head *qe)
    +{
    + struct list_head *tqe;
    +
    + tqe = bfa_q_next(q);
    + while (tqe != q) {
    + if (tqe == qe)
    + return (1);
    + tqe = bfa_q_next(tqe);
    + if (tqe == NULL)
    + break;
    + }
    + return (0);
    +}
    +
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_fabric.c patch/drivers/scsi/bfa/bfa_fabric.c
    --- orig/drivers/scsi/bfa/bfa_fabric.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_fabric.c 2009-04-01 20:08:47.129626000 -0700
    @@ -0,0 +1,541 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +/**
    + * fabric.c Fabric module implementation.
    + */
    +
    +#include <bfa.h>
    +#include <bfa_lport.h>
    +#include <bfa_vport.h>
    +#include <bfa_fabric.h>
    +#include <log/bfa_log_hal.h>
    +#include <bfa_auth.h>
    +#include <bfi/bfi_fabric.h>
    +
    +BFA_TRC_FILE(HAL, FABRIC);
    +BFA_MODULE(fabric);
    +
    +#define BFA_FABRIC_RETRY_DELAY (2000) /* Milliseconds */
    +#define BFA_FABRIC_CLEANUP_DELAY (10000) /* Milliseconds */
    +
    +#define bfa_fabric_set_opertype(__fabric) do { \
    + if (bfa_pport_get_topology((__fabric)->bfa) \
    + == BFA_PPORT_TOPOLOGY_P2P) \
    + (__fabric)->oper_type = BFA_PPORT_TYPE_NPORT; \
    + else \
    + (__fabric)->oper_type = BFA_PPORT_TYPE_NLPORT; \
    +} while (0)
    +
    +
    +/*
    + * forward declarations
    + */
    +static void bfa_fabric_init(struct bfa_fabric_s *fabric);
    +static void bfa_fabric_delete(struct bfa_fabric_s *fabric);
    +/**
    + * bfa_fabric_sm fabric state machine functions
    + */
    +
    +/**
    + * Fabric state machine events
    + */
    +enum bfa_fabric_event {
    + BFA_FABRIC_SM_ONLINE = 1, /* linkup from FW*/
    + BFA_FABRIC_SM_OFFLINE = 2, /* link down from FW*/
    + BFA_FABRIC_SM_IOC_DISABLE = 3, /* ioc diasble from BFA IOC*/
    + BFA_FABRIC_SM_DELETE = 4, /* delete*/
    +};
    +bfa_fsm_state_decl(bfa_fabric, uninit, struct bfa_fabric_s,
    + enum bfa_fabric_event)
    +bfa_fsm_state_decl(bfa_fabric, offline, struct bfa_fabric_s,
    + enum bfa_fabric_event)
    +bfa_fsm_state_decl(bfa_fabric, online, struct bfa_fabric_s,
    + enum bfa_fabric_event)
    +bfa_fsm_state_decl(bfa_fabric, ioc_down, struct bfa_fabric_s,
    + enum bfa_fabric_event)
    +
    +static void
    +bfa_fabric_sm_uninit_entry(struct bfa_fabric_s *fabric)
    +{
    +}
    +
    +static void
    +bfa_fabric_sm_uninit(struct bfa_fabric_s *fabric, enum bfa_fabric_event evt)
    +{
    + bfa_trc(fabric->bfa, evt);
    +
    + switch (evt) {
    + case BFA_FABRIC_SM_ONLINE:
    + bfa_trc(fabric->bfa, fabric->bport.port_cfg.pwwn);
    + bfa_fabric_set_opertype(fabric);
    + bfa_trc(fabric->bfa, fabric->fab_type);
    + bfa_fsm_set_state(fabric, bfa_fabric_sm_online);
    + break;
    + case BFA_FABRIC_SM_IOC_DISABLE:
    + bfa_fsm_set_state(fabric, bfa_fabric_sm_ioc_down);
    + break;
    + case BFA_FABRIC_SM_DELETE:
    + break;
    + default:
    + bfa_assert(0);
    + break;
    + }
    +
    +}
    +static void
    +bfa_fabric_sm_offline_entry(struct bfa_fabric_s *fabric)
    +{
    +}
    +static void
    +bfa_fabric_sm_offline(struct bfa_fabric_s *fabric, enum bfa_fabric_event evt)
    +{
    + bfa_trc(fabric->bfa, evt);
    +
    + switch (evt) {
    + case BFA_FABRIC_SM_ONLINE:
    + bfa_trc(fabric->bfa, fabric->bport.port_cfg.pwwn);
    + bfa_fabric_set_opertype(fabric);
    + bfa_trc(fabric->bfa, fabric->fab_type);
    + bfa_fsm_set_state(fabric, bfa_fabric_sm_online);
    + break;
    + case BFA_FABRIC_SM_IOC_DISABLE:
    + bfa_fsm_set_state(fabric, bfa_fabric_sm_ioc_down);
    + break;
    + case BFA_FABRIC_SM_DELETE:
    + bfa_fsm_set_state(fabric, bfa_fabric_sm_uninit);
    + break;
    + default:
    + bfa_assert(0);
    + }
    +}
    +static void
    +bfa_fabric_sm_online_entry(struct bfa_fabric_s *fabric)
    +{
    +}
    +static void
    +bfa_fabric_sm_online(struct bfa_fabric_s *fabric, enum bfa_fabric_event evt)
    +{
    + bfa_trc(fabric->bfa, evt);
    +
    + switch (evt) {
    + case BFA_FABRIC_SM_OFFLINE:
    + if (fabric->auth_reqd)
    + bfa_auth_stop(fabric);
    + bfa_cb_vf_stop(bfa_vf_get_drv_vf(fabric));
    + bfa_fsm_set_state(fabric, bfa_fabric_sm_offline);
    + break;
    + case BFA_FABRIC_SM_IOC_DISABLE:
    + bfa_fsm_set_state(fabric, bfa_fabric_sm_ioc_down);
    + break;
    + case BFA_FABRIC_SM_DELETE:
    + bfa_fsm_set_state(fabric, bfa_fabric_sm_uninit);
    + break;
    + case BFA_FABRIC_SM_ONLINE:
    + bfa_trc(fabric->bfa, evt);
    + bfa_trc(fabric->bfa, fabric->fab_type);
    + break;
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +static void
    +bfa_fabric_sm_ioc_down_entry(struct bfa_fabric_s *fabric)
    +{
    +}
    +
    +static void
    +bfa_fabric_sm_ioc_down(struct bfa_fabric_s *fabric, enum bfa_fabric_event evt)
    +{
    + bfa_trc(fabric->bfa, evt);
    +
    + switch (evt) {
    + case BFA_FABRIC_SM_ONLINE:
    + bfa_trc(fabric->bfa, fabric->bport.port_cfg.pwwn);
    + bfa_fabric_set_opertype(fabric);
    + bfa_trc(fabric->bfa, fabric->fab_type);
    + bfa_fsm_set_state(fabric, bfa_fabric_sm_online);
    + /* lport will take care of vport create.
    + TODO Run through vf queue and create VF in FW */
    + break;
    + case BFA_FABRIC_SM_IOC_DISABLE:
    + case BFA_FABRIC_SM_DELETE:
    + bfa_fsm_set_state(fabric, bfa_fabric_sm_uninit);
    + break;
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +
    +
    +/**
    + * bfa_fabric_private fabric private functions
    + */
    +
    +static void
    +bfa_fabric_start(struct bfa_s *bfa)
    +{
    +}
    +static void
    +bfa_fabric_stop(struct bfa_s *bfa)
    +{
    + bfa_vf_stop(&bfa->fabric);
    + //bfa_cb_vf_stop(bfa->fabric.vf_drv);
    +}
    +static void
    +bfa_fabric_init(struct bfa_fabric_s *fabric)
    +{
    + struct bfa_port_cfg_s *port_cfg = &fabric->bport.port_cfg;
    +
    + port_cfg->roles = bfa_bport_role(fabric->bfa);
    + /* FCS_BRINGUP*/
    + port_cfg->roles = BFA_PORT_ROLE_FCP_IM;
    + port_cfg->nwwn = bfa_ioc_get_nwwn(&fabric->bfa->ioc);
    + port_cfg->pwwn = bfa_ioc_get_pwwn(&fabric->bfa->ioc);
    +
    +}
    +
    +/**
    + * Delete all vports and wait for vport delete completions.
    + */
    +static void
    +bfa_fabric_delete(struct bfa_fabric_s *fabric)
    +{
    + /*
    + * there is no need to inform FW as fabric_modexit
    + * will be issued by IOC
    + */
    + bfa_fsm_send_event(fabric, BFA_FABRIC_SM_DELETE);
    +}
    +
    +
    +/**
    + * Compute and return memory needed by FCP(tm) module.
    + */
    +static void
    +bfa_fabric_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
    + u32 *dm_len)
    +{
    + /* TODO memory for VF*/
    + *km_len += sizeof(struct bfa_fabric_s);
    +}
    +
    +static void
    +bfa_fabric_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
    + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
    +{
    + struct bfa_fabric_s *fabric = &bfa->fabric;
    + bfa_os_memset(fabric, 0, sizeof(struct bfa_fabric_s));
    +
    + fabric->bfa = bfa;
    + /**
    + * Initialize base fabric.
    + */
    + INIT_LIST_HEAD(&fabric->vport_q);
    + INIT_LIST_HEAD(&fabric->vf_q);
    + bfa_fabric_init(fabric);
    + bfa_lport_init(&fabric->bport, fabric->bfa, 0,
    + NULL, &fabric->bport.port_cfg, NULL);
    + bfa_fsm_set_state(fabric, bfa_fabric_sm_uninit);
    +}
    +
    +static void
    +bfa_fabric_initdone(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_fabric_detach(struct bfa_s *bfa)
    +{
    + bfa_trc(bfa, 0);
    + /**
    + * Cleanup base fabric.
    + */
    + bfa_fabric_delete(&bfa->fabric);
    +}
    +
    +static void
    +bfa_fabric_iocdisable(struct bfa_s *bfa)
    +{
    + bfa_fsm_send_event(&bfa->fabric, BFA_FABRIC_SM_IOC_DISABLE);
    + /* if vf queue has vfs send iocdisable to them TODO*/
    +}
    +
    +void
    +bfa_fabric_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
    +{
    + union bfi_fabric_i2h_msg_u req;
    + struct bfa_fabric_s *vf;
    + u16 fabric_tag = 0;
    +
    + req.msg = m;
    + switch (m->mhdr.msg_id) {
    + case BFI_FABRIC_I2H_AUTH_START_RSP:
    + fabric_tag = bfa_os_ntohs(req.auth_rsp->fw_handle);
    + vf = bfa_vf_lookup(bfa, fabric_tag);
    + if (vf->auth_reqd) {
    + vf->auth.status = req.auth_rsp->status;
    + vf->auth.algo = req.auth_rsp->algo;
    + vf->auth.group = req.auth_rsp->group;
    + bfa_auth_start_rsp(vf);
    + }
    + break;
    + case BFI_FABRIC_I2H_ONLINE:
    + fabric_tag = bfa_os_ntohs(req.status_rsp->fw_handle);
    + vf = bfa_vf_lookup(bfa, fabric_tag);
    + bfa_fabric_init(vf);
    + vf->fab_type = req.status_rsp->status;
    + vf->fabric_name = req.status_rsp->fabric_name;
    + bfa_fsm_send_event(vf, BFA_FABRIC_SM_ONLINE);
    + break;
    + case BFI_FABRIC_I2H_OFFLINE:
    + fabric_tag = bfa_os_ntohs(req.status_rsp->fw_handle);
    + vf = bfa_vf_lookup(bfa, fabric_tag);
    + vf->fab_type = req.status_rsp->status;
    + bfa_fsm_send_event(vf, BFA_FABRIC_SM_OFFLINE);
    + break;
    + default:
    + bfa_assert(0);
    + break;
    + }
    +}
    +
    +
    +/**
    + * bfa_fabric_public fabric public functions
    + */
    +
    +/**
    + * Port Symbolic Name Creation for base port.
    + */
    +void
    +bfa_fabric_psymb_init(struct bfa_fabric_s *fabric)
    +{
    + struct bfa_port_cfg_s *port_cfg = &fabric->bport.port_cfg;
    + struct bfa_adapter_attr_s adapter_attr;
    + struct bfa_driver_info_s *driver_info = &fabric->bfa->driver_info;
    +
    +
    + bfa_os_memset((void *)&adapter_attr, 0,
    + sizeof(struct bfa_adapter_attr_s));
    + bfa_ioc_get_adapter_attr(&fabric->bfa->ioc, &adapter_attr);
    +
    + /* Model name/number */
    + strncpy((char *)&port_cfg->sym_name, adapter_attr.model,
    + BFA_PORT_SYMBNAME_MODEL_SZ);
    + strncat((char *)&port_cfg->sym_name, BFA_PORT_SYMBNAME_SEPARATOR,
    + sizeof(BFA_PORT_SYMBNAME_SEPARATOR));
    +
    + /* Driver Version */
    + strncat((char *)&port_cfg->sym_name, (char *)driver_info->version,
    + BFA_PORT_SYMBNAME_VERSION_SZ);
    + strncat((char *)&port_cfg->sym_name, BFA_PORT_SYMBNAME_SEPARATOR,
    + sizeof(BFA_PORT_SYMBNAME_SEPARATOR));
    +
    + /* Host machine name */
    + strncat((char *)&port_cfg->sym_name,
    + (char *)driver_info->host_machine_name,
    + BFA_PORT_SYMBNAME_MACHINENAME_SZ);
    + strncat((char *)&port_cfg->sym_name, BFA_PORT_SYMBNAME_SEPARATOR,
    + sizeof(BFA_PORT_SYMBNAME_SEPARATOR));
    +
    + /*
    + * Host OS Info :
    + * If OS Patch Info is not there, do not truncate any bytes from the
    + * OS name string and instead copy the entire OS info string ( 64 bytes).
    + */
    + if (driver_info->host_os_patch[0] == '\0') {
    + strncat((char *)&port_cfg->sym_name,
    + (char *)driver_info->host_os_name, BFA_OS_STR_LEN);
    + strncat((char *)&port_cfg->sym_name,
    + BFA_PORT_SYMBNAME_SEPARATOR,
    + sizeof(BFA_PORT_SYMBNAME_SEPARATOR));
    + } else {
    + strncat((char *)&port_cfg->sym_name,
    + (char *)driver_info->host_os_name,
    + BFA_PORT_SYMBNAME_OSINFO_SZ);
    + strncat((char *)&port_cfg->sym_name,
    + BFA_PORT_SYMBNAME_SEPARATOR,
    + sizeof(BFA_PORT_SYMBNAME_SEPARATOR));
    +
    + /* Append host OS Patch Info */
    + strncat((char *)&port_cfg->sym_name,
    + (char *)driver_info->host_os_patch,
    + BFA_PORT_SYMBNAME_OSPATCH_SZ);
    + }
    +
    + /* null terminate */
    + port_cfg->sym_name.symname[BFA_SYMNAME_MAXLEN - 1] = 0;
    +}
    +
    +
    +
    +/**
    + * Return true if fabric in loopback mode.
    + */
    +bfa_boolean_t
    +bfa_fabric_is_loopback(struct bfa_fabric_s *fabric)
    +{
    + bfa_trc(fabric->bfa, fabric->fab_type);
    + if (fabric->fab_type == FABRIC_LOOPBACK)
    + return BFA_TRUE;
    +
    + return BFA_FALSE;
    +}
    +
    +/**
    + * Given a fabric, return oper_type.
    + */
    +enum bfa_pport_type
    +bfa_fabric_port_type(struct bfa_fabric_s *fabric)
    +{
    + bfa_trc(fabric->bfa, fabric->oper_type);
    + return fabric->oper_type;
    +}
    +
    +
    +/**
    + * A child vport is being created in the fabric.
    + *
    + * Call from vport module at vport creation. A list of base port and vports
    + * belonging to a fabric is maintained to propagate link events.
    + *
    + * param[in] fabric - Fabric instance. This can be a base fabric or vf.
    + * param[in] vport - Vport being created.
    + *
    + * @return None (always succeeds)
    + */
    +void
    +bfa_fabric_add_vport(struct bfa_fabric_s *fabric, struct bfa_vport_s *vport)
    +{
    + /**
    + * - add vport to fabric's vport_q
    + */
    + bfa_trc(fabric->bfa, fabric->vf_id);
    +
    + list_add_tail(&vport->qe, &fabric->vport_q);
    + fabric->num_vports++;
    +}
    +
    +/**
    + * A child vport is being deleted from fabric.
    + *
    + * Vport is being deleted.
    + */
    +void
    +bfa_fabric_del_vport(struct bfa_fabric_s *fabric, struct bfa_vport_s *vport)
    +{
    + list_del(&vport->qe);
    + fabric->num_vports--;
    +}
    +
    +/**
    + * Check if fabric is online.
    + *
    + * param[in] fabric - Fabric instance. This can be a base fabric or vf.
    + *
    + * @return TRUE/FALSE
    + */
    +bfa_boolean_t
    +bfa_fabric_is_online(struct bfa_fabric_s *fabric)
    +{
    + bfa_trc(fabric->bfa, fabric->oper_type);
    + bfa_trc(fabric->bfa, fabric->fab_type);
    + if ((fabric->fab_type == FABRIC_SWITCHED) &&
    + (bfa_fsm_cmp_state(fabric, bfa_fabric_sm_online)))
    + return BFA_TRUE;
    +
    + return BFA_FALSE;
    +}
    +
    +
    +bfa_status_t
    +bfa_fabric_addvf(struct bfa_fabric_s *vf, struct bfa_s *bfa,
    + struct bfa_port_cfg_s *port_cfg, struct bfad_vf_s *vf_drv)
    +{
    + /* TODO add VF to vf-queue and send to FW*/
    + bfa_fsm_set_state(vf, bfa_fabric_sm_uninit);
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * Lookup for a vport withing a fabric given its pwwn
    + */
    +struct bfa_vport_s *
    +bfa_fabric_vport_lookup(struct bfa_fabric_s *fabric, wwn_t pwwn)
    +{
    + struct bfa_vport_s *vport = NULL;
    + struct list_head *qe = NULL;
    +
    + list_for_each(qe, &fabric->vport_q) {
    + vport = (struct bfa_vport_s *) qe;
    + bfa_assert(vport);
    + if (bfa_lport_get_pwwn(&vport->lport) == pwwn)
    + return vport;
    + }
    +
    + return NULL;
    +}
    +
    +/**
    + * In a given fabric, return the number of vports.
    + *
    + * param[in] fabric - Fabric instance. This can be a base fabric or vf.
    + *
    +* @return : 1 or more.
    + */
    +u16
    +bfa_fabric_vport_count(struct bfa_fabric_s *fabric)
    +{
    + return (fabric->num_vports);
    +}
    +/**
    + * update auth parameter.
    + */
    +
    +void
    +bfa_vf_auth_update(struct bfa_fabric_s *fabric)
    +{
    + struct bfi_fabric_setauth_req_s req;
    +
    + req.mh.msg_id = BFI_FABRIC_H2I_SETAUTH;
    + req.fw_handle = fabric->vf_id;
    + req.algo = fabric->auth.algo;
    + req.group = fabric->auth.group;
    + req.policy = fabric->auth.policy;
    + memcpy(req.secret, fabric->auth.secret, fabric->auth.secret_len);
    + req.secret_len = fabric->auth.secret_len;
    +
    + bfi_h2i_set(req.mh, BFI_MC_FABRIC, BFI_FABRIC_H2I_SETAUTH,
    + bfa_lpuid(fabric->bfa));
    + /**
    + * queue I/O message to firmware
    + */
    + bfa_reqq_produce(fabric->bfa, fabric->reqq);
    +
    +}
    +/**
    + * In a given fabric, return the base port handle.
    + */
    +struct bfa_lport_s *
    +bfa_fabric_get_bport(struct bfa_fabric_s *fabric)
    +{
    + return &fabric->bport;
    +}
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_fabric.h patch/drivers/scsi/bfa/bfa_fabric.h
    --- orig/drivers/scsi/bfa/bfa_fabric.h 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_fabric.h 2009-04-01 20:08:47.137647000 -0700
    @@ -0,0 +1,163 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +/**
    + * BFA Fabric interfaces
    + */
    +
    +#ifndef __BFA_FABRIC_H__
    +#define __BFA_FABRIC_H__
    +
    +#include <bfa_vport.h>
    +#include <bfa_lport.h>
    +#include <bfa_auth.h>
    +#include <bfi/bfi_fabric.h>
    +#include <cs/bfa_q.h>
    +#include <defs/bfa_defs_vf.h>
    +
    +/**
    + * P R I V A T E D E F I N I T I O N S
    + * - Used & visible to BFA FABRIC module alone (private)
    + */
    +
    +/*
    + * forward declaration
    + */
    +struct bfad_vf_s;
    +enum bfa_fabric_state{
    + BFA_FABRIC_UNINIT = 0,
    + BFA_FABRIC_OFFLINE = 1,
    + BFA_FABRIC_ONLINE = 2,
    +};
    +/**
    + * Symbolic Name related defines
    + * Total bytes 255.
    + * Physical Port's symbolic name 128 bytes.
    + * For Vports, Vport's symbolic name is appended to the Physical port's
    + * Symbolic Name.
    + *
    + * Physical Port's symbolic name Format : (Total 128 bytes)
    + * Adapter Model number/name : 12 bytes
    + * Driver Version : 10 bytes
    + * Host Machine Name : 30 bytes
    + * Host OS Info : 48 bytes
    + * Host OS PATCH Info : 16 bytes
    + * ( remaining 12 bytes reserved to be used for separator)
    + */
    +#define BFA_PORT_SYMBNAME_SEPARATOR " | "
    +
    +#define BFA_PORT_SYMBNAME_MODEL_SZ 12
    +#define BFA_PORT_SYMBNAME_VERSION_SZ 10
    +#define BFA_PORT_SYMBNAME_MACHINENAME_SZ 30
    +#define BFA_PORT_SYMBNAME_OSINFO_SZ 48
    +#define BFA_PORT_SYMBNAME_OSPATCH_SZ 16
    +
    +
    +#define BFA_FABRIC_IPADDR_SZ 256
    +
    +struct bfa_fabric_s {
    + struct bfa_s *bfa; /* bfa instance */
    + bfa_fsm_t fsm; /* BFA fabric state machine */
    + struct bfa_lport_s bport; /* base logical port */
    + enum bfa_fabric_type fab_type; /* fabric type loopback, no fabric */
    + enum bfa_pport_type oper_type; /* current link topology */
    + u8 is_vf; /* is virtual fabric? */
    + u8 is_npiv; /* is NPIV supported ? */
    + u8 is_auth; /* is Security/Auth supported ? */
    + u16 bb_credit; /* BB credit from fabric */
    + u16 vf_id; /* virtual fabric ID */
    + u16 num_vports; /* num vports */
    + u16 rsvd;
    + struct list_head vport_q; /* queue of virtual ports */
    + struct list_head vf_q; /* queue of virtual fabrics */
    + struct bfad_vf_s *vf_drv; /* driver vf structure */
    + wwn_t fabric_name; /* attached fabric name */
    + u8 fabric_ip_addr[BFA_FABRIC_IPADDR_SZ]; /* attached fabric's ip addr */
    + bfa_boolean_t auth_reqd; /* authentication required */
    + union {
    + u16 swp_vfid; /* switch port VF id */
    + } event_arg;
    + struct bfa_auth_s auth; /* authentication config */
    + struct bfa_vf_stats_s stats; /* fabric/vf stats */
    + u8 reqq; /* CQ for requests */
    +};
    +
    +#define bfa_fabric_npiv_capable(__f) (__f)->is_npiv
    +#define bfa_fabric_is_switched(__f) \
    + ((__f)->fab_type == FABRIC_SWITCHED)
    +
    +/**
    + * The design calls for a single implementation of base fabric and vf.
    + */
    +
    +struct bfa_vf_event_s {
    + u32 undefined;
    +};
    +
    +
    +/*
    + * P R O T E C T E D D E F I N I T I O N S
    + * - Shared between modules within BFA layer (protected)
    + */
    +void bfa_fabric_add_vport(struct bfa_fabric_s *fabric,
    + struct bfa_vport_s *vport);
    +void bfa_fabric_del_vport(struct bfa_fabric_s *fabric,
    + struct bfa_vport_s *vport);
    +struct bfa_vport_s *bfa_fabric_vport_lookup(struct bfa_fabric_s *fabric,
    + wwn_t pwwn);
    +u16 bfa_fabric_vport_count(struct bfa_fabric_s *fabric);
    +bfa_boolean_t bfa_fabric_is_loopback(struct bfa_fabric_s *fabric);
    +bfa_boolean_t bfa_fabric_is_online(struct bfa_fabric_s *fabric);
    +enum bfa_pport_type bfa_fabric_port_type(struct bfa_fabric_s *fabric);
    +void bfa_fabric_psymb_init(struct bfa_fabric_s *fabric);
    +bfa_status_t bfa_fabric_addvf(struct bfa_fabric_s *vf, struct bfa_s *bfa,
    + struct bfa_port_cfg_s *port_cfg, struct bfad_vf_s *vf_drv);
    +struct bfa_lport_s *bfa_fabric_get_bport(struct bfa_fabric_s *fabric);
    +void bfa_fabric_isr(struct bfa_s *bfa, struct bfi_msg_s *m);
    +
    +/**
    + * P U B L I C D E F I N I T I O N S
    + * - Shared between BFA layer & Host Drivers (public)
    + */
    +bfa_status_t bfa_vf_mode_enable(struct bfa_s *bfa, u16 vf_id);
    +bfa_status_t bfa_vf_mode_disable(struct bfa_s *bfa);
    +bfa_status_t bfa_vf_create(struct bfa_fabric_s *vf, struct bfa_s *bfa,
    + u16 vf_id, struct bfa_port_cfg_s *port_cfg,
    + struct bfad_vf_s *vf_drv);
    +bfa_status_t bfa_vf_delete(struct bfa_fabric_s *vf);
    +void bfa_vf_start(struct bfa_fabric_s *vf);
    +bfa_status_t bfa_vf_stop(struct bfa_fabric_s *vf);
    +void bfa_vf_list(struct bfa_s *bfa, u16 *vf_ids, int *nvfs);
    +void bfa_vf_list_all(struct bfa_s *bfa, u16 *vf_ids, int *nvfs);
    +void bfa_vf_get_attr(struct bfa_fabric_s *vf, struct bfa_vf_attr_s *vf_attr);
    +void bfa_vf_get_stats(struct bfa_fabric_s *vf,
    + struct bfa_vf_stats_s *vf_stats);
    +void bfa_vf_clear_stats(struct bfa_fabric_s *vf);
    +void bfa_vf_get_ports(struct bfa_fabric_s *vf, wwn_t vpwwn[], int *nports);
    +struct bfa_fabric_s *bfa_vf_lookup(struct bfa_s *bfa, u16 vf_id);
    +struct bfad_vf_s *bfa_vf_get_drv_vf(struct bfa_fabric_s *vf);
    +/**
    + * Completion callback for bfa_fcs_vf_stop().
    + *
    + * @param[in] vf_drv - driver instance of vf
    + *
    + * @return None
    + */
    +void bfa_cb_vf_stop(struct bfad_vf_s *vf_drv);
    +void bfa_vf_auth_update(struct bfa_fabric_s *fabric);
    +
    +#endif /* __BFA_FABRIC_H__ */
    diff -urpN orig/drivers/scsi/bfa/bfa_fcpim.c patch/drivers/scsi/bfa/bfa_fcpim.c
    --- orig/drivers/scsi/bfa/bfa_fcpim.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_fcpim.c 2009-04-01 20:08:47.145738000 -0700
    @@ -0,0 +1,187 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#include <bfa.h>
    +#include <log/bfa_log_hal.h>
    +
    +BFA_TRC_FILE(HAL, FCPIM);
    +BFA_MODULE(fcpim);
    +
    +/**
    + * hal_fcpim_mod BFA FCP Initiator Mode module
    + */
    +
    +/**
    + * Compute and return memory needed by FCP(im) module.
    + */
    +static void
    +bfa_fcpim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
    + u32 *dm_len)
    +{
    + bfa_itnim_meminfo(cfg, km_len, dm_len);
    +
    + /**
    + * IO memory
    + */
    + if (cfg->fwcfg.num_ioim_reqs < BFA_IOIM_MIN)
    + cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MIN;
    + *km_len += cfg->fwcfg.num_ioim_reqs *
    + (sizeof(struct bfa_ioim_s) + sizeof(struct bfa_ioim_sp_s));
    +
    + *dm_len += cfg->fwcfg.num_ioim_reqs * BFI_IOIM_SNSLEN;
    +
    + /**
    + * task management command memory
    + */
    + if (cfg->fwcfg.num_tskim_reqs < BFA_TSKIM_MIN)
    + cfg->fwcfg.num_tskim_reqs = BFA_TSKIM_MIN;
    + *km_len += cfg->fwcfg.num_tskim_reqs * sizeof(struct bfa_tskim_s);
    +}
    +
    +
    +static void
    +bfa_fcpim_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
    + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
    +{
    + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
    +
    + bfa_trc(bfa, cfg->drvcfg.path_tov);
    + bfa_trc(bfa, cfg->fwcfg.num_rports);
    + bfa_trc(bfa, cfg->fwcfg.num_ioim_reqs);
    + bfa_trc(bfa, cfg->fwcfg.num_tskim_reqs);
    +
    + fcpim->bfa = bfa;
    + fcpim->num_itnims = cfg->fwcfg.num_rports;
    + fcpim->num_ioim_reqs = cfg->fwcfg.num_ioim_reqs;
    + fcpim->num_tskim_reqs = cfg->fwcfg.num_tskim_reqs;
    + fcpim->path_tov = cfg->drvcfg.path_tov;
    + fcpim->delay_comp = cfg->drvcfg.delay_comp;
    +
    + bfa_itnim_attach(fcpim, meminfo);
    + bfa_tskim_attach(fcpim, meminfo);
    + bfa_ioim_attach(fcpim, meminfo);
    +}
    +
    +static void
    +bfa_fcpim_initdone(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_fcpim_detach(struct bfa_s *bfa)
    +{
    + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
    +
    + bfa_ioim_detach(fcpim);
    + bfa_tskim_detach(fcpim);
    +}
    +
    +static void
    +bfa_fcpim_start(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_fcpim_stop(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_fcpim_iocdisable(struct bfa_s *bfa)
    +{
    + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
    + struct bfa_itnim_s *itnim;
    + struct list_head *qe, *qen;
    +
    + list_for_each_safe(qe, qen, &fcpim->itnim_q) {
    + itnim = (struct bfa_itnim_s *) qe;
    + bfa_itnim_iocdisable(itnim);
    + }
    +}
    +
    +void
    +bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov)
    +{
    + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
    +
    + fcpim->path_tov = path_tov * 1000;
    + if (fcpim->path_tov > BFA_FCPIM_PATHTOV_MAX)
    + fcpim->path_tov = BFA_FCPIM_PATHTOV_MAX;
    +}
    +
    +u16
    +bfa_fcpim_path_tov_get(struct bfa_s *bfa)
    +{
    + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
    +
    + return (fcpim->path_tov / 1000);
    +}
    +
    +void
    +bfa_fcpim_qdepth_set(struct bfa_s *bfa, u16 q_depth)
    +{
    + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
    +
    + bfa_assert(q_depth <= BFA_IOCFC_QDEPTH_MAX);
    +
    + fcpim->q_depth = q_depth;
    +}
    +
    +u16
    +bfa_fcpim_qdepth_get(struct bfa_s *bfa)
    +{
    + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
    +
    + return (fcpim->q_depth);
    +}
    +bfa_status_t
    +bfa_itnim_stats_get(struct bfa_lport_s *port, wwn_t rpwwn,
    + struct bfa_itnim_stats_s *stats)
    +{
    + return 0;
    +}
    +bfa_status_t
    +bfa_itnim_stats_clear(struct bfa_lport_s *port,
    + wwn_t rpwwn)
    +{
    + return 0;
    +}
    +struct bfa_itnim_s *
    +bfa_itnim_lookup(struct bfa_lport_s *port,
    + wwn_t rpwwn)
    +{
    + return NULL;
    +}
    +bfa_status_t
    +bfa_itnim_attr_get(struct bfa_lport_s *port, wwn_t rpwwn,
    + struct bfa_itnim_attr_s *attr)
    +{
    + return 0;
    +}
    +int
    +bfa_itnim_get_maxfrsize(struct bfa_itnim_s *itnim)
    +{
    + return 0;
    +}
    +/* supported classes*/
    +int
    +bfa_itnim_get_cos(struct bfa_itnim_s *itnim)
    +{
    + return 0;
    +}
    +
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_fcpim.h patch/drivers/scsi/bfa/bfa_fcpim.h
    --- orig/drivers/scsi/bfa/bfa_fcpim.h 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_fcpim.h 2009-04-01 20:08:47.153205000 -0700
    @@ -0,0 +1,409 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#ifndef __BFA_FCPIM_H__
    +#define __BFA_FCPIM_H__
    +
    +#include <protocol/bfa_protocol.h>
    +#include <cs/bfa_wc.h>
    +#include <bfa_lport.h>
    +#include <bfi/bfi_fcpim.h>
    +#include "bfa_sgpg_priv.h"
    +
    +#define BFA_ITNIM_MIN 32
    +#define BFA_ITNIM_MAX 1024
    +
    +#define BFA_IOIM_MIN 8
    +#define BFA_IOIM_MAX 2000
    +
    +#define BFA_TSKIM_MIN 4
    +#define BFA_TSKIM_MAX 512
    +#define BFA_FCPIM_PATHTOV_DEF (30 * 1000) /* in millisecs */
    +#define BFA_FCPIM_PATHTOV_MAX (90 * 1000) /* in millisecs */
    +
    +struct bfa_fcpim_stats_s {
    + u32 total_ios; /* Total IO count */
    + u32 qresumes; /* IO waiting for CQ space */
    + u32 no_iotags; /* NO IO contexts */
    + u32 io_aborts; /* IO abort requests */
    + u32 no_tskims; /* NO task management contexts */
    + u32 iocomp_ok; /* IO completions with OK status */
    + u32 iocomp_underrun; /* IO underrun (good) */
    + u32 iocomp_overrun; /* IO overrun (good) */
    + u32 iocomp_aborted; /* Aborted IO requests */
    + u32 iocomp_timedout; /* IO timeouts */
    + u32 iocom_nexus_abort; /* IO selection timeouts */
    + u32 iocom_proto_err; /* IO protocol errors */
    + u32 iocom_dif_err; /* IO SBC-3 protection errors */
    + u32 iocom_tm_abort; /* IO aborted by TM requests */
    + u32 iocom_sqer_needed; /* IO retry for SQ error
    + *recovery */
    + u32 iocom_res_free; /* Delayed freeing of IO resources */
    + u32 iocomp_scsierr; /* IO with non-good SCSI status */
    + u32 iocom_hostabrts; /* Host IO abort requests */
    + u32 iocom_utags; /* IO comp with unknown tags */
    + u32 io_cleanups; /* IO implicitly aborted */
    + u32 io_tmaborts; /* IO aborted due to TM commands */
    + u32 rsvd;
    +};
    +#define bfa_fcpim_stats(__fcpim, __stats) \
    + (__fcpim)->stats.__stats ++
    +
    +#define BFA_ITNIM_FROM_TAG(_fcpim, _tag) \
    + ((_fcpim)->itnim_arr + ((_tag) & ((_fcpim)->num_itnims - 1)))
    +
    +struct bfa_fcpim_mod_s {
    + struct bfa_s *bfa;
    + struct bfa_itnim_s *itnim_arr;
    + struct bfa_ioim_s *ioim_arr;
    + struct bfa_ioim_sp_s *ioim_sp_arr;
    + struct bfa_tskim_s *tskim_arr;
    + struct bfa_dma_s snsbase;
    + int num_itnims;
    + int num_ioim_reqs;
    + int num_tskim_reqs;
    + u32 path_tov;
    + u16 q_depth;
    + u16 rsvd;
    + struct list_head itnim_q; /* queue of active itnim */
    + struct list_head ioim_free_q; /* free IO resources */
    + struct list_head ioim_resfree_q;/* IOs waiting for f/w */
    + struct list_head ioim_comp_q; /* IO global comp Q */
    + struct list_head tskim_free_q;
    + u32 ios_active; /* current active IOs */
    + u32 delay_comp;
    + struct bfa_fcpim_stats_s stats;
    +};
    +
    +struct bfa_ioim_s;
    +struct bfa_tskim_s;
    +
    +/**
    + * BFA IO (initiator mode)
    + */
    +struct bfa_ioim_s {
    + struct list_head qe; /* queue elememt */
    + bfa_sm_t sm; /* BFA ioim state machine */
    + struct bfa_s *bfa; /* BFA module */
    + struct bfa_fcpim_mod_s *fcpim; /* parent fcpim module */
    + struct bfa_itnim_s *itnim; /* i-t-n nexus for this IO */
    + struct bfad_ioim_s *dio; /* driver IO handle */
    + u16 iotag; /* FWI IO tag */
    + u16 abort_tag; /* unqiue abort request tag*/
    + u16 nsges; /* number of SG elements */
    + u16 nsgpgs; /* number of SG pages */
    + struct bfa_sgpg_s *sgpg; /* first SG page */
    + struct list_head sgpg_q; /* allocated SG pages */
    + struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */
    + bfa_cb_cbfn_t io_cbfn; /* IO completion handler */
    + struct bfa_ioim_sp_s *iosp; /* slow-path IO handling */
    +};
    +
    +struct bfa_ioim_sp_s {
    + struct bfi_msg_s comp_rspmsg; /* IO comp f/w response */
    + u8 *snsinfo; /* sense info for this IO */
    + struct bfa_sgpg_wqe_s sgpg_wqe; /* waitq elem for sgpg */
    + struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq*/
    + bfa_boolean_t abort_explicit; /* aborted by OS */
    + struct bfa_tskim_s *tskim; /* Relevant TM cmd */
    +};
    +
    +/**
    + * BFA Task management command (initiator mode)
    + */
    +struct bfa_tskim_s {
    + struct list_head qe;
    + bfa_sm_t sm;
    + struct bfa_s *bfa; /* BFA module */
    + struct bfa_fcpim_mod_s *fcpim; /* parent fcpim module */
    + struct bfa_itnim_s *itnim; /* i-t-n nexus for this IO */
    + struct bfad_tskim_s *dtsk; /* driver task mgmt cmnd */
    + bfa_boolean_t notify; /* notify itnim on TM comp */
    + lun_t lun; /* lun if applicable */
    + enum fcp_tm_cmnd tm_cmnd; /* task management command */
    + u16 tsk_tag; /* FWI IO tag */
    + u8 tsecs; /* timeout in seconds */
    + struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */
    + struct list_head io_q; /* queue of affected IOs */
    + struct bfa_wc_s wc; /* waiting counter */
    + struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */
    + enum bfi_tskim_status tsk_status; /* TM status */
    +};
    +
    +/**
    + * BFA i-t-n (initiator mode)
    + */
    +struct bfa_itnim_s {
    + struct list_head qe; /* queue element */
    + bfa_sm_t sm; /* i-t-n im BFA state machine */
    + struct bfa_s *bfa; /* bfa instance */
    + struct bfa_rport_s *rport; /* bfa rport */
    + void *ditn; /* driver i-t-n structure */
    + struct bfi_mhdr_s mhdr; /* pre-built mhdr */
    + u8 msg_no; /* itnim/rport firmware handle */
    + u8 reqq; /* CQ for requests */
    + struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */
    + struct list_head pending_q; /* queue of pending IO requests*/
    + struct list_head io_q; /* queue of active IO requests */
    + struct list_head io_cleanup_q; /* IO being cleaned up */
    + struct list_head tsk_q; /* queue of active TM commands */
    + struct list_head delay_comp_q; /* queue of failed inflight cmds*/
    + bfa_boolean_t seq_rec; /* SQER supported */
    + bfa_boolean_t rec_support; /* REC supported */
    + bfa_boolean_t conf_comp; /* FCP_CONF supported */
    + bfa_boolean_t task_retry_id; /* task retry id supprted */
    + bfa_boolean_t is_online; /* itnim is ONLINE for IO */
    + bfa_boolean_t iotov_active; /* IO TOV timer is active */
    + struct bfa_wc_s wc; /* waiting counter */
    + struct bfa_timer_s timer; /* pending IO TOV */
    + struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */
    + struct bfa_fcpim_mod_s *fcpim; /* fcpim module */
    + struct bfa_itnim_stats_s itnim_stats;
    + struct bfa_itnim_hal_stats_s stats;
    +};
    +
    +#define bfa_itnim_is_online(_itnim) (_itnim)->is_online
    +#define BFA_FCPIM_MOD(_hal) (&(_hal)->modules.fcpim_mod)
    +#define BFA_IOIM_FROM_TAG(_fcpim, _iotag) \
    + (&fcpim->ioim_arr[_iotag])
    +#define BFA_TSKIM_FROM_TAG(_fcpim, _tmtag) \
    + (&fcpim->tskim_arr[_tmtag & (fcpim->num_tskim_reqs - 1)])
    +
    +/*
    + * function prototypes
    + */
    +void bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim,
    + struct bfa_meminfo_s *minfo);
    +void bfa_ioim_detach(struct bfa_fcpim_mod_s *fcpim);
    +void bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
    +void bfa_ioim_good_comp_isr(struct bfa_s *bfa,
    + struct bfi_msg_s *msg);
    +void bfa_ioim_cleanup(struct bfa_ioim_s *ioim);
    +void bfa_ioim_cleanup_tm(struct bfa_ioim_s *ioim,
    + struct bfa_tskim_s *tskim);
    +void bfa_ioim_iocdisable(struct bfa_ioim_s *ioim);
    +void bfa_ioim_tov(struct bfa_ioim_s *ioim);
    +
    +void bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim,
    + struct bfa_meminfo_s *minfo);
    +void bfa_tskim_detach(struct bfa_fcpim_mod_s *fcpim);
    +void bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
    +void bfa_tskim_iodone(struct bfa_tskim_s *tskim);
    +void bfa_tskim_iocdisable(struct bfa_tskim_s *tskim);
    +void bfa_tskim_cleanup(struct bfa_tskim_s *tskim);
    +
    +void bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
    + u32 *dm_len);
    +void bfa_itnim_attach(struct bfa_fcpim_mod_s *fcpim,
    + struct bfa_meminfo_s *minfo);
    +void bfa_itnim_detach(struct bfa_fcpim_mod_s *fcpim);
    +void bfa_itnim_iocdisable(struct bfa_itnim_s *itnim);
    +void bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
    +void bfa_itnim_iodone(struct bfa_itnim_s *itnim);
    +void bfa_itnim_tskdone(struct bfa_itnim_s *itnim);
    +void bfa_itnim_qresume(void *cbarg);
    +bfa_boolean_t bfa_itnim_hold_io(struct bfa_itnim_s *itnim);
    +
    +
    +/**
    + * P U B L I C D E F I N I T I O N S - Shared between BFA layer & Host Drivers (public)
    + */
    +struct bfad_s;
    +struct bfad_itnim_s;
    +
    +struct bfa_itnim_s;
    +struct bfa_ioim_s;
    +struct bfa_tskim_s;
    +struct bfad_ioim_s;
    +struct bfad_tskim_s;
    +
    +/*
    + * bfa fcpim module API functions
    + */
    +void bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov);
    +u16 bfa_fcpim_path_tov_get(struct bfa_s *bfa);
    +void bfa_fcpim_qdepth_set(struct bfa_s *bfa, u16 q_depth);
    +u16 bfa_fcpim_qdepth_get(struct bfa_s *bfa);
    +
    +/*
    + * bfa itnim API function for allocation
    + */
    +void bfa_cb_itnim_alloc(struct bfad_s *bfad, struct bfa_itnim_s *itnim,
    + struct bfad_itnim_s **itnim_drv);
    +/*
    + * bfa itnim API functions
    + */
    +struct bfa_itnim_s *bfa_itnim_create(struct bfa_s *bfa,
    + struct bfa_rport_s *rport, void *itnim);
    +void bfa_itnim_delete(struct bfa_itnim_s *itnim);
    +void bfa_itnim_online(struct bfa_itnim_s *itnim,
    + bfa_boolean_t seq_rec);
    +void bfa_itnim_offline(struct bfa_itnim_s *itnim);
    +void bfa_itnim_clear_stats(struct bfa_itnim_s *itnim);
    +
    +/**
    + * HAL completion callback for bfa_itnim_online().
    + *
    + * @param[in] itnim driver itnim instance
    + *
    + * return None
    + */
    +void bfa_cb_itnim_online(void *itnim);
    +
    +/**
    + * HAL completion callback for bfa_itnim_offline().
    + *
    + * @param[in] itnim driver itnim instance
    + *
    + * return None
    + */
    +void bfa_cb_itnim_offline(void *itnim);
    +void bfa_cb_itnim_tov_begin(void *itnim);
    +void bfa_cb_itnim_tov(void *itnim);
    +
    +/**
    + * HAL notification to driver for second level error recovery.
    + *
    + * Atleast one I/O request has timedout and target is unresponsive to
    + * repeated abort requests. Second level error recovery should be initiated
    + * by starting implicit logout and recovery procedures.
    + *
    + * @param[in] itnim driver itnim instance
    + *
    + * return None
    + */
    +void bfa_cb_itnim_sler(void *itnim);
    +
    +
    +/*
    + * bfa ioim API functions
    + */
    +struct bfa_ioim_s *bfa_ioim_alloc(struct bfa_s *bfa,
    + struct bfad_ioim_s *dio,
    + struct bfa_itnim_s *itnim,
    + u16 nsgles);
    +
    +void bfa_ioim_free(struct bfa_ioim_s *ioim);
    +void bfa_ioim_start(struct bfa_ioim_s *ioim);
    +void bfa_ioim_abort(struct bfa_ioim_s *ioim);
    +void bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim,
    + bfa_boolean_t iotov);
    +
    +/**
    + * I/O completion notification.
    + *
    + * @param[in] dio driver IO structure
    + * @param[in] io_status IO completion status
    + * @param[in] scsi_status SCSI status returned by target
    + * @param[in] sns_len SCSI sense length, 0 if none
    + * @param[in] sns_info SCSI sense data, if any
    + * @param[in] residue Residual length
    + *
    + * @return None
    + */
    +void bfa_cb_ioim_done(void *bfad, struct bfad_ioim_s *dio,
    + enum bfi_ioim_status io_status,
    + u8 scsi_status, int sns_len,
    + u8 *sns_info, s32 residue);
    +
    +/**
    + * I/O good completion notification.
    + *
    + * @param[in] dio driver IO structure
    + *
    + * @return None
    + */
    +void bfa_cb_ioim_good_comp(void *bfad, struct bfad_ioim_s *dio);
    +
    +/**
    + * I/O abort completion notification
    + *
    + * @param[in] dio driver IO that was aborted
    + *
    + * @return None
    + */
    +void bfa_cb_ioim_abort(void *bfad, struct bfad_ioim_s *dio);
    +void bfa_cb_ioim_resfree(void *hcb_bfad);
    +
    +void bfa_cb_ioim_resfree(void *hcb_bfad);
    +
    +/*
    + * bfa tskim API functions
    + */
    +struct bfa_tskim_s *bfa_tskim_alloc(struct bfa_s *bfa,
    + struct bfad_tskim_s *dtsk);
    +void bfa_tskim_free(struct bfa_tskim_s *tskim);
    +void bfa_tskim_start(struct bfa_tskim_s *tskim,
    + struct bfa_itnim_s *itnim, lun_t lun,
    + enum fcp_tm_cmnd tm, u8 t_secs);
    +void bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk,
    + enum bfi_tskim_status tsk_status);
    +/**
    + * bfa FCP Initiator mode API functions
    + */
    +void bfa_itnim_get_attr(struct bfa_itnim_s *itnim,
    + struct bfa_itnim_attr_s *attr);
    +void bfa_itnim_get_stats(struct bfa_itnim_s *itnim,
    + struct bfa_itnim_stats_s *stats);
    +struct bfa_itnim_s *bfa_itnim_lookup(struct bfa_lport_s *port,
    + wwn_t rpwwn);
    +bfa_status_t bfa_itnim_attr_get(struct bfa_lport_s *port, wwn_t rpwwn,
    + struct bfa_itnim_attr_s *attr);
    +bfa_status_t bfa_itnim_stats_get(struct bfa_lport_s *port, wwn_t rpwwn,
    + struct bfa_itnim_stats_s *stats);
    +bfa_status_t bfa_itnim_stats_clear(struct bfa_lport_s *port,
    + wwn_t rpwwn);
    +struct bfad_port_s *bfa_itnim_get_drvport(struct bfa_itnim_s *itnim);
    +
    +/*
    +static inline struct bfad_port_s *
    +bfa_itnim_get_drvport(struct bfa_itnim_s *itnim)
    +{
    + bfa_lport_t *lp;
    + bfa_rport_t *rp;
    + rp = (bfa_rport_t *)itnim->rport;
    + lp = (bfa_lport_t *)BFA_LPORT_FROM_TAG(itnim->bfa, rp->lport_tag);
    + return (lp->bfad_port);
    +}
    + */
    +
    +static inline wwn_t
    +bfa_itnim_get_nwwn(struct bfa_itnim_s *itnim)
    +{
    + return itnim->rport->rport_info.nwwn;
    +}
    +
    +
    +static inline wwn_t
    +bfa_itnim_get_pwwn(struct bfa_itnim_s *itnim)
    +{
    + return itnim->rport->rport_info.pwwn;
    +}
    +
    +
    +static inline u32
    +bfa_itnim_get_fcid(struct bfa_itnim_s *itnim)
    +{
    + return itnim->rport->rport_info.pid;
    +}
    +int bfa_itnim_get_maxfrsize(struct bfa_itnim_s *itnim);
    +int bfa_itnim_get_cos(struct bfa_itnim_s *itnim);
    +
    +
    +
    +#endif /* __BFA_FCPIM_H__ */
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_fcxp.c patch/drivers/scsi/bfa/bfa_fcxp.c
    --- orig/drivers/scsi/bfa/bfa_fcxp.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_fcxp.c 2009-04-01 20:08:47.161596000 -0700
    @@ -0,0 +1,714 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#include <bfa.h>
    +#include <bfi/bfi_uf.h>
    +#include <cs/bfa_debug.h>
    +
    +BFA_TRC_FILE(HAL, FCXP);
    +BFA_MODULE(fcxp);
    +
    +/**
    + * forward declarations
    + */
    +static void __bfa_fcxp_send_cbfn(void *cbarg, bfa_boolean_t complete);
    +static void hal_fcxp_rx_plog(struct bfa_s *bfa, struct bfa_fcxp_s *fcxp,
    + struct bfi_fcxp_send_rsp_s *fcxp_rsp);
    +static void hal_fcxp_tx_plog(struct bfa_s *bfa, u32 reqlen,
    + struct bfa_fcxp_s *fcxp, struct fchs_s *fchs);
    +
    +/**
    + * fcxp_pvt BFA FCXP private functions
    + */
    +
    +static void
    +claim_fcxp_req_rsp_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi)
    +{
    + u8 *dm_kva = NULL;
    + u64 dm_pa;
    + u32 buf_pool_sz;
    +
    + dm_kva = bfa_meminfo_dma_virt(mi);
    + dm_pa = bfa_meminfo_dma_phys(mi);
    +
    + buf_pool_sz = mod->req_pld_sz * mod->num_fcxps;
    +
    + /*
    + * Initialize the fcxp req payload list
    + */
    + mod->req_pld_list_kva = dm_kva;
    + mod->req_pld_list_pa = dm_pa;
    + dm_kva += buf_pool_sz;
    + dm_pa += buf_pool_sz;
    + bfa_os_memset(mod->req_pld_list_kva, 0, buf_pool_sz);
    +
    + /*
    + * Initialize the fcxp rsp payload list
    + */
    + buf_pool_sz = mod->rsp_pld_sz * mod->num_fcxps;
    + mod->rsp_pld_list_kva = dm_kva;
    + mod->rsp_pld_list_pa = dm_pa;
    + dm_kva += buf_pool_sz;
    + dm_pa += buf_pool_sz;
    + bfa_os_memset(mod->rsp_pld_list_kva, 0, buf_pool_sz);
    +
    + bfa_meminfo_dma_virt(mi) = dm_kva;
    + bfa_meminfo_dma_phys(mi) = dm_pa;
    +}
    +
    +static void
    +claim_fcxps_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi)
    +{
    + u16 i;
    + struct bfa_fcxp_s *fcxp;
    +
    + fcxp = (struct bfa_fcxp_s *) bfa_meminfo_kva(mi);
    + bfa_os_memset(fcxp, 0, sizeof(struct bfa_fcxp_s) * mod->num_fcxps);
    +
    + INIT_LIST_HEAD(&mod->fcxp_free_q);
    + INIT_LIST_HEAD(&mod->fcxp_active_q);
    +
    + mod->fcxp_list = fcxp;
    +
    + for (i = 0; i < mod->num_fcxps; i++) {
    + fcxp->fcxp_mod = mod;
    + fcxp->fcxp_tag = i;
    +
    + list_add_tail(&fcxp->qe, &mod->fcxp_free_q);
    + fcxp = fcxp + 1;
    + }
    +
    + bfa_meminfo_kva(mi) = (void *)fcxp;
    +}
    +
    +static void
    +bfa_fcxp_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len,
    + u32 *dm_len)
    +{
    + u16 num_fcxp_reqs = cfg->fwcfg.num_fcxp_reqs;
    +
    + if (num_fcxp_reqs == 0)
    + return;
    +
    + /*
    + * Account for req/rsp payload
    + */
    + *dm_len += BFA_FCXP_MAX_IBUF_SZ * num_fcxp_reqs;
    + if (cfg->drvcfg.min_cfg)
    + *dm_len += BFA_FCXP_MAX_IBUF_SZ * num_fcxp_reqs;
    + else
    + *dm_len += BFA_FCXP_MAX_LBUF_SZ * num_fcxp_reqs;
    +
    + /*
    + * Account for fcxp structs
    + */
    + *ndm_len += sizeof(struct bfa_fcxp_s) * num_fcxp_reqs;
    +}
    +
    +static void
    +bfa_fcxp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
    + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
    +{
    + struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
    +
    + bfa_os_memset(mod, 0, sizeof(struct bfa_fcxp_mod_s));
    + mod->bfa = bfa;
    + mod->num_fcxps = cfg->fwcfg.num_fcxp_reqs;
    +
    + /**
    + * Initialize FCXP request and response payload sizes.
    + */
    + mod->req_pld_sz = mod->rsp_pld_sz = BFA_FCXP_MAX_IBUF_SZ;
    + if (!cfg->drvcfg.min_cfg)
    + mod->rsp_pld_sz = BFA_FCXP_MAX_LBUF_SZ;
    +
    + INIT_LIST_HEAD(&mod->wait_q);
    +
    + claim_fcxp_req_rsp_mem(mod, meminfo);
    + claim_fcxps_mem(mod, meminfo);
    +}
    +
    +static void
    +bfa_fcxp_initdone(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_fcxp_detach(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_fcxp_start(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_fcxp_stop(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_fcxp_iocdisable(struct bfa_s *bfa)
    +{
    + struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
    + struct bfa_fcxp_s *fcxp;
    + struct list_head *qe, *qen;
    +
    + list_for_each_safe(qe, qen, &mod->fcxp_active_q) {
    + fcxp = (struct bfa_fcxp_s *) qe;
    + if (fcxp->caller == NULL)
    + fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg,
    + BFA_STATUS_IOC_FAILURE, 0, 0, NULL);
    + else {
    + fcxp->rsp_status = BFA_STATUS_IOC_FAILURE;
    + bfa_cb_queue(bfa, &fcxp->hcb_qe,
    + __bfa_fcxp_send_cbfn, fcxp);
    + }
    + }
    +}
    +
    +static struct bfa_fcxp_s *
    +bfa_fcxp_get(struct bfa_fcxp_mod_s *fm)
    +{
    + struct bfa_fcxp_s *fcxp;
    +
    + bfa_q_deq(&fm->fcxp_free_q, &fcxp);
    +
    + if (fcxp)
    + list_add_tail(&fcxp->qe, &fm->fcxp_active_q);
    +
    + return (fcxp);
    +}
    +
    +static void
    +bfa_fcxp_put(struct bfa_fcxp_s *fcxp)
    +{
    + struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod;
    + struct bfa_fcxp_wqe_s *wqe;
    +
    + bfa_q_deq(&mod->wait_q, &wqe);
    + if (wqe) {
    + bfa_trc(mod->bfa, fcxp->fcxp_tag);
    + wqe->alloc_cbfn(wqe->alloc_cbarg, fcxp);
    + return;
    + }
    +
    + bfa_assert(bfa_q_is_on_q(&mod->fcxp_active_q, fcxp));
    + list_del(&fcxp->qe);
    + list_add_tail(&fcxp->qe, &mod->fcxp_free_q);
    +}
    +
    +static void
    +bfa_fcxp_null_comp(void *bfad_fcxp, struct bfa_fcxp_s *fcxp, void *cbarg,
    + bfa_status_t req_status, u32 rsp_len,
    + u32 resid_len, struct fchs_s *rsp_fchs)
    +{
    + /**discarded fcxp completion */
    +}
    +
    +static void
    +__bfa_fcxp_send_cbfn(void *cbarg, bfa_boolean_t complete)
    +{
    + struct bfa_fcxp_s *fcxp = cbarg;
    +
    + if (complete) {
    + fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg,
    + fcxp->rsp_status, fcxp->rsp_len,
    + fcxp->residue_len, &fcxp->rsp_fchs);
    + } else {
    + bfa_fcxp_free(fcxp);
    + }
    +}
    +
    +static void
    +hal_fcxp_send_comp(struct bfa_s *bfa, struct bfi_fcxp_send_rsp_s *fcxp_rsp)
    +{
    + struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
    + struct bfa_fcxp_s *fcxp;
    + u16 fcxp_tag = bfa_os_ntohs(fcxp_rsp->fcxp_tag);
    +
    + bfa_trc(bfa, fcxp_tag);
    +
    + fcxp_rsp->rsp_len = bfa_os_ntohl(fcxp_rsp->rsp_len);
    +
    + /**
    + * @todo f/w should not set residue to non-0 when everything
    + * is received.
    + */
    + if (fcxp_rsp->req_status == BFA_STATUS_OK)
    + fcxp_rsp->residue_len = 0;
    + else
    + fcxp_rsp->residue_len = bfa_os_ntohl(fcxp_rsp->residue_len);
    +
    + fcxp = BFA_FCXP_FROM_TAG(mod, fcxp_tag);
    +
    + bfa_assert(fcxp->send_cbfn != NULL);
    +
    + hal_fcxp_rx_plog(mod->bfa, fcxp, fcxp_rsp);
    +
    + if (fcxp->send_cbfn != NULL) {
    + if (fcxp->caller == NULL) {
    + bfa_trc(mod->bfa, fcxp->fcxp_tag);
    +
    + fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg,
    + fcxp_rsp->req_status, fcxp_rsp->rsp_len,
    + fcxp_rsp->residue_len, &fcxp_rsp->fchs);
    + /*
    + * fcxp automatically freed on return from the callback
    + */
    + bfa_fcxp_free(fcxp);
    + } else {
    + bfa_trc(mod->bfa, fcxp->fcxp_tag);
    + fcxp->rsp_status = fcxp_rsp->req_status;
    + fcxp->rsp_len = fcxp_rsp->rsp_len;
    + fcxp->residue_len = fcxp_rsp->residue_len;
    + fcxp->rsp_fchs = fcxp_rsp->fchs;
    +
    + bfa_cb_queue(bfa, &fcxp->hcb_qe,
    + __bfa_fcxp_send_cbfn, fcxp);
    + }
    + } else {
    + bfa_trc(bfa, fcxp_tag);
    + }
    +}
    +
    +static void
    +hal_fcxp_set_local_sges(struct bfi_sge_s *sge, u32 reqlen, u64 req_pa)
    +{
    + union bfi_addr_u sga_zero = { {0} };
    +
    + sge->sg_len = reqlen;
    + sge->flags = BFI_SGE_DATA_LAST;
    + bfa_dma_addr_set(sge[0].sga, req_pa);
    + bfa_sge_to_be(sge);
    + sge++;
    +
    + sge->sga = sga_zero;
    + sge->sg_len = reqlen;
    + sge->flags = BFI_SGE_PGDLEN;
    + bfa_sge_to_be(sge);
    +}
    +
    +static void
    +hal_fcxp_tx_plog(struct bfa_s *bfa, u32 reqlen, struct bfa_fcxp_s *fcxp,
    + struct fchs_s *fchs)
    +{
    + /*
    + * TODO: TX ox_id
    + */
    + if (reqlen > 0) {
    + if (fcxp->use_ireqbuf) {
    + u32 pld_w0 =
    + *((u32 *) BFA_FCXP_REQ_PLD(fcxp));
    +
    + bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_FCXP,
    + BFA_PL_EID_TX,
    + reqlen + sizeof(struct fchs_s),
    + fchs, pld_w0);
    + } else {
    + bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP,
    + BFA_PL_EID_TX, reqlen +
    + sizeof(struct fchs_s), fchs);
    + }
    + } else {
    + bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, BFA_PL_EID_TX,
    + reqlen + sizeof(struct fchs_s), fchs);
    + }
    +}
    +
    +static void
    +hal_fcxp_rx_plog(struct bfa_s *bfa, struct bfa_fcxp_s *fcxp,
    + struct bfi_fcxp_send_rsp_s *fcxp_rsp)
    +{
    + if (fcxp_rsp->rsp_len > 0) {
    + if (fcxp->use_irspbuf) {
    + u32 pld_w0 =
    + *((u32 *) BFA_FCXP_RSP_PLD(fcxp));
    +
    + bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_FCXP,
    + BFA_PL_EID_RX,
    + (u16) fcxp_rsp->rsp_len,
    + &fcxp_rsp->fchs, pld_w0);
    + } else {
    + bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP,
    + BFA_PL_EID_RX,
    + (u16) fcxp_rsp->rsp_len,
    + &fcxp_rsp->fchs);
    + }
    + } else {
    + bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, BFA_PL_EID_RX,
    + (u16) fcxp_rsp->rsp_len, &fcxp_rsp->fchs);
    + }
    +}
    +
    +/**
    + * hal_fcxp_api BFA FCXP API
    + */
    +
    +/**
    + * Allocate an FCXP instance to send a response or to send a request
    + * that has a response. Request/response buffers are allocated by caller.
    + *
    + * @param[in] bfa BFA bfa instance
    + * @param[in] nreq_sgles Number of SG elements required for request
    + * buffer. 0, if fcxp internal buffers are used.
    + * Use bfa_fcxp_get_reqbuf() to get the
    + * internal req buffer.
    + * @param[in] req_sgles SG elements describing request buffer. Will be
    + * copied in by BFA and hence can be freed on
    + * return from this function.
    + * @param[in] get_req_sga function ptr to be called to get a request SG
    + * Address (given the sge index).
    + * @param[in] get_req_sglen function ptr to be called to get a request SG
    + * len (given the sge index).
    + * @param[in] get_rsp_sga function ptr to be called to get a response SG
    + * Address (given the sge index).
    + * @param[in] get_rsp_sglen function ptr to be called to get a response SG
    + * len (given the sge index).
    + *
    + * @return FCXP instance. NULL on failure.
    + */
    +struct bfa_fcxp_s *
    +bfa_fcxp_alloc(void *caller, struct bfa_s *bfa, int nreq_sgles,
    + int nrsp_sgles, bfa_fcxp_get_sgaddr_t req_sga_cbfn,
    + bfa_fcxp_get_sglen_t req_sglen_cbfn,
    + bfa_fcxp_get_sgaddr_t rsp_sga_cbfn,
    + bfa_fcxp_get_sglen_t rsp_sglen_cbfn)
    +{
    + struct bfa_fcxp_s *fcxp = NULL;
    + u32 nreq_sgpg, nrsp_sgpg;
    +
    + bfa_assert(bfa != NULL);
    +
    + fcxp = bfa_fcxp_get(BFA_FCXP_MOD(bfa));
    + if (fcxp == NULL)
    + return (NULL);
    +
    + bfa_trc(bfa, fcxp->fcxp_tag);
    +
    + fcxp->caller = caller;
    +
    + if (nreq_sgles == 0) {
    + fcxp->use_ireqbuf = 1;
    + } else {
    + bfa_assert(req_sga_cbfn != NULL);
    + bfa_assert(req_sglen_cbfn != NULL);
    +
    + fcxp->use_ireqbuf = 0;
    + fcxp->req_sga_cbfn = req_sga_cbfn;
    + fcxp->req_sglen_cbfn = req_sglen_cbfn;
    +
    + fcxp->nreq_sgles = nreq_sgles;
    +
    + /*
    + * alloc required sgpgs
    + */
    + if (nreq_sgles > BFI_SGE_INLINE) {
    + nreq_sgpg = BFA_SGPG_NPAGE(nreq_sgles);
    +
    + if (bfa_sgpg_malloc
    + (bfa, &fcxp->req_sgpg_q, nreq_sgpg)
    + != BFA_STATUS_OK) {
    + /* bfa_sgpg_wait(bfa, &fcxp->req_sgpg_wqe,
    + nreq_sgpg); */
    + /*
    + * TODO
    + */
    + }
    + }
    + }
    +
    + if (nrsp_sgles == 0) {
    + fcxp->use_irspbuf = 1;
    + } else {
    + bfa_assert(rsp_sga_cbfn != NULL);
    + bfa_assert(rsp_sglen_cbfn != NULL);
    +
    + fcxp->use_irspbuf = 0;
    + fcxp->rsp_sga_cbfn = rsp_sga_cbfn;
    + fcxp->rsp_sglen_cbfn = rsp_sglen_cbfn;
    +
    + fcxp->nrsp_sgles = nrsp_sgles;
    + /*
    + * alloc required sgpgs
    + */
    + if (nrsp_sgles > BFI_SGE_INLINE) {
    + nrsp_sgpg = BFA_SGPG_NPAGE(nreq_sgles);
    +
    + if (bfa_sgpg_malloc
    + (bfa, &fcxp->rsp_sgpg_q, nrsp_sgpg)
    + != BFA_STATUS_OK) {
    + /* bfa_sgpg_wait(bfa, &fcxp->rsp_sgpg_wqe,
    + nrsp_sgpg); */
    + /*
    + * TODO
    + */
    + }
    + }
    + }
    +
    + return (fcxp);
    +}
    +
    +/**
    + * Get the internal request buffer pointer
    + *
    + * @param[in] fcxp BFA fcxp pointer
    + *
    + * @return pointer to the internal request buffer
    + */
    +void *
    +bfa_fcxp_get_reqbuf(struct bfa_fcxp_s *fcxp)
    +{
    + struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod;
    + void *reqbuf;
    +
    + bfa_assert(fcxp->use_ireqbuf == 1);
    + reqbuf = ((u8 *)mod->req_pld_list_kva) +
    + fcxp->fcxp_tag * mod->req_pld_sz;
    + return reqbuf;
    +}
    +
    +u32
    +bfa_fcxp_get_reqbufsz(struct bfa_fcxp_s *fcxp)
    +{
    + struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod;
    +
    + return mod->req_pld_sz;
    +}
    +
    +/**
    + * Get the internal response buffer pointer
    + *
    + * @param[in] fcxp BFA fcxp pointer
    + *
    + * @return pointer to the internal request buffer
    + */
    +void *
    +bfa_fcxp_get_rspbuf(struct bfa_fcxp_s *fcxp)
    +{
    + struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod;
    + void *rspbuf;
    +
    + bfa_assert(fcxp->use_irspbuf == 1);
    +
    + rspbuf = ((u8 *)mod->rsp_pld_list_kva) +
    + fcxp->fcxp_tag * mod->rsp_pld_sz;
    + return rspbuf;
    +}
    +
    +/**
    + * Free the BFA FCXP
    + *
    + * @param[in] fcxp BFA fcxp pointer
    + *
    + * @return void
    + */
    +void
    +bfa_fcxp_free(struct bfa_fcxp_s *fcxp)
    +{
    + struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod;
    +
    + bfa_assert(fcxp != NULL);
    + bfa_trc(mod->bfa, fcxp->fcxp_tag);
    + bfa_fcxp_put(fcxp);
    +}
    +
    +/**
    + * Send a FCXP request
    + *
    + * @param[in] fcxp BFA fcxp pointer
    + * @param[in] rport BFA rport pointer. Could be left NULL for WKA rports
    + * @param[in] vf_id virtual Fabric ID
    + * @param[in] cts use Continous sequence
    + * @param[in] cos fc Class of Service
    + * @param[in] reqlen request length, does not include FCHS length
    + * @param[in] fchs fc Header Pointer. The header content will be copied
    + * in by BFA.
    + *
    + * @param[in] cbfn call back function to be called on receiving
    + * the response
    + * @param[in] cbarg arg for cbfn
    + * @param[in] rsp_timeout
    + * response timeout
    + *
    + * @return bfa_status_t
    + */
    +void
    +bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport,
    + u16 vf_id, bfa_boolean_t cts, enum fc_cos cos,
    + u32 reqlen, struct fchs_s *fchs, bfa_cb_fcxp_send_t cbfn,
    + void *cbarg, u32 rsp_maxlen, u8 rsp_timeout)
    +{
    + struct bfi_fcxp_send_req_s *send_req;
    + struct bfa_s *bfa = fcxp->fcxp_mod->bfa;
    +
    + send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP);
    +
    + bfi_h2i_set(send_req->mh, BFI_MC_FCXP, BFI_FCXP_H2I_SEND_REQ,
    + bfa_lpuid(bfa));
    +
    + bfa_trc(bfa, fcxp->fcxp_tag);
    +
    + send_req->fcxp_tag = bfa_os_htons(fcxp->fcxp_tag);
    +
    + if (rport != NULL) {
    + if (rport->rport_info.maxfrsize == 0) {
    + bfa_assert(0);
    + send_req->max_frmsz = bfa_os_htons(FC_MAX_PDUSZ);
    + } else
    + send_req->max_frmsz =
    + bfa_os_htons(rport->rport_info.maxfrsize);
    + send_req->rport_fw_hndl = rport->rport_tag;
    + } else {
    + send_req->max_frmsz = bfa_os_htons(FC_MAX_PDUSZ);
    + send_req->rport_fw_hndl = 0;
    + }
    +
    + send_req->vf_id = bfa_os_htons(vf_id);
    + send_req->class = cos;
    + send_req->rsp_timeout = rsp_timeout;
    + send_req->cts = cts;
    +
    + bfa_os_memcpy((void *)&send_req->fchs, (void *)fchs,
    + sizeof(struct fchs_s));
    +
    + send_req->req_len = bfa_os_htonl(reqlen);
    + send_req->rsp_maxlen = bfa_os_htonl(rsp_maxlen);
    +
    + /*
    + * setup req sgles
    + */
    + if (fcxp->use_ireqbuf == 1) {
    + hal_fcxp_set_local_sges(send_req->req_sge, reqlen,
    + BFA_FCXP_REQ_PLD_PA(fcxp));
    + } else {
    + if (fcxp->nreq_sgles > 0) {
    + bfa_assert(fcxp->nreq_sgles == 1);
    + hal_fcxp_set_local_sges(send_req->req_sge, reqlen,
    + fcxp->req_sga_cbfn(fcxp->caller,
    + 0));
    + } else {
    + bfa_assert(reqlen == 0);
    + hal_fcxp_set_local_sges(send_req->rsp_sge, 0, 0);
    + }
    + }
    +
    + /*
    + * setup rsp sgles
    + */
    + if (fcxp->use_irspbuf == 1) {
    + bfa_assert(rsp_maxlen <= BFA_FCXP_MAX_LBUF_SZ);
    +
    + hal_fcxp_set_local_sges(send_req->rsp_sge, rsp_maxlen,
    + BFA_FCXP_RSP_PLD_PA(fcxp));
    +
    + } else {
    + if (fcxp->nrsp_sgles > 0) {
    + bfa_assert(fcxp->nrsp_sgles == 1);
    + hal_fcxp_set_local_sges(send_req->rsp_sge, rsp_maxlen,
    + fcxp->rsp_sga_cbfn(fcxp->caller,
    + 0));
    + } else {
    + bfa_assert(rsp_maxlen == 0);
    + hal_fcxp_set_local_sges(send_req->rsp_sge, 0, 0);
    + }
    + }
    +
    + hal_fcxp_tx_plog(bfa, reqlen, fcxp, fchs);
    +
    + fcxp->send_cbfn = cbfn ? cbfn : bfa_fcxp_null_comp;
    + fcxp->send_cbarg = cbarg;
    +
    + bfa_reqq_produce(bfa, BFA_REQQ_FCXP);
    +
    + bfa_trc(bfa, bfa_reqq_pi(bfa, BFA_REQQ_FCXP));
    + bfa_trc(bfa, bfa_reqq_ci(bfa, BFA_REQQ_FCXP));
    +}
    +
    +/**
    + * Abort a BFA FCXP
    + *
    + * @param[in] fcxp BFA fcxp pointer
    + *
    + * @return void
    + */
    +bfa_status_t
    +bfa_fcxp_abort(struct bfa_fcxp_s *fcxp)
    +{
    + bfa_assert(0);
    + return (BFA_STATUS_OK);
    +}
    +
    +void
    +bfa_fcxp_alloc_wait(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe,
    + bfa_fcxp_alloc_cbfn_t alloc_cbfn, void *alloc_cbarg)
    +{
    + struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
    +
    + bfa_assert(list_empty(&mod->fcxp_free_q));
    +
    + wqe->alloc_cbfn = alloc_cbfn;
    + wqe->alloc_cbarg = alloc_cbarg;
    + list_add_tail(&wqe->qe, &mod->wait_q);
    +}
    +
    +void
    +bfa_fcxp_walloc_cancel(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe)
    +{
    + struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
    +
    + bfa_assert(bfa_q_is_on_q(&mod->wait_q, wqe));
    + list_del(&wqe->qe);
    +}
    +
    +void
    +bfa_fcxp_discard(struct bfa_fcxp_s *fcxp)
    +{
    + fcxp->send_cbfn = bfa_fcxp_null_comp;
    +}
    +
    +
    +
    +/**
    + * hal_fcxp_public BFA FCXP public functions
    + */
    +
    +void
    +bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
    +{
    + switch (msg->mhdr.msg_id) {
    + case BFI_FCXP_I2H_SEND_RSP:
    + hal_fcxp_send_comp(bfa, (struct bfi_fcxp_send_rsp_s *) msg);
    + break;
    +
    + default:
    + bfa_trc(bfa, msg->mhdr.msg_id);
    + bfa_assert(0);
    + }
    +}
    +
    +u32
    +bfa_fcxp_get_maxrsp(struct bfa_s *bfa)
    +{
    + struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
    +
    + return mod->rsp_pld_sz;
    +}
    +
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_fcxp_priv.h patch/drivers/scsi/bfa/bfa_fcxp_priv.h
    --- orig/drivers/scsi/bfa/bfa_fcxp_priv.h 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_fcxp_priv.h 2009-04-01 20:08:47.170473000 -0700
    @@ -0,0 +1,137 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#ifndef __BFA_FCXP_PRIV_H__
    +#define __BFA_FCXP_PRIV_H__
    +
    +#include <cs/bfa_sm.h>
    +#include <protocol/bfa_protocol.h>
    +#include <bfa_svc.h>
    +#include <bfi/bfi_fcxp.h>
    +
    +#define BFA_FCXP_MIN (1)
    +#define BFA_FCXP_MAX_IBUF_SZ (2 * 1024 + 256)
    +#define BFA_FCXP_MAX_LBUF_SZ (4 * 1024 + 256)
    +
    +struct bfa_fcxp_mod_s {
    + struct bfa_s *bfa; /* backpointer to BFA */
    + struct bfa_fcxp_s *fcxp_list; /* array of FCXPs */
    + u16 num_fcxps; /* max num FCXP requests */
    + struct list_head fcxp_free_q; /* free FCXPs */
    + struct list_head fcxp_active_q; /* active FCXPs */
    + void *req_pld_list_kva; /* list of FCXP req pld */
    + u64 req_pld_list_pa; /* list of FCXP req pld */
    + void *rsp_pld_list_kva; /* list of FCXP resp pld */
    + u64 rsp_pld_list_pa; /* list of FCXP resp pld */
    + struct list_head wait_q; /* wait queue for free fcxp */
    + u32 req_pld_sz;
    + u32 rsp_pld_sz;
    +};
    +
    +#define BFA_FCXP_MOD(__bfa) (&(__bfa)->modules.fcxp_mod)
    +#define BFA_FCXP_FROM_TAG(__mod, __tag) (&(__mod)->fcxp_list[__tag])
    +
    +typedef void (*fcxp_send_cb_t) (struct bfa_s *ioc, struct bfa_fcxp_s *fcxp,
    + void *cb_arg, bfa_status_t req_status,
    + u32 rsp_len, u32 resid_len,
    + struct fchs_s *rsp_fchs);
    +
    +/**
    + * Information needed for a FCXP request
    + */
    +struct bfa_fcxp_req_info_s {
    + struct bfa_rport_s *bfa_rport; /* Pointer to the bfa rport that was
    + *returned from bfa_rport_create().
    + *This could be left NULL for WKA or for
    + *FCXP interactions before the rport
    + *nexus is established
    + */
    + u8 cts; /* continous sequence */
    + u8 class; /* FC class for the request/response */
    + u16 max_frmsz; /* max send frame size */
    + u16 vf_id; /* vsan tag if applicable */
    + struct fchs_s fchs; /* request FC header structure */
    + u32 req_tot_len; /* request payload total length */
    +};
    +
    +struct bfa_fcxp_rsp_info_s {
    + struct fchs_s rsp_fchs; /* Response frame's FC header will
    + *be *sent back in this field */
    + u8 rsp_timeout; /* timeout in seconds, 0-no response
    + */
    + u8 rsvd2[3];
    + u32 rsp_maxlen; /* max response length expected */
    +};
    +
    +struct bfa_fcxp_s {
    + struct list_head qe; /* fcxp queue element */
    + bfa_sm_t sm; /* state machine */
    + void *caller; /* driver or fcs */
    + struct bfa_fcxp_mod_s *fcxp_mod;
    + /* back pointer to fcxp mod */
    + u16 fcxp_tag; /* internal tag */
    + struct bfa_fcxp_req_info_s req_info;
    + /* request info */
    + struct bfa_fcxp_rsp_info_s rsp_info;
    + /* response info */
    + u8 use_ireqbuf; /* use internal req buf */
    + u8 use_irspbuf; /* use internal rsp buf */
    + u32 nreq_sgles; /* num request SGLEs */
    + u32 nrsp_sgles; /* num response SGLEs */
    + struct list_head req_sgpg_q; /* SG pages for request buf */
    + struct list_head req_sgpg_wqe; /* wait queue for req SG page */
    + struct list_head rsp_sgpg_q; /* SG pages for response buf */
    + struct list_head rsp_sgpg_wqe; /* wait queue for rsp SG page */
    +
    + bfa_fcxp_get_sgaddr_t req_sga_cbfn;
    + /* SG elem addr user function */
    + bfa_fcxp_get_sglen_t req_sglen_cbfn;
    + /* SG elem len user function */
    + bfa_fcxp_get_sgaddr_t rsp_sga_cbfn;
    + /* SG elem addr user function */
    + bfa_fcxp_get_sglen_t rsp_sglen_cbfn;
    + /* SG elem len user function */
    + bfa_cb_fcxp_send_t send_cbfn; /* send completion callback */
    + void *send_cbarg; /* callback arg */
    + struct bfa_sge_s req_sge[BFA_FCXP_MAX_SGES];
    + /* req SG elems */
    + struct bfa_sge_s rsp_sge[BFA_FCXP_MAX_SGES];
    + /* rsp SG elems */
    + u8 rsp_status; /* comp: rsp status */
    + u32 rsp_len; /* comp: actual response len */
    + u32 residue_len; /* comp: residual rsp length */
    + struct fchs_s rsp_fchs; /* comp: response fchs */
    + struct bfa_cb_qe_s hcb_qe; /* comp: callback qelem */
    + struct bfa_reqq_wait_s reqq_wqe;
    + bfa_boolean_t reqq_waiting;
    +};
    +
    +#define BFA_FCXP_REQ_PLD(_fcxp) (bfa_fcxp_get_reqbuf(_fcxp))
    +
    +#define BFA_FCXP_RSP_FCHS(_fcxp) (&((_fcxp)->rsp_info.fchs))
    +#define BFA_FCXP_RSP_PLD(_fcxp) (bfa_fcxp_get_rspbuf(_fcxp))
    +
    +#define BFA_FCXP_REQ_PLD_PA(_fcxp) \
    + ((_fcxp)->fcxp_mod->req_pld_list_pa + \
    + ((_fcxp)->fcxp_mod->req_pld_sz * (_fcxp)->fcxp_tag))
    +
    +#define BFA_FCXP_RSP_PLD_PA(_fcxp) \
    + ((_fcxp)->fcxp_mod->rsp_pld_list_pa + \
    + ((_fcxp)->fcxp_mod->rsp_pld_sz * (_fcxp)->fcxp_tag))
    +
    +void bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
    +#endif /* __BFA_FCXP_PRIV_H__ */
    diff -urpN orig/drivers/scsi/bfa/bfa_fwimg_priv.h patch/drivers/scsi/bfa/bfa_fwimg_priv.h
    --- orig/drivers/scsi/bfa/bfa_fwimg_priv.h 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_fwimg_priv.h 2009-04-01 20:08:47.177603000 -0700
    @@ -0,0 +1,31 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#ifndef __BFA_FWIMG_PRIV_TOB_H__
    +#define __BFA_FWIMG_PRIV_TOB_H__
    +
    +extern u32 *bfi_image;
    +extern u32 bfi_image_size;
    +extern u32 *bfad_fwimg_buf;
    +extern char __bfa_ident[];
    +
    +#define BFI_FLASH_CHUNK_SZ 256 /* Flash chunk size */
    +#define BFI_FLASH_CHUNK_SZ_WORDS (BFI_FLASH_CHUNK_SZ/sizeof(u32))
    +
    +extern u32 *bfi_image_get_chunk(u32 off);
    +
    +#endif /* __BFA_FWIMG_PRIV_TOB_H__ */
    diff -urpN orig/drivers/scsi/bfa/bfa_hw_cb.c patch/drivers/scsi/bfa/bfa_hw_cb.c
    --- orig/drivers/scsi/bfa/bfa_hw_cb.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_hw_cb.c 2009-04-01 20:08:47.185476000 -0700
    @@ -0,0 +1,60 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#include <bfa_priv.h>
    +#include <bfi/bfi_cbreg.h>
    +
    +void
    +bfa_hwcb_reginit(struct bfa_s *bfa)
    +{
    + struct bfa_iocfc_regs_s *bfa_regs = &bfa->iocfc.bfa_regs;
    + bfa_os_addr_t kva = bfa_ioc_bar0(&bfa->ioc);
    + int i, q, fn = bfa_ioc_pcifn(&bfa->ioc);
    +
    + if (fn == 0) {
    + bfa_regs->intr_status = (kva + HOSTFN0_INT_STATUS);
    + bfa_regs->intr_mask = (kva + HOSTFN0_INT_MSK);
    + } else {
    + bfa_regs->intr_status = (kva + HOSTFN1_INT_STATUS);
    + bfa_regs->intr_mask = (kva + HOSTFN1_INT_MSK);
    + }
    +
    + for (i = 0; i < BFI_IOC_MAX_CQS; i++) {
    + /*
    + * CPE registers
    + */
    + q = CPE_Q_NUM(fn, i);
    + bfa_regs->cpe_q_pi[i] = (kva + CPE_Q_PI(q));
    + bfa_regs->cpe_q_ci[i] = (kva + CPE_Q_CI(q));
    + bfa_regs->cpe_q_depth[i] = (kva + CPE_Q_DEPTH(q));
    +
    + /*
    + * RME registers
    + */
    + q = CPE_Q_NUM(fn, i);
    + bfa_regs->rme_q_pi[i] = (kva + RME_Q_PI(q));
    + bfa_regs->rme_q_ci[i] = (kva + RME_Q_CI(q));
    + bfa_regs->rme_q_depth[i] = (kva + RME_Q_DEPTH(q));
    + }
    +}
    +
    +void
    +bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq)
    +{
    +}
    +
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_hw_ct.c patch/drivers/scsi/bfa/bfa_hw_ct.c
    --- orig/drivers/scsi/bfa/bfa_hw_ct.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_hw_ct.c 2009-04-01 20:08:47.192833000 -0700
    @@ -0,0 +1,66 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#include <bfa_priv.h>
    +#include <bfi/bfi_ctreg.h>
    +
    +void
    +bfa_hwct_reginit(struct bfa_s *bfa)
    +{
    + struct bfa_iocfc_regs_s *bfa_regs = &bfa->iocfc.bfa_regs;
    + bfa_os_addr_t kva = bfa_ioc_bar0(&bfa->ioc);
    + int i, q, fn = bfa_ioc_pcifn(&bfa->ioc);
    +
    + if (fn == 0) {
    + bfa_regs->intr_status = (kva + HOSTFN0_INT_STATUS);
    + bfa_regs->intr_mask = (kva + HOSTFN0_INT_MSK);
    + } else {
    + bfa_regs->intr_status = (kva + HOSTFN1_INT_STATUS);
    + bfa_regs->intr_mask = (kva + HOSTFN1_INT_MSK);
    + }
    +
    + for (i = 0; i < BFI_IOC_MAX_CQS; i++) {
    + /*
    + * CPE registers
    + */
    + q = CPE_Q_NUM(fn, i);
    + bfa_regs->cpe_q_pi[i] = (kva + CPE_PI_PTR_Q(q << 5));
    + bfa_regs->cpe_q_ci[i] = (kva + CPE_CI_PTR_Q(q << 5));
    + bfa_regs->cpe_q_depth[i] = (kva + CPE_DEPTH_Q(q << 5));
    + bfa_regs->cpe_q_ctrl[i] = (kva + CPE_QCTRL_Q(q << 5));
    +
    + /*
    + * RME registers
    + */
    + q = CPE_Q_NUM(fn, i);
    + bfa_regs->rme_q_pi[i] = (kva + RME_PI_PTR_Q(q << 5));
    + bfa_regs->rme_q_ci[i] = (kva + RME_CI_PTR_Q(q << 5));
    + bfa_regs->rme_q_depth[i] = (kva + RME_DEPTH_Q(q << 5));
    + bfa_regs->rme_q_ctrl[i] = (kva + RME_QCTRL_Q(q << 5));
    + }
    +}
    +
    +void
    +bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq)
    +{
    + u32 r32;
    +
    + r32 = bfa_reg_read(bfa->iocfc.bfa_regs.rme_q_ctrl[rspq]);
    + bfa_reg_write(bfa->iocfc.bfa_regs.rme_q_ctrl[rspq], r32);
    +}
    +
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_intr.c patch/drivers/scsi/bfa/bfa_intr.c
    --- orig/drivers/scsi/bfa/bfa_intr.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_intr.c 2009-04-01 20:08:47.201829000 -0700
    @@ -0,0 +1,260 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +#include <bfa.h>
    +#include <bfi/bfi_cbreg.h>
    +#include <bfa_port_priv.h>
    +#include <bfa_intr_priv.h>
    +#include <cs/bfa_debug.h>
    +
    +BFA_TRC_FILE(HAL, INTR);
    +
    +/**
    + * Resume request queue once it was full and now non-full
    + */
    +static void
    +bfa_reqq_resume(struct bfa_s *bfa, int qid)
    +{
    + struct list_head *waitq, *qe, *qen;
    + struct bfa_reqq_wait_s *wqe;
    +
    + waitq = bfa_reqq(bfa, qid);
    + list_for_each_safe(qe, qen, waitq) {
    + /**
    + * Callback only as long as there is room in request queue
    + */
    + if (bfa_reqq_full(bfa, qid))
    + break;
    +
    + list_del(qe);
    + wqe = (struct bfa_reqq_wait_s *) qe;
    + wqe->qresume(wqe->cbarg);
    + }
    +}
    +
    +/**
    + * hal_intr_api
    + */
    +enum bfa_isr_status
    +bfa_intx(struct bfa_s *bfa)
    +{
    + u32 intr;
    + int vec;
    +
    + intr = bfa_reg_read(bfa->iocfc.bfa_regs.intr_status);
    + if (!intr)
    + return BFA_ISR_NOTCLAIMED;
    +
    + /**
    + * mailbox interrupt
    + */
    + if (bfa_ioc_pcifn(&bfa->ioc) == 0) {
    + if (intr & __HFN_INT_MBOX_LPU0)
    + bfa_msix_lpu(bfa);
    + } else {
    + if (intr & __HFN_INT_MBOX_LPU1)
    + bfa_msix_lpu(bfa);
    + }
    + /**
    + * RME completion queue interrupt
    + */
    + for (vec = HFN_MSIX_RME_Q0; vec <= HFN_MSIX_RME_Q7; vec++)
    + if (intr & (__HFN_INT_RME_Q0 << (vec - HFN_MSIX_RME_Q0)))
    + bfa_msix_rspq(bfa, vec);
    +
    + /**
    + * CPE completion queue interrupt
    + */
    + for (vec = HFN_MSIX_CPE_Q0; vec <= HFN_MSIX_CPE_Q7; vec++)
    + if (intr & (__HFN_INT_CPE_Q0 << (vec - HFN_MSIX_CPE_Q0)))
    + bfa_msix_reqq(bfa, vec);
    +
    + if (intr & (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 |
    + __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS))
    + bfa_msix_errint(bfa);
    +
    + return (BFA_ISR_CLAIMED_COMP);
    +}
    +
    +void
    +bfa_isr_enable(struct bfa_s *bfa)
    +{
    + u32 intr_unmask;
    + int pci_func = bfa_ioc_pcifn(&bfa->ioc);
    +
    + bfa_trc(bfa, pci_func);
    +
    + intr_unmask = (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 |
    + __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS);
    +
    + if (pci_func == 0)
    + intr_unmask |= (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 |
    + __HFN_INT_CPE_Q2 | __HFN_INT_CPE_Q3 |
    + __HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 |
    + __HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 |
    + __HFN_INT_MBOX_LPU0);
    + else
    + intr_unmask |= (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 |
    + __HFN_INT_CPE_Q6 | __HFN_INT_CPE_Q7 |
    + __HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 |
    + __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 |
    + __HFN_INT_MBOX_LPU1);
    +
    + bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, ~intr_unmask);
    +}
    +
    +void
    +bfa_isr_disable(struct bfa_s *bfa)
    +{
    + bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, -1L);
    +}
    +
    +void
    +bfa_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap,
    + u32 *num_vecs, u32 *max_vec_bit)
    +{
    +#define __HFN_NUMINTS 13
    + if (bfa_ioc_pcifn(&bfa->ioc) == 0) {
    + *msix_vecs_bmap = (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 |
    + __HFN_INT_CPE_Q2 | __HFN_INT_CPE_Q3 |
    + __HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 |
    + __HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 |
    + __HFN_INT_MBOX_LPU0);
    + *max_vec_bit = __HFN_INT_MBOX_LPU0;
    + } else {
    + *msix_vecs_bmap = (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 |
    + __HFN_INT_CPE_Q6 | __HFN_INT_CPE_Q7 |
    + __HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 |
    + __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 |
    + __HFN_INT_MBOX_LPU1);
    + *max_vec_bit = __HFN_INT_MBOX_LPU1;
    + }
    +
    + *msix_vecs_bmap |= (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 |
    + __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS);
    + *num_vecs = __HFN_NUMINTS;
    +}
    +
    +enum bfa_isr_status
    +bfa_msix_reqq(struct bfa_s *bfa, int qid)
    +{
    + /**
    + * ack the interrupt first
    + */
    + bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, (1 << (qid)));
    +
    + qid &= (BFI_IOC_MAX_CQS - 1);
    + bfa_reqq_resume(bfa, qid);
    + return (BFA_ISR_CLAIMED_COMP);
    +}
    +
    +void
    +bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m)
    +{
    + bfa_trc(bfa, m->mhdr.msg_class);
    + bfa_trc(bfa, m->mhdr.msg_id);
    + bfa_trc(bfa, m->mhdr.mtag.i2htok);
    + bfa_assert(0);
    + bfa_trc_stop(bfa->trcmod);
    +}
    +
    +enum bfa_isr_status
    +bfa_msix_rspq(struct bfa_s *bfa, int rsp_qid)
    +{
    + struct bfi_msg_s *m;
    + u32 pi, ci;
    +
    + bfa_trc_fp(bfa, rsp_qid);
    +
    + /**
    + * ack the interrupt first
    + */
    + bfa_reg_write(bfa->iocfc.bfa_regs.intr_status,
    + (1 << (rsp_qid)));
    +
    + rsp_qid &= (BFI_IOC_MAX_CQS - 1);
    +
    + ci = bfa_rspq_ci(bfa, rsp_qid);
    + pi = bfa_rspq_pi(bfa, rsp_qid);
    +
    + bfa_trc_fp(bfa, ci);
    + bfa_trc_fp(bfa, pi);
    +
    + while (ci != pi) {
    + m = bfa_rspq_elem(bfa, rsp_qid, ci);
    + bfa_assert_fp(m->mhdr.msg_class < BFI_MC_MAX);
    + bfa_isrs[m->mhdr.msg_class] (bfa, m);
    +
    + CQ_INCR(ci, bfa->iocfc.cfg.drvcfg.num_rspq_elems);
    + }
    +
    + /**
    + * update CI
    + */
    + bfa_rspq_ci(bfa, rsp_qid) = ci;
    + bfa_reg_write(bfa->iocfc.bfa_regs.rme_q_ci[rsp_qid],
    + bfa->iocfc.rsp_cq_ci[rsp_qid]);
    + bfa->iocfc.hwif.hw_rspq_ack(bfa, rsp_qid);
    + bfa_os_mmiowb();
    +
    + /**
    + * Resume corresponding request queue.
    + */
    + bfa_reqq_resume(bfa, rsp_qid);
    +
    + return (BFA_ISR_CLAIMED_COMP);
    +}
    +
    +enum bfa_isr_status
    +bfa_msix_lpu(struct bfa_s *bfa)
    +{
    + bfa_ioc_mbox_isr(&bfa->ioc);
    +
    + /**
    + * ack the mailbox interrupt
    + */
    + if (bfa_ioc_pcifn(&bfa->ioc) == 0) {
    + bfa_reg_write(bfa->iocfc.bfa_regs.intr_status,
    + __HFN_INT_MBOX_LPU0);
    + } else {
    + bfa_reg_write(bfa->iocfc.bfa_regs.intr_status,
    + __HFN_INT_MBOX_LPU1);
    + }
    +
    + return (BFA_ISR_CLAIMED_COMP);
    +}
    +
    +enum bfa_isr_status
    +bfa_msix_errint(struct bfa_s *bfa)
    +{
    + u32 intr;
    +
    + intr = bfa_reg_read(bfa->iocfc.bfa_regs.intr_status);
    + bfa_trc(bfa, intr);
    + bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, intr);
    + bfa_isr_disable(bfa);
    + bfa_assert(0);
    +
    + return (BFA_ISR_CLAIMED_COMP);
    +}
    +
    +void
    +bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func)
    +{
    + bfa_isrs[mc] = isr_func;
    +}
    +
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_intr_priv.h patch/drivers/scsi/bfa/bfa_intr_priv.h
    --- orig/drivers/scsi/bfa/bfa_intr_priv.h 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_intr_priv.h 2009-04-01 20:08:47.209233000 -0700
    @@ -0,0 +1,116 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#ifndef __BFA_INTR_PRIV_H__
    +#define __BFA_INTR_PRIV_H__
    +
    +/**
    + * Message handler
    + */
    +typedef void (*bfa_isr_func_t) (struct bfa_s *bfa, struct bfi_msg_s *m);
    +void bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m);
    +void bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func);
    +
    +
    +#define bfa_reqq_pi(__bfa, __reqq) (__bfa)->iocfc.req_cq_pi[__reqq]
    +#define bfa_reqq_ci(__bfa, __reqq) \
    + *(u32 *)((__bfa)->iocfc.req_cq_shadow_ci[__reqq].kva)
    +
    +#define bfa_reqq_full(__bfa, __reqq) \
    + (((bfa_reqq_pi(__bfa, __reqq) + 1) & \
    + ((__bfa)->iocfc.cfg.drvcfg.num_reqq_elems - 1)) == \
    + bfa_reqq_ci(__bfa, __reqq))
    +
    +#define bfa_reqq_next(__bfa, __reqq) \
    + (bfa_reqq_full(__bfa, __reqq) ? NULL : \
    + ((void *)((struct bfi_msg_s *)((__bfa)->iocfc.req_cq_ba[__reqq].kva) \
    + + bfa_reqq_pi((__bfa), (__reqq)))))
    +
    +#define bfa_reqq_produce(__bfa, __reqq) do { \
    + (__bfa)->iocfc.req_cq_pi[__reqq]++; \
    + (__bfa)->iocfc.req_cq_pi[__reqq] &= \
    + ((__bfa)->iocfc.cfg.drvcfg.num_reqq_elems - 1); \
    + bfa_reg_write((__bfa)->iocfc.bfa_regs.cpe_q_pi[__reqq], \
    + (__bfa)->iocfc.req_cq_pi[__reqq]); \
    + bfa_os_mmiowb(); \
    +} while (0)
    +
    +#define bfa_rspq_pi(__bfa, __rspq) \
    + *(u32 *)((__bfa)->iocfc.rsp_cq_shadow_pi[__rspq].kva)
    +
    +#define bfa_rspq_ci(__bfa, __rspq) (__bfa)->iocfc.rsp_cq_ci[__rspq]
    +#define bfa_rspq_elem(__bfa, __rspq, __ci) \
    + &((struct bfi_msg_s *)((__bfa)->iocfc.rsp_cq_ba[__rspq].kva))[__ci]
    +
    +#define CQ_INCR(__index, __size) \
    + (__index)++; (__index) &= ((__size) - 1)
    +
    +/**
    + * Queue element to wait for room in request queue. FIFO order is
    + * maintained when fullfilling requests.
    + */
    +struct bfa_reqq_wait_s {
    + struct list_head qe;
    + void (*qresume) (void *cbarg);
    + void *cbarg;
    +};
    +
    +/**
    + * Circular queue usage assignments
    + */
    +enum {
    + BFA_REQQ_IOC = 0, /* all low-priority IOC msgs */
    + BFA_REQQ_FCXP = 0, /* all FCXP messages */
    + BFA_REQQ_LPS = 0, /* all lport service msgs */
    + BFA_REQQ_PORT = 0, /* all port messages */
    + BFA_REQQ_FLASH = 0, /* for flash module */
    + BFA_REQQ_DIAG = 0, /* for diag module */
    + BFA_REQQ_RPORT = 0, /* all port messages */
    + BFA_REQQ_SBOOT = 0, /* all san boot messages */
    + BFA_REQQ_VPORT = 0, /* all san boot messages */
    + BFA_REQQ_QOS_LO = 1, /* all low priority IO */
    + BFA_REQQ_QOS_MD = 2, /* all medium priority IO */
    + BFA_REQQ_QOS_HI = 3, /* all high priority IO */
    +};
    +
    +static inline void
    +bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg),
    + void *cbarg)
    +{
    + wqe->qresume = qresume;
    + wqe->cbarg = cbarg;
    +}
    +
    +#define bfa_reqq(__bfa, __reqq) &(__bfa)->reqq_waitq[__reqq]
    +
    +/**
    + * static inline void
    + * bfa_reqq_wait(struct bfa_s *bfa, int reqq, struct bfa_reqq_wait_s *wqe)
    + */
    +#define bfa_reqq_wait(__bfa, __reqq, __wqe) do { \
    + \
    + struct list_head *waitq = bfa_reqq(__bfa, __reqq); \
    + \
    + bfa_assert(((__reqq) < BFI_IOC_MAX_CQS)); \
    + bfa_assert((__wqe)->qresume && (__wqe)->cbarg); \
    + \
    + list_add_tail(&(__wqe)->qe, waitq); \
    +} while (0)
    +
    +#define bfa_reqq_wcancel(__wqe) list_del(&(__wqe)->qe)
    +
    +#endif /* __BFA_INTR_PRIV_H__ */
    diff -urpN orig/drivers/scsi/bfa/bfa_ioc.c patch/drivers/scsi/bfa/bfa_ioc.c
    --- orig/drivers/scsi/bfa/bfa_ioc.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_ioc.c 2009-04-01 20:08:47.219038000 -0700
    @@ -0,0 +1,1841 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#include <bfa.h>
    +#include <bfa_ioc.h>
    +#include <bfa_fwimg_priv.h>
    +#include <bfa_trcmod_priv.h>
    +#include <cs/bfa_debug.h>
    +#include <bfi/bfi_ioc.h>
    +#include <bfi/bfi_ctreg.h>
    +#include <aen/bfa_aen_ioc.h>
    +#include <aen/bfa_aen.h>
    +#include <log/bfa_log_hal.h>
    +#include <defs/bfa_defs_pci.h>
    +
    +BFA_TRC_FILE(HAL, IOC);
    +
    +/**
    + * IOC local definitions
    + */
    +#define BFA_IOC_TOV 10000 /* msecs */
    +#define BFA_IOC_HB_TOV 2000 /* msecs */
    +#define BFA_IOC_HB_FAIL_MAX 10
    +#define BFA_IOC_HWINIT_MAX 2
    +#define BFA_IOC_FWIMG_MINSZ (16 * 1024)
    +
    +#define bfa_ioc_timer_start(__ioc) \
    + bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->ioc_timer, \
    + bfa_ioc_timeout, (__ioc), BFA_IOC_TOV)
    +#define bfa_ioc_timer_stop(__ioc) bfa_timer_stop(&(__ioc)->ioc_timer)
    +
    +#define BFA_DBG_FWTRC_ENTS (BFI_IOC_TRC_ENTS)
    +#define BFA_DBG_FWTRC_LEN \
    + (BFA_DBG_FWTRC_ENTS * sizeof(struct bfa_trc_s) + \
    + (sizeof(struct bfa_trc_mod_s) - \
    + BFA_TRC_MAX * sizeof(struct bfa_trc_s)))
    +#define BFA_DBG_FWTRC_OFF(_fn) (BFI_IOC_TRC_OFF + BFA_DBG_FWTRC_LEN * (_fn))
    +#define bfa_ioc_stats(_ioc, _stats) (_ioc)->stats._stats ++
    +
    +#define BFA_FLASH_CHUNK_NO(off) (off / BFI_FLASH_CHUNK_SZ_WORDS)
    +#define BFA_FLASH_OFFSET_IN_CHUNK(off) (off % BFI_FLASH_CHUNK_SZ_WORDS)
    +#define BFA_FLASH_CHUNK_ADDR(chunkno) (chunkno * BFI_FLASH_CHUNK_SZ_WORDS)
    +bfa_boolean_t bfa_auto_recover = BFA_FALSE;
    +
    +/*
    + * forward declarations
    + */
    +static void bfa_ioc_aen_post(struct bfa_ioc_s *bfa,
    + enum bfa_ioc_aen_event event);
    +static void bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc);
    +static void bfa_ioc_hw_sem_release(struct bfa_ioc_s *ioc);
    +static void bfa_ioc_hw_sem_get_cancel(struct bfa_ioc_s *ioc);
    +static void bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force);
    +static void bfa_ioc_timeout(void *ioc);
    +static void bfa_ioc_send_enable(struct bfa_ioc_s *ioc);
    +static void bfa_ioc_send_disable(struct bfa_ioc_s *ioc);
    +static void bfa_ioc_send_getattr(struct bfa_ioc_s *ioc);
    +static void bfa_ioc_hb_monitor(struct bfa_ioc_s *ioc);
    +static void bfa_ioc_hb_stop(struct bfa_ioc_s *ioc);
    +static void bfa_ioc_reset(struct bfa_ioc_s *ioc, bfa_boolean_t force);
    +static void bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc);
    +static void bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc);
    +static void bfa_ioc_recover(struct bfa_ioc_s *ioc);
    +
    +/**
    + * hal_ioc_sm
    + */
    +
    +/**
    + * IOC state machine events
    + */
    +enum ioc_event {
    + IOC_E_ENABLE = 1,
    + IOC_E_DISABLE = 2,
    + IOC_E_TIMEOUT = 3,
    + IOC_E_FWREADY = 4,
    + IOC_E_FWRSP_GETATTR = 5,
    + IOC_E_FWRSP_ENABLE = 6,
    + IOC_E_FWRSP_DISABLE = 7,
    + IOC_E_HBFAIL = 8, /* heartbeat failure */
    + IOC_E_SEMLOCKED = 9, /* h/w semaphore is locked */
    +};
    +
    +
    +bfa_fsm_state_decl(bfa_ioc, reset, struct bfa_ioc_s, enum ioc_event)
    + bfa_fsm_state_decl(bfa_ioc, semwait, struct bfa_ioc_s, enum ioc_event)
    + bfa_fsm_state_decl(bfa_ioc, hwinit, struct bfa_ioc_s, enum ioc_event)
    + bfa_fsm_state_decl(bfa_ioc, enabling, struct bfa_ioc_s, enum ioc_event)
    + bfa_fsm_state_decl(bfa_ioc, getattr, struct bfa_ioc_s, enum ioc_event)
    + bfa_fsm_state_decl(bfa_ioc, op, struct bfa_ioc_s, enum ioc_event)
    + bfa_fsm_state_decl(bfa_ioc, initfail, struct bfa_ioc_s, enum ioc_event)
    + bfa_fsm_state_decl(bfa_ioc, hbfail, struct bfa_ioc_s, enum ioc_event)
    + bfa_fsm_state_decl(bfa_ioc, disabling, struct bfa_ioc_s, enum ioc_event)
    + bfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc_s, enum ioc_event)
    +
    + static struct bfa_sm_table_s ioc_sm_table[] = {
    + {BFA_SM(bfa_ioc_sm_reset), BFA_IOC_RESET},
    + {BFA_SM(bfa_ioc_sm_semwait), BFA_IOC_SEMWAIT},
    + {BFA_SM(bfa_ioc_sm_hwinit), BFA_IOC_HWINIT},
    + {BFA_SM(bfa_ioc_sm_getattr), BFA_IOC_GETATTR},
    + {BFA_SM(bfa_ioc_sm_op), BFA_IOC_OPERATIONAL},
    + {BFA_SM(bfa_ioc_sm_initfail), BFA_IOC_INITFAIL},
    + {BFA_SM(bfa_ioc_sm_hbfail), BFA_IOC_HBFAIL},
    + {BFA_SM(bfa_ioc_sm_disabling), BFA_IOC_DISABLING},
    + {BFA_SM(bfa_ioc_sm_disabled), BFA_IOC_DISABLED},
    +};
    +
    +
    +static void
    +bfa_ioc_sm_reset_entry(struct bfa_ioc_s *ioc)
    +{
    + ioc->hwinit_count = 0;
    + ioc->auto_recover = bfa_auto_recover;
    +}
    +
    +/**
    + * Beginning state. IOC is in reset state.
    + */
    +static void
    +bfa_ioc_sm_reset(struct bfa_ioc_s *ioc, enum ioc_event event)
    +{
    + bfa_trc(ioc, event);
    +
    + switch (event) {
    + case IOC_E_ENABLE:
    + bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +
    +static void
    +bfa_ioc_sm_semwait_entry(struct bfa_ioc_s *ioc)
    +{
    + bfa_ioc_hw_sem_get(ioc);
    +}
    +
    +/**
    + * Awaiting release of h/w semaphore.
    + */
    +static void
    +bfa_ioc_sm_semwait(struct bfa_ioc_s *ioc, enum ioc_event event)
    +{
    + bfa_trc(ioc, event);
    +
    + switch (event) {
    + case IOC_E_SEMLOCKED:
    + bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit);
    + break;
    +
    + case IOC_E_DISABLE:
    + bfa_ioc_hw_sem_get_cancel(ioc);
    + bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
    + break;
    +
    + case IOC_E_FWREADY:
    + bfa_ioc_hw_sem_get_cancel(ioc);
    + bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +
    +static void
    +bfa_ioc_sm_hwinit_entry(struct bfa_ioc_s *ioc)
    +{
    + ioc->hwinit_count = 0;
    + bfa_ioc_timer_start(ioc);
    + bfa_ioc_reset(ioc, BFA_FALSE);
    +}
    +
    +/**
    + * Hardware is being initialized. Interrupts are enabled.
    + * Holding hardware semaphore lock.
    + */
    +static void
    +bfa_ioc_sm_hwinit(struct bfa_ioc_s *ioc, enum ioc_event event)
    +{
    + bfa_trc(ioc, event);
    +
    + switch (event) {
    + case IOC_E_FWREADY:
    + bfa_ioc_timer_stop(ioc);
    + bfa_ioc_hw_sem_release(ioc);
    + bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling);
    + break;
    +
    + case IOC_E_TIMEOUT:
    + ioc->hwinit_count++;
    + if (ioc->hwinit_count < BFA_IOC_HWINIT_MAX) {
    + bfa_ioc_timer_start(ioc);
    + bfa_ioc_reset(ioc, BFA_TRUE);
    + break;
    + }
    +
    + bfa_ioc_hw_sem_release(ioc);
    + bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
    + break;
    +
    + case IOC_E_DISABLE:
    + bfa_ioc_hw_sem_release(ioc);
    + bfa_ioc_timer_stop(ioc);
    + bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +
    +static void
    +bfa_ioc_sm_enabling_entry(struct bfa_ioc_s *ioc)
    +{
    + bfa_ioc_timer_start(ioc);
    + bfa_ioc_send_enable(ioc);
    +}
    +
    +/**
    + * Host IOC function is being enabled, awaiting response from firmware.
    + * Host semaphore is released.
    + */
    +static void
    +bfa_ioc_sm_enabling(struct bfa_ioc_s *ioc, enum ioc_event event)
    +{
    + bfa_trc(ioc, event);
    +
    + switch (event) {
    + case IOC_E_FWRSP_ENABLE:
    + bfa_ioc_timer_stop(ioc);
    + bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr);
    + break;
    +
    + case IOC_E_TIMEOUT:
    + bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
    + break;
    +
    + case IOC_E_DISABLE:
    + bfa_ioc_timer_stop(ioc);
    + bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
    + break;
    +
    + case IOC_E_FWREADY:
    + bfa_ioc_send_enable(ioc);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +
    +static void
    +bfa_ioc_sm_getattr_entry(struct bfa_ioc_s *ioc)
    +{
    + bfa_ioc_timer_start(ioc);
    + bfa_ioc_send_getattr(ioc);
    +}
    +
    +/**
    + * IOC configuration in progress. Timer is active.
    + */
    +static void
    +bfa_ioc_sm_getattr(struct bfa_ioc_s *ioc, enum ioc_event event)
    +{
    + bfa_trc(ioc, event);
    +
    + switch (event) {
    + case IOC_E_FWRSP_GETATTR:
    + bfa_ioc_timer_stop(ioc);
    + bfa_fsm_set_state(ioc, bfa_ioc_sm_op);
    + break;
    +
    + case IOC_E_TIMEOUT:
    + bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
    + break;
    +
    + case IOC_E_DISABLE:
    + bfa_ioc_timer_stop(ioc);
    + bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +
    +static void
    +bfa_ioc_sm_op_entry(struct bfa_ioc_s *ioc)
    +{
    + ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK);
    + bfa_ioc_hb_monitor(ioc);
    + bfa_ioc_aen_post(ioc, BFA_IOC_AEN_ENABLE);
    +}
    +
    +static void
    +bfa_ioc_sm_op(struct bfa_ioc_s *ioc, enum ioc_event event)
    +{
    + bfa_trc(ioc, event);
    +
    + switch (event) {
    + case IOC_E_DISABLE:
    + bfa_ioc_hb_stop(ioc);
    + bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
    + break;
    +
    + case IOC_E_FWREADY:
    + /**
    + * IOC recovery by other function. Treat it same as heartbeat failure.
    + */
    + bfa_ioc_hb_stop(ioc);
    + /* !!! fall through !!! */
    +
    + case IOC_E_HBFAIL:
    + bfa_fsm_set_state(ioc, bfa_ioc_sm_hbfail);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +
    +static void
    +bfa_ioc_sm_disabling_entry(struct bfa_ioc_s *ioc)
    +{
    + bfa_ioc_aen_post(ioc, BFA_IOC_AEN_DISABLE);
    + bfa_ioc_timer_start(ioc);
    + bfa_ioc_send_disable(ioc);
    +}
    +
    +/**
    + * IOC is being disabled
    + */
    +static void
    +bfa_ioc_sm_disabling(struct bfa_ioc_s *ioc, enum ioc_event event)
    +{
    + bfa_trc(ioc, event);
    +
    + switch (event) {
    + case IOC_E_FWRSP_DISABLE:
    + bfa_ioc_timer_stop(ioc);
    + /*
    + * !!! fall through !!!
    + */
    +
    + case IOC_E_TIMEOUT:
    + bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * IOC disable completion entry.
    + */
    +static void
    +bfa_ioc_sm_disabled_entry(struct bfa_ioc_s *ioc)
    +{
    + struct list_head *qe;
    + struct bfa_ioc_hbfail_notify_s *notify;
    +
    + ioc->cbfn->disable_cbfn(ioc->bfa);
    +
    + /**
    + * Notify common modules registered for notification.
    + */
    + list_for_each(qe, &ioc->hb_notify_q) {
    + notify = (struct bfa_ioc_hbfail_notify_s *) qe;
    + notify->cbfn(notify->cbarg);
    + }
    +}
    +
    +static void
    +bfa_ioc_sm_disabled(struct bfa_ioc_s *ioc, enum ioc_event event)
    +{
    + bfa_trc(ioc, event);
    +
    + switch (event) {
    + case IOC_E_ENABLE:
    + bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait);
    + break;
    +
    + case IOC_E_DISABLE:
    + ioc->cbfn->disable_cbfn(ioc->bfa);
    + break;
    +
    + case IOC_E_FWREADY:
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +
    +static void
    +bfa_ioc_sm_initfail_entry(struct bfa_ioc_s *ioc)
    +{
    + ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
    +}
    +
    +/**
    + * Hardware initialization failed.
    + */
    +static void
    +bfa_ioc_sm_initfail(struct bfa_ioc_s *ioc, enum ioc_event event)
    +{
    + bfa_trc(ioc, event);
    +
    + switch (event) {
    + case IOC_E_DISABLE:
    + bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +
    +static void
    +bfa_ioc_sm_hbfail_entry(struct bfa_ioc_s *ioc)
    +{
    + struct list_head *qe;
    + struct bfa_ioc_hbfail_notify_s *notify;
    +
    + /**
    + * Mark IOC as failed in hardware.
    + */
    + bfa_reg_write(ioc->ioc_regs.ioc_fwstate, BFI_IOC_HBFAIL);
    +
    + /**
    + * Notify driver and common modules registered for notification.
    + */
    + ioc->cbfn->hbfail_cbfn(ioc->bfa);
    + list_for_each(qe, &ioc->hb_notify_q) {
    + notify = (struct bfa_ioc_hbfail_notify_s *) qe;
    + notify->cbfn(notify->cbarg);
    + }
    +
    + /**
    + * Flush any queued up mailbox requests.
    + */
    + bfa_ioc_mbox_hbfail(ioc);
    + bfa_ioc_aen_post(ioc, BFA_IOC_AEN_HBFAIL);
    +
    + /**
    + * Trigger auto-recovery after a delay.
    + */
    + if (ioc->auto_recover)
    + bfa_ioc_timer_start(ioc);
    +}
    +
    +/**
    + * IOC heartbeat failure.
    + */
    +static void
    +bfa_ioc_sm_hbfail(struct bfa_ioc_s *ioc, enum ioc_event event)
    +{
    + bfa_trc(ioc, event);
    +
    + switch (event) {
    + case IOC_E_DISABLE:
    + if (ioc->auto_recover)
    + bfa_ioc_timer_stop(ioc);
    + bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
    + break;
    +
    + case IOC_E_TIMEOUT:
    + bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait);
    + break;
    +
    + case IOC_E_FWREADY:
    + /**
    + * Recovery is already initiated by other function.
    + */
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +
    +
    +/**
    + * hal_ioc_pvt BFA IOC private functions
    + */
    +
    +static void
    +bfa_ioc_sem_timeout(void *ioc_arg)
    +{
    + struct bfa_ioc_s *ioc = (struct bfa_ioc_s *) ioc_arg;
    +
    + bfa_ioc_hw_sem_get(ioc);
    +}
    +
    +static void
    +bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc)
    +{
    + u32 r32;
    +
    + /**
    + * First read to the semaphore register will return 0, subsequent reads
    + * will return 1. Semaphore is released by writing 0 to the register
    + */
    + r32 = bfa_reg_read(ioc->ioc_regs.host_sem0_reg);
    + if (r32 == 0) {
    + bfa_fsm_send_event(ioc, IOC_E_SEMLOCKED);
    + return;
    + }
    +
    + bfa_timer_begin(ioc->timer_mod, &ioc->sem_timer, bfa_ioc_sem_timeout,
    + ioc, BFA_IOC_TOV);
    +}
    +
    +static void
    +bfa_ioc_hw_sem_release(struct bfa_ioc_s *ioc)
    +{
    + bfa_reg_write(ioc->ioc_regs.host_sem0_reg, 1);
    +}
    +
    +static void
    +bfa_ioc_hw_sem_get_cancel(struct bfa_ioc_s *ioc)
    +{
    + bfa_timer_stop(&ioc->sem_timer);
    +}
    +
    +/**
    + * Initialize LPU local memory (aka secondary memory / SRAM)
    + */
    +static void
    +bfa_ioc_lmem_init(struct bfa_ioc_s *ioc)
    +{
    + u32 pss_ctl;
    + int i;
    +#define PSS_LMEM_INIT_TIME 10000
    +
    + pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg);
    + pss_ctl &= ~__PSS_LMEM_RESET;
    + pss_ctl |= __PSS_LMEM_INIT_EN;
    + pss_ctl |= __PSS_I2C_CLK_DIV(3UL); /* i2c workaround 12.5khz clock
    + */
    + bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl);
    +
    + /**
    + * wait for memory initialization to be complete
    + */
    + i = 0;
    + do {
    + pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg);
    + i++;
    + } while (!(pss_ctl & __PSS_LMEM_INIT_DONE) && (i < PSS_LMEM_INIT_TIME));
    +
    + /**
    + * If memory initialization is not successful, IOC timeout will catch
    + * such failures.
    + */
    + bfa_assert(pss_ctl & __PSS_LMEM_INIT_DONE);
    + bfa_trc(ioc, pss_ctl);
    +
    + pss_ctl &= ~(__PSS_LMEM_INIT_DONE | __PSS_LMEM_INIT_EN);
    + bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl);
    +}
    +
    +static void
    +bfa_ioc_lpu_start(struct bfa_ioc_s *ioc)
    +{
    + u32 pss_ctl;
    +
    + /**
    + * Take processor out of reset.
    + */
    + pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg);
    + pss_ctl &= ~__PSS_LPU0_RESET;
    +
    + bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl);
    +}
    +
    +/**
    + * Return true if current running version is same as driver version.
    + */
    +static bfa_boolean_t
    +bfa_ioc_fwver_check(struct bfa_ioc_s *ioc)
    +{
    + u32 pgnum, pgoff;
    + u32 loff = 0;
    + int i;
    + struct bfi_ioc_image_hdr_s fwhdr, *drv_fwhdr;
    + u32 *fwsig = (u32 *) &fwhdr;
    +
    + pgnum = bfa_ioc_smem_pgnum(ioc, loff);
    + pgoff = bfa_ioc_smem_pgoff(ioc, loff);
    + bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
    +
    + for (i = 0; i < (sizeof(struct bfi_ioc_image_hdr_s) / sizeof(u32));
    + i++) {
    + fwsig[i] =
    + bfa_mem_read(ioc->ioc_regs.smem_page_start, loff);
    + loff += sizeof(u32);
    + }
    +
    + bfa_trc(ioc, fwhdr.signature);
    + bfa_trc(ioc, fwhdr.cksum);
    + bfa_trc(ioc, fwhdr.exec);
    + bfa_trc(ioc, fwhdr.param);
    +
    + drv_fwhdr = (struct bfi_ioc_image_hdr_s *) bfi_image_get_chunk(0);
    +
    + bfa_trc(ioc, drv_fwhdr->signature);
    + bfa_trc(ioc, drv_fwhdr->cksum);
    + bfa_trc(ioc, drv_fwhdr->exec);
    + bfa_trc(ioc, drv_fwhdr->param);
    +
    + return (((fwhdr.signature == drv_fwhdr->signature))
    + && (fwhdr.cksum == drv_fwhdr->cksum)
    + && (fwhdr.exec == drv_fwhdr->exec)
    +);
    +}
    +
    +/**
    + * Conditionally flush any pending message from firmware at start.
    + */
    +static void
    +bfa_ioc_msgflush(struct bfa_ioc_s *ioc)
    +{
    + u32 r32;
    +
    + r32 = bfa_reg_read(ioc->ioc_regs.lpu_mbox_cmd);
    + if (r32)
    + bfa_reg_write(ioc->ioc_regs.lpu_mbox_cmd, 1);
    +}
    +
    +
    +static void
    +bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force)
    +{
    + enum bfi_ioc_state ioc_fwstate;
    +
    + ioc_fwstate = bfa_reg_read(ioc->ioc_regs.ioc_fwstate);
    +
    + if (force)
    + ioc_fwstate = BFI_IOC_UNINIT;
    +
    + bfa_trc(ioc, ioc_fwstate);
    +
    + /**
    + * If hardware initialization is in progress (initialized by other IOC),
    + * just wait for an initialization completion interrupt.
    + */
    + if ((ioc_fwstate == BFI_IOC_INITING) && bfa_ioc_fwver_check(ioc)) {
    + bfa_trc(ioc, ioc_fwstate);
    + return;
    + }
    +
    + /**
    + * If IOC function is disabled and firmware version is same,
    + * just re-enable IOC.
    + */
    + if ((ioc_fwstate == BFI_IOC_DISABLED || ioc_fwstate == BFI_IOC_OP)
    + && bfa_ioc_fwver_check(ioc)) {
    + bfa_trc(ioc, ioc_fwstate);
    + /**
    + * When using MSI-X any pending firmware ready event should
    + * be flushed. Otherwise MSI-X interrupts are not delivered.
    + */
    + bfa_ioc_msgflush(ioc);
    + bfa_fsm_send_event(ioc, IOC_E_FWREADY);
    + return;
    + }
    +
    + /**
    + * Initialize the h/w for any other states.
    + */
    + bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id);
    +}
    +
    +static void
    +bfa_ioc_timeout(void *ioc_arg)
    +{
    + struct bfa_ioc_s *ioc = (struct bfa_ioc_s *) ioc_arg;
    +
    + bfa_trc(ioc, 0);
    + bfa_fsm_send_event(ioc, IOC_E_TIMEOUT);
    +}
    +
    +void
    +bfa_ioc_mbox_send(struct bfa_ioc_s *ioc, void *ioc_msg, int len)
    +{
    + u32 *msgp = (u32 *) ioc_msg;
    + u32 i;
    +
    + bfa_trc(ioc, msgp[0]);
    + bfa_trc(ioc, len);
    +
    + bfa_assert(len <= BFI_IOC_MSGLEN_MAX);
    +
    + /*
    + * first write msg to mailbox registers
    + */
    + for (i = 0; i < len / sizeof(u32); i++)
    + bfa_reg_write(ioc->ioc_regs.hfn_mbox + i * sizeof(u32),
    + bfa_os_wtole(msgp[i]));
    +
    + for (; i < BFI_IOC_MSGLEN_MAX / sizeof(u32); i++)
    + bfa_reg_write(ioc->ioc_regs.hfn_mbox + i * sizeof(u32), 0);
    +
    + /*
    + * write 1 to mailbox CMD to trigger LPU event
    + */
    + bfa_reg_write(ioc->ioc_regs.hfn_mbox_cmd, 1);
    + (void)bfa_reg_read(ioc->ioc_regs.hfn_mbox_cmd);
    +}
    +
    +static void
    +bfa_ioc_send_enable(struct bfa_ioc_s *ioc)
    +{
    + struct bfi_ioc_ctrl_req_s enable_req;
    +
    + bfi_h2i_set(enable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_ENABLE_REQ,
    + bfa_ioc_portid(ioc));
    + enable_req.ioc_class = ioc->ioc_mc;
    + bfa_ioc_mbox_send(ioc, &enable_req, sizeof(struct bfi_ioc_ctrl_req_s));
    +}
    +
    +static void
    +bfa_ioc_send_disable(struct bfa_ioc_s *ioc)
    +{
    + struct bfi_ioc_ctrl_req_s disable_req;
    +
    + bfi_h2i_set(disable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_DISABLE_REQ,
    + bfa_ioc_portid(ioc));
    + bfa_ioc_mbox_send(ioc, &disable_req, sizeof(struct bfi_ioc_ctrl_req_s));
    +}
    +
    +static void
    +bfa_ioc_send_getattr(struct bfa_ioc_s *ioc)
    +{
    + struct bfi_ioc_getattr_req_s attr_req;
    +
    + bfi_h2i_set(attr_req.mh, BFI_MC_IOC, BFI_IOC_H2I_GETATTR_REQ,
    + bfa_ioc_portid(ioc));
    + bfa_dma_be_addr_set(attr_req.attr_addr, ioc->attr_dma.pa);
    + bfa_ioc_mbox_send(ioc, &attr_req, sizeof(attr_req));
    +}
    +
    +static void
    +bfa_ioc_hb_check(void *cbarg)
    +{
    + struct bfa_ioc_s *ioc = cbarg;
    + u32 hb_count;
    +
    + hb_count = bfa_reg_read(ioc->ioc_regs.heartbeat);
    + if (ioc->hb_count == hb_count) {
    + ioc->hb_fail++;
    + } else {
    + ioc->hb_count = hb_count;
    + ioc->hb_fail = 0;
    + }
    +
    + if (ioc->hb_fail >= BFA_IOC_HB_FAIL_MAX) {
    + bfa_log(ioc->logm, BFA_LOG_HAL_HEARTBEAT_FAILURE,
    + hb_count);
    + ioc->hb_fail = 0;
    + bfa_ioc_recover(ioc);
    + return;
    + }
    +
    + bfa_ioc_mbox_poll(ioc);
    + bfa_timer_begin(ioc->timer_mod, &ioc->ioc_timer, bfa_ioc_hb_check,
    + ioc, BFA_IOC_HB_TOV);
    +}
    +
    +static void
    +bfa_ioc_hb_monitor(struct bfa_ioc_s *ioc)
    +{
    + ioc->hb_fail = 0;
    + ioc->hb_count = bfa_reg_read(ioc->ioc_regs.heartbeat);
    + bfa_timer_begin(ioc->timer_mod, &ioc->ioc_timer, bfa_ioc_hb_check,
    + ioc, BFA_IOC_HB_TOV);
    +}
    +
    +static void
    +bfa_ioc_hb_stop(struct bfa_ioc_s *ioc)
    +{
    + bfa_timer_stop(&ioc->ioc_timer);
    +}
    +
    +/**
    + * Host to LPU mailbox message addresses
    + */
    +static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = {
    + { HOSTFN0_LPU_MBOX0_0, LPU_HOSTFN0_MBOX0_0, HOST_PAGE_NUM_FN0 },
    + { HOSTFN1_LPU_MBOX0_8, LPU_HOSTFN1_MBOX0_8, HOST_PAGE_NUM_FN1 },
    + { HOSTFN2_LPU_MBOX0_0, LPU_HOSTFN2_MBOX0_0, HOST_PAGE_NUM_FN2 },
    + { HOSTFN3_LPU_MBOX0_8, LPU_HOSTFN3_MBOX0_8, HOST_PAGE_NUM_FN3 }
    +};
    +
    +/**
    + * Host <-> LPU mailbox command/status registers - port 0
    + */
    +static struct { u32 hfn, lpu; } iocreg_mbcmd_p0[] = {
    + { HOSTFN0_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN0_MBOX0_CMD_STAT },
    + { HOSTFN1_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN1_MBOX0_CMD_STAT },
    + { HOSTFN2_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN2_MBOX0_CMD_STAT },
    + { HOSTFN3_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN3_MBOX0_CMD_STAT }
    +};
    +
    +/**
    + * Host <-> LPU mailbox command/status registers - port 1
    + */
    +static struct { u32 hfn, lpu; } iocreg_mbcmd_p1[] = {
    + { HOSTFN0_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN0_MBOX0_CMD_STAT },
    + { HOSTFN1_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN1_MBOX0_CMD_STAT },
    + { HOSTFN2_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN2_MBOX0_CMD_STAT },
    + { HOSTFN3_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN3_MBOX0_CMD_STAT }
    +};
    +
    +static void
    +bfa_ioc_reg_init(struct bfa_ioc_s *ioc)
    +{
    + bfa_os_addr_t rb;
    + int pcifn = bfa_ioc_pcifn(ioc);
    +
    + rb = bfa_ioc_bar0(ioc);
    +
    + ioc->ioc_regs.hfn_mbox = rb + iocreg_fnreg[pcifn].hfn_mbox;
    + ioc->ioc_regs.lpu_mbox = rb + iocreg_fnreg[pcifn].lpu_mbox;
    + ioc->ioc_regs.host_page_num_fn = rb + iocreg_fnreg[pcifn].hfn_pgn;
    +
    + if (ioc->port_id == 0) {
    + ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG;
    + ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG;
    + ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].hfn;
    + ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].lpu;
    + } else {
    + ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG);
    + ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG);
    + ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].hfn;
    + ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].lpu;
    + }
    +
    + /*
    + * PSS control registers
    + */
    + ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG);
    + ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_425_CTL_REG);
    + ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_312_CTL_REG);
    +
    + /*
    + * host semaphore registers
    + */
    + ioc->ioc_regs.host_sem0_reg = (rb + HOST_SEM0_REG);
    + ioc->ioc_regs.host_sem1_reg = (rb + HOST_SEM1_REG);
    + ioc->ioc_regs.host_sem2_reg = (rb + HOST_SEM2_REG);
    + ioc->ioc_regs.host_sem3_reg = (rb + HOST_SEM3_REG);
    +
    + /**
    + * sram memory access
    + */
    + ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START);
    + ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CB;
    + if (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT)
    + ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CT;
    +}
    +
    +/**
    + * Initiate a full firmware download.
    + */
    +static void
    +bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type,
    + u32 boot_param)
    +{
    + u32 *fwimg;
    + u32 pgnum, pgoff;
    + u32 loff = 0;
    + u32 chunkno = 0;
    + u32 i;
    +
    + /**
    + * Initialize LMEM first before code download
    + */
    + bfa_ioc_lmem_init(ioc);
    +
    + /**
    + * Flash based firmware boot
    + */
    + bfa_trc(ioc, bfi_image_size);
    + if (bfi_image_size < BFA_IOC_FWIMG_MINSZ)
    + boot_type = BFI_BOOT_TYPE_FLASH;
    + fwimg = bfi_image_get_chunk(chunkno);
    + fwimg[BFI_BOOT_TYPE_OFF / sizeof(u32)] =
    + bfa_os_swap32(boot_type);
    + fwimg[BFI_BOOT_PARAM_OFF / sizeof(u32)] =
    + bfa_os_swap32(boot_param);
    +
    + pgnum = bfa_ioc_smem_pgnum(ioc, loff);
    + pgoff = bfa_ioc_smem_pgoff(ioc, loff);
    +
    + bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
    +
    + for (i = 0; i < bfi_image_size; i++) {
    +
    + if (BFA_FLASH_CHUNK_NO(i) != chunkno) {
    + chunkno = BFA_FLASH_CHUNK_NO(i);
    + fwimg = bfi_image_get_chunk(BFA_FLASH_CHUNK_ADDR(chunkno));
    + }
    +
    + /**
    + * write smem
    + */
    + bfa_mem_write(ioc->ioc_regs.smem_page_start, loff,
    + fwimg[BFA_FLASH_OFFSET_IN_CHUNK(i)]);
    +
    + loff += sizeof(u32);
    +
    + /**
    + * handle page offset wrap around
    + */
    + loff = PSS_SMEM_PGOFF(loff);
    + if (loff == 0) {
    + pgnum++;
    + bfa_reg_write(ioc->ioc_regs.host_page_num_fn,
    + pgnum);
    + }
    + }
    +
    + bfa_reg_write(ioc->ioc_regs.host_page_num_fn,
    + bfa_ioc_smem_pgnum(ioc, 0));
    +}
    +
    +static void
    +bfa_ioc_reset(struct bfa_ioc_s *ioc, bfa_boolean_t force)
    +{
    + bfa_ioc_hwinit(ioc, force);
    + ioc->cbfn->reset_cbfn(ioc->bfa);
    +}
    +
    +/**
    + * Update BFA configuration from firmware configuration.
    + */
    +static void
    +bfa_ioc_getattr_reply(struct bfa_ioc_s *ioc)
    +{
    + struct bfi_ioc_attr_s *attr = ioc->attr;
    +
    + attr->adapter_prop = bfa_os_ntohl(attr->adapter_prop);
    + attr->maxfrsize = bfa_os_ntohs(attr->maxfrsize);
    +
    + bfa_fsm_send_event(ioc, IOC_E_FWRSP_GETATTR);
    +}
    +
    +/**
    + * Attach time initialization of mbox logic.
    + */
    +static void
    +bfa_ioc_mbox_attach(struct bfa_ioc_s *ioc)
    +{
    + struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;
    + int mc;
    +
    + INIT_LIST_HEAD(&mod->cmd_q);
    + for (mc = 0; mc < BFI_MC_MAX; mc++) {
    + mod->mbhdlr[mc].cbfn = NULL;
    + mod->mbhdlr[mc].cbarg = ioc->bfa;
    + }
    +}
    +
    +/**
    + * Mbox poll timer -- restarts any pending mailbox requests.
    + */
    +static void
    +bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc)
    +{
    + struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;
    + struct bfa_mbox_cmd_s *cmd;
    + u32 stat;
    +
    + /**
    + * If no command pending, do nothing
    + */
    + if (list_empty(&mod->cmd_q))
    + return;
    +
    + /**
    + * If previous command is not yet fetched by firmware, do nothing
    + */
    + stat = bfa_reg_read(ioc->ioc_regs.hfn_mbox_cmd);
    + if (stat)
    + return;
    +
    + /**
    + * Enqueue command to firmware.
    + */
    + bfa_q_deq(&mod->cmd_q, &cmd);
    + bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
    +}
    +
    +/**
    + * Cleanup any pending requests.
    + */
    +static void
    +bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc)
    +{
    + struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;
    + struct bfa_mbox_cmd_s *cmd;
    +
    + while (!list_empty(&mod->cmd_q))
    + bfa_q_deq(&mod->cmd_q, &cmd);
    +}
    +
    +/**
    + * Initialize IOC to port mapping.
    + */
    +static void
    +bfa_ioc_map_port(struct bfa_ioc_s *ioc)
    +{
    + bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva;
    + u32 r32;
    +
    + /**
    + * For crossbow, port id is same as pci function.
    + */
    + if (ioc->pcidev.device_id != BFA_PCI_DEVICE_ID_CT) {
    + ioc->port_id = bfa_ioc_pcifn(ioc);
    + return;
    + }
    +
    + /**
    + * For catapult, base port id on personality register and IOC type
    + */
    + r32 = bfa_reg_read(rb + FNC_PERS_REG);
    + r32 >>= (bfa_ioc_pcifn(ioc)) * 8;
    + ioc->port_id = (r32 & __F0_PORT_MAP_MK) >> __F0_PORT_MAP_SH;
    +
    + bfa_trc(ioc, bfa_ioc_pcifn(ioc));
    + bfa_trc(ioc, ioc->port_id);
    +}
    +
    +
    +
    +/**
    + * hal_ioc_public
    + */
    +
    +bfa_status_t
    +bfa_ioc_pll_init(struct bfa_ioc_s *ioc)
    +{
    + bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva;
    + u32 pll_sclk, pll_fclk, r32;
    +
    + if (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT) {
    + pll_sclk = __APP_PLL_312_ENABLE | __APP_PLL_312_LRESETN |
    + __APP_PLL_312_RSEL200500 | __APP_PLL_312_P0_1(0U) |
    + __APP_PLL_312_JITLMT0_1(3U) |
    + __APP_PLL_312_CNTLMT0_1(1U);
    + pll_fclk = __APP_PLL_425_ENABLE | __APP_PLL_425_LRESETN |
    + __APP_PLL_425_RSEL200500 | __APP_PLL_425_P0_1(0U) |
    + __APP_PLL_425_JITLMT0_1(3U) |
    + __APP_PLL_425_CNTLMT0_1(1U);
    +
    + /**
    + * For catapult, choose operational mode FC/FCoE
    + */
    + if (ioc->fcmode) {
    + bfa_reg_write((rb + OP_MODE), 0);
    + bfa_reg_write((rb + ETH_MAC_SER_REG),
    + __APP_EMS_CMLCKSEL |
    + __APP_EMS_REFCKBUFEN2 |
    + __APP_EMS_CHANNEL_SEL);
    + } else {
    + ioc->pllinit = BFA_TRUE;
    + bfa_reg_write((rb + OP_MODE), __GLOBAL_FCOE_MODE);
    + bfa_reg_write((rb + ETH_MAC_SER_REG),
    + __APP_EMS_REFCKBUFEN1);
    + }
    + } else {
    + pll_sclk = __APP_PLL_312_ENABLE | __APP_PLL_312_LRESETN |
    + __APP_PLL_312_P0_1(3U) |
    + __APP_PLL_312_JITLMT0_1(3U) |
    + __APP_PLL_312_CNTLMT0_1(3U);
    + pll_fclk = __APP_PLL_425_ENABLE | __APP_PLL_425_LRESETN |
    + __APP_PLL_425_RSEL200500 | __APP_PLL_425_P0_1(3U) |
    + __APP_PLL_425_JITLMT0_1(3U) |
    + __APP_PLL_425_CNTLMT0_1(3U);
    + }
    +
    + bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_UNINIT);
    + bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_UNINIT);
    +
    + bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU);
    + bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU);
    +
    + bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
    + __APP_PLL_312_LOGIC_SOFT_RESET);
    + bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
    + __APP_PLL_312_BYPASS |
    + __APP_PLL_312_LOGIC_SOFT_RESET);
    + bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
    + __APP_PLL_425_LOGIC_SOFT_RESET);
    + bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
    + __APP_PLL_425_BYPASS |
    + __APP_PLL_425_LOGIC_SOFT_RESET);
    + bfa_os_udelay(2);
    + bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
    + __APP_PLL_312_LOGIC_SOFT_RESET);
    + bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
    + __APP_PLL_425_LOGIC_SOFT_RESET);
    +
    + bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
    + pll_sclk | __APP_PLL_312_LOGIC_SOFT_RESET);
    + bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
    + pll_fclk | __APP_PLL_425_LOGIC_SOFT_RESET);
    +
    + /**
    + * Wait for PLLs to lock.
    + */
    + bfa_os_udelay(2000);
    + bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU);
    + bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU);
    +
    + bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, pll_sclk);
    + bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, pll_fclk);
    +
    + if (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT) {
    + bfa_reg_write((rb + MBIST_CTL_REG), __EDRAM_BISTR_START);
    + bfa_os_udelay(1000);
    + r32 = bfa_reg_read((rb + MBIST_STAT_REG));
    + bfa_trc(ioc, r32);
    + }
    +
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * Interface used by diag module to do firmware boot with memory test
    + * as the entry vector.
    + */
    +void
    +bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_param)
    +{
    + bfa_os_addr_t rb;
    +
    + bfa_ioc_stats(ioc, ioc_boots);
    +
    + if (bfa_ioc_pll_init(ioc) != BFA_STATUS_OK)
    + return;
    +
    + /**
    + * Initialize IOC state of all functions on a chip reset.
    + */
    + rb = ioc->pcidev.pci_bar_kva;
    + if (boot_param == BFI_BOOT_TYPE_MEMTEST) {
    + bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_MEMTEST);
    + bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_MEMTEST);
    + } else {
    + bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_INITING);
    + bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_INITING);
    + }
    +
    + bfa_ioc_download_fw(ioc, boot_type, boot_param);
    +
    + /**
    + * Enable interrupts just before starting LPU
    + */
    + bfa_ioc_lpu_start(ioc);
    +}
    +
    +/**
    + * Enable/disable IOC failure auto recovery.
    + */
    +void
    +bfa_ioc_auto_recover(bfa_boolean_t auto_recover)
    +{
    + bfa_auto_recover = BFA_FALSE;
    +}
    +
    +
    +bfa_boolean_t
    +bfa_ioc_is_operational(struct bfa_ioc_s *ioc)
    +{
    + return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_op);
    +}
    +
    +void
    +bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg)
    +{
    + u32 *msgp = mbmsg;
    + u32 r32;
    + int i;
    +
    + /**
    + * read the MBOX msg
    + */
    + for (i = 0; i < (sizeof(union bfi_ioc_i2h_msg_u) / sizeof(u32));
    + i++) {
    + r32 = bfa_reg_read(ioc->ioc_regs.lpu_mbox +
    + i * sizeof(u32));
    + msgp[i] = bfa_os_htonl(r32);
    + }
    +
    + /**
    + * turn off mailbox interrupt by clearing mailbox status
    + */
    + bfa_reg_write(ioc->ioc_regs.lpu_mbox_cmd, 1);
    + bfa_reg_read(ioc->ioc_regs.lpu_mbox_cmd);
    +}
    +
    +void
    +bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *m)
    +{
    + union bfi_ioc_i2h_msg_u *msg;
    +
    + msg = (union bfi_ioc_i2h_msg_u *) m;
    +
    + bfa_ioc_stats(ioc, ioc_isrs);
    + bfa_trc(ioc, msg->mh.msg_id);
    +
    + switch (msg->mh.msg_id) {
    + case BFI_IOC_I2H_READY_EVENT:
    + bfa_fsm_send_event(ioc, IOC_E_FWREADY);
    + break;
    +
    + case BFI_IOC_I2H_ENABLE_REPLY:
    + bfa_fsm_send_event(ioc, IOC_E_FWRSP_ENABLE);
    + break;
    +
    + case BFI_IOC_I2H_DISABLE_REPLY:
    + bfa_fsm_send_event(ioc, IOC_E_FWRSP_DISABLE);
    + break;
    +
    + case BFI_IOC_I2H_GETATTR_REPLY:
    + bfa_ioc_getattr_reply(ioc);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * IOC attach time initialization and setup.
    + *
    + * @param[in] ioc memory for IOC
    + * @param[in] bfa driver instance structure
    + * @param[in] trcmod kernel trace module
    + * @param[in] aen kernel aen event module
    + * @param[in] logm kernel logging module
    + */
    +void
    +bfa_ioc_attach(struct bfa_ioc_s *ioc, void *bfa, struct bfa_ioc_cbfn_s *cbfn,
    + struct bfa_timer_mod_s *timer_mod, struct bfa_trc_mod_s *trcmod,
    + struct bfa_aen_s *aen, struct bfa_log_mod_s *logm)
    +{
    + ioc->bfa = bfa;
    + ioc->cbfn = cbfn;
    + ioc->timer_mod = timer_mod;
    + ioc->trcmod = trcmod;
    + ioc->aen = aen;
    + ioc->logm = logm;
    + ioc->fcmode = BFA_FALSE;
    + ioc->pllinit = BFA_FALSE;
    +
    + bfa_ioc_mbox_attach(ioc);
    + INIT_LIST_HEAD(&ioc->hb_notify_q);
    +
    + bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
    +}
    +
    +/**
    + * Setup IOC PCI properties.
    + *
    + * @param[in] pcidev PCI device information for this IOC
    + */
    +void
    +bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev,
    + enum bfi_mclass mc)
    +{
    + ioc->ioc_mc = mc;
    + ioc->pcidev = *pcidev;
    +
    + bfa_ioc_map_port(ioc);
    + bfa_ioc_reg_init(ioc);
    +}
    +
    +/**
    + * Initialize IOC dma memory
    + *
    + * @param[in] dm_kva kernel virtual address of IOC dma memory
    + * @param[in] dm_pa physical address of IOC dma memory
    + */
    +void
    +bfa_ioc_mem_claim(struct bfa_ioc_s *ioc, u8 *dm_kva, u64 dm_pa)
    +{
    + /**
    + * dma memory for firmware attribute
    + */
    + ioc->attr_dma.kva = dm_kva;
    + ioc->attr_dma.pa = dm_pa;
    + ioc->attr = (struct bfi_ioc_attr_s *) dm_kva;
    +}
    +
    +/**
    + * Return size of dma memory required.
    + */
    +u32
    +bfa_ioc_meminfo(void)
    +{
    + return BFA_ROUNDUP(sizeof(struct bfi_ioc_attr_s), BFA_DMA_ALIGN_SZ);
    +}
    +
    +bfa_status_t
    +bfa_ioc_enable(struct bfa_ioc_s *ioc)
    +{
    + bfa_ioc_stats(ioc, ioc_enables);
    + bfa_fsm_send_event(ioc, IOC_E_ENABLE);
    +
    + return BFA_STATUS_OK;
    +}
    +
    +void
    +bfa_ioc_disable(struct bfa_ioc_s *ioc)
    +{
    + bfa_ioc_stats(ioc, ioc_disables);
    + bfa_fsm_send_event(ioc, IOC_E_DISABLE);
    +}
    +
    +/**
    + * Returns memory required for saving firmware trace in case of crash.
    + * Driver must call this interface to allocate memory required for
    + * automatic saving of firmware trace. Driver should call
    + * bfa_ioc_debug_memclaim() right after bfa_ioc_attach() to setup this
    + * trace memory.
    + */
    +int
    +bfa_ioc_debug_trcsz(bfa_boolean_t auto_recover)
    +{
    + return (auto_recover) ? BFA_DBG_FWTRC_LEN : 0;
    +}
    +
    +/**
    + * Initialize memory for saving firmware trace. Driver must initialize
    + * trace memory before call bfa_ioc_enable().
    + */
    +void
    +bfa_ioc_debug_memclaim(struct bfa_ioc_s *ioc, void *dbg_fwsave)
    +{
    + bfa_assert(ioc->auto_recover);
    + ioc->dbg_fwsave = dbg_fwsave;
    + ioc->dbg_fwsave_len = bfa_ioc_debug_trcsz(ioc->auto_recover);
    +}
    +
    +u32
    +bfa_ioc_smem_pgnum(struct bfa_ioc_s *ioc, u32 fmaddr)
    +{
    + return PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, fmaddr);
    +}
    +
    +u32
    +bfa_ioc_smem_pgoff(struct bfa_ioc_s *ioc, u32 fmaddr)
    +{
    + return PSS_SMEM_PGOFF(fmaddr);
    +}
    +
    +/**
    + * Register mailbox message handler functions
    + *
    + * @param[in] ioc IOC instance
    + * @param[in] mcfuncs message class handler functions
    + */
    +void
    +bfa_ioc_mbox_register(struct bfa_ioc_s *ioc, bfa_ioc_mbox_mcfunc_t *mcfuncs)
    +{
    + struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;
    + int mc;
    +
    + for (mc = 0; mc < BFI_MC_MAX; mc++)
    + mod->mbhdlr[mc].cbfn = mcfuncs[mc];
    +}
    +
    +/**
    + * Register mailbox message handler function, to be called by common modules
    + */
    +void
    +bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc,
    + bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg)
    +{
    + struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;
    +
    + mod->mbhdlr[mc].cbfn = cbfn;
    + mod->mbhdlr[mc].cbarg = cbarg;
    +}
    +
    +/**
    + * Queue a mailbox command request to firmware. Waits if mailbox is busy.
    + * Responsibility of caller to serialize
    + *
    + * @param[in] ioc IOC instance
    + * @param[i] cmd Mailbox command
    + */
    +void
    +bfa_ioc_mbox_queue(struct bfa_ioc_s *ioc, struct bfa_mbox_cmd_s *cmd)
    +{
    + struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;
    + u32 stat;
    +
    + /**
    + * If a previous command is pending, queue new command
    + */
    + if (!list_empty(&mod->cmd_q)) {
    + list_add_tail(&cmd->qe, &mod->cmd_q);
    + return;
    + }
    +
    + /**
    + * If mailbox is busy, queue command for poll timer
    + */
    + stat = bfa_reg_read(ioc->ioc_regs.hfn_mbox_cmd);
    + if (stat) {
    + list_add_tail(&cmd->qe, &mod->cmd_q);
    + return;
    + }
    +
    + /**
    + * mailbox is free -- queue command to firmware
    + */
    + bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
    +}
    +
    +/**
    + * Handle mailbox interrupts
    + */
    +void
    +bfa_ioc_mbox_isr(struct bfa_ioc_s *ioc)
    +{
    + struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;
    + struct bfi_mbmsg_s m;
    + int mc;
    +
    + bfa_ioc_msgget(ioc, &m);
    +
    + bfa_trc(ioc, ((u32 *)&m)[0]);
    +
    + /**
    + * Treat IOC message class as special.
    + */
    + mc = m.mh.msg_class;
    + if (mc == BFI_MC_IOC) {
    + bfa_ioc_isr(ioc, &m);
    + return;
    + }
    +
    + if ((mc > BFI_MC_MAX) || (mod->mbhdlr[mc].cbfn == NULL)) {
    + bfa_assert(0);
    + bfa_trc_stop(ioc->trcmod);
    + return;
    + }
    +
    + mod->mbhdlr[mc].cbfn(mod->mbhdlr[mc].cbarg, &m);
    +}
    +
    +#ifndef BFA_BIOS_BUILD
    +
    +
    +bfa_boolean_t
    +bfa_ioc_is_disabled(struct bfa_ioc_s *ioc)
    +{
    + return (bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabling) ||
    + bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled));
    +}
    +
    +#define bfa_ioc_state_disabled(__sm) \
    + (((__sm) == BFI_IOC_UNINIT) || \
    + ((__sm) == BFI_IOC_INITING) || \
    + ((__sm) == BFI_IOC_HWINIT) || \
    + ((__sm) == BFI_IOC_DISABLED) || \
    + ((__sm) == BFI_IOC_HBFAIL) || \
    + ((__sm) == BFI_IOC_CFG_DISABLED))
    +
    +/**
    + * Check if adapter is disabled -- both IOCs should be in a disabled
    + * state.
    + */
    +bfa_boolean_t
    +bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc)
    +{
    + u32 ioc_state;
    + bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva;
    +
    + if (!bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled))
    + return BFA_FALSE;
    +
    + ioc_state = bfa_reg_read(rb + BFA_IOC0_STATE_REG);
    + if (!bfa_ioc_state_disabled(ioc_state))
    + return BFA_FALSE;
    +
    + ioc_state = bfa_reg_read(rb + BFA_IOC1_STATE_REG);
    + if (!bfa_ioc_state_disabled(ioc_state))
    + return BFA_FALSE;
    +
    + return BFA_TRUE;
    +}
    +
    +/**
    + * Add to IOC heartbeat failure notification queue. To be used by common
    + * modules such as
    + */
    +void
    +bfa_ioc_hbfail_register(struct bfa_ioc_s *ioc,
    + struct bfa_ioc_hbfail_notify_s *notify)
    +{
    + list_add_tail(&notify->qe, &ioc->hb_notify_q);
    +}
    +
    +#define BFA_MFG_NAME "Brocade"
    +void
    +bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc,
    + struct bfa_adapter_attr_s *ad_attr)
    +{
    + struct bfi_ioc_attr_s *ioc_attr;
    + char model[BFA_ADAPTER_MODEL_NAME_LEN];
    +
    + ioc_attr = ioc->attr;
    + bfa_os_memcpy((void *)&ad_attr->serial_num,
    + (void *)ioc_attr->brcd_serialnum,
    + BFA_ADAPTER_SERIAL_NUM_LEN);
    +
    + bfa_os_memcpy(&ad_attr->fw_ver, ioc_attr->fw_version, BFA_VERSION_LEN);
    + bfa_os_memcpy(&ad_attr->optrom_ver, ioc_attr->optrom_version,
    + BFA_VERSION_LEN);
    + bfa_os_memcpy(&ad_attr->manufacturer, BFA_MFG_NAME,
    + BFA_ADAPTER_MFG_NAME_LEN);
    + bfa_os_memcpy(&ad_attr->vpd, &ioc_attr->vpd,
    + sizeof(struct bfa_mfg_vpd_s));
    +
    + ad_attr->nports = BFI_ADAPTER_GETP(NPORTS, ioc_attr->adapter_prop);
    + ad_attr->max_speed = BFI_ADAPTER_GETP(SPEED, ioc_attr->adapter_prop);
    +
    + /**
    + * model name
    + */
    + if (BFI_ADAPTER_GETP(SPEED, ioc_attr->adapter_prop) == 10) {
    + strcpy(model, "BR-10?0");
    + model[5] = '0' + ad_attr->nports;
    + } else {
    + strcpy(model, "Brocade-??5");
    + model[8] = '0' +
    + BFI_ADAPTER_GETP(SPEED,
    + ioc_attr->adapter_prop);
    + model[9] = '0' + ad_attr->nports;
    + }
    +
    + if (BFI_ADAPTER_IS_SPECIAL(ioc_attr->adapter_prop))
    + ad_attr->prototype = 1;
    + else
    + ad_attr->prototype = 0;
    +
    + bfa_os_memcpy(&ad_attr->model, model, BFA_ADAPTER_MODEL_NAME_LEN);
    + bfa_os_memcpy(&ad_attr->model_descr, &ad_attr->model,
    + BFA_ADAPTER_MODEL_NAME_LEN);
    +
    + ad_attr->pwwn = bfa_ioc_get_pwwn(ioc);
    + ad_attr->mac = bfa_ioc_get_mac(ioc);
    +
    + ad_attr->pcie_gen = ioc_attr->pcie_gen;
    + ad_attr->pcie_lanes = ioc_attr->pcie_lanes;
    + ad_attr->pcie_lanes_orig = ioc_attr->pcie_lanes_orig;
    + ad_attr->asic_rev = ioc_attr->asic_rev;
    + ad_attr->hw_ver[0] = 'R';
    + ad_attr->hw_ver[1] = 'e';
    + ad_attr->hw_ver[2] = 'v';
    + ad_attr->hw_ver[3] = '-';
    + ad_attr->hw_ver[4] = ioc_attr->asic_rev;
    + ad_attr->hw_ver[5] = '\0';
    +
    +}
    +
    +void
    +bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr)
    +{
    + bfa_os_memset((void *)ioc_attr, 0, sizeof(struct bfa_ioc_attr_s));
    +
    + ioc_attr->state = bfa_sm_to_state(ioc_sm_table, ioc->fsm);
    + ioc_attr->port_id = ioc->port_id;
    +
    + bfa_ioc_get_adapter_attr(ioc, &ioc_attr->adapter_attr);
    +
    + ioc_attr->pci_attr.chip_rev[0] = 'R';
    + ioc_attr->pci_attr.chip_rev[1] = 'e';
    + ioc_attr->pci_attr.chip_rev[2] = 'v';
    + ioc_attr->pci_attr.chip_rev[3] = '-';
    + ioc_attr->pci_attr.chip_rev[4] = ioc_attr->adapter_attr.asic_rev;
    + ioc_attr->pci_attr.chip_rev[5] = '\0';
    +}
    +
    +/**
    + * hal_wwn_public
    + */
    +wwn_t
    +bfa_ioc_get_pwwn(struct bfa_ioc_s *ioc)
    +{
    + union {
    + wwn_t wwn;
    + u8 byte[sizeof(wwn_t)];
    + } w;
    +
    + w.wwn = ioc->attr->mfg_wwn;
    +
    + if (bfa_ioc_portid(ioc) == 1)
    + w.byte[7]++;
    +
    + return w.wwn;
    +}
    +
    +wwn_t
    +bfa_ioc_get_nwwn(struct bfa_ioc_s *ioc)
    +{
    + union {
    + wwn_t wwn;
    + u8 byte[sizeof(wwn_t)];
    + } w;
    +
    + w.wwn = ioc->attr->mfg_wwn;
    +
    + if (bfa_ioc_portid(ioc) == 1)
    + w.byte[7]++;
    +
    + w.byte[0] = 0x20;
    +
    + return w.wwn;
    +}
    +
    +wwn_t
    +bfa_ioc_get_wwn_naa5(struct bfa_ioc_s *ioc, u16 inst)
    +{
    + union {
    + wwn_t wwn;
    + u8 byte[sizeof(wwn_t)];
    + } w, w5;
    +
    + bfa_trc(ioc, inst);
    +
    + w.wwn = ioc->attr->mfg_wwn;
    + w5.byte[0] = 0x50 | w.byte[2] >> 4;
    + w5.byte[1] = w.byte[2] << 4 | w.byte[3] >> 4;
    + w5.byte[2] = w.byte[3] << 4 | w.byte[4] >> 4;
    + w5.byte[3] = w.byte[4] << 4 | w.byte[5] >> 4;
    + w5.byte[4] = w.byte[5] << 4 | w.byte[6] >> 4;
    + w5.byte[5] = w.byte[6] << 4 | w.byte[7] >> 4;
    + w5.byte[6] = w.byte[7] << 4 | (inst & 0x0f00) >> 8;
    + w5.byte[7] = (inst & 0xff);
    +
    + return w5.wwn;
    +}
    +
    +u64
    +bfa_ioc_get_adid(struct bfa_ioc_s *ioc)
    +{
    + return ioc->attr->mfg_wwn;
    +}
    +
    +struct mac_s
    +bfa_ioc_get_mac(struct bfa_ioc_s *ioc)
    +{
    + struct mac_s mac;
    +
    + mac = ioc->attr->mfg_mac;
    + mac.mac[MAC_ADDRLEN - 1] += bfa_ioc_pcifn(ioc);
    +
    + return mac;
    +}
    +
    +void
    +bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc)
    +{
    + ioc->fcmode = BFA_TRUE;
    + ioc->port_id = bfa_ioc_pcifn(ioc);
    +}
    +
    +bfa_boolean_t
    +bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc)
    +{
    + return ioc->fcmode || (ioc->pcidev.device_id != BFA_PCI_DEVICE_ID_CT);
    +}
    +
    +/**
    + * Send AEN notification
    + */
    +static void
    +bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event)
    +{
    + union bfa_aen_data_u aen_data;
    + struct bfa_log_mod_s *logmod = ioc->logm;
    + s32 inst_num = 0;
    +
    + switch (event) {
    + case BFA_IOC_AEN_HBGOOD:
    + bfa_log(logmod, BFA_AEN_IOC_HBGOOD, inst_num);
    + break;
    + case BFA_IOC_AEN_HBFAIL:
    + bfa_log(logmod, BFA_AEN_IOC_HBFAIL, inst_num);
    + break;
    + case BFA_IOC_AEN_ENABLE:
    + bfa_log(logmod, BFA_AEN_IOC_ENABLE, inst_num);
    + break;
    + case BFA_IOC_AEN_DISABLE:
    + bfa_log(logmod, BFA_AEN_IOC_DISABLE, inst_num);
    + break;
    + default:
    + break;
    + }
    +
    + aen_data.ioc.pwwn = bfa_ioc_get_pwwn(ioc);
    + aen_data.ioc.mac = bfa_ioc_get_mac(ioc);
    +}
    +
    +/**
    + * Retrieve saved firmware trace from a prior IOC failure.
    + */
    +bfa_status_t
    +bfa_ioc_debug_fwsave(struct bfa_ioc_s *ioc, void *trcdata, int *trclen)
    +{
    + int tlen;
    +
    + if (ioc->dbg_fwsave_len == 0)
    + return BFA_STATUS_ENOFSAVE;
    +
    + tlen = *trclen;
    + if (tlen > ioc->dbg_fwsave_len)
    + tlen = ioc->dbg_fwsave_len;
    +
    + bfa_os_memcpy(trcdata, ioc->dbg_fwsave, tlen);
    + *trclen = tlen;
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * Retrieve saved firmware trace from a prior IOC failure.
    + */
    +bfa_status_t
    +bfa_ioc_debug_fwtrc(struct bfa_ioc_s *ioc, void *trcdata, int *trclen)
    +{
    + u32 pgnum;
    + u32 loff = BFA_DBG_FWTRC_OFF(bfa_ioc_portid(ioc));
    + int i, tlen;
    + u32 *tbuf = trcdata, r32;
    +
    + bfa_trc(ioc, *trclen);
    +
    + pgnum = bfa_ioc_smem_pgnum(ioc, loff);
    + loff = bfa_ioc_smem_pgoff(ioc, loff);
    + bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
    +
    + tlen = *trclen;
    + if (tlen > BFA_DBG_FWTRC_LEN)
    + tlen = BFA_DBG_FWTRC_LEN;
    + tlen /= sizeof(u32);
    +
    + bfa_trc(ioc, tlen);
    +
    + for (i = 0; i < tlen; i++) {
    + r32 = bfa_mem_read(ioc->ioc_regs.smem_page_start, loff);
    + tbuf[i] = bfa_os_ntohl(r32);
    + loff += sizeof(u32);
    +
    + /**
    + * handle page offset wrap around
    + */
    + loff = PSS_SMEM_PGOFF(loff);
    + if (loff == 0) {
    + pgnum++;
    + bfa_reg_write(ioc->ioc_regs.host_page_num_fn,
    + pgnum);
    + }
    + }
    + bfa_reg_write(ioc->ioc_regs.host_page_num_fn,
    + bfa_ioc_smem_pgnum(ioc, 0));
    + bfa_trc(ioc, pgnum);
    +
    + *trclen = tlen * sizeof(u32);
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * Save firmware trace if configured.
    + */
    +static void
    +bfa_ioc_debug_save(struct bfa_ioc_s *ioc)
    +{
    + int tlen;
    +
    + if (ioc->dbg_fwsave_len) {
    + tlen = ioc->dbg_fwsave_len;
    + bfa_ioc_debug_fwtrc(ioc, ioc->dbg_fwsave, &tlen);
    + }
    +}
    +
    +/**
    + * Firmware failure detected. Start recovery actions.
    + */
    +static void
    +bfa_ioc_recover(struct bfa_ioc_s *ioc)
    +{
    + bfa_ioc_stats(ioc, ioc_hbfails);
    + bfa_ioc_debug_save(ioc);
    + bfa_fsm_send_event(ioc, IOC_E_HBFAIL);
    +}
    +#else
    +static void
    +bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event)
    +{ }
    +
    +static void
    +bfa_ioc_recover(struct bfa_ioc_s *ioc)
    +{ }
    +#endif
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_ioc.h patch/drivers/scsi/bfa/bfa_ioc.h
    --- orig/drivers/scsi/bfa/bfa_ioc.h 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_ioc.h 2009-04-01 20:08:47.229401000 -0700
    @@ -0,0 +1,249 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#ifndef __BFA_IOC_H__
    +#define __BFA_IOC_H__
    +
    +#include <cs/bfa_sm.h>
    +#include <bfi/bfi.h>
    +#include <bfi/bfi_ioc.h>
    +#include <bfi/bfi_boot.h>
    +#include <bfa_timer.h>
    +
    +/**
    + * PCI device information required by IOC
    + */
    +struct bfa_pcidev_s {
    + int pci_slot;
    + u8 pci_func;
    + u16 device_id;
    + bfa_os_addr_t pci_bar_kva;
    +};
    +
    +/**
    + * Structure used to remember the DMA-able memory block's KVA and Physical
    + * Address
    + */
    +struct bfa_dma_s {
    + void *kva; /*! Kernel virtual address */
    + u64 pa; /*! Physical address */
    +};
    +
    +#define BFA_DMA_ALIGN_SZ 256
    +#define BFA_ROUNDUP(_l, _s) (((_l) + ((_s) - 1)) & ~((_s) - 1))
    +
    +
    +
    +#define bfa_dma_addr_set(dma_addr, pa) \
    + __bfa_dma_addr_set(&dma_addr, (u64)pa)
    +
    +static inline void
    +__bfa_dma_addr_set(union bfi_addr_u *dma_addr, u64 pa)
    +{
    + dma_addr->a32.addr_lo = (u32) pa;
    + dma_addr->a32.addr_hi = (u32) (bfa_os_u32(pa));
    +}
    +
    +
    +#define bfa_dma_be_addr_set(dma_addr, pa) \
    + __bfa_dma_be_addr_set(&dma_addr, (u64)pa)
    +static inline void
    +__bfa_dma_be_addr_set(union bfi_addr_u *dma_addr, u64 pa)
    +{
    + dma_addr->a32.addr_lo = (u32) bfa_os_htonl(pa);
    + dma_addr->a32.addr_hi = (u32) bfa_os_htonl(bfa_os_u32(pa));
    +}
    +
    +struct bfa_ioc_regs_s {
    + bfa_os_addr_t hfn_mbox_cmd;
    + bfa_os_addr_t hfn_mbox;
    + bfa_os_addr_t lpu_mbox_cmd;
    + bfa_os_addr_t lpu_mbox;
    + bfa_os_addr_t pss_ctl_reg;
    + bfa_os_addr_t app_pll_fast_ctl_reg;
    + bfa_os_addr_t app_pll_slow_ctl_reg;
    + bfa_os_addr_t host_sem0_reg;
    + bfa_os_addr_t host_sem1_reg;
    + bfa_os_addr_t host_sem2_reg;
    + bfa_os_addr_t host_sem3_reg;
    + bfa_os_addr_t host_page_num_fn;
    + bfa_os_addr_t heartbeat;
    + bfa_os_addr_t ioc_fwstate;
    + bfa_os_addr_t smem_page_start;
    + u32 smem_pg0;
    +};
    +
    +#define bfa_reg_read(_raddr) bfa_os_reg_read(_raddr)
    +#define bfa_reg_write(_raddr, _val) bfa_os_reg_write(_raddr, _val)
    +#define bfa_mem_read(_raddr, _off) bfa_os_mem_read(_raddr, _off)
    +#define bfa_mem_write(_raddr, _off, _val) \
    + bfa_os_mem_write(_raddr, _off, _val)
    +/**
    + * IOC Mailbox structures
    + */
    +struct bfa_mbox_cmd_s {
    + struct list_head qe;
    + u32 msg[BFI_IOC_MSGSZ];
    +};
    +
    +/**
    + * IOC mailbox module
    + */
    +typedef void (*bfa_ioc_mbox_mcfunc_t)(void *cbarg, struct bfi_mbmsg_s *m);
    +struct bfa_ioc_mbox_mod_s {
    + struct list_head cmd_q; /* pending mbox queue */
    + int nmclass;/* number of handlers */
    + struct {
    + bfa_ioc_mbox_mcfunc_t cbfn; /* message handlers */
    + void *cbarg;
    + } mbhdlr[BFI_MC_MAX];
    +};
    +
    +/**
    + * IOC callback function interfaces
    + */
    +typedef void (*bfa_ioc_enable_cbfn_t)(void *bfa, enum bfa_status status);
    +typedef void (*bfa_ioc_disable_cbfn_t)(void *bfa);
    +typedef void (*bfa_ioc_hbfail_cbfn_t)(void *bfa);
    +typedef void (*bfa_ioc_reset_cbfn_t)(void *bfa);
    +struct bfa_ioc_cbfn_s {
    + bfa_ioc_enable_cbfn_t enable_cbfn;
    + bfa_ioc_disable_cbfn_t disable_cbfn;
    + bfa_ioc_hbfail_cbfn_t hbfail_cbfn;
    + bfa_ioc_reset_cbfn_t reset_cbfn;
    +};
    +
    +/**
    + * Heartbeat failure notification queue element.
    + */
    +struct bfa_ioc_hbfail_notify_s {
    + struct list_head qe;
    + bfa_ioc_hbfail_cbfn_t cbfn;
    + void *cbarg;
    +};
    +
    +/**
    + * Initialize a heartbeat failure notification structure
    + */
    +#define bfa_ioc_hbfail_init(__notify, __cbfn, __cbarg) do { \
    + (__notify)->cbfn = (__cbfn); \
    + (__notify)->cbarg = (__cbarg); \
    +} while (0)
    +
    +struct bfa_ioc_s {
    + bfa_fsm_t fsm;
    + struct bfa_s *bfa;
    + struct bfa_pcidev_s pcidev;
    + struct bfa_timer_mod_s *timer_mod;
    + struct bfa_timer_s ioc_timer;
    + struct bfa_timer_s sem_timer;
    + u32 hb_count;
    + u32 hb_fail;
    + u32 hwinit_count;
    + struct list_head hb_notify_q;
    + void *dbg_fwsave;
    + int dbg_fwsave_len;
    + enum bfi_mclass ioc_mc;
    + struct bfa_ioc_regs_s ioc_regs;
    + struct bfa_trc_mod_s *trcmod;
    + struct bfa_aen_s *aen;
    + struct bfa_log_mod_s *logm;
    + struct bfa_ioc_drv_stats_s stats;
    + bfa_boolean_t auto_recover;
    + bfa_boolean_t fcmode;
    + bfa_boolean_t pllinit;
    + u8 port_id;
    +
    + struct bfa_dma_s attr_dma;
    + struct bfi_ioc_attr_s *attr;
    + struct bfa_ioc_cbfn_s *cbfn;
    + struct bfa_ioc_mbox_mod_s mbox_mod;
    +};
    +
    +#define bfa_ioc_pcifn(__ioc) (__ioc)->pcidev.pci_func
    +#define bfa_ioc_devid(__ioc) (__ioc)->pcidev.device_id
    +#define bfa_ioc_bar0(__ioc) (__ioc)->pcidev.pci_bar_kva
    +#define bfa_ioc_portid(__ioc) ((__ioc)->port_id)
    +#define bfa_ioc_fetch_stats(__ioc, __stats) \
    + ((__stats)->drv_stats) = (__ioc)->stats
    +#define bfa_ioc_clr_stats(__ioc) \
    + bfa_os_memset(&(__ioc)->stats, 0, sizeof((__ioc)->stats))
    +#define bfa_ioc_maxfrsize(__ioc) (__ioc)->attr->maxfrsize
    +#define bfa_ioc_rx_bbcredit(__ioc) (__ioc)->attr->rx_bbcredit
    +#define bfa_ioc_speed_sup(__ioc) \
    + BFI_ADAPTER_GETP(SPEED, (__ioc)->attr->adapter_prop)
    +
    +/**
    + * IOC mailbox interface
    + */
    +void bfa_ioc_mbox_queue(struct bfa_ioc_s *ioc, struct bfa_mbox_cmd_s *cmd);
    +void bfa_ioc_mbox_register(struct bfa_ioc_s *ioc,
    + bfa_ioc_mbox_mcfunc_t *mcfuncs);
    +void bfa_ioc_mbox_isr(struct bfa_ioc_s *ioc);
    +void bfa_ioc_mbox_send(struct bfa_ioc_s *ioc, void *ioc_msg, int len);
    +void bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg);
    +void bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc,
    + bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg);
    +
    +/**
    + * IOC interfaces
    + */
    +void bfa_ioc_attach(struct bfa_ioc_s *ioc, void *bfa,
    + struct bfa_ioc_cbfn_s *cbfn, struct bfa_timer_mod_s *timer_mod,
    + struct bfa_trc_mod_s *trcmod,
    + struct bfa_aen_s *aen, struct bfa_log_mod_s *logm);
    +void bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev,
    + enum bfi_mclass mc);
    +u32 bfa_ioc_meminfo(void);
    +void bfa_ioc_mem_claim(struct bfa_ioc_s *ioc, u8 *dm_kva, u64 dm_pa);
    +bfa_status_t bfa_ioc_enable(struct bfa_ioc_s *ioc);
    +void bfa_ioc_disable(struct bfa_ioc_s *ioc);
    +
    +void bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_param);
    +void bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *msg);
    +bfa_status_t bfa_ioc_pll_init(struct bfa_ioc_s *ioc);
    +bfa_boolean_t bfa_ioc_is_operational(struct bfa_ioc_s *ioc);
    +bfa_boolean_t bfa_ioc_is_disabled(struct bfa_ioc_s *ioc);
    +bfa_boolean_t bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc);
    +void bfa_ioc_cfg_complete(struct bfa_ioc_s *ioc);
    +void bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr);
    +void bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc,
    + struct bfa_adapter_attr_s *ad_attr);
    +int bfa_ioc_debug_trcsz(bfa_boolean_t auto_recover);
    +void bfa_ioc_debug_memclaim(struct bfa_ioc_s *ioc, void *dbg_fwsave);
    +bfa_status_t bfa_ioc_debug_fwsave(struct bfa_ioc_s *ioc, void *trcdata,
    + int *trclen);
    +bfa_status_t bfa_ioc_debug_fwtrc(struct bfa_ioc_s *ioc, void *trcdata,
    + int *trclen);
    +u32 bfa_ioc_smem_pgnum(struct bfa_ioc_s *ioc, u32 fmaddr);
    +u32 bfa_ioc_smem_pgoff(struct bfa_ioc_s *ioc, u32 fmaddr);
    +void bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc);
    +bfa_boolean_t bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc);
    +void bfa_ioc_hbfail_register(struct bfa_ioc_s *ioc,
    + struct bfa_ioc_hbfail_notify_s *notify);
    +
    +/*
    + * bfa mfg wwn API functions
    + */
    +wwn_t bfa_ioc_get_pwwn(struct bfa_ioc_s *ioc);
    +wwn_t bfa_ioc_get_nwwn(struct bfa_ioc_s *ioc);
    +wwn_t bfa_ioc_get_wwn_naa5(struct bfa_ioc_s *ioc, u16 inst);
    +struct mac_s bfa_ioc_get_mac(struct bfa_ioc_s *ioc);
    +u64 bfa_ioc_get_adid(struct bfa_ioc_s *ioc);
    +
    +#endif /* __BFA_IOC_H__ */
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_iocfc.c patch/drivers/scsi/bfa/bfa_iocfc.c
    --- orig/drivers/scsi/bfa/bfa_iocfc.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_iocfc.c 2009-04-01 20:08:47.237352000 -0700
    @@ -0,0 +1,832 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#include <cs/bfa_debug.h>
    +#include <bfa_priv.h>
    +#include <log/bfa_log_hal.h>
    +#include <bfi/bfi_boot.h>
    +#include <bfi/bfi_cbreg.h>
    +#include <aen/bfa_aen_ioc.h>
    +#include <defs/bfa_defs_iocfc.h>
    +#include <defs/bfa_defs_pci.h>
    +#include "bfa_callback_priv.h"
    +
    +BFA_TRC_FILE(HAL, IOCFC);
    +
    +/**
    + * IOC local definitions
    + */
    +#define BFA_IOCFC_TOV 5000 /* msecs */
    +
    +enum {
    + BFA_IOCFC_ACT_NONE = 0,
    + BFA_IOCFC_ACT_INIT = 1,
    + BFA_IOCFC_ACT_STOP = 2,
    + BFA_IOCFC_ACT_DISABLE = 3,
    +};
    +
    +/*
    + * forward declarations
    + */
    +static void bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status);
    +static void bfa_iocfc_disable_cbfn(void *bfa_arg);
    +static void bfa_iocfc_hbfail_cbfn(void *bfa_arg);
    +static void bfa_iocfc_reset_cbfn(void *bfa_arg);
    +static void bfa_iocfc_stats_clear(void *bfa_arg);
    +static void bfa_iocfc_stats_swap(struct bfa_fw_stats_s *d,
    + struct bfa_fw_stats_s *s);
    +static void bfa_iocfc_stats_clr_cb(void *bfa_arg, bfa_boolean_t complete);
    +static void bfa_iocfc_stats_clr_timeout(void *bfa_arg);
    +static void bfa_iocfc_stats_cb(void *bfa_arg, bfa_boolean_t complete);
    +static void bfa_iocfc_stats_timeout(void *bfa_arg);
    +
    +static struct bfa_ioc_cbfn_s bfa_iocfc_cbfn;
    +
    +/**
    + * hal_ioc_pvt BFA IOC private functions
    + */
    +
    +static void
    +bfa_iocfc_cqs_sz(struct bfa_iocfc_cfg_s *cfg, u32 *dm_len)
    +{
    + int i, per_reqq_sz, per_rspq_sz;
    +
    + per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ),
    + BFA_DMA_ALIGN_SZ);
    + per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ),
    + BFA_DMA_ALIGN_SZ);
    +
    + /*
    + * Calculate CQ size
    + */
    + for (i = 0; i < cfg->fwcfg.num_cqs; i++) {
    + *dm_len = *dm_len + per_reqq_sz;
    + *dm_len = *dm_len + per_rspq_sz;
    + }
    +
    + /*
    + * Calculate Shadow CI/PI size
    + */
    + for (i = 0; i < cfg->fwcfg.num_cqs; i++)
    + *dm_len += (2 * BFA_CACHELINE_SZ);
    +}
    +
    +static void
    +bfa_iocfc_fw_cfg_sz(struct bfa_iocfc_cfg_s *cfg, u32 *dm_len)
    +{
    + *dm_len +=
    + BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ);
    + *dm_len +=
    + BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s),
    + BFA_CACHELINE_SZ);
    + *dm_len += BFA_ROUNDUP(sizeof(struct bfa_fw_stats_s), BFA_CACHELINE_SZ);
    +}
    +
    +/**
    + * Use the Mailbox interface to send BFI_IOCFC_H2I_CFG_REQ
    + */
    +static void
    +bfa_iocfc_send_cfg(void *bfa_arg)
    +{
    + struct bfa_s *bfa = bfa_arg;
    + struct bfa_iocfc_s *iocfc = &bfa->iocfc;
    + struct bfi_iocfc_cfg_req_s cfg_req;
    + struct bfi_iocfc_cfg_s *cfg_info = iocfc->cfginfo;
    + struct bfa_iocfc_cfg_s *cfg = &iocfc->cfg;
    + int i;
    +
    + bfa_assert(cfg->fwcfg.num_cqs <= BFI_IOC_MAX_CQS);
    + bfa_trc(bfa, cfg->fwcfg.num_cqs);
    +
    + iocfc->cfgdone = BFA_FALSE;
    +
    + /**
    + * initialize IOC configuration info
    + */
    + cfg_info->endian_sig = BFI_IOC_ENDIAN_SIG;
    + cfg_info->num_cqs = cfg->fwcfg.num_cqs;
    +
    + cfg_info->rport_del_tov = cfg->drvcfg.rport_del_tov;
    + cfg_info->fw_disc_enabled = cfg->drvcfg.fw_disc_enabled;
    + cfg_info->bport_role = cfg->drvcfg.bport_role;
    + strncpy(cfg_info->bport_sym_name, bfa_sym_name(bfa),
    + BFA_SYMNAME_MAXLEN);
    +
    + bfa_dma_be_addr_set(cfg_info->cfgrsp_addr, iocfc->cfgrsp_dma.pa);
    + bfa_dma_be_addr_set(cfg_info->stats_addr, iocfc->stats_pa);
    +
    + /**
    + * dma map REQ and RSP circular queues and shadow pointers
    + */
    + for (i = 0; i < cfg->fwcfg.num_cqs; i++) {
    + bfa_dma_be_addr_set(cfg_info->req_cq_ba[i],
    + iocfc->req_cq_ba[i].pa);
    + bfa_dma_be_addr_set(cfg_info->req_shadow_ci[i],
    + iocfc->req_cq_shadow_ci[i].pa);
    + cfg_info->req_cq_elems[i] =
    + bfa_os_htons(cfg->drvcfg.num_reqq_elems);
    +
    + bfa_dma_be_addr_set(cfg_info->rsp_cq_ba[i],
    + iocfc->rsp_cq_ba[i].pa);
    + bfa_dma_be_addr_set(cfg_info->rsp_shadow_pi[i],
    + iocfc->rsp_cq_shadow_pi[i].pa);
    + cfg_info->rsp_cq_elems[i] =
    + bfa_os_htons(cfg->drvcfg.num_rspq_elems);
    + }
    +
    + /**
    + * dma map IOC configuration itself
    + */
    + bfi_h2i_set(cfg_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_CFG_REQ,
    + bfa_lpuid(bfa));
    + bfa_dma_be_addr_set(cfg_req.ioc_cfg_dma_addr, iocfc->cfg_info.pa);
    +
    + bfa_ioc_mbox_send(&bfa->ioc, &cfg_req,
    + sizeof(struct bfi_iocfc_cfg_req_s));
    +}
    +
    +static void
    +bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
    + struct bfa_pcidev_s *pcidev)
    +{
    + struct bfa_iocfc_s *iocfc = &bfa->iocfc;
    +
    + bfa->bfad = bfad;
    + iocfc->bfa = bfa;
    + iocfc->action = BFA_IOCFC_ACT_NONE;
    +
    + iocfc->cfg = *cfg;
    +
    + /**
    + * Initialize chip specific handlers.
    + */
    + if (bfa_ioc_devid(&bfa->ioc) == BFA_PCI_DEVICE_ID_CT) {
    + iocfc->hwif.hw_reginit = bfa_hwct_reginit;
    + iocfc->hwif.hw_rspq_ack = bfa_hwct_rspq_ack;
    + } else {
    + iocfc->hwif.hw_reginit = bfa_hwcb_reginit;
    + iocfc->hwif.hw_rspq_ack = bfa_hwcb_rspq_ack;
    + }
    +
    + iocfc->hwif.hw_reginit(bfa);
    +}
    +
    +static void
    +bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg,
    + struct bfa_meminfo_s *meminfo)
    +{
    + u8 *dm_kva;
    + u64 dm_pa;
    + int i, per_reqq_sz, per_rspq_sz;
    + struct bfa_iocfc_s *iocfc = &bfa->iocfc;
    + int dbgsz;
    +
    + dm_kva = bfa_meminfo_dma_virt(meminfo);
    + dm_pa = bfa_meminfo_dma_phys(meminfo);
    +
    + /*
    + * First allocate dma memory for IOC.
    + */
    + bfa_ioc_mem_claim(&bfa->ioc, dm_kva, dm_pa);
    + dm_kva += bfa_ioc_meminfo();
    + dm_pa += bfa_ioc_meminfo();
    +
    + /*
    + * Claim DMA-able memory for the request/response queues and for shadow
    + * ci/pi registers
    + */
    + per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ),
    + BFA_DMA_ALIGN_SZ);
    + per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ),
    + BFA_DMA_ALIGN_SZ);
    +
    + for (i = 0; i < cfg->fwcfg.num_cqs; i++) {
    + iocfc->req_cq_ba[i].kva = dm_kva;
    + iocfc->req_cq_ba[i].pa = dm_pa;
    + bfa_os_memset(dm_kva, 0, per_reqq_sz);
    + dm_kva += per_reqq_sz;
    + dm_pa += per_reqq_sz;
    +
    + iocfc->rsp_cq_ba[i].kva = dm_kva;
    + iocfc->rsp_cq_ba[i].pa = dm_pa;
    + bfa_os_memset(dm_kva, 0, per_rspq_sz);
    + dm_kva += per_rspq_sz;
    + dm_pa += per_rspq_sz;
    + }
    +
    + for (i = 0; i < cfg->fwcfg.num_cqs; i++) {
    + iocfc->req_cq_shadow_ci[i].kva = dm_kva;
    + iocfc->req_cq_shadow_ci[i].pa = dm_pa;
    + dm_kva += BFA_CACHELINE_SZ;
    + dm_pa += BFA_CACHELINE_SZ;
    +
    + iocfc->rsp_cq_shadow_pi[i].kva = dm_kva;
    + iocfc->rsp_cq_shadow_pi[i].pa = dm_pa;
    + dm_kva += BFA_CACHELINE_SZ;
    + dm_pa += BFA_CACHELINE_SZ;
    + }
    +
    + /*
    + * Claim DMA-able memory for the config info page
    + */
    + bfa->iocfc.cfg_info.kva = dm_kva;
    + bfa->iocfc.cfg_info.pa = dm_pa;
    + bfa->iocfc.cfginfo = (struct bfi_iocfc_cfg_s *) dm_kva;
    + dm_kva += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ);
    + dm_pa += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ);
    +
    + /*
    + * Claim DMA-able memory for the config response
    + */
    + bfa->iocfc.cfgrsp_dma.kva = dm_kva;
    + bfa->iocfc.cfgrsp_dma.pa = dm_pa;
    + bfa->iocfc.cfgrsp = (struct bfi_iocfc_cfgrsp_s *) dm_kva;
    +
    + dm_kva +=
    + BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s),
    + BFA_CACHELINE_SZ);
    + dm_pa += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s),
    + BFA_CACHELINE_SZ);
    +
    + /*
    + * Claim DMA-able memory for iocfc stats
    + */
    + bfa->iocfc.stats_kva = dm_kva;
    + bfa->iocfc.stats_pa = dm_pa;
    + bfa->iocfc.fw_stats = (struct bfa_fw_stats_s *) dm_kva;
    + dm_kva += BFA_ROUNDUP(sizeof(struct bfa_fw_stats_s), BFA_CACHELINE_SZ);
    + dm_pa += BFA_ROUNDUP(sizeof(struct bfa_fw_stats_s), BFA_CACHELINE_SZ);
    +
    + bfa_meminfo_dma_virt(meminfo) = dm_kva;
    + bfa_meminfo_dma_phys(meminfo) = dm_pa;
    +
    + dbgsz = bfa_ioc_debug_trcsz(bfa_auto_recover);
    + if (dbgsz > 0) {
    + bfa_ioc_debug_memclaim(&bfa->ioc, bfa_meminfo_kva(meminfo));
    + bfa_meminfo_kva(meminfo) += dbgsz;
    + }
    +}
    +
    +/**
    + * BFA submodules initialization completion notification.
    + */
    +static void
    +bfa_iocfc_initdone_submod(struct bfa_s *bfa)
    +{
    + int i;
    +
    + for (i = 0; hal_mods[i]; i++)
    + hal_mods[i]->initdone(bfa);
    +}
    +
    +/**
    + * Start BFA submodules.
    + */
    +static void
    +bfa_iocfc_start_submod(struct bfa_s *bfa)
    +{
    + int i;
    +
    + for (i = 0; hal_mods[i]; i++)
    + hal_mods[i]->start(bfa);
    +}
    +
    +/**
    + * Disable BFA submodules.
    + */
    +static void
    +bfa_iocfc_disable_submod(struct bfa_s *bfa)
    +{
    + int i;
    +
    + for (i = 0; hal_mods[i]; i++)
    + hal_mods[i]->iocdisable(bfa);
    +}
    +
    +static void
    +bfa_iocfc_init_cb(void *bfa_arg, bfa_boolean_t complete)
    +{
    + struct bfa_s *bfa = bfa_arg;
    +
    + if (complete) {
    + if (bfa->iocfc.cfgdone)
    + bfa_cb_init(bfa->bfad, BFA_STATUS_OK);
    + else
    + bfa_cb_init(bfa->bfad, BFA_STATUS_FAILED);
    + } else
    + bfa->iocfc.action = BFA_IOCFC_ACT_NONE;
    +}
    +
    +static void
    +bfa_iocfc_stop_cb(void *bfa_arg, bfa_boolean_t complete)
    +{
    + struct bfa_s *bfa = bfa_arg;
    +
    + if (complete)
    + bfa_cb_stop(bfa->bfad, BFA_STATUS_OK);
    + else
    + bfa->iocfc.action = BFA_IOCFC_ACT_NONE;
    +}
    +
    +static void
    +bfa_iocfc_disable_cb(void *bfa_arg, bfa_boolean_t complete)
    +{
    + struct bfa_s *bfa = bfa_arg;
    +
    + if (complete)
    + bfa_cb_ioc_disable(bfa->bfad);
    +}
    +
    +/**
    + * Update BFA configuration from firmware configuration.
    + */
    +static void
    +bfa_iocfc_cfgrsp(struct bfa_s *bfa)
    +{
    + struct bfa_iocfc_s *iocfc = &bfa->iocfc;
    + struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp;
    + struct bfa_iocfc_fwcfg_s *fwcfg = &cfgrsp->fwcfg;
    + struct bfi_iocfc_cfg_s *cfginfo = iocfc->cfginfo;
    +
    + fwcfg->num_cqs = fwcfg->num_cqs;
    + fwcfg->num_ioim_reqs = bfa_os_ntohs(fwcfg->num_ioim_reqs);
    + fwcfg->num_tskim_reqs = bfa_os_ntohs(fwcfg->num_tskim_reqs);
    + fwcfg->num_fcxp_reqs = bfa_os_ntohs(fwcfg->num_fcxp_reqs);
    + fwcfg->num_uf_bufs = bfa_os_ntohs(fwcfg->num_uf_bufs);
    + fwcfg->num_rports = bfa_os_ntohs(fwcfg->num_rports);
    +
    + cfginfo->intr_attr.coalesce = cfgrsp->intr_attr.coalesce;
    + cfginfo->intr_attr.delay = bfa_os_ntohs(cfgrsp->intr_attr.delay);
    + cfginfo->intr_attr.latency = bfa_os_ntohs(cfgrsp->intr_attr.latency);
    +
    + iocfc->cfgdone = BFA_TRUE;
    +
    + /**
    + * Configuration is complete - initialize/start submodules
    + */
    + if (iocfc->action == BFA_IOCFC_ACT_INIT)
    + bfa_cb_queue(bfa, &iocfc->init_hcb_qe, bfa_iocfc_init_cb, bfa);
    + else
    + bfa_iocfc_start_submod(bfa);
    +}
    +
    +static void
    +bfa_iocfc_stats_clear(void *bfa_arg)
    +{
    + struct bfa_s *bfa = bfa_arg;
    + struct bfa_iocfc_s *iocfc = &bfa->iocfc;
    + struct bfi_iocfc_stats_req_s stats_req;
    +
    + bfa_timer_start(bfa, &iocfc->stats_timer,
    + bfa_iocfc_stats_clr_timeout, bfa,
    + BFA_IOCFC_TOV);
    +
    + bfi_h2i_set(stats_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_CLEAR_STATS_REQ,
    + bfa_lpuid(bfa));
    + bfa_ioc_mbox_send(&bfa->ioc, &stats_req,
    + sizeof(struct bfi_iocfc_stats_req_s));
    +}
    +
    +static void
    +bfa_iocfc_stats_swap(struct bfa_fw_stats_s *d, struct bfa_fw_stats_s *s)
    +{
    + u32 *dip = (u32 *) d;
    + u32 *sip = (u32 *) s;
    + int i;
    +
    + for (i = 0; i < (sizeof(struct bfa_fw_stats_s) / sizeof(u32)); i++)
    + dip[i] = bfa_os_ntohl(sip[i]);
    +}
    +
    +static void
    +bfa_iocfc_stats_clr_cb(void *bfa_arg, bfa_boolean_t complete)
    +{
    + struct bfa_s *bfa = bfa_arg;
    + struct bfa_iocfc_s *iocfc = &bfa->iocfc;
    +
    + if (complete) {
    + bfa_ioc_clr_stats(&bfa->ioc);
    + iocfc->stats_cbfn(iocfc->stats_cbarg, iocfc->stats_status);
    + } else {
    + iocfc->stats_busy = BFA_FALSE;
    + iocfc->stats_status = BFA_STATUS_OK;
    + }
    +}
    +
    +static void
    +bfa_iocfc_stats_clr_timeout(void *bfa_arg)
    +{
    + struct bfa_s *bfa = bfa_arg;
    + struct bfa_iocfc_s *iocfc = &bfa->iocfc;
    +
    + bfa_trc(bfa, 0);
    +
    + iocfc->stats_status = BFA_STATUS_ETIMER;
    + bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, bfa_iocfc_stats_clr_cb, bfa);
    +}
    +
    +static void
    +bfa_iocfc_stats_cb(void *bfa_arg, bfa_boolean_t complete)
    +{
    + struct bfa_s *bfa = bfa_arg;
    + struct bfa_iocfc_s *iocfc = &bfa->iocfc;
    +
    + if (complete) {
    + if (iocfc->stats_status == BFA_STATUS_OK) {
    + bfa_os_memset(iocfc->stats_ret, 0,
    + sizeof(*iocfc->stats_ret));
    + bfa_iocfc_stats_swap(&iocfc->stats_ret->fw_stats,
    + iocfc->fw_stats);
    + }
    + iocfc->stats_cbfn(iocfc->stats_cbarg, iocfc->stats_status);
    + } else {
    + iocfc->stats_busy = BFA_FALSE;
    + iocfc->stats_status = BFA_STATUS_OK;
    + }
    +}
    +
    +static void
    +bfa_iocfc_stats_timeout(void *bfa_arg)
    +{
    + struct bfa_s *bfa = bfa_arg;
    + struct bfa_iocfc_s *iocfc = &bfa->iocfc;
    +
    + bfa_trc(bfa, 0);
    +
    + iocfc->stats_status = BFA_STATUS_ETIMER;
    + bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, bfa_iocfc_stats_cb, bfa);
    +}
    +
    +static void
    +bfa_iocfc_stats_query(struct bfa_s *bfa)
    +{
    + struct bfa_iocfc_s *iocfc = &bfa->iocfc;
    + struct bfi_iocfc_stats_req_s stats_req;
    +
    + bfa_timer_start(bfa, &iocfc->stats_timer,
    + bfa_iocfc_stats_timeout, bfa, BFA_IOCFC_TOV);
    +
    + bfi_h2i_set(stats_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_GET_STATS_REQ,
    + bfa_lpuid(bfa));
    + bfa_ioc_mbox_send(&bfa->ioc, &stats_req,
    + sizeof(struct bfi_iocfc_stats_req_s));
    +}
    +
    +static void
    +bfa_iocfc_reset_queues(struct bfa_s *bfa)
    +{
    + int q;
    +
    + for (q = 0; q < BFI_IOC_MAX_CQS; q++) {
    + bfa_rspq_ci(bfa, q) = 0;
    + bfa_reqq_pi(bfa, q) = 0;
    + }
    +}
    +
    +/**
    + * IOC enable request is complete
    + */
    +static void
    +bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status)
    +{
    + struct bfa_s *bfa = bfa_arg;
    +
    + if ((status != BFA_STATUS_OK) &&
    + (bfa->iocfc.action == BFA_IOCFC_ACT_INIT)) {
    + bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe, bfa_iocfc_init_cb,
    + bfa);
    + return;
    + }
    +
    + bfa_iocfc_initdone_submod(bfa);
    + bfa_iocfc_send_cfg(bfa);
    +}
    +
    +/**
    + * IOC disable request is complete
    + */
    +static void
    +bfa_iocfc_disable_cbfn(void *bfa_arg)
    +{
    + struct bfa_s *bfa = bfa_arg;
    +
    + bfa_isr_disable(bfa);
    + bfa_iocfc_disable_submod(bfa);
    +
    + if (bfa->iocfc.action == BFA_IOCFC_ACT_STOP)
    + bfa_cb_queue(bfa, &bfa->iocfc.stop_hcb_qe, bfa_iocfc_stop_cb,
    + bfa);
    + else {
    + bfa_assert(bfa->iocfc.action == BFA_IOCFC_ACT_DISABLE);
    + bfa_cb_queue(bfa, &bfa->iocfc.dis_hcb_qe, bfa_iocfc_disable_cb,
    + bfa);
    + }
    +}
    +
    +/**
    + * Notify sub-modules of hardware failure.
    + */
    +static void
    +bfa_iocfc_hbfail_cbfn(void *bfa_arg)
    +{
    + struct bfa_s *bfa = bfa_arg;
    +
    + bfa_iocfc_disable_submod(bfa);
    +
    + if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT)
    + bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe, bfa_iocfc_init_cb,
    + bfa);
    +}
    +
    +/**
    + * Actions on chip-reset completion.
    + */
    +static void
    +bfa_iocfc_reset_cbfn(void *bfa_arg)
    +{
    + struct bfa_s *bfa = bfa_arg;
    +
    + bfa_iocfc_reset_queues(bfa);
    + bfa_isr_enable(bfa);
    +}
    +
    +
    +
    +/**
    + * hal_ioc_public
    + */
    +
    +void
    +bfa_iocfc_set_snsbase(struct bfa_s *bfa, u64 snsbase_pa)
    +{
    + struct bfa_iocfc_s *iocfc = &bfa->iocfc;
    +
    + iocfc->cfginfo->sense_buf_len = (BFI_IOIM_SNSLEN - 1);
    + bfa_dma_be_addr_set(iocfc->cfginfo->ioim_snsbase, snsbase_pa);
    +}
    +
    +bfa_status_t
    +bfa_iocfc_get_stats(struct bfa_s *bfa, struct bfa_iocfc_stats_s *stats,
    + bfa_cb_ioc_t cbfn, void *cbarg)
    +{
    + struct bfa_iocfc_s *iocfc = &bfa->iocfc;
    +
    + if (iocfc->stats_busy) {
    + bfa_trc(bfa, iocfc->stats_busy);
    + return (BFA_STATUS_DEVBUSY);
    + }
    +
    + iocfc->stats_busy = BFA_TRUE;
    + iocfc->stats_ret = stats;
    + iocfc->stats_cbfn = cbfn;
    + iocfc->stats_cbarg = cbarg;
    +
    + bfa_iocfc_stats_query(bfa);
    +
    + return (BFA_STATUS_OK);
    +}
    +
    +bfa_status_t
    +bfa_iocfc_clear_stats(struct bfa_s *bfa, bfa_cb_ioc_t cbfn, void *cbarg)
    +{
    + struct bfa_iocfc_s *iocfc = &bfa->iocfc;
    +
    + if (iocfc->stats_busy) {
    + bfa_trc(bfa, iocfc->stats_busy);
    + return (BFA_STATUS_DEVBUSY);
    + }
    +
    + iocfc->stats_busy = BFA_TRUE;
    + iocfc->stats_cbfn = cbfn;
    + iocfc->stats_cbarg = cbarg;
    +
    + bfa_iocfc_stats_clear(bfa);
    + return (BFA_STATUS_OK);
    +}
    +
    +/**
    + * Query IOC memory requirement information.
    + */
    +void
    +bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
    + u32 *dm_len)
    +{
    + bfa_iocfc_fw_cfg_sz(cfg, dm_len);
    + bfa_iocfc_cqs_sz(cfg, dm_len);
    + *km_len += bfa_ioc_debug_trcsz(bfa_auto_recover);
    +}
    +
    +/**
    + * Query IOC memory requirement information.
    + */
    +void
    +bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
    + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
    +{
    + int i;
    +
    + bfa_iocfc_cbfn.enable_cbfn = bfa_iocfc_enable_cbfn;
    + bfa_iocfc_cbfn.disable_cbfn = bfa_iocfc_disable_cbfn;
    + bfa_iocfc_cbfn.hbfail_cbfn = bfa_iocfc_hbfail_cbfn;
    + bfa_iocfc_cbfn.reset_cbfn = bfa_iocfc_reset_cbfn;
    +
    + bfa_ioc_attach(&bfa->ioc, bfa, &bfa_iocfc_cbfn, &bfa->timer_mod,
    + bfa->trcmod, bfa->aen, bfa->logm);
    + bfa_ioc_pci_init(&bfa->ioc, pcidev, BFI_MC_IOCFC);
    + bfa_ioc_mbox_register(&bfa->ioc, bfa_mbox_isrs);
    +
    + /**
    + * Choose FC (ssid: 0x1C) v/s FCoE (ssid: 0x14) mode.
    + */
    + if (0)
    + bfa_ioc_set_fcmode(&bfa->ioc);
    +
    + bfa_iocfc_init_mem(bfa, bfad, cfg, pcidev);
    + bfa_iocfc_mem_claim(bfa, cfg, meminfo);
    + bfa_timer_init(&bfa->timer_mod);
    +
    + INIT_LIST_HEAD(&bfa->comp_q);
    + for (i = 0; i < BFI_IOC_MAX_CQS; i++)
    + INIT_LIST_HEAD(&bfa->reqq_waitq[i]);
    +}
    +
    +/**
    + * Query IOC memory requirement information.
    + */
    +void
    +bfa_iocfc_detach(struct bfa_s *bfa)
    +{
    + /*
    + * no-op
    + */
    +}
    +
    +/**
    + * Query IOC memory requirement information.
    + */
    +void
    +bfa_iocfc_init(struct bfa_s *bfa)
    +{
    + bfa->iocfc.action = BFA_IOCFC_ACT_INIT;
    + bfa_ioc_enable(&bfa->ioc);
    +}
    +
    +/**
    + * IOC start called from bfa_start(). Called to start IOC operations
    + * at driver instantiation for this instance.
    + */
    +void
    +bfa_iocfc_start(struct bfa_s *bfa)
    +{
    + if (bfa->iocfc.cfgdone)
    + bfa_iocfc_start_submod(bfa);
    +}
    +
    +/**
    + * IOC stop called from bfa_stop(). Called only when driver is unloaded
    + * for this instance.
    + */
    +void
    +bfa_iocfc_stop(struct bfa_s *bfa)
    +{
    + bfa->iocfc.action = BFA_IOCFC_ACT_STOP;
    + bfa_ioc_disable(&bfa->ioc);
    +}
    +
    +/**
    + * Enable IOC after it is disabled.
    + */
    +bfa_status_t
    +bfa_iocfc_enable(struct bfa_s *bfa)
    +{
    + bfa_plog_str(bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_MISC, 0,
    + "IOC Enable");
    + return bfa_ioc_enable(&bfa->ioc);
    +}
    +
    +void
    +bfa_iocfc_disable(struct bfa_s *bfa)
    +{
    + bfa_plog_str(bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_MISC, 0,
    + "IOC Disable");
    + bfa->iocfc.action = BFA_IOCFC_ACT_DISABLE;
    + bfa_ioc_disable(&bfa->ioc);
    +}
    +
    +
    +bfa_boolean_t
    +bfa_iocfc_is_operational(struct bfa_s *bfa)
    +{
    + return bfa_ioc_is_operational(&bfa->ioc) && bfa->iocfc.cfgdone;
    +}
    +
    +void
    +bfa_iocfc_isr(void *bfaarg, struct bfi_mbmsg_s *m)
    +{
    + struct bfa_s *bfa = bfaarg;
    + struct bfa_iocfc_s *iocfc = &bfa->iocfc;
    + union bfi_iocfc_i2h_msg_u *msg;
    +
    + msg = (union bfi_iocfc_i2h_msg_u *) m;
    + bfa_trc(bfa, msg->mh.msg_id);
    +
    + switch (msg->mh.msg_id) {
    + case BFI_IOCFC_I2H_CFG_REPLY:
    + iocfc->cfg_reply = &msg->cfg_reply;
    + bfa_iocfc_cfgrsp(bfa);
    + break;
    +
    + case BFI_IOCFC_I2H_GET_STATS_RSP:
    + if (iocfc->stats_busy == BFA_FALSE
    + || iocfc->stats_status == BFA_STATUS_ETIMER)
    + break;
    +
    + bfa_timer_stop(&iocfc->stats_timer);
    + iocfc->stats_status = BFA_STATUS_OK;
    + bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, bfa_iocfc_stats_cb,
    + bfa);
    + break;
    + case BFI_IOCFC_I2H_CLEAR_STATS_RSP:
    + /*
    + * check for timer pop before processing the rsp
    + */
    + if (iocfc->stats_busy == BFA_FALSE
    + || iocfc->stats_status == BFA_STATUS_ETIMER)
    + break;
    +
    + bfa_timer_stop(&iocfc->stats_timer);
    + iocfc->stats_status = BFA_STATUS_OK;
    + bfa_cb_queue(bfa, &iocfc->stats_hcb_qe,
    + bfa_iocfc_stats_clr_cb, bfa);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +#ifndef BFA_BIOS_BUILD
    +void
    +bfa_adapter_get_attr(struct bfa_s *bfa, struct bfa_adapter_attr_s *ad_attr)
    +{
    + bfa_ioc_get_adapter_attr(&bfa->ioc, ad_attr);
    +}
    +
    +u64
    +bfa_adapter_get_id(struct bfa_s *bfa)
    +{
    + return bfa_ioc_get_adid(&bfa->ioc);
    +}
    +
    +void
    +bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr)
    +{
    + struct bfa_iocfc_s *iocfc = &bfa->iocfc;
    +
    + attr->intr_attr = iocfc->cfginfo->intr_attr;
    + attr->config = iocfc->cfg;
    +}
    +
    +bfa_status_t
    +bfa_iocfc_israttr_set(struct bfa_s *bfa, struct bfa_iocfc_intr_attr_s *attr)
    +{
    + struct bfa_iocfc_s *iocfc = &bfa->iocfc;
    + struct bfi_iocfc_set_intr_req_s *m;
    +
    + iocfc->cfginfo->intr_attr = *attr;
    + if (!bfa_iocfc_is_operational(bfa))
    + return BFA_STATUS_OK;
    +
    + m = bfa_reqq_next(bfa, BFA_REQQ_IOC);
    + if (!m)
    + return BFA_STATUS_DEVBUSY;
    +
    + bfi_h2i_set(m->mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_SET_INTR_REQ,
    + bfa_lpuid(bfa));
    + m->coalesce = attr->coalesce;
    + m->delay = bfa_os_htons(attr->delay);
    + m->latency = bfa_os_htons(attr->latency);
    +
    + bfa_trc(bfa, attr->delay);
    + bfa_trc(bfa, attr->latency);
    +
    + bfa_reqq_produce(bfa, BFA_REQQ_IOC);
    + return BFA_STATUS_OK;
    +}
    +#endif
    +
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_iocfc.h patch/drivers/scsi/bfa/bfa_iocfc.h
    --- orig/drivers/scsi/bfa/bfa_iocfc.h 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_iocfc.h 2009-04-01 20:08:47.245163000 -0700
    @@ -0,0 +1,117 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#ifndef __BFA_IOCFC_H__
    +#define __BFA_IOCFC_H__
    +
    +#include <bfa_ioc.h>
    +#include <bfa.h>
    +#include <bfi/bfi_iocfc.h>
    +#include <bfa_callback_priv.h>
    +
    +#define BFA_REQQ_NELEMS_MIN (16)
    +#define BFA_RSPQ_NELEMS_MIN (16)
    +
    +struct bfa_iocfc_regs_s {
    + bfa_os_addr_t intr_status;
    + bfa_os_addr_t intr_mask;
    + bfa_os_addr_t cpe_q_pi[BFI_IOC_MAX_CQS];
    + bfa_os_addr_t cpe_q_ci[BFI_IOC_MAX_CQS];
    + bfa_os_addr_t cpe_q_depth[BFI_IOC_MAX_CQS];
    + bfa_os_addr_t cpe_q_ctrl[BFI_IOC_MAX_CQS];
    + bfa_os_addr_t rme_q_ci[BFI_IOC_MAX_CQS];
    + bfa_os_addr_t rme_q_pi[BFI_IOC_MAX_CQS];
    + bfa_os_addr_t rme_q_depth[BFI_IOC_MAX_CQS];
    + bfa_os_addr_t rme_q_ctrl[BFI_IOC_MAX_CQS];
    +};
    +
    +/**
    + * Chip specific interfaces
    + */
    +struct bfa_hwif_s {
    + void (*hw_reginit)(struct bfa_s *bfa);
    + void (*hw_rspq_ack)(struct bfa_s *bfa, int rspq);
    +};
    +
    +struct bfa_iocfc_s {
    + struct bfa_s *bfa;
    + struct bfa_iocfc_cfg_s cfg;
    + int action;
    +
    + u32 req_cq_pi[BFI_IOC_MAX_CQS];
    + u32 rsp_cq_ci[BFI_IOC_MAX_CQS];
    +
    + struct bfa_cb_qe_s init_hcb_qe;
    + struct bfa_cb_qe_s stop_hcb_qe;
    + struct bfa_cb_qe_s dis_hcb_qe;
    + struct bfa_cb_qe_s stats_hcb_qe;
    + bfa_boolean_t cfgdone;
    +
    + struct bfa_dma_s cfg_info;
    + struct bfi_iocfc_cfg_s *cfginfo;
    + struct bfa_dma_s cfgrsp_dma;
    + struct bfi_iocfc_cfgrsp_s *cfgrsp;
    + struct bfi_iocfc_cfg_reply_s *cfg_reply;
    +
    + u8 *stats_kva;
    + u64 stats_pa;
    + struct bfa_fw_stats_s *fw_stats;
    + struct bfa_timer_s stats_timer; /* timer */
    + struct bfa_iocfc_stats_s *stats_ret; /* driver stats location */
    + bfa_status_t stats_status; /* stats/statsclr status */
    + bfa_boolean_t stats_busy; /* outstanding stats */
    + bfa_cb_ioc_t stats_cbfn; /* driver callback function */
    + void *stats_cbarg; /* user callback arg */
    +
    + struct bfa_dma_s req_cq_ba[BFI_IOC_MAX_CQS];
    + struct bfa_dma_s req_cq_shadow_ci[BFI_IOC_MAX_CQS];
    + struct bfa_dma_s rsp_cq_ba[BFI_IOC_MAX_CQS];
    + struct bfa_dma_s rsp_cq_shadow_pi[BFI_IOC_MAX_CQS];
    + struct bfa_iocfc_regs_s bfa_regs; /* BFA device registers */
    + struct bfa_hwif_s hwif;
    +};
    +
    +#define bfa_lpuid(__bfa) bfa_ioc_portid(&(__bfa)->ioc)
    +#define bfa_sym_name(__bfa) __bfa->fabric.bport.port_cfg.sym_name.symname
    +
    +/*
    + * FC specific IOC functions.
    + */
    +void bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
    + u32 *dm_len);
    +void bfa_iocfc_attach(struct bfa_s *bfa, void *bfad,
    + struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo,
    + struct bfa_pcidev_s *pcidev);
    +void bfa_iocfc_detach(struct bfa_s *bfa);
    +void bfa_iocfc_init(struct bfa_s *bfa);
    +void bfa_iocfc_start(struct bfa_s *bfa);
    +void bfa_iocfc_stop(struct bfa_s *bfa);
    +void bfa_iocfc_isr(void *bfa, struct bfi_mbmsg_s *msg);
    +void bfa_iocfc_set_snsbase(struct bfa_s *bfa, u64 snsbase_pa);
    +bfa_boolean_t bfa_iocfc_is_operational(struct bfa_s *bfa);
    +
    +void bfa_hwcb_reginit(struct bfa_s *bfa);
    +void bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq);
    +void bfa_hwct_reginit(struct bfa_s *bfa);
    +void bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq);
    +
    +void bfa_com_meminfo(bfa_boolean_t mincfg, u32 *dm_len);
    +void bfa_com_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi,
    + bfa_boolean_t mincfg);
    +
    +#endif /* __BFA_IOCFC_H__ */
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_ioim.c patch/drivers/scsi/bfa/bfa_ioim.c
    --- orig/drivers/scsi/bfa/bfa_ioim.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_ioim.c 2009-04-01 20:08:47.253842000 -0700
    @@ -0,0 +1,1292 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#include <bfa.h>
    +#include <cs/bfa_debug.h>
    +#include <bfa_cb_ioim_macros.h>
    +
    +BFA_TRC_FILE(HAL, IOIM);
    +
    +/*
    + * forward declarations.
    + */
    +static bfa_boolean_t bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim);
    +static bfa_boolean_t bfa_ioim_sge_setup(struct bfa_ioim_s *ioim);
    +static void bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim);
    +static bfa_boolean_t bfa_ioim_send_abort(struct bfa_ioim_s *ioim);
    +static void bfa_ioim_notify_cleanup(struct bfa_ioim_s *ioim);
    +static void __bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete);
    +static void __bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete);
    +static void __bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete);
    +static void __bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete);
    +static void __bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete);
    +
    +/**
    + * hal_ioim_sm
    + */
    +
    +/**
    + * IO state machine events
    + */
    +enum bfa_ioim_event {
    + BFA_IOIM_SM_START = 1, /* io start request from host */
    + BFA_IOIM_SM_COMP_GOOD = 2, /* io good comp, resource free */
    + BFA_IOIM_SM_COMP = 3, /* io comp, resource is free */
    + BFA_IOIM_SM_COMP_UTAG = 4, /* io comp, resource is free */
    + BFA_IOIM_SM_DONE = 5, /* io comp, resource not free */
    + BFA_IOIM_SM_FREE = 6, /* io resource is freed */
    + BFA_IOIM_SM_ABORT = 7, /* abort request from scsi stack */
    + BFA_IOIM_SM_ABORT_COMP = 8, /* abort from f/w */
    + BFA_IOIM_SM_ABORT_DONE = 9, /* abort completion from f/w */
    + BFA_IOIM_SM_QRESUME = 10,/* CQ space available to queue IO */
    + BFA_IOIM_SM_SGALLOCED = 11,/* SG page allocation successful */
    + BFA_IOIM_SM_SQRETRY = 12,/* sequence recovery retry */
    + BFA_IOIM_SM_HCB = 13,/* bfa callback complete */
    + BFA_IOIM_SM_CLEANUP = 14,/* IO cleanup from itnim */
    + BFA_IOIM_SM_TMSTART = 15,/* IO cleanup from tskim */
    + BFA_IOIM_SM_TMDONE = 16,/* IO cleanup from tskim */
    + BFA_IOIM_SM_HWFAIL = 17,/* IOC h/w failure event */
    + BFA_IOIM_SM_IOTOV = 18,/* ITN offline TOV */
    +};
    +
    +/*
    + * forward declaration of IO state machine
    + */
    +static void bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim,
    + enum bfa_ioim_event event);
    +static void bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim,
    + enum bfa_ioim_event event);
    +static void bfa_ioim_sm_active(struct bfa_ioim_s *ioim,
    + enum bfa_ioim_event event);
    +static void bfa_ioim_sm_abort(struct bfa_ioim_s *ioim,
    + enum bfa_ioim_event event);
    +static void bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim,
    + enum bfa_ioim_event event);
    +static void bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim,
    + enum bfa_ioim_event event);
    +static void bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim,
    + enum bfa_ioim_event event);
    +static void bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim,
    + enum bfa_ioim_event event);
    +static void bfa_ioim_sm_hcb(struct bfa_ioim_s *ioim,
    + enum bfa_ioim_event event);
    +static void bfa_ioim_sm_hcb_free(struct bfa_ioim_s *ioim,
    + enum bfa_ioim_event event);
    +static void bfa_ioim_sm_resfree(struct bfa_ioim_s *ioim,
    + enum bfa_ioim_event event);
    +
    +/**
    + * IO is not started (unallocated).
    + */
    +static void
    +bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
    +{
    + bfa_trc_fp(ioim->bfa, ioim->iotag);
    + bfa_trc_fp(ioim->bfa, event);
    +
    + switch (event) {
    + case BFA_IOIM_SM_START:
    + if (!bfa_itnim_is_online(ioim->itnim)) {
    + if (!bfa_itnim_hold_io(ioim->itnim)) {
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + list_del(&ioim->qe);
    + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
    + __bfa_cb_ioim_pathtov, ioim);
    + } else {
    + list_del(&ioim->qe);
    + list_add_tail(&ioim->qe, &ioim->itnim->pending_q);
    + }
    + break;
    + }
    +
    + if (ioim->nsges > BFI_SGE_INLINE) {
    + if (!bfa_ioim_sge_setup(ioim)) {
    + bfa_sm_set_state(ioim, bfa_ioim_sm_sgalloc);
    + return;
    + }
    + }
    +
    + if (!bfa_ioim_send_ioreq(ioim)) {
    + printk(KERN_INFO "IO start: %s, Line %d Tag %d \n",
    + __func__, __LINE__, ioim->iotag);
    + bfa_sm_set_state(ioim, bfa_ioim_sm_qfull);
    + break;
    + }
    +
    + bfa_sm_set_state(ioim, bfa_ioim_sm_active);
    + break;
    +
    + case BFA_IOIM_SM_IOTOV:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
    + __bfa_cb_ioim_pathtov, ioim);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * IO is waiting for SG pages.
    + */
    +static void
    +bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
    +{
    + bfa_trc(ioim->bfa, ioim->iotag);
    + bfa_trc(ioim->bfa, event);
    +
    + switch (event) {
    + case BFA_IOIM_SM_SGALLOCED:
    + if (!bfa_ioim_send_ioreq(ioim)) {
    + bfa_sm_set_state(ioim, bfa_ioim_sm_qfull);
    + break;
    + }
    + bfa_sm_set_state(ioim, bfa_ioim_sm_active);
    + break;
    +
    + case BFA_IOIM_SM_CLEANUP:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
    + ioim);
    + bfa_ioim_notify_cleanup(ioim);
    + break;
    +
    + case BFA_IOIM_SM_ABORT:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
    + ioim);
    + break;
    +
    + case BFA_IOIM_SM_HWFAIL:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
    + ioim);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * IO is active.
    + */
    +static void
    +bfa_ioim_sm_active(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
    +{
    + bfa_trc_fp(ioim->bfa, ioim->iotag);
    + bfa_trc_fp(ioim->bfa, event);
    +
    + switch (event) {
    + case BFA_IOIM_SM_COMP_GOOD:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
    + __bfa_cb_ioim_good_comp, ioim);
    + break;
    +
    + case BFA_IOIM_SM_COMP:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_comp,
    + ioim);
    + break;
    +
    + case BFA_IOIM_SM_DONE:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_comp,
    + ioim);
    + break;
    +
    + case BFA_IOIM_SM_ABORT:
    + ioim->iosp->abort_explicit = BFA_TRUE;
    + ioim->io_cbfn = __bfa_cb_ioim_abort;
    +
    + if (bfa_ioim_send_abort(ioim))
    + bfa_sm_set_state(ioim, bfa_ioim_sm_abort);
    + else {
    + bfa_sm_set_state(ioim, bfa_ioim_sm_abort_qfull);
    + bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq,
    + &ioim->iosp->reqq_wait);
    + }
    + break;
    +
    + case BFA_IOIM_SM_CLEANUP:
    + ioim->iosp->abort_explicit = BFA_FALSE;
    + ioim->io_cbfn = __bfa_cb_ioim_failed;
    +
    + if (bfa_ioim_send_abort(ioim))
    + bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup);
    + else {
    + bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull);
    + bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq,
    + &ioim->iosp->reqq_wait);
    + }
    + break;
    +
    + case BFA_IOIM_SM_HWFAIL:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
    + ioim);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * IO is being aborted, waiting for completion from firmware.
    + */
    +static void
    +bfa_ioim_sm_abort(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
    +{
    + bfa_trc(ioim->bfa, ioim->iotag);
    + bfa_trc(ioim->bfa, event);
    +
    + switch (event) {
    + case BFA_IOIM_SM_COMP_GOOD:
    + case BFA_IOIM_SM_COMP:
    + case BFA_IOIM_SM_DONE:
    + case BFA_IOIM_SM_FREE:
    + break;
    +
    + case BFA_IOIM_SM_ABORT_DONE:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
    + ioim);
    + break;
    +
    + case BFA_IOIM_SM_ABORT_COMP:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
    + ioim);
    + break;
    +
    + case BFA_IOIM_SM_COMP_UTAG:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
    + ioim);
    + break;
    +
    + case BFA_IOIM_SM_CLEANUP:
    + bfa_assert(ioim->iosp->abort_explicit == BFA_TRUE);
    + ioim->iosp->abort_explicit = BFA_FALSE;
    +
    + if (bfa_ioim_send_abort(ioim))
    + bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup);
    + else {
    + bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull);
    + bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq,
    + &ioim->iosp->reqq_wait);
    + }
    + break;
    +
    + case BFA_IOIM_SM_HWFAIL:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
    + ioim);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * IO is being cleaned up (implicit abort), waiting for completion from
    + * firmware.
    + */
    +static void
    +bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
    +{
    + bfa_trc(ioim->bfa, ioim->iotag);
    + bfa_trc(ioim->bfa, event);
    +
    + switch (event) {
    + case BFA_IOIM_SM_COMP_GOOD:
    + case BFA_IOIM_SM_COMP:
    + case BFA_IOIM_SM_DONE:
    + case BFA_IOIM_SM_FREE:
    + break;
    +
    + case BFA_IOIM_SM_ABORT:
    + /**
    + * IO is already being aborted implicitly
    + */
    + ioim->io_cbfn = __bfa_cb_ioim_abort;
    + break;
    +
    + case BFA_IOIM_SM_ABORT_DONE:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim);
    + bfa_ioim_notify_cleanup(ioim);
    + break;
    +
    + case BFA_IOIM_SM_ABORT_COMP:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim);
    + bfa_ioim_notify_cleanup(ioim);
    + break;
    +
    + case BFA_IOIM_SM_COMP_UTAG:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim);
    + bfa_ioim_notify_cleanup(ioim);
    + break;
    +
    + case BFA_IOIM_SM_HWFAIL:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
    + ioim);
    + break;
    +
    + case BFA_IOIM_SM_CLEANUP:
    + /**
    + * IO can be in cleanup state already due to TM command. 2nd cleanup
    + * request comes from ITN offline event.
    + */
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * IO is waiting for room in request CQ
    + */
    +static void
    +bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
    +{
    + bfa_trc(ioim->bfa, ioim->iotag);
    + bfa_trc(ioim->bfa, event);
    +
    + switch (event) {
    + case BFA_IOIM_SM_QRESUME:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_active);
    + bfa_ioim_send_ioreq(ioim);
    + break;
    +
    + case BFA_IOIM_SM_ABORT:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
    + ioim);
    + break;
    +
    + case BFA_IOIM_SM_CLEANUP:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
    + ioim);
    + bfa_ioim_notify_cleanup(ioim);
    + break;
    +
    + case BFA_IOIM_SM_HWFAIL:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
    + ioim);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Active IO is being aborted, waiting for room in request CQ.
    + */
    +static void
    +bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
    +{
    + bfa_trc(ioim->bfa, ioim->iotag);
    + bfa_trc(ioim->bfa, event);
    +
    + switch (event) {
    + case BFA_IOIM_SM_QRESUME:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_abort);
    + bfa_ioim_send_abort(ioim);
    + break;
    +
    + case BFA_IOIM_SM_CLEANUP:
    + bfa_assert(ioim->iosp->abort_explicit == BFA_TRUE);
    + ioim->iosp->abort_explicit = BFA_FALSE;
    + bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull);
    + break;
    +
    + case BFA_IOIM_SM_COMP_GOOD:
    + case BFA_IOIM_SM_COMP:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
    + ioim);
    + break;
    +
    + case BFA_IOIM_SM_DONE:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
    + bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
    + ioim);
    + break;
    +
    + case BFA_IOIM_SM_HWFAIL:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
    + ioim);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Active IO is being cleaned up, waiting for room in request CQ.
    + */
    +static void
    +bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
    +{
    + bfa_trc(ioim->bfa, ioim->iotag);
    + bfa_trc(ioim->bfa, event);
    +
    + switch (event) {
    + case BFA_IOIM_SM_QRESUME:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup);
    + bfa_ioim_send_abort(ioim);
    + break;
    +
    + case BFA_IOIM_SM_ABORT:
    + /**
    + * IO is alraedy being cleaned up implicitly
    + */
    + ioim->io_cbfn = __bfa_cb_ioim_abort;
    + break;
    +
    + case BFA_IOIM_SM_COMP_GOOD:
    + case BFA_IOIM_SM_COMP:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim);
    + bfa_ioim_notify_cleanup(ioim);
    + break;
    +
    + case BFA_IOIM_SM_DONE:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
    + bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim);
    + bfa_ioim_notify_cleanup(ioim);
    + break;
    +
    + case BFA_IOIM_SM_HWFAIL:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
    + ioim);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * IO bfa callback is pending.
    + */
    +static void
    +bfa_ioim_sm_hcb(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
    +{
    + bfa_trc_fp(ioim->bfa, ioim->iotag);
    + bfa_trc_fp(ioim->bfa, event);
    +
    + switch (event) {
    + case BFA_IOIM_SM_HCB:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_uninit);
    + bfa_ioim_free(ioim);
    + bfa_cb_ioim_resfree(ioim->bfa->bfad);
    + break;
    +
    + case BFA_IOIM_SM_CLEANUP:
    + bfa_ioim_notify_cleanup(ioim);
    + break;
    +
    + case BFA_IOIM_SM_HWFAIL:
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * IO bfa callback is pending. IO resource cannot be freed.
    + */
    +static void
    +bfa_ioim_sm_hcb_free(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
    +{
    + bfa_trc(ioim->bfa, ioim->iotag);
    + bfa_trc(ioim->bfa, event);
    +
    + switch (event) {
    + case BFA_IOIM_SM_HCB:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_resfree);
    + list_del(&ioim->qe);
    + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_resfree_q);
    + break;
    +
    + case BFA_IOIM_SM_FREE:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + break;
    +
    + case BFA_IOIM_SM_CLEANUP:
    + bfa_ioim_notify_cleanup(ioim);
    + break;
    +
    + case BFA_IOIM_SM_HWFAIL:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * IO is completed, waiting resource free from firmware.
    + */
    +static void
    +bfa_ioim_sm_resfree(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
    +{
    + bfa_trc(ioim->bfa, ioim->iotag);
    + bfa_trc(ioim->bfa, event);
    +
    + switch (event) {
    + case BFA_IOIM_SM_FREE:
    + bfa_sm_set_state(ioim, bfa_ioim_sm_uninit);
    + bfa_ioim_free(ioim);
    + bfa_cb_ioim_resfree(ioim->bfa->bfad);
    + break;
    +
    + case BFA_IOIM_SM_CLEANUP:
    + bfa_ioim_notify_cleanup(ioim);
    + break;
    +
    + case BFA_IOIM_SM_HWFAIL:
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +
    +
    +/**
    + * hal_ioim_private
    + */
    +
    +static void
    +__bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete)
    +{
    + struct bfa_ioim_s *ioim = cbarg;
    +
    + if (!complete) {
    + bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
    + return;
    + }
    +
    + bfa_cb_ioim_good_comp(ioim->bfa->bfad, ioim->dio);
    +}
    +
    +static void
    +__bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete)
    +{
    + struct bfa_ioim_s *ioim = cbarg;
    + struct bfi_ioim_rsp_s *m;
    + u8 *snsinfo = NULL;
    + u8 sns_len = 0;
    + s32 residue = 0;
    +
    + if (!complete) {
    + bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
    + return;
    + }
    +
    + m = (struct bfi_ioim_rsp_s *) &ioim->iosp->comp_rspmsg;
    + if (m->io_status == BFI_IOIM_STS_OK) {
    + /**
    + * setup sense information, if present
    + */
    + if (m->scsi_status == SCSI_STATUS_CHECK_CONDITION
    + && m->sns_len) {
    + sns_len = m->sns_len;
    + snsinfo = ioim->iosp->snsinfo;
    + }
    +
    + /**
    + * setup residue value correctly for normal completions
    + */
    + if (m->resid_flags == FCP_RESID_UNDER)
    + residue = bfa_os_ntohl(m->residue);
    + if (m->resid_flags == FCP_RESID_OVER) {
    + residue = bfa_os_ntohl(m->residue);
    + residue = -residue;
    + }
    + }
    +
    + bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, m->io_status,
    + m->scsi_status, sns_len, snsinfo, residue);
    +}
    +
    +static void
    +__bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete)
    +{
    + struct bfa_ioim_s *ioim = cbarg;
    +
    + if (!complete) {
    + bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
    + return;
    + }
    +
    + bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_ABORTED,
    + 0, 0, NULL, 0);
    +}
    +
    +static void
    +__bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete)
    +{
    + struct bfa_ioim_s *ioim = cbarg;
    +
    + if (!complete) {
    + bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
    + return;
    + }
    +
    + bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_PATHTOV,
    + 0, 0, NULL, 0);
    +}
    +
    +static void
    +__bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete)
    +{
    + struct bfa_ioim_s *ioim = cbarg;
    +
    + if (!complete) {
    + bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
    + return;
    + }
    +
    + bfa_cb_ioim_abort(ioim->bfa->bfad, ioim->dio);
    +}
    +
    +static void
    +bfa_ioim_sgpg_alloced(void *cbarg)
    +{
    + struct bfa_ioim_s *ioim = cbarg;
    +
    + ioim->nsgpgs = BFA_SGPG_NPAGE(ioim->nsges);
    + list_splice_tail_init(&ioim->iosp->sgpg_wqe.sgpg_q, &ioim->sgpg_q);
    + bfa_ioim_sgpg_setup(ioim);
    + bfa_sm_send_event(ioim, BFA_IOIM_SM_SGALLOCED);
    +}
    +
    +/**
    + * Send I/O request to firmware.
    + */
    +static bfa_boolean_t
    +bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)
    +{
    + struct bfa_itnim_s *itnim = ioim->itnim;
    + struct bfi_ioim_req_s *m;
    + static struct fcp_cmnd_s cmnd_z0 = { 0 };
    + struct bfi_sge_s *sge;
    + u32 pgdlen = 0;
    +
    + /**
    + * check for room in queue to send request now
    + */
    + m = bfa_reqq_next(ioim->bfa, itnim->reqq);
    + if (!m) {
    + bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq,
    + &ioim->iosp->reqq_wait);
    + return BFA_FALSE;
    + }
    +
    + /**
    + * build i/o request message next
    + */
    + m->io_tag = bfa_os_htons(ioim->iotag);
    + m->rport_hdl = bfa_os_htons(ioim->itnim->rport->rport_tag);
    + m->io_timeout = bfa_cb_ioim_get_timeout(ioim->dio);
    +
    + /**
    + * build inline IO SG element here
    + */
    + sge = &m->sges[0];
    + if (ioim->nsges) {
    + sge->sga = bfa_cb_ioim_get_sgaddr(ioim->dio, 0);
    + pgdlen = bfa_cb_ioim_get_sglen(ioim->dio, 0);
    + sge->sg_len = pgdlen;
    + sge->flags = (ioim->nsges > BFI_SGE_INLINE) ?
    + BFI_SGE_DATA_CPL : BFI_SGE_DATA_LAST;
    + bfa_sge_to_be(sge);
    + sge++;
    + }
    +
    + if (ioim->nsges > BFI_SGE_INLINE) {
    + sge->sga = ioim->sgpg->sgpg_pa;
    + } else {
    + sge->sga.a32.addr_lo = 0;
    + sge->sga.a32.addr_hi = 0;
    + }
    + sge->sg_len = pgdlen;
    + sge->flags = BFI_SGE_PGDLEN;
    + bfa_sge_to_be(sge);
    +
    + /**
    + * set up I/O command parameters
    + */
    + m->cmnd = cmnd_z0;
    + m->cmnd.lun = bfa_cb_ioim_get_lun(ioim->dio);
    + m->cmnd.iodir = bfa_cb_ioim_get_iodir(ioim->dio);
    + m->cmnd.cdb = *(struct scsi_cdb_s *) bfa_cb_ioim_get_cdb(ioim->dio);
    + m->cmnd.fcp_dl = bfa_os_htonl(bfa_cb_ioim_get_size(ioim->dio));
    +
    + /**
    + * set up I/O message header
    + */
    + switch (m->cmnd.iodir) {
    + case FCP_IODIR_READ:
    + bfi_h2i_set(m->mh, BFI_MC_IOIM_READ, 0, bfa_lpuid(ioim->bfa));
    + break;
    + case FCP_IODIR_WRITE:
    + bfi_h2i_set(m->mh, BFI_MC_IOIM_WRITE, 0, bfa_lpuid(ioim->bfa));
    + break;
    + default:
    + bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_lpuid(ioim->bfa));
    + }
    + if (itnim->seq_rec ||
    + (bfa_cb_ioim_get_size(ioim->dio) & (sizeof(u32) - 1)))
    + bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_lpuid(ioim->bfa));
    +
    +#ifdef IOIM_ADVANCED
    + m->cmnd.crn = bfa_cb_ioim_get_crn(ioim->dio);
    + m->cmnd.priority = bfa_cb_ioim_get_priority(ioim->dio);
    + m->cmnd.taskattr = bfa_cb_ioim_get_taskattr(ioim->dio);
    +
    + /**
    + * Handle large CDB (>16 bytes).
    + */
    + m->cmnd.addl_cdb_len = (bfa_cb_ioim_get_cdblen(ioim->dio) -
    + FCP_CMND_CDB_LEN) / sizeof(u32);
    + if (m->cmnd.addl_cdb_len) {
    + memcpy(&m->cmnd.cdb + 1, (struct scsi_cdb_s *)
    + bfa_cb_ioim_get_cdb(ioim->dio) + 1,
    + m->cmnd.addl_cdb_len * sizeof(u32));
    + fcp_cmnd_fcpdl(&m->cmnd) =
    + bfa_os_htonl(bfa_cb_ioim_get_size(ioim->dio));
    + }
    +#endif
    +
    + /**
    + * queue I/O message to firmware
    + */
    + bfa_reqq_produce(ioim->bfa, itnim->reqq);
    + return BFA_TRUE;
    +}
    +
    +/**
    + * Setup any additional SG pages needed.Inline SG element is setup
    + * at queuing time.
    + */
    +static bfa_boolean_t
    +bfa_ioim_sge_setup(struct bfa_ioim_s *ioim)
    +{
    + u16 nsgpgs;
    +
    + bfa_assert(ioim->nsges > BFI_SGE_INLINE);
    +
    + /**
    + * allocate SG pages needed
    + */
    + nsgpgs = BFA_SGPG_NPAGE(ioim->nsges);
    + if (!nsgpgs)
    + return BFA_TRUE;
    +
    + if (bfa_sgpg_malloc(ioim->bfa, &ioim->sgpg_q, nsgpgs)
    + != BFA_STATUS_OK) {
    + bfa_sgpg_wait(ioim->bfa, &ioim->iosp->sgpg_wqe, nsgpgs);
    + return BFA_FALSE;
    + }
    +
    + ioim->nsgpgs = nsgpgs;
    + bfa_ioim_sgpg_setup(ioim);
    +
    + return BFA_TRUE;
    +}
    +
    +static void
    +bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim)
    +{
    + int sgeid, nsges, i;
    + struct bfi_sge_s *sge;
    + struct bfa_sgpg_s *sgpg;
    + u32 pgcumsz;
    +
    + sgeid = BFI_SGE_INLINE;
    + ioim->sgpg = sgpg = bfa_q_first(&ioim->sgpg_q);
    +
    + do {
    + sge = sgpg->sgpg->sges;
    + nsges = ioim->nsges - sgeid;
    + if (nsges > BFI_SGPG_DATA_SGES)
    + nsges = BFI_SGPG_DATA_SGES;
    +
    + pgcumsz = 0;
    + for (i = 0; i < nsges; i++, sge++, sgeid++) {
    + sge->sga = bfa_cb_ioim_get_sgaddr(ioim->dio, sgeid);
    + sge->sg_len = bfa_cb_ioim_get_sglen(ioim->dio, sgeid);
    + pgcumsz += sge->sg_len;
    +
    + /**
    + * set flags
    + */
    + if (i < (nsges - 1))
    + sge->flags = BFI_SGE_DATA;
    + else if (sgeid < (ioim->nsges - 1))
    + sge->flags = BFI_SGE_DATA_CPL;
    + else
    + sge->flags = BFI_SGE_DATA_LAST;
    + }
    +
    + sgpg = (struct bfa_sgpg_s *) bfa_q_next(sgpg);
    +
    + /**
    + * set the link element of each page
    + */
    + if (sgeid == ioim->nsges) {
    + sge->flags = BFI_SGE_PGDLEN;
    + sge->sga.a32.addr_lo = 0;
    + sge->sga.a32.addr_hi = 0;
    + } else {
    + sge->flags = BFI_SGE_LINK;
    + sge->sga = sgpg->sgpg_pa;
    + }
    + sge->sg_len = pgcumsz;
    + } while (sgeid < ioim->nsges);
    +}
    +
    +/**
    + * Send I/O abort request to firmware.
    + */
    +static bfa_boolean_t
    +bfa_ioim_send_abort(struct bfa_ioim_s *ioim)
    +{
    + struct bfa_itnim_s *itnim = ioim->itnim;
    + struct bfi_ioim_abort_req_s *m;
    + enum bfi_ioim_h2i msgop;
    +
    + /**
    + * check for room in queue to send request now
    + */
    + m = bfa_reqq_next(ioim->bfa, itnim->reqq);
    + if (!m)
    + return BFA_FALSE;
    +
    + /**
    + * build i/o request message next
    + */
    + if (ioim->iosp->abort_explicit)
    + msgop = BFI_IOIM_H2I_IOABORT_REQ;
    + else
    + msgop = BFI_IOIM_H2I_IOCLEANUP_REQ;
    +
    + bfi_h2i_set(m->mh, BFI_MC_IOIM, msgop, bfa_lpuid(ioim->bfa));
    + m->io_tag = bfa_os_htons(ioim->iotag);
    + m->abort_tag = ++ioim->abort_tag;
    +
    + /**
    + * queue I/O message to firmware
    + */
    + bfa_reqq_produce(ioim->bfa, itnim->reqq);
    + return BFA_TRUE;
    +}
    +
    +/**
    + * Call to resume any I/O requests waiting for room in request queue.
    + */
    +static void
    +bfa_ioim_qresume(void *cbarg)
    +{
    + struct bfa_ioim_s *ioim = cbarg;
    +
    + bfa_fcpim_stats(ioim->fcpim, qresumes);
    + bfa_sm_send_event(ioim, BFA_IOIM_SM_QRESUME);
    +}
    +
    +
    +static void
    +bfa_ioim_notify_cleanup(struct bfa_ioim_s *ioim)
    +{
    + /**
    + * Move IO from itnim queue to fcpim global queue since itnim will be
    + * freed.
    + */
    + list_del(&ioim->qe);
    + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
    +
    + if (!ioim->iosp->tskim) {
    + if (ioim->fcpim->delay_comp && ioim->itnim->iotov_active) {
    + bfa_cb_dequeue(&ioim->hcb_qe);
    + list_del(&ioim->qe);
    + list_add_tail(&ioim->qe, &ioim->itnim->delay_comp_q);
    + }
    + bfa_itnim_iodone(ioim->itnim);
    + } else
    + bfa_tskim_iodone(ioim->iosp->tskim);
    +}
    +
    +/**
    + * or after the link comes back.
    + */
    +void
    +bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim, bfa_boolean_t iotov)
    +{
    + /**
    + * If path tov timer expired, failback with PATHTOV status - these
    + * IO requests are not normally retried by IO stack.
    + *
    + * Otherwise device cameback online and fail it with normal failed
    + * status so that IO stack retries these failed IO requests.
    + */
    + if (iotov)
    + ioim->io_cbfn = __bfa_cb_ioim_pathtov;
    + else
    + ioim->io_cbfn = __bfa_cb_ioim_failed;
    +
    + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim);
    +
    + /**
    + * Move IO to fcpim global queue since itnim will be
    + * freed.
    + */
    + list_del(&ioim->qe);
    + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
    +}
    +
    +
    +
    +/**
    + * hal_ioim_friend
    + */
    +
    +/**
    + * Memory allocation and initialization.
    + */
    +void
    +bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
    +{
    + struct bfa_ioim_s *ioim;
    + struct bfa_ioim_sp_s *iosp;
    + u16 i;
    + u8 *snsinfo;
    + u32 snsbufsz;
    +
    + /**
    + * claim memory first
    + */
    + ioim = (struct bfa_ioim_s *) bfa_meminfo_kva(minfo);
    + fcpim->ioim_arr = ioim;
    + bfa_meminfo_kva(minfo) = (u8 *) (ioim + fcpim->num_ioim_reqs);
    +
    + iosp = (struct bfa_ioim_sp_s *) bfa_meminfo_kva(minfo);
    + fcpim->ioim_sp_arr = iosp;
    + bfa_meminfo_kva(minfo) = (u8 *) (iosp + fcpim->num_ioim_reqs);
    +
    + /**
    + * Claim DMA memory for per IO sense data.
    + */
    + snsbufsz = fcpim->num_ioim_reqs * BFI_IOIM_SNSLEN;
    + fcpim->snsbase.pa = bfa_meminfo_dma_phys(minfo);
    + bfa_meminfo_dma_phys(minfo) += snsbufsz;
    +
    + fcpim->snsbase.kva = bfa_meminfo_dma_virt(minfo);
    + bfa_meminfo_dma_virt(minfo) += snsbufsz;
    + snsinfo = fcpim->snsbase.kva;
    + bfa_iocfc_set_snsbase(fcpim->bfa, fcpim->snsbase.pa);
    +
    + /**
    + * Initialize ioim free queues
    + */
    + INIT_LIST_HEAD(&fcpim->ioim_free_q);
    + INIT_LIST_HEAD(&fcpim->ioim_resfree_q);
    + INIT_LIST_HEAD(&fcpim->ioim_comp_q);
    +
    + for (i = 0; i < fcpim->num_ioim_reqs;
    + i++, ioim++, iosp++, snsinfo += BFI_IOIM_SNSLEN) {
    + /*
    + * initialize IOIM
    + */
    + bfa_os_memset(ioim, 0, sizeof(struct bfa_ioim_s));
    + ioim->iotag = i;
    + ioim->bfa = fcpim->bfa;
    + ioim->fcpim = fcpim;
    + ioim->iosp = iosp;
    + iosp->snsinfo = snsinfo;
    + INIT_LIST_HEAD(&ioim->sgpg_q);
    + bfa_reqq_winit(&ioim->iosp->reqq_wait,
    + bfa_ioim_qresume, ioim);
    + bfa_sgpg_winit(&ioim->iosp->sgpg_wqe,
    + bfa_ioim_sgpg_alloced, ioim);
    + bfa_sm_set_state(ioim, bfa_ioim_sm_uninit);
    +
    + list_add_tail(&ioim->qe, &fcpim->ioim_free_q);
    + }
    +}
    +
    +/**
    + * Driver detach time call.
    + */
    +void
    +bfa_ioim_detach(struct bfa_fcpim_mod_s *fcpim)
    +{
    +}
    +
    +void
    +bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
    +{
    + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
    + struct bfi_ioim_rsp_s *rsp = (struct bfi_ioim_rsp_s *) m;
    + struct bfa_ioim_s *ioim;
    + u16 iotag;
    + enum bfa_ioim_event evt = BFA_IOIM_SM_COMP;
    +
    + iotag = bfa_os_ntohs(rsp->io_tag);
    +
    + ioim = BFA_IOIM_FROM_TAG(fcpim, iotag);
    + bfa_assert(ioim->iotag == iotag);
    + bfa_trc(ioim->bfa, ioim->iotag);
    + bfa_trc(ioim->bfa, rsp->io_status);
    + bfa_trc(ioim->bfa, rsp->reuse_io_tag);
    +
    + if (bfa_sm_cmp_state(ioim, bfa_ioim_sm_active))
    + ioim->iosp->comp_rspmsg = *m;
    +
    + switch (rsp->io_status) {
    + case BFI_IOIM_STS_OK:
    + bfa_fcpim_stats(fcpim, iocomp_ok);
    + if (rsp->reuse_io_tag == 0)
    + evt = BFA_IOIM_SM_DONE;
    + else
    + evt = BFA_IOIM_SM_COMP;
    + break;
    +
    + case BFI_IOIM_STS_TIMEDOUT:
    + case BFI_IOIM_STS_ABORTED:
    + rsp->io_status = BFI_IOIM_STS_ABORTED;
    + bfa_fcpim_stats(fcpim, iocomp_aborted);
    + if (rsp->reuse_io_tag == 0)
    + evt = BFA_IOIM_SM_DONE;
    + else
    + evt = BFA_IOIM_SM_COMP;
    + break;
    +
    + case BFI_IOIM_STS_PROTO_ERR:
    + bfa_fcpim_stats(fcpim, iocom_proto_err);
    + bfa_assert(rsp->reuse_io_tag);
    + evt = BFA_IOIM_SM_COMP;
    + break;
    +
    + case BFI_IOIM_STS_SQER_NEEDED:
    + bfa_fcpim_stats(fcpim, iocom_sqer_needed);
    + bfa_assert(rsp->reuse_io_tag == 0);
    + evt = BFA_IOIM_SM_SQRETRY;
    + break;
    +
    + case BFI_IOIM_STS_RES_FREE:
    + bfa_fcpim_stats(fcpim, iocom_res_free);
    + evt = BFA_IOIM_SM_FREE;
    + break;
    +
    + case BFI_IOIM_STS_HOST_ABORTED:
    + bfa_fcpim_stats(fcpim, iocom_hostabrts);
    + if (rsp->abort_tag != ioim->abort_tag) {
    + bfa_trc(ioim->bfa, rsp->abort_tag);
    + bfa_trc(ioim->bfa, ioim->abort_tag);
    + return;
    + }
    +
    + if (rsp->reuse_io_tag)
    + evt = BFA_IOIM_SM_ABORT_COMP;
    + else
    + evt = BFA_IOIM_SM_ABORT_DONE;
    + break;
    +
    + case BFI_IOIM_STS_UTAG:
    + bfa_fcpim_stats(fcpim, iocom_utags);
    + evt = BFA_IOIM_SM_COMP_UTAG;
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +
    + bfa_sm_send_event(ioim, evt);
    +}
    +
    +void
    +bfa_ioim_good_comp_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
    +{
    + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
    + struct bfi_ioim_rsp_s *rsp = (struct bfi_ioim_rsp_s *) m;
    + struct bfa_ioim_s *ioim;
    + u16 iotag;
    +
    + iotag = bfa_os_ntohs(rsp->io_tag);
    +
    + ioim = BFA_IOIM_FROM_TAG(fcpim, iotag);
    + bfa_assert(ioim->iotag == iotag);
    +
    + bfa_trc_fp(ioim->bfa, ioim->iotag);
    + bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD);
    +}
    +
    +/**
    + * Called by itnim to clean up IO while going offline.
    + */
    +void
    +bfa_ioim_cleanup(struct bfa_ioim_s *ioim)
    +{
    + bfa_trc(ioim->bfa, ioim->iotag);
    + bfa_fcpim_stats(ioim->fcpim, io_cleanups);
    +
    + ioim->iosp->tskim = NULL;
    + bfa_sm_send_event(ioim, BFA_IOIM_SM_CLEANUP);
    +}
    +
    +void
    +bfa_ioim_cleanup_tm(struct bfa_ioim_s *ioim, struct bfa_tskim_s *tskim)
    +{
    + bfa_trc(ioim->bfa, ioim->iotag);
    + bfa_fcpim_stats(ioim->fcpim, io_tmaborts);
    +
    + ioim->iosp->tskim = tskim;
    + bfa_sm_send_event(ioim, BFA_IOIM_SM_CLEANUP);
    +}
    +
    +/**
    + * IOC failure handling.
    + */
    +void
    +bfa_ioim_iocdisable(struct bfa_ioim_s *ioim)
    +{
    + bfa_sm_send_event(ioim, BFA_IOIM_SM_HWFAIL);
    +}
    +
    +/**
    + * IO offline TOV popped. Fail the pending IO.
    + */
    +void
    +bfa_ioim_tov(struct bfa_ioim_s *ioim)
    +{
    + bfa_sm_send_event(ioim, BFA_IOIM_SM_IOTOV);
    +}
    +
    +
    +
    +/**
    + * hal_ioim_api
    + */
    +
    +/**
    + * Allocate IOIM resource for initiator mode I/O request.
    + */
    +struct bfa_ioim_s *
    +bfa_ioim_alloc(struct bfa_s *bfa, struct bfad_ioim_s *dio,
    + struct bfa_itnim_s *itnim, u16 nsges)
    +{
    + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
    + struct bfa_ioim_s *ioim;
    +
    + /**
    + * alocate IOIM resource
    + */
    + bfa_q_deq(&fcpim->ioim_free_q, &ioim);
    + if (!ioim) {
    + bfa_fcpim_stats(fcpim, no_iotags);
    + return NULL;
    + }
    +
    + ioim->dio = dio;
    + ioim->itnim = itnim;
    + ioim->nsges = nsges;
    + ioim->nsgpgs = 0;
    +
    + bfa_stats(fcpim, total_ios);
    + bfa_stats(itnim, ios);
    + fcpim->ios_active++;
    +
    + list_add_tail(&ioim->qe, &itnim->io_q);
    + bfa_trc_fp(ioim->bfa, ioim->iotag);
    +
    + return ioim;
    +}
    +
    +void
    +bfa_ioim_free(struct bfa_ioim_s *ioim)
    +{
    + struct bfa_fcpim_mod_s *fcpim = ioim->fcpim;
    +
    + bfa_trc_fp(ioim->bfa, ioim->iotag);
    + bfa_assert_fp(bfa_sm_cmp_state(ioim, bfa_ioim_sm_uninit));
    +
    + bfa_assert_fp(list_empty(&ioim->sgpg_q)
    + || (ioim->nsges > BFI_SGE_INLINE));
    +
    + if (ioim->nsgpgs > 0)
    + bfa_sgpg_mfree(ioim->bfa, &ioim->sgpg_q, ioim->nsgpgs);
    +
    + bfa_stats(ioim->itnim, io_comps);
    + fcpim->ios_active--;
    +
    + list_del(&ioim->qe);
    + list_add_tail(&ioim->qe, &fcpim->ioim_free_q);
    +}
    +
    +void
    +bfa_ioim_start(struct bfa_ioim_s *ioim)
    +{
    + bfa_trc_fp(ioim->bfa, ioim->iotag);
    + bfa_sm_send_event(ioim, BFA_IOIM_SM_START);
    +}
    +
    +/**
    + * Driver I/O abort request.
    + */
    +void
    +bfa_ioim_abort(struct bfa_ioim_s *ioim)
    +{
    + bfa_trc(ioim->bfa, ioim->iotag);
    + bfa_fcpim_stats(ioim->fcpim, io_aborts);
    + bfa_sm_send_event(ioim, BFA_IOIM_SM_ABORT);
    +}
    +
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_itnim.c patch/drivers/scsi/bfa/bfa_itnim.c
    --- orig/drivers/scsi/bfa/bfa_itnim.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_itnim.c 2009-04-01 20:08:47.266617000 -0700
    @@ -0,0 +1,1168 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#include <bfa.h>
    +#include <bfa_fcpim.h>
    +#include "bfa_fcpim.h"
    +
    +BFA_TRC_FILE(HAL, ITNIM);
    +
    +#define bfa_fcpim_additn(__itnim) \
    + list_add_tail(&(__itnim)->qe, &(__itnim)->fcpim->itnim_q)
    +#define bfa_fcpim_delitn(__itnim) do { \
    + bfa_assert(bfa_q_is_on_q(&(__itnim)->fcpim->itnim_q, __itnim)); \
    + list_del(&(__itnim)->qe); \
    + bfa_assert(list_empty(&(__itnim)->io_q)); \
    + bfa_assert(list_empty(&(__itnim)->io_cleanup_q)); \
    + bfa_assert(list_empty(&(__itnim)->pending_q)); \
    +} while (0)
    +
    +#define bfa_itnim_online_cb(__itnim) do { \
    + bfa_cb_queue((__itnim)->bfa, &(__itnim)->hcb_qe, \
    + __bfa_cb_itnim_online, (__itnim)); \
    +} while (0)
    +
    +#define bfa_itnim_offline_cb(__itnim) do { \
    + bfa_cb_queue((__itnim)->bfa, &(__itnim)->hcb_qe, \
    + __bfa_cb_itnim_offline, (__itnim)); \
    +} while (0)
    +
    +#define bfa_itnim_sler_cb(__itnim) do { \
    + if (bfa_fw_disc_enabled((__itnim)->bfa)) \
    + bfa_rport_itnim_sler((__itnim)->ditn); \
    + else { \
    + bfa_cb_queue((__itnim)->bfa, &(__itnim)->hcb_qe, \
    + __bfa_cb_itnim_sler, (__itnim)); \
    + } \
    +} while (0)
    +
    +/*
    + * forward declarations
    + */
    +static void bfa_itnim_iocdisable_cleanup(struct bfa_itnim_s *itnim);
    +static bfa_boolean_t bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim);
    +static bfa_boolean_t bfa_itnim_send_fwdelete(struct bfa_itnim_s *itnim);
    +static void bfa_itnim_cleanp_comp(void *itnim_cbarg);
    +static void bfa_itnim_cleanup(struct bfa_itnim_s *itnim);
    +static void __bfa_cb_itnim_online(void *cbarg, bfa_boolean_t complete);
    +static void __bfa_cb_itnim_offline(void *cbarg, bfa_boolean_t complete);
    +/*
    +static void __bfa_cb_itnim_sler(void *cbarg, bfa_boolean_t complete);
    +*/
    +static void bfa_itnim_iotov_online(struct bfa_itnim_s *itnim);
    +static void bfa_itnim_iotov_cleanup(struct bfa_itnim_s *itnim);
    +static void bfa_itnim_iotov(void *itnim_arg);
    +static void bfa_itnim_iotov_start(struct bfa_itnim_s *itnim);
    +static void bfa_itnim_iotov_stop(struct bfa_itnim_s *itnim);
    +static void bfa_itnim_iotov_delete(struct bfa_itnim_s *itnim);
    +
    +static bfa_boolean_t bfa_itnim_send_prlo_rsp(struct bfa_itnim_s *itnim);
    +
    +/**
    + * bfa_itnim_sm BFA itnim state machine
    + */
    +
    +
    +enum bfa_itnim_event {
    + BFA_ITNIM_SM_CREATE = 1, /* itnim is created */
    + BFA_ITNIM_SM_ONLINE = 2, /* itnim is online */
    + BFA_ITNIM_SM_OFFLINE = 3, /* itnim is offline */
    + BFA_ITNIM_SM_FWRSP = 4, /* firmware response */
    + BFA_ITNIM_SM_DELETE = 5, /* deleting an existing itnim */
    + BFA_ITNIM_SM_CLEANUP = 6, /* IO cleanup completion */
    + BFA_ITNIM_SM_SLER = 7, /* second level error recovery */
    + BFA_ITNIM_SM_HWFAIL = 8, /* IOC h/w failure event */
    +
    + /*
    + * These events are generated as part of
    + * FCS functionality in fw
    + */
    + BFA_ITNIM_SM_UP = 9, /* fw created itnim instance */
    + BFA_ITNIM_SM_DOWN = 10, /* fw created itnim instance */
    + BFA_ITNIM_SM_PRLO = 11, /* prlo received */
    +};
    +
    +static void bfa_itnim_sm_uninit(struct bfa_itnim_s *itnim,
    + enum bfa_itnim_event event);
    +static void bfa_itnim_sm_created(struct bfa_itnim_s *itnim,
    + enum bfa_itnim_event event);
    +static void bfa_itnim_sm_fwcreate(struct bfa_itnim_s *itnim,
    + enum bfa_itnim_event event);
    +static void bfa_itnim_sm_delete_pending(struct bfa_itnim_s *itnim,
    + enum bfa_itnim_event event);
    +static void bfa_itnim_sm_online(struct bfa_itnim_s *itnim,
    + enum bfa_itnim_event event);
    +static void bfa_itnim_sm_sler(struct bfa_itnim_s *itnim,
    + enum bfa_itnim_event event);
    +static void bfa_itnim_sm_cleanup_offline(struct bfa_itnim_s *itnim,
    + enum bfa_itnim_event event);
    +static void bfa_itnim_sm_cleanup_delete(struct bfa_itnim_s *itnim,
    + enum bfa_itnim_event event);
    +static void bfa_itnim_sm_fwdelete(struct bfa_itnim_s *itnim,
    + enum bfa_itnim_event event);
    +static void bfa_itnim_sm_offline(struct bfa_itnim_s *itnim,
    + enum bfa_itnim_event event);
    +static void bfa_itnim_sm_iocdisable(struct bfa_itnim_s *itnim,
    + enum bfa_itnim_event event);
    +static void bfa_itnim_sm_deleting(struct bfa_itnim_s *itnim,
    + enum bfa_itnim_event event);
    +/**
    + * FW FCS related itnim states
    + */
    +static void bfa_itnim_sm_up(struct bfa_itnim_s *itnim,
    + enum bfa_itnim_event event);
    +static void bfa_itnim_sm_cleanup_remove(struct bfa_itnim_s *itnim,
    + enum bfa_itnim_event event);
    +static void bfa_itnim_sm_cleanup_login(struct bfa_itnim_s *itnim,
    + enum bfa_itnim_event event);
    +
    +/**
    + * Beginning/unallocated state - no events expected.
    + */
    +static void
    +bfa_itnim_sm_uninit(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
    +{
    + bfa_trc(itnim->bfa, itnim->rport->rport_tag);
    + bfa_trc(itnim->bfa, event);
    +
    + switch (event) {
    + case BFA_ITNIM_SM_CREATE:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_created);
    + itnim->is_online = BFA_FALSE;
    + bfa_fcpim_additn(itnim);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Beginning state, only online event expected.
    + */
    +static void
    +bfa_itnim_sm_created(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
    +{
    + bfa_trc(itnim->bfa, itnim->rport->rport_tag);
    + bfa_trc(itnim->bfa, event);
    +
    + switch (event) {
    + case BFA_ITNIM_SM_ONLINE:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate);
    + bfa_itnim_send_fwcreate(itnim);
    + break;
    +
    + case BFA_ITNIM_SM_DELETE:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
    + bfa_fcpim_delitn(itnim);
    + break;
    +
    + case BFA_ITNIM_SM_HWFAIL:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
    + break;
    +
    + case BFA_ITNIM_SM_UP:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_up);
    + itnim->is_online = BFA_TRUE;
    + //bfa_itnim_iotov_online(itnim);
    + bfa_cb_itnim_online(itnim->ditn);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Waiting for itnim create response from firmware.
    + */
    +static void
    +bfa_itnim_sm_fwcreate(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
    +{
    + bfa_trc(itnim->bfa, itnim->rport->rport_tag);
    + bfa_trc(itnim->bfa, event);
    +
    + switch (event) {
    + case BFA_ITNIM_SM_FWRSP:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_online);
    + itnim->is_online = BFA_TRUE;
    + bfa_itnim_iotov_online(itnim);
    + bfa_itnim_online_cb(itnim);
    + break;
    +
    + case BFA_ITNIM_SM_DELETE:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_delete_pending);
    + break;
    +
    + case BFA_ITNIM_SM_OFFLINE:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete);
    + bfa_itnim_send_fwdelete(itnim);
    + break;
    +
    + case BFA_ITNIM_SM_HWFAIL:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Waiting for itnim create response from firmware, a delete is pending.
    + */
    +static void
    +bfa_itnim_sm_delete_pending(struct bfa_itnim_s *itnim,
    + enum bfa_itnim_event event)
    +{
    + bfa_trc(itnim->bfa, itnim->rport->rport_tag);
    + bfa_trc(itnim->bfa, event);
    +
    + switch (event) {
    + case BFA_ITNIM_SM_FWRSP:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_deleting);
    + bfa_itnim_send_fwdelete(itnim);
    + break;
    +
    + case BFA_ITNIM_SM_HWFAIL:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
    + bfa_fcpim_delitn(itnim);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Online state - normal parking state.
    + */
    +static void
    +bfa_itnim_sm_online(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
    +{
    + bfa_trc(itnim->bfa, itnim->rport->rport_tag);
    + bfa_trc(itnim->bfa, event);
    +
    + switch (event) {
    + case BFA_ITNIM_SM_OFFLINE:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_offline);
    + itnim->is_online = BFA_FALSE;
    + bfa_itnim_iotov_start(itnim);
    + bfa_itnim_cleanup(itnim);
    + break;
    +
    + case BFA_ITNIM_SM_DELETE:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_delete);
    + itnim->is_online = BFA_FALSE;
    + bfa_itnim_cleanup(itnim);
    + break;
    +
    + case BFA_ITNIM_SM_SLER:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_sler);
    + itnim->is_online = BFA_FALSE;
    + bfa_itnim_iotov_start(itnim);
    + /*
    + * NOW SLER is routed thru' f/w
    + * so no SLER event is received in bfa
    + * TODO: This code can be removed can be removed
    + * bfa_itnim_sler_cb(itnim);
    + */
    + break;
    +
    + case BFA_ITNIM_SM_HWFAIL:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
    + itnim->is_online = BFA_FALSE;
    + bfa_itnim_iotov_start(itnim);
    + bfa_itnim_iocdisable_cleanup(itnim);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Second level error recovery need.
    + */
    +static void
    +bfa_itnim_sm_sler(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
    +{
    + bfa_trc(itnim->bfa, itnim->rport->rport_tag);
    + bfa_trc(itnim->bfa, event);
    +
    + switch (event) {
    + case BFA_ITNIM_SM_OFFLINE:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_offline);
    + bfa_itnim_cleanup(itnim);
    + break;
    +
    + case BFA_ITNIM_SM_DELETE:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_delete);
    + bfa_itnim_cleanup(itnim);
    + bfa_itnim_iotov_delete(itnim);
    + break;
    +
    + case BFA_ITNIM_SM_HWFAIL:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
    + bfa_itnim_iocdisable_cleanup(itnim);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Going offline. Waiting for active IO cleanup.
    + */
    +static void
    +bfa_itnim_sm_cleanup_offline(struct bfa_itnim_s *itnim,
    + enum bfa_itnim_event event)
    +{
    + bfa_trc(itnim->bfa, itnim->rport->rport_tag);
    + bfa_trc(itnim->bfa, event);
    +
    + switch (event) {
    + case BFA_ITNIM_SM_CLEANUP:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete);
    + bfa_itnim_send_fwdelete(itnim);
    + break;
    +
    + case BFA_ITNIM_SM_DELETE:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_delete);
    + bfa_itnim_iotov_delete(itnim);
    + break;
    +
    + case BFA_ITNIM_SM_HWFAIL:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
    + bfa_itnim_iocdisable_cleanup(itnim);
    + bfa_itnim_offline_cb(itnim);
    + break;
    +
    + case BFA_ITNIM_SM_SLER:
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Deleting itnim. Waiting for active IO cleanup.
    + */
    +static void
    +bfa_itnim_sm_cleanup_delete(struct bfa_itnim_s *itnim,
    + enum bfa_itnim_event event)
    +{
    + bfa_trc(itnim->bfa, itnim->rport->rport_tag);
    + bfa_trc(itnim->bfa, event);
    +
    + switch (event) {
    + case BFA_ITNIM_SM_CLEANUP:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_deleting);
    + bfa_itnim_send_fwdelete(itnim);
    + break;
    +
    + case BFA_ITNIM_SM_HWFAIL:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
    + bfa_itnim_iocdisable_cleanup(itnim);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Rport offline. Fimrware itnim is being deleted - awaiting f/w response.
    + */
    +static void
    +bfa_itnim_sm_fwdelete(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
    +{
    + bfa_trc(itnim->bfa, itnim->rport->rport_tag);
    + bfa_trc(itnim->bfa, event);
    +
    + switch (event) {
    + case BFA_ITNIM_SM_FWRSP:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_offline);
    + bfa_itnim_offline_cb(itnim);
    + break;
    +
    + case BFA_ITNIM_SM_DELETE:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_deleting);
    + break;
    +
    + case BFA_ITNIM_SM_HWFAIL:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
    + bfa_itnim_offline_cb(itnim);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Offline state.
    + */
    +static void
    +bfa_itnim_sm_offline(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
    +{
    + bfa_trc(itnim->bfa, itnim->rport->rport_tag);
    + bfa_trc(itnim->bfa, event);
    +
    + switch (event) {
    + case BFA_ITNIM_SM_DELETE:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
    + bfa_itnim_iotov_delete(itnim);
    + bfa_fcpim_delitn(itnim);
    + break;
    +
    + case BFA_ITNIM_SM_ONLINE:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate);
    + bfa_itnim_send_fwcreate(itnim);
    + break;
    +
    + case BFA_ITNIM_SM_HWFAIL:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * IOC h/w failed state.
    + */
    +static void
    +bfa_itnim_sm_iocdisable(struct bfa_itnim_s *itnim,
    + enum bfa_itnim_event event)
    +{
    + bfa_trc(itnim->bfa, itnim->rport->rport_tag);
    + bfa_trc(itnim->bfa, event);
    +
    + switch (event) {
    + case BFA_ITNIM_SM_DELETE:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
    + bfa_itnim_iotov_delete(itnim);
    + bfa_fcpim_delitn(itnim);
    + break;
    +
    + case BFA_ITNIM_SM_OFFLINE:
    + bfa_itnim_offline_cb(itnim);
    + break;
    +
    + case BFA_ITNIM_SM_ONLINE:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate);
    + bfa_itnim_send_fwcreate(itnim);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Itnim is deleted, waiting for firmware response to delete.
    + */
    +static void
    +bfa_itnim_sm_deleting(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
    +{
    + bfa_trc(itnim->bfa, itnim->rport->rport_tag);
    + bfa_trc(itnim->bfa, event);
    +
    + switch (event) {
    + case BFA_ITNIM_SM_FWRSP:
    + case BFA_ITNIM_SM_HWFAIL:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
    + bfa_fcpim_delitn(itnim);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Itnim is created in f/w and is current up & ready for IO.
    + */
    +static void
    +bfa_itnim_sm_up(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
    +{
    + bfa_trc(itnim->bfa, itnim->rport->rport_tag);
    + bfa_trc(itnim->bfa, event);
    +
    + switch (event) {
    + case BFA_ITNIM_SM_OFFLINE:
    + case BFA_ITNIM_SM_PRLO:
    + if (event == BFA_ITNIM_SM_OFFLINE)
    + bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_remove);
    + else
    + bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_login);
    +
    + itnim->is_online = BFA_FALSE;
    + bfa_itnim_iotov_start(itnim);
    + bfa_cb_itnim_offline(itnim->ditn);
    + bfa_itnim_cleanup(itnim);
    + break;
    +
    + case BFA_ITNIM_SM_HWFAIL:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
    + itnim->is_online = BFA_FALSE;
    + bfa_itnim_iotov_start(itnim);
    + bfa_itnim_iocdisable_cleanup(itnim);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Itnim io clean up in progress. Delete itnim after cleanup complete
    + */
    +static void
    +bfa_itnim_sm_cleanup_remove(struct bfa_itnim_s *itnim,
    + enum bfa_itnim_event event)
    +{
    + bfa_trc(itnim->bfa, itnim->rport->rport_tag);
    + bfa_trc(itnim->bfa, event);
    +
    + switch (event) {
    + case BFA_ITNIM_SM_CLEANUP:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
    + bfa_fcpim_delitn(itnim);
    + bfa_rport_cleanup_cb(itnim->bfa, itnim->rport);
    + break;
    +
    + case BFA_ITNIM_SM_HWFAIL:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
    + /*
    + * TODO: io cleanup in progress what now ??
    + */
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Itnim io clean up in progress. Relogin after cleanup complete
    + */
    +static void
    +bfa_itnim_sm_cleanup_login(struct bfa_itnim_s *itnim,
    + enum bfa_itnim_event event)
    +{
    + bfa_trc(itnim->bfa, itnim->rport->rport_tag);
    + bfa_trc(itnim->bfa, event);
    +
    + switch (event) {
    + case BFA_ITNIM_SM_CLEANUP:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_created);
    + itnim->is_online = BFA_FALSE;
    + bfa_itnim_send_prlo_rsp(itnim);
    + break;
    +
    + case BFA_ITNIM_SM_UP:
    + bfa_sm_set_state(itnim, bfa_itnim_sm_up);
    + itnim->is_online = BFA_TRUE;
    + bfa_itnim_iotov_online(itnim);
    + bfa_itnim_online_cb(itnim);
    +
    + break;
    +
    + case BFA_ITNIM_SM_HWFAIL:
    + /*
    + * TODO: io cleanup in progress what now ??
    + */
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +
    +
    +/**
    + * bfa_itnim_private
    + */
    +
    +/**
    + * Initiate cleanup of all IOs on an IOC failure.
    + */
    +static void
    +bfa_itnim_iocdisable_cleanup(struct bfa_itnim_s *itnim)
    +{
    + struct bfa_tskim_s *tskim;
    + struct bfa_ioim_s *ioim;
    + struct list_head *qe, *qen;
    +
    + list_for_each_safe(qe, qen, &itnim->tsk_q) {
    + tskim = (struct bfa_tskim_s *) qe;
    + bfa_tskim_iocdisable(tskim);
    + }
    +
    + list_for_each_safe(qe, qen, &itnim->io_q) {
    + ioim = (struct bfa_ioim_s *) qe;
    + bfa_ioim_iocdisable(ioim);
    + }
    +
    + /**
    + * For IO request in pending queue, we pretend an early timeout.
    + */
    + list_for_each_safe(qe, qen, &itnim->pending_q) {
    + ioim = (struct bfa_ioim_s *) qe;
    + bfa_ioim_tov(ioim);
    + }
    +
    + list_for_each_safe(qe, qen, &itnim->io_cleanup_q) {
    + ioim = (struct bfa_ioim_s *) qe;
    + bfa_ioim_iocdisable(ioim);
    + }
    +}
    +
    +/**
    + * IO cleanup completion
    + */
    +static void
    +bfa_itnim_cleanp_comp(void *itnim_cbarg)
    +{
    + struct bfa_itnim_s *itnim = itnim_cbarg;
    +
    + bfa_sm_send_event(itnim, BFA_ITNIM_SM_CLEANUP);
    +}
    +
    +/**
    + * Initiate cleanup of all IOs.
    + */
    +static void
    +bfa_itnim_cleanup(struct bfa_itnim_s *itnim)
    +{
    + struct bfa_ioim_s *ioim;
    + struct bfa_tskim_s *tskim;
    + struct list_head *qe, *qen;
    +
    + bfa_wc_init(&itnim->wc, bfa_itnim_cleanp_comp, itnim);
    +
    + list_for_each_safe(qe, qen, &itnim->io_q) {
    + ioim = (struct bfa_ioim_s *) qe;
    +
    + /**
    + * Move IO to a cleanup queue from active queue so that a later
    + * TM will not pickup this IO.
    + */
    + list_del(&ioim->qe);
    + list_add_tail(&ioim->qe, &itnim->io_cleanup_q);
    +
    + bfa_wc_up(&itnim->wc);
    + bfa_ioim_cleanup(ioim);
    + }
    +
    + list_for_each_safe(qe, qen, &itnim->tsk_q) {
    + tskim = (struct bfa_tskim_s *) qe;
    + bfa_wc_up(&itnim->wc);
    + bfa_tskim_cleanup(tskim);
    + }
    +
    + bfa_wc_wait(&itnim->wc);
    +}
    +
    +static void
    +__bfa_cb_itnim_online(void *cbarg, bfa_boolean_t complete)
    +{
    + struct bfa_itnim_s *itnim = cbarg;
    +
    + if (complete)
    + bfa_cb_itnim_online(itnim->ditn);
    +}
    +
    +static void
    +__bfa_cb_itnim_offline(void *cbarg, bfa_boolean_t complete)
    +{
    + struct bfa_itnim_s *itnim = cbarg;
    +
    + if (complete)
    + bfa_cb_itnim_offline(itnim->ditn);
    +}
    +
    +#if 0
    +static void
    +__bfa_cb_itnim_sler(void *cbarg, bfa_boolean_t complete)
    +{
    + struct bfa_itnim_s *itnim = cbarg;
    +
    + if (complete)
    + bfa_cb_itnim_sler(itnim->ditn);
    +}
    +#endif
    +
    +
    +
    +/**
    + * bfa_itnim_public
    + */
    +
    +void
    +bfa_itnim_iodone(struct bfa_itnim_s *itnim)
    +{
    + bfa_wc_down(&itnim->wc);
    +}
    +
    +void
    +bfa_itnim_tskdone(struct bfa_itnim_s *itnim)
    +{
    + bfa_wc_down(&itnim->wc);
    +}
    +
    +void
    +bfa_itnim_qresume(void *cbarg)
    +{
    + bfa_assert(0);
    +}
    +
    +void
    +bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
    + u32 *dm_len)
    +{
    + /**
    + * ITN memory
    + */
    + *km_len += cfg->fwcfg.num_rports * sizeof(struct bfa_itnim_s);
    +}
    +
    +void
    +bfa_itnim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
    +{
    + struct bfa_s *bfa = fcpim->bfa;
    + struct bfa_itnim_s *itnim;
    + int i;
    +
    + INIT_LIST_HEAD(&fcpim->itnim_q);
    +
    + itnim = (struct bfa_itnim_s *) bfa_meminfo_kva(minfo);
    + fcpim->itnim_arr = itnim;
    +
    + for (i = 0; i < fcpim->num_itnims; i++, itnim++) {
    + bfa_os_memset(itnim, 0, sizeof(struct bfa_itnim_s));
    + itnim->bfa = bfa;
    + itnim->fcpim = fcpim;
    + itnim->reqq = BFA_REQQ_QOS_LO;
    + itnim->rport = BFA_RPORT_FROM_TAG(bfa, i);
    + itnim->iotov_active = BFA_FALSE;
    + INIT_LIST_HEAD(&itnim->io_q);
    + INIT_LIST_HEAD(&itnim->io_cleanup_q);
    + INIT_LIST_HEAD(&itnim->pending_q);
    + INIT_LIST_HEAD(&itnim->tsk_q);
    + INIT_LIST_HEAD(&itnim->delay_comp_q);
    + bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
    + }
    +
    + bfa_meminfo_kva(minfo) = (u8 *) itnim;
    +}
    +
    +void
    +bfa_itnim_iocdisable(struct bfa_itnim_s *itnim)
    +{
    + bfa_sm_send_event(itnim, BFA_ITNIM_SM_HWFAIL);
    +}
    +
    +static bfa_boolean_t
    +bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim)
    +{
    + struct bfi_itnim_create_req_s *m;
    +
    + itnim->msg_no++;
    +
    + /**
    + * check for room in queue to send request now
    + */
    + m = bfa_reqq_next(itnim->bfa, itnim->reqq);
    + if (!m) {
    + bfa_reqq_wait(itnim->bfa, itnim->reqq, &itnim->reqq_wait);
    + return BFA_FALSE;
    + }
    +
    + bfi_h2i_set(m->mh, BFI_MC_ITNIM, BFI_ITNIM_H2I_CREATE_REQ,
    + bfa_lpuid(itnim->bfa));
    + m->itnim_tag = itnim->rport->rport_tag;
    + m->class = FC_CLASS_3;
    + m->seq_rec = itnim->seq_rec;
    + m->msg_no = itnim->msg_no;
    +
    + /**
    + * queue I/O message to firmware
    + */
    + bfa_reqq_produce(itnim->bfa, itnim->reqq);
    + return BFA_TRUE;
    +}
    +
    +static bfa_boolean_t
    +bfa_itnim_send_fwdelete(struct bfa_itnim_s *itnim)
    +{
    + struct bfi_itnim_delete_req_s *m;
    +
    + /**
    + * check for room in queue to send request now
    + */
    + m = bfa_reqq_next(itnim->bfa, itnim->reqq);
    + if (!m) {
    + bfa_reqq_wait(itnim->bfa, itnim->reqq, &itnim->reqq_wait);
    + return BFA_FALSE;
    + }
    +
    + bfi_h2i_set(m->mh, BFI_MC_ITNIM, BFI_ITNIM_H2I_DELETE_REQ,
    + bfa_lpuid(itnim->bfa));
    + m->itnim_tag = itnim->rport->rport_tag;
    +
    + /**
    + * queue I/O message to firmware
    + */
    + bfa_reqq_produce(itnim->bfa, itnim->reqq);
    + return BFA_TRUE;
    +}
    +
    +/**
    + * Cleanup all pending failed inflight requests.
    + */
    +static void
    +bfa_itnim_delayed_comp(struct bfa_itnim_s *itnim, bfa_boolean_t iotov)
    +{
    + struct bfa_ioim_s *ioim;
    + struct list_head *qe, *qen;
    +
    + list_for_each_safe(qe, qen, &itnim->delay_comp_q) {
    + ioim = (struct bfa_ioim_s *)qe;
    + bfa_ioim_delayed_comp(ioim, iotov);
    + }
    +}
    +
    +static bfa_boolean_t
    +bfa_itnim_send_prlo_rsp(struct bfa_itnim_s *itnim)
    +{
    + struct bfi_itnim_delete_req_s *m;
    +
    + /**
    + * check for room in queue to send request now
    + */
    + m = bfa_reqq_next(itnim->bfa, itnim->reqq);
    + if (!m) {
    + bfa_reqq_wait(itnim->bfa, itnim->reqq, &itnim->reqq_wait);
    + return BFA_FALSE;
    + }
    +
    + bfi_h2i_set(m->mh, BFI_MC_ITNIM, BFI_ITNIM_H2I_PRLO_RSP,
    + bfa_lpuid(itnim->bfa));
    + m->itnim_tag = itnim->rport->rport_tag;
    +
    + /**
    + * queue I/O message to firmware
    + */
    + bfa_reqq_produce(itnim->bfa, itnim->reqq);
    + return BFA_TRUE;
    +}
    +
    +/**
    + * Start all pending IO requests.
    + */
    +static void
    +bfa_itnim_iotov_online(struct bfa_itnim_s *itnim)
    +{
    + struct bfa_ioim_s *ioim;
    +
    + bfa_itnim_iotov_stop(itnim);
    +
    + /**
    + * Abort all inflight IO requests in the queue
    + */
    + bfa_itnim_delayed_comp(itnim, BFA_FALSE);
    +
    + /**
    + * Start all pending IO requests.
    + */
    + while (!list_empty(&itnim->pending_q)) {
    + bfa_q_deq(&itnim->pending_q, &ioim);
    + list_add_tail(&ioim->qe, &itnim->io_q);
    + bfa_ioim_start(ioim);
    + }
    +}
    +
    +/**
    + * Fail all pending IO requests
    + */
    +static void
    +bfa_itnim_iotov_cleanup(struct bfa_itnim_s *itnim)
    +{
    + struct bfa_ioim_s *ioim;
    +
    + /**
    + * Fail all inflight IO requests in the queue
    + */
    + bfa_itnim_delayed_comp(itnim, BFA_TRUE);
    +
    + /**
    + * Fail any pending IO requests.
    + */
    + while (!list_empty(&itnim->pending_q)) {
    + bfa_q_deq(&itnim->pending_q, &ioim);
    + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
    + bfa_ioim_tov(ioim);
    + }
    +}
    +
    +/**
    + * IO TOV timer callback. Fail any pending IO requests.
    + */
    +static void
    +bfa_itnim_iotov(void *itnim_arg)
    +{
    + struct bfa_itnim_s *itnim = itnim_arg;
    +
    + itnim->iotov_active = BFA_FALSE;
    +
    + bfa_cb_itnim_tov_begin(itnim->ditn);
    + bfa_itnim_iotov_cleanup(itnim);
    + bfa_cb_itnim_tov(itnim->ditn);
    +}
    +
    +/**
    + * Start IO TOV timer for failing back pending IO requests in offline state.
    + */
    +static void
    +bfa_itnim_iotov_start(struct bfa_itnim_s *itnim)
    +{
    + if (itnim->fcpim->path_tov > 0) {
    +
    + itnim->iotov_active = BFA_TRUE;
    + bfa_assert(bfa_itnim_hold_io(itnim));
    + bfa_timer_start(itnim->bfa, &itnim->timer,
    + bfa_itnim_iotov, itnim, itnim->fcpim->path_tov);
    + }
    +}
    +
    +/**
    + * Stop IO TOV timer.
    + */
    +static void
    +bfa_itnim_iotov_stop(struct bfa_itnim_s *itnim)
    +{
    + if (itnim->iotov_active) {
    + itnim->iotov_active = BFA_FALSE;
    + bfa_timer_stop(&itnim->timer);
    + }
    +}
    +
    +/**
    + * Stop IO TOV timer.
    + */
    +static void
    +bfa_itnim_iotov_delete(struct bfa_itnim_s *itnim)
    +{
    + bfa_boolean_t pathtov_active = BFA_FALSE;
    +
    + if (itnim->iotov_active)
    + pathtov_active = BFA_TRUE;
    +
    + bfa_itnim_iotov_stop(itnim);
    + if (pathtov_active)
    + bfa_cb_itnim_tov_begin(itnim->ditn);
    + bfa_itnim_iotov_cleanup(itnim);
    + if (pathtov_active)
    + bfa_cb_itnim_tov(itnim->ditn);
    +}
    +
    +
    +
    +/**
    + * bfa_itnim_public
    + */
    +
    +/**
    + * Itnim interrupt processing.
    + */
    +void
    +bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
    +{
    + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
    + union bfi_itnim_i2h_msg_u msg;
    + struct bfa_itnim_s *itnim;
    + u16 itnim_tag;
    +
    + bfa_trc(bfa, m->mhdr.msg_id);
    +
    + msg.msg = m;
    +
    + switch (m->mhdr.msg_id) {
    + case BFI_ITNIM_I2H_CREATE_RSP:
    + itnim = BFA_ITNIM_FROM_TAG(fcpim,
    + msg.create_rsp->itnim_tag);
    + bfa_assert(msg.create_rsp->status == BFA_STATUS_OK);
    + bfa_stats(itnim, create_comps);
    + bfa_sm_send_event(itnim, BFA_ITNIM_SM_FWRSP);
    + break;
    +
    + case BFI_ITNIM_I2H_DELETE_RSP:
    + itnim = BFA_ITNIM_FROM_TAG(fcpim,
    + msg.delete_rsp->itnim_tag);
    + bfa_assert(msg.delete_rsp->status == BFA_STATUS_OK);
    + bfa_stats(itnim, delete_comps);
    + bfa_sm_send_event(itnim, BFA_ITNIM_SM_FWRSP);
    + break;
    +
    + case BFI_ITNIM_I2H_SLER_EVENT:
    + itnim = BFA_ITNIM_FROM_TAG(fcpim,
    + msg.sler_event->itnim_tag);
    + bfa_stats(itnim, sler_events);
    + bfa_sm_send_event(itnim, BFA_ITNIM_SM_SLER);
    + break;
    +
    + case BFI_ITNIM_I2H_UP:
    + itnim_tag = bfa_os_ntohs(msg.add_event->itnim_tag);
    + itnim = BFA_ITNIM_FROM_TAG(fcpim, itnim_tag);
    +
    + bfa_trc(bfa, (unsigned long) itnim);
    + bfa_trc(bfa, itnim_tag);
    + bfa_trc(bfa, itnim->rport->rport_info.pid);
    + /*
    + * Note: ITNIM instance is already alloced & linked to active
    + * queue, but in online flag is false.
    + */
    + /* Update all ITNIM fields */
    + itnim->seq_rec = msg.add_event->seq_rec;
    + itnim->rec_support = msg.add_event->rec_support;
    + itnim->task_retry_id = msg.add_event->task_retry_id;
    + itnim->conf_comp = msg.add_event->confirm;
    +
    + bfa_sm_send_event(itnim, BFA_ITNIM_SM_UP);
    +
    + break;
    +
    + case BFI_ITNIM_I2H_DOWN:
    + itnim_tag = bfa_os_ntohs(msg.add_event->itnim_tag);
    + itnim = BFA_ITNIM_FROM_TAG(fcpim, itnim_tag);
    +
    + bfa_sm_send_event(itnim, BFA_ITNIM_SM_DOWN);
    + break;
    +
    + case BFI_ITNIM_I2H_PRLO:
    + itnim_tag = bfa_os_ntohs(msg.add_event->itnim_tag);
    + itnim = BFA_ITNIM_FROM_TAG(fcpim, itnim_tag);
    + bfa_sm_send_event(itnim, BFA_ITNIM_SM_PRLO);
    + break;
    +
    + default:
    + bfa_trc(bfa, m->mhdr.msg_id);
    + bfa_assert(0);
    + }
    +}
    +
    +
    +
    +/**
    + * bfa_itnim_api
    + */
    +
    +struct bfa_itnim_s *
    +bfa_itnim_create(struct bfa_s *bfa, struct bfa_rport_s *rport, void *ditn)
    +{
    + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
    + struct bfa_itnim_s *itnim;
    +
    + bfa_trc(bfa, rport->rport_tag);
    + itnim = BFA_ITNIM_FROM_TAG(fcpim, rport->rport_tag);
    +
    + bfa_trc(bfa, (unsigned long) itnim);
    +
    + itnim->ditn = ditn;
    + itnim->rport = rport;
    + bfa_trc(bfa, (unsigned long) itnim);
    + bfa_stats(itnim, creates);
    + bfa_sm_send_event(itnim, BFA_ITNIM_SM_CREATE);
    +
    + return (itnim);
    +}
    +
    +void
    +bfa_itnim_delete(struct bfa_itnim_s *itnim)
    +{
    + bfa_stats(itnim, deletes);
    + bfa_sm_send_event(itnim, BFA_ITNIM_SM_DELETE);
    +}
    +
    +void
    +bfa_itnim_online(struct bfa_itnim_s *itnim, bfa_boolean_t seq_rec)
    +{
    + itnim->seq_rec = seq_rec;
    + bfa_stats(itnim, onlines);
    + bfa_sm_send_event(itnim, BFA_ITNIM_SM_ONLINE);
    +}
    +
    +void
    +bfa_itnim_offline(struct bfa_itnim_s *itnim)
    +{
    + bfa_stats(itnim, offlines);
    + bfa_sm_send_event(itnim, BFA_ITNIM_SM_OFFLINE);
    +}
    +
    +/**
    + * Return true if itnim is considered offline for holding off IO request.
    + * IO is not held if itnim is being deleted.
    + */
    +bfa_boolean_t
    +bfa_itnim_hold_io(struct bfa_itnim_s *itnim)
    +{
    + return (
    + itnim->fcpim->path_tov && itnim->iotov_active &&
    + (bfa_sm_cmp_state(itnim, bfa_itnim_sm_fwcreate) ||
    + bfa_sm_cmp_state(itnim, bfa_itnim_sm_sler) ||
    + bfa_sm_cmp_state(itnim, bfa_itnim_sm_cleanup_offline) ||
    + bfa_sm_cmp_state(itnim, bfa_itnim_sm_fwdelete) ||
    + bfa_sm_cmp_state(itnim, bfa_itnim_sm_offline) ||
    + bfa_sm_cmp_state(itnim, bfa_itnim_sm_iocdisable))
    +);
    +}
    +
    +void
    +bfa_itnim_get_stats(struct bfa_itnim_s *itnim,
    + struct bfa_itnim_stats_s *stats)
    +{
    + memcpy(&itnim->itnim_stats.hal_stats, &itnim->stats,
    + sizeof(struct bfa_itnim_hal_stats_s));
    + *stats = itnim->itnim_stats;
    +}
    +
    +void
    +bfa_itnim_clear_stats(struct bfa_itnim_s *itnim)
    +{
    + bfa_os_memset(&itnim->stats, 0, sizeof(itnim->stats));
    +}
    +
    +struct bfad_port_s *
    +bfa_itnim_get_drvport(struct bfa_itnim_s *itnim)
    +{
    + struct bfa_lport_s *lp;
    + struct bfa_rport_s *rp;
    +
    + rp = (struct bfa_rport_s *)itnim->rport;
    + lp = (struct bfa_lport_s *)BFA_LPORT_FROM_TAG(itnim->bfa, rp->lport_tag);
    +
    + return (lp->bfad_port);
    +}
    +
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_log.c patch/drivers/scsi/bfa/bfa_log.c
    --- orig/drivers/scsi/bfa/bfa_log.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_log.c 2009-04-01 20:08:47.277549000 -0700
    @@ -0,0 +1,344 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +/**
    + * bfa_log.c BFA log library
    + */
    +
    +#include <bfa_os_inc.h>
    +#include <cs/bfa_log.h>
    +
    +/*
    + * global log info structure
    + */
    +struct bfa_log_info_s {
    + u32 start_idx; /* start index for a module */
    + u32 total_count; /* total count for a module */
    + enum bfa_log_severity level; /* global log level */
    + bfa_log_cb_t cbfn; /* callback function */
    +};
    +
    +static struct bfa_log_info_s bfa_log_info[BFA_LOG_MODULE_ID_MAX + 1];
    +static u32 bfa_log_msg_total_count;
    +static int bfa_log_initialized;
    +
    +static char *bfa_log_severity[] =
    + { "[none]", "[critical]", "[error]", "[warn]", "[info]" };
    +
    +/**
    + * BFA log library initialization
    + *
    + * The log library initialization includes the following,
    + * - set log instance name and callback function
    + * - read the message array generated from xml files
    + * - calculate start index for each module
    + * - calculate message count for each module
    + * - perform error checking
    + *
    + * @param[in] log_mod - log module info
    + * @param[in] instance_name - instance name
    + * @param[in] cbfn - callback function
    + *
    + * It return 0 on success, or -1 on failure
    + */
    +int
    +bfa_log_init(struct bfa_log_mod_s *log_mod, char *instance_name,
    + bfa_log_cb_t cbfn)
    +{
    + struct bfa_log_msgdef_s *msg;
    + u32 pre_mod_id = 0;
    + u32 cur_mod_id = 0;
    + u32 i, pre_idx, idx, msg_id;
    +
    + /*
    + * set instance name
    + */
    + if (log_mod) {
    + strncpy(log_mod->instance_info, instance_name,
    + sizeof(log_mod->instance_info));
    + log_mod->cbfn = cbfn;
    + for (i = 0; i <= BFA_LOG_MODULE_ID_MAX; i++)
    + log_mod->log_level[i] = BFA_LOG_WARNING;
    + }
    +
    + if (bfa_log_initialized)
    + return 0;
    +
    + for (i = 0; i <= BFA_LOG_MODULE_ID_MAX; i++) {
    + bfa_log_info[i].start_idx = 0;
    + bfa_log_info[i].total_count = 0;
    + bfa_log_info[i].level = BFA_LOG_WARNING;
    + bfa_log_info[i].cbfn = cbfn;
    + }
    +
    + pre_idx = 0;
    + idx = 0;
    + msg = bfa_log_msg_array;
    + msg_id = BFA_LOG_GET_MSG_ID(msg);
    + pre_mod_id = BFA_LOG_GET_MOD_ID(msg_id);
    + while (msg_id != 0) {
    + cur_mod_id = BFA_LOG_GET_MOD_ID(msg_id);
    +
    + if (cur_mod_id > BFA_LOG_MODULE_ID_MAX) {
    + cbfn(log_mod, msg_id,
    + "%s%s log: module id %u out of range\n",
    + BFA_LOG_CAT_NAME,
    + bfa_log_severity[BFA_LOG_ERROR],
    + cur_mod_id);
    + return -1;
    + }
    +
    + if (pre_mod_id > BFA_LOG_MODULE_ID_MAX) {
    + cbfn(log_mod, msg_id,
    + "%s%s log: module id %u out of range\n",
    + BFA_LOG_CAT_NAME,
    + bfa_log_severity[BFA_LOG_ERROR],
    + pre_mod_id);
    + return -1;
    + }
    +
    + if (cur_mod_id != pre_mod_id) {
    + bfa_log_info[pre_mod_id].start_idx = pre_idx;
    + bfa_log_info[pre_mod_id].total_count = idx - pre_idx;
    + pre_mod_id = cur_mod_id;
    + pre_idx = idx;
    + }
    +
    + idx++;
    + msg++;
    + msg_id = BFA_LOG_GET_MSG_ID(msg);
    + }
    +
    + bfa_log_info[cur_mod_id].start_idx = pre_idx;
    + bfa_log_info[cur_mod_id].total_count = idx - pre_idx;
    + bfa_log_msg_total_count = idx;
    +
    + cbfn(log_mod, msg_id, "%s%s log: init OK, msg total count %u\n",
    + BFA_LOG_CAT_NAME,
    + bfa_log_severity[BFA_LOG_INFO], bfa_log_msg_total_count);
    +
    + bfa_log_initialized = 1;
    +
    + return 0;
    +}
    +
    +/**
    + * BFA log set log level for a module
    + *
    + * @param[in] log_mod - log module info
    + * @param[in] mod_id - module id
    + * @param[in] log_level - log severity level
    + *
    + * It return BFA_STATUS_OK on success, or > 0 on failure
    + */
    +bfa_status_t
    +bfa_log_set_level(struct bfa_log_mod_s *log_mod, int mod_id,
    + enum bfa_log_severity log_level)
    +{
    + if (mod_id <= BFA_LOG_UNUSED_ID || mod_id > BFA_LOG_MODULE_ID_MAX)
    + return BFA_STATUS_EINVAL;
    +
    + if (log_level <= BFA_LOG_INVALID || log_level > BFA_LOG_LEVEL_MAX)
    + return BFA_STATUS_EINVAL;
    +
    + if (log_mod)
    + log_mod->log_level[mod_id] = log_level;
    + else
    + bfa_log_info[mod_id].level = log_level;
    +
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * BFA log set log level for all modules
    + *
    + * @param[in] log_mod - log module info
    + * @param[in] log_level - log severity level
    + *
    + * It return BFA_STATUS_OK on success, or > 0 on failure
    + */
    +bfa_status_t
    +bfa_log_set_level_all(struct bfa_log_mod_s *log_mod,
    + enum bfa_log_severity log_level)
    +{
    + int mod_id = BFA_LOG_UNUSED_ID + 1;
    +
    + if (log_level <= BFA_LOG_INVALID || log_level > BFA_LOG_LEVEL_MAX)
    + return BFA_STATUS_EINVAL;
    +
    + if (log_mod) {
    + for (; mod_id <= BFA_LOG_MODULE_ID_MAX; mod_id++)
    + log_mod->log_level[mod_id] = log_level;
    + } else {
    + for (; mod_id <= BFA_LOG_MODULE_ID_MAX; mod_id++)
    + bfa_log_info[mod_id].level = log_level;
    + }
    +
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * BFA log set log level for all aen sub-modules
    + *
    + * @param[in] log_mod - log module info
    + * @param[in] log_level - log severity level
    + *
    + * It return BFA_STATUS_OK on success, or > 0 on failure
    + */
    +bfa_status_t
    +bfa_log_set_level_aen(struct bfa_log_mod_s *log_mod,
    + enum bfa_log_severity log_level)
    +{
    + int mod_id = BFA_LOG_AEN_MIN + 1;
    +
    + if (log_mod) {
    + for (; mod_id <= BFA_LOG_AEN_MAX; mod_id++)
    + log_mod->log_level[mod_id] = log_level;
    + } else {
    + for (; mod_id <= BFA_LOG_AEN_MAX; mod_id++)
    + bfa_log_info[mod_id].level = log_level;
    + }
    +
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * BFA log get log level for a module
    + *
    + * @param[in] log_mod - log module info
    + * @param[in] mod_id - module id
    + *
    + * It returns log level or -1 on error
    + */
    +enum bfa_log_severity
    +bfa_log_get_level(struct bfa_log_mod_s *log_mod, int mod_id)
    +{
    + if (mod_id <= BFA_LOG_UNUSED_ID || mod_id > BFA_LOG_MODULE_ID_MAX)
    + return BFA_LOG_INVALID;
    +
    + if (log_mod)
    + return (log_mod->log_level[mod_id]);
    + else
    + return (bfa_log_info[mod_id].level);
    +}
    +
    +enum bfa_log_severity
    +bfa_log_get_msg_level(struct bfa_log_mod_s *log_mod, u32 msg_id)
    +{
    + struct bfa_log_msgdef_s *msg;
    + u32 mod = BFA_LOG_GET_MOD_ID(msg_id);
    + u32 idx = BFA_LOG_GET_MSG_IDX(msg_id) - 1;
    +
    + if (!bfa_log_initialized)
    + return BFA_LOG_INVALID;
    +
    + if (mod > BFA_LOG_MODULE_ID_MAX)
    + return BFA_LOG_INVALID;
    +
    + if (idx >= bfa_log_info[mod].total_count) {
    + bfa_log_info[mod].cbfn(log_mod, msg_id,
    + "%s%s log: inconsistent idx %u vs. total count %u\n",
    + BFA_LOG_CAT_NAME, bfa_log_severity[BFA_LOG_ERROR], idx,
    + bfa_log_info[mod].total_count);
    + return BFA_LOG_INVALID;
    + }
    +
    + msg = bfa_log_msg_array + bfa_log_info[mod].start_idx + idx;
    + if (msg_id != BFA_LOG_GET_MSG_ID(msg)) {
    + bfa_log_info[mod].cbfn(log_mod, msg_id,
    + "%s%s log: inconsistent msg id %u array msg id %u\n",
    + BFA_LOG_CAT_NAME, bfa_log_severity[BFA_LOG_ERROR],
    + msg_id, BFA_LOG_GET_MSG_ID(msg));
    + return BFA_LOG_INVALID;
    + }
    +
    + return BFA_LOG_GET_SEVERITY(msg);
    +}
    +
    +/**
    + * BFA log message handling
    + *
    + * BFA log message handling finds the message based on message id and prints
    + * out the message based on its format and arguments. It also does prefix
    + * the severity etc.
    + *
    + * @param[in] log_mod - log module info
    + * @param[in] msg_id - message id
    + * @param[in] ... - message arguments
    + *
    + * It return 0 on success, or -1 on errors
    + */
    +int
    +bfa_log(struct bfa_log_mod_s *log_mod, u32 msg_id, ...)
    +{
    + va_list ap;
    + char buf[256];
    + struct bfa_log_msgdef_s *msg;
    + int log_level;
    + u32 mod = BFA_LOG_GET_MOD_ID(msg_id);
    + u32 idx = BFA_LOG_GET_MSG_IDX(msg_id) - 1;
    +
    + if (!bfa_log_initialized)
    + return -1;
    +
    + if (mod > BFA_LOG_MODULE_ID_MAX)
    + return -1;
    +
    + if (idx >= bfa_log_info[mod].total_count) {
    + bfa_log_info[mod].
    + cbfn
    + (log_mod, msg_id,
    + "%s%s log: inconsistent idx %u vs. total count %u\n",
    + BFA_LOG_CAT_NAME, bfa_log_severity[BFA_LOG_ERROR], idx,
    + bfa_log_info[mod].total_count);
    + return -1;
    + }
    +
    + msg = bfa_log_msg_array + bfa_log_info[mod].start_idx + idx;
    + if (msg_id != BFA_LOG_GET_MSG_ID(msg)) {
    + bfa_log_info[mod].
    + cbfn
    + (log_mod, msg_id,
    + "%s%s log: inconsistent msg id %u array msg id %u\n",
    + BFA_LOG_CAT_NAME, bfa_log_severity[BFA_LOG_ERROR],
    + msg_id, BFA_LOG_GET_MSG_ID(msg));
    + return -1;
    + }
    +
    + log_level = log_mod ? log_mod->log_level[mod] : bfa_log_info[mod].level;
    + if (BFA_LOG_GET_SEVERITY(msg) > log_level)
    + return 0;
    +
    + va_start(ap, msg_id);
    + bfa_os_vsprintf(buf, BFA_LOG_GET_MSG_FMT_STRING(msg), ap);
    + va_end(ap);
    +
    + if (log_mod)
    + log_mod->cbfn(log_mod, msg_id, "%s[%s]%s%s %s: %s\n",
    + BFA_LOG_CAT_NAME, log_mod->instance_info,
    + bfa_log_severity[BFA_LOG_GET_SEVERITY(msg)],
    + (msg->attributes & BFA_LOG_ATTR_AUDIT)
    + ? " (audit) " : "", msg->msg_value, buf);
    + else
    + bfa_log_info[mod].cbfn(log_mod, msg_id, "%s%s%s %s: %s\n",
    + BFA_LOG_CAT_NAME,
    + bfa_log_severity[BFA_LOG_GET_SEVERITY(msg)],
    + (msg->attributes & BFA_LOG_ATTR_AUDIT) ?
    + " (audit) " : "", msg->msg_value, buf);
    +
    + return 0;
    +}
    diff -urpN orig/drivers/scsi/bfa/bfa_log_module.c patch/drivers/scsi/bfa/bfa_log_module.c
    --- orig/drivers/scsi/bfa/bfa_log_module.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_log_module.c 2009-04-01 20:08:47.286229000 -0700
    @@ -0,0 +1,448 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +/*
    + * Copyright (c) 2008 by Brocade Communications Systems, Inc.
    + * All rights reserved.
    + *
    + * File Name: bfa_log_module.c
    + *
    + * PLEASE DO NOT EDIT THIS FILE. THIS FILE IS AUTO GENERATED!!
    + *
    + * Description:
    + *
    + * The log messages defined in each XML files will be converted to a C code
    + * style message file. The message file will be named the same as XML file.
    + *
    + * These coded instructions and statements contain unpublished trade
    + * secrets and proprietary information. They are protected by federal
    + * copyright law and by trade secret law, and may not be disclosed to
    + * third parties or used, copied, or duplicated in any form, in whole
    + * or in part, without the prior written consent of Brocade Communications.
    + *
    + */
    +#include <cs/bfa_log.h>
    +#include <aen/bfa_aen_adapter.h>
    +#include <aen/bfa_aen_audit.h>
    +#include <aen/bfa_aen_ethport.h>
    +#include <aen/bfa_aen_ioc.h>
    +#include <aen/bfa_aen_itnim.h>
    +#include <aen/bfa_aen_lport.h>
    +#include <aen/bfa_aen_port.h>
    +#include <aen/bfa_aen_rport.h>
    +#include <log/bfa_log_fcs.h>
    +#include <log/bfa_log_hal.h>
    +#include <log/bfa_log_linux.h>
    +#include <log/bfa_log_wdrv.h>
    +
    +struct bfa_log_msgdef_s bfa_log_msg_array[] = {
    +
    +
    +/* messages define for BFA_AEN_CAT_ADAPTER Module */
    +{BFA_AEN_ADAPTER_ADD, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_ADAPTER_ADD",
    + "New adapter found: SN = %s, base port WWN = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
    +
    +{BFA_AEN_ADAPTER_REMOVE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_WARNING, "BFA_AEN_ADAPTER_REMOVE",
    + "Adapter removed: SN = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +
    +
    +
    +/* messages define for BFA_AEN_CAT_AUDIT Module */
    +{BFA_AEN_AUDIT_AUTH_ENABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_INFO, "BFA_AEN_AUDIT_AUTH_ENABLE",
    + "Authentication enabled for base port: WWN = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_AEN_AUDIT_AUTH_DISABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_INFO, "BFA_AEN_AUDIT_AUTH_DISABLE",
    + "Authentication disabled for base port: WWN = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +
    +
    +
    +/* messages define for BFA_AEN_CAT_ETHPORT Module */
    +{BFA_AEN_ETHPORT_LINKUP, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_ETHPORT_LINKUP",
    + "Base port ethernet linkup: mac = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_AEN_ETHPORT_LINKDOWN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_ETHPORT_LINKDOWN",
    + "Base port ethernet linkdown: mac = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_AEN_ETHPORT_ENABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_ETHPORT_ENABLE",
    + "Base port ethernet interface enabled: mac = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_AEN_ETHPORT_DISABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_ETHPORT_DISABLE",
    + "Base port ethernet interface disabled: mac = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +
    +
    +
    +/* messages define for BFA_AEN_CAT_IOC Module */
    +{BFA_AEN_IOC_HBGOOD, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_IOC_HBGOOD",
    + "Heart Beat of IOC %d is good.",
    + ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_AEN_IOC_HBFAIL, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_CRITICAL,
    + "BFA_AEN_IOC_HBFAIL",
    + "Heart Beat of IOC %d has failed.",
    + ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_AEN_IOC_ENABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_IOC_ENABLE",
    + "IOC %d is enabled.",
    + ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_AEN_IOC_DISABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_IOC_DISABLE",
    + "IOC %d is disabled.",
    + ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1},
    +
    +
    +
    +
    +/* messages define for BFA_AEN_CAT_ITNIM Module */
    +{BFA_AEN_ITNIM_ONLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_ITNIM_ONLINE",
    + "Target (WWN = %s) is online for initiator (WWN = %s).",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
    +
    +{BFA_AEN_ITNIM_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_ITNIM_OFFLINE",
    + "Target (WWN = %s) offlined by initiator (WWN = %s).",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
    +
    +{BFA_AEN_ITNIM_DISCONNECT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_ERROR, "BFA_AEN_ITNIM_DISCONNECT",
    + "Target (WWN = %s) connectivity lost for initiator (WWN = %s).",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
    +
    +
    +
    +
    +/* messages define for BFA_AEN_CAT_LPORT Module */
    +{BFA_AEN_LPORT_NEW, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_LPORT_NEW",
    + "New logical port created: WWN = %s, Role = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
    +
    +{BFA_AEN_LPORT_DELETE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_LPORT_DELETE",
    + "Logical port deleted: WWN = %s, Role = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
    +
    +{BFA_AEN_LPORT_ONLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_LPORT_ONLINE",
    + "Logical port online: WWN = %s, Role = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
    +
    +{BFA_AEN_LPORT_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_LPORT_OFFLINE",
    + "Logical port taken offline: WWN = %s, Role = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
    +
    +{BFA_AEN_LPORT_DISCONNECT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_ERROR, "BFA_AEN_LPORT_DISCONNECT",
    + "Logical port lost fabric connectivity: WWN = %s, Role = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
    +
    +{BFA_AEN_LPORT_NEW_PROP, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_LPORT_NEW_PROP",
    + "New virtual port created using proprietary interface: WWN = %s, Role = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
    +
    +{BFA_AEN_LPORT_DELETE_PROP, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_INFO, "BFA_AEN_LPORT_DELETE_PROP",
    + "Virtual port deleted using proprietary interface: WWN = %s, Role = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
    +
    +{BFA_AEN_LPORT_NEW_STANDARD, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_INFO, "BFA_AEN_LPORT_NEW_STANDARD",
    + "New virtual port created using standard interface: WWN = %s, Role = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
    +
    +{BFA_AEN_LPORT_DELETE_STANDARD, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_INFO, "BFA_AEN_LPORT_DELETE_STANDARD",
    + "Virtual port deleted using standard interface: WWN = %s, Role = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
    +
    +{BFA_AEN_LPORT_NPIV_DUP_WWN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_WARNING, "BFA_AEN_LPORT_NPIV_DUP_WWN",
    + "Virtual port login failed. Duplicate WWN = %s reported by fabric.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_AEN_LPORT_NPIV_FABRIC_MAX, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_WARNING, "BFA_AEN_LPORT_NPIV_FABRIC_MAX",
    + "Virtual port (WWN = %s) login failed. Max NPIV ports already exist in fabric/fport.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_AEN_LPORT_NPIV_UNKNOWN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_WARNING, "BFA_AEN_LPORT_NPIV_UNKNOWN",
    + "Virtual port (WWN = %s) login failed.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +
    +
    +
    +/* messages define for BFA_AEN_CAT_PORT Module */
    +{BFA_AEN_PORT_ONLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_WARNING,
    + "BFA_AEN_PORT_ONLINE",
    + "Base port online: WWN = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_AEN_PORT_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_WARNING,
    + "BFA_AEN_PORT_OFFLINE",
    + "Base port offline: WWN = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_AEN_PORT_RLIR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_PORT_RLIR",
    + "RLIR event not supported.",
    + (0), 0},
    +
    +{BFA_AEN_PORT_SFP_INSERT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_PORT_SFP_INSERT",
    + "New SFP found: port %d, WWN = %s.",
    + ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
    +
    +{BFA_AEN_PORT_SFP_REMOVE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_WARNING, "BFA_AEN_PORT_SFP_REMOVE",
    + "SFP removed: port %d, WWN = %s.",
    + ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
    +
    +{BFA_AEN_PORT_SFP_POM, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_WARNING,
    + "BFA_AEN_PORT_SFP_POM",
    + "SFP POM level to %s: port %d, WWN = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) |
    + (BFA_LOG_S << BFA_LOG_ARG2) | 0), 3},
    +
    +{BFA_AEN_PORT_ENABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_PORT_ENABLE",
    + "Base port enabled: WWN = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_AEN_PORT_DISABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_PORT_DISABLE",
    + "Base port disabled: WWN = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_AEN_PORT_AUTH_ON, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_PORT_AUTH_ON",
    + "Authentication successful for base port: WWN = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_AEN_PORT_AUTH_OFF, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_ERROR,
    + "BFA_AEN_PORT_AUTH_OFF",
    + "Authentication unsuccessful for base port: WWN = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_AEN_PORT_DISCONNECT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_ERROR,
    + "BFA_AEN_PORT_DISCONNECT",
    + "Base port (WWN = %s) lost fabric connectivity.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_AEN_PORT_QOS_NEG, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_WARNING,
    + "BFA_AEN_PORT_QOS_NEG",
    + "QOS negotiation failed for base port: WWN = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_AEN_PORT_FABRIC_NAME_CHANGE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_WARNING, "BFA_AEN_PORT_FABRIC_NAME_CHANGE",
    + "Base port WWN = %s, Fabric WWN = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
    +
    +
    +
    +
    +/* messages define for BFA_AEN_CAT_RPORT Module */
    +{BFA_AEN_RPORT_ONLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_RPORT_ONLINE",
    + "Remote port (WWN = %s) online for logical port (WWN = %s).",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
    +
    +{BFA_AEN_RPORT_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_RPORT_OFFLINE",
    + "Remote port (WWN = %s) offlined by logical port (WWN = %s).",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
    +
    +{BFA_AEN_RPORT_DISCONNECT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_ERROR, "BFA_AEN_RPORT_DISCONNECT",
    + "Remote port (WWN = %s) connectivity lost for logical port (WWN = %s).",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
    +
    +{BFA_AEN_RPORT_QOS_PRIO, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_RPORT_QOS_PRIO",
    + "QOS priority changed to %s: RPWWN = %s and LPWWN = %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) |
    + (BFA_LOG_S << BFA_LOG_ARG2) | 0), 3},
    +
    +{BFA_AEN_RPORT_QOS_FLOWID, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "BFA_AEN_RPORT_QOS_FLOWID",
    + "QOS flow ID changed to %d: RPWWN = %s and LPWWN = %s.",
    + ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) |
    + (BFA_LOG_S << BFA_LOG_ARG2) | 0), 3},
    +
    +
    +
    +
    +/* messages define for FCS Module */
    +{BFA_LOG_FCS_FABRIC_NOSWITCH, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_INFO, "FCS_FABRIC_NOSWITCH",
    + "No switched fabric presence is detected.",
    + (0), 0},
    +
    +{BFA_LOG_FCS_FABRIC_ISOLATED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_INFO, "FCS_FABRIC_ISOLATED",
    + "Port is isolated due to VF_ID mismatch. PWWN: %s, Port VF_ID: %04x and switch port VF_ID: %04x.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_X << BFA_LOG_ARG1) |
    + (BFA_LOG_X << BFA_LOG_ARG2) | 0), 3},
    +
    +
    +
    +
    +/* messages define for HAL Module */
    +{BFA_LOG_HAL_ASSERT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_ERROR,
    + "HAL_ASSERT",
    + "Assertion failure: %s:%d: %s",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) |
    + (BFA_LOG_S << BFA_LOG_ARG2) | 0), 3},
    +
    +{BFA_LOG_HAL_HEARTBEAT_FAILURE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_CRITICAL, "HAL_HEARTBEAT_FAILURE",
    + "Firmware heartbeat failure at %d",
    + ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_LOG_HAL_FCPIM_PARM_INVALID, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_INFO, "HAL_FCPIM_PARM_INVALID",
    + "Driver configuration %s value %d is invalid. Value should be within %d and %d.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) |
    + (BFA_LOG_D << BFA_LOG_ARG2) | (BFA_LOG_D << BFA_LOG_ARG3) | 0), 4},
    +
    +
    +
    +
    +/* messages define for LINUX Module */
    +{BFA_LOG_LINUX_DEVICE_CLAIMED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_INFO, "LINUX_DEVICE_CLAIMED",
    + "bfa device at %s claimed.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_LOG_LINUX_HASH_INIT_FAILED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_INFO, "LINUX_HASH_INIT_FAILED",
    + "Hash table initialization failure for the port %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_LOG_LINUX_SYSFS_FAILED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_INFO, "LINUX_SYSFS_FAILED",
    + "sysfs file creation failure for the port %s.",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_LOG_LINUX_MEM_ALLOC_FAILED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_INFO, "LINUX_MEM_ALLOC_FAILED",
    + "Memory allocation failed: %s. ",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_LOG_LINUX_DRIVER_REGISTRATION_FAILED,
    + BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "LINUX_DRIVER_REGISTRATION_FAILED",
    + "%s. ",
    + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_LOG_LINUX_ITNIM_FREE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "LINUX_ITNIM_FREE",
    + "scsi%d: FCID: %s WWPN: %s",
    + ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) |
    + (BFA_LOG_S << BFA_LOG_ARG2) | 0), 3},
    +
    +{BFA_LOG_LINUX_ITNIM_ONLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_INFO, "LINUX_ITNIM_ONLINE",
    + "Target: %d:0:%d FCID: %s WWPN: %s",
    + ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) |
    + (BFA_LOG_S << BFA_LOG_ARG2) | (BFA_LOG_S << BFA_LOG_ARG3) | 0), 4},
    +
    +{BFA_LOG_LINUX_ITNIM_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_INFO, "LINUX_ITNIM_OFFLINE",
    + "Target: %d:0:%d FCID: %s WWPN: %s",
    + ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) |
    + (BFA_LOG_S << BFA_LOG_ARG2) | (BFA_LOG_S << BFA_LOG_ARG3) | 0), 4},
    +
    +{BFA_LOG_LINUX_SCSI_HOST_FREE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_INFO, "LINUX_SCSI_HOST_FREE",
    + "Free scsi%d",
    + ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1},
    +
    +{BFA_LOG_LINUX_SCSI_ABORT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
    + "LINUX_SCSI_ABORT",
    + "scsi%d: abort cmnd %p, iotag %x",
    + ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_P << BFA_LOG_ARG1) |
    + (BFA_LOG_X << BFA_LOG_ARG2) | 0), 3},
    +
    +{BFA_LOG_LINUX_SCSI_ABORT_COMP, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_INFO, "LINUX_SCSI_ABORT_COMP",
    + "scsi%d: complete abort 0x%p, iotag 0x%x",
    + ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_P << BFA_LOG_ARG1) |
    + (BFA_LOG_X << BFA_LOG_ARG2) | 0), 3},
    +
    +
    +
    +
    +/* messages define for WDRV Module */
    +{BFA_LOG_WDRV_IOC_INIT_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_INFO, "WDRV_IOC_INIT_ERROR",
    + "IOC initialization has failed.",
    + (0), 0},
    +
    +{BFA_LOG_WDRV_IOC_INTERNAL_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_INFO, "WDRV_IOC_INTERNAL_ERROR",
    + "IOC internal error. ",
    + (0), 0},
    +
    +{BFA_LOG_WDRV_IOC_START_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_INFO, "WDRV_IOC_START_ERROR",
    + "IOC could not be started. ",
    + (0), 0},
    +
    +{BFA_LOG_WDRV_IOC_STOP_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_INFO, "WDRV_IOC_STOP_ERROR",
    + "IOC could not be stopped. ",
    + (0), 0},
    +
    +{BFA_LOG_WDRV_INSUFFICIENT_RESOURCES, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_INFO, "WDRV_INSUFFICIENT_RESOURCES",
    + "Insufficient memory. ",
    + (0), 0},
    +
    +{BFA_LOG_WDRV_BASE_ADDRESS_MAP_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
    + BFA_LOG_INFO, "WDRV_BASE_ADDRESS_MAP_ERROR",
    + "Unable to map the IOC onto the system address space. ",
    + (0), 0},
    +
    +
    +{0, 0, 0, "", "", 0, 0},
    +};
    diff -urpN orig/drivers/scsi/bfa/bfa_lport.c patch/drivers/scsi/bfa/bfa_lport.c
    --- orig/drivers/scsi/bfa/bfa_lport.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_lport.c 2009-04-01 20:08:47.294329000 -0700
    @@ -0,0 +1,585 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +/**
    + * lport.c BFA LPORT
    + */
    +
    +#include <bfa.h>
    +#include <bfa_lport.h>
    +#include <bfa_rport.h>
    +#include <bfa_fabric.h>
    +#include <bfi/bfi_lport.h>
    +
    +BFA_TRC_FILE(HAL, LPORT);
    +BFA_MODULE(lport);
    +
    +/**
    + * lport_priv BFA LPORT Private Functions
    + */
    +
    +static void
    +bfa_lport_event(struct bfa_lport_s *lport, enum bfi_lport_state_e state)
    +{
    + struct bfa_s *bfa = lport->bfa;
    +
    + bfa_trc(bfa, state);
    + switch (state) {
    + case BFI_LPORT_ONLINE:
    + bfa_cb_lport_online(bfa->bfad, lport->port_cfg.roles,
    + bfa_vf_get_drv_vf(lport->fabric),
    + (lport->vport == NULL) ? NULL :
    + bfa_vport_get_vpdrv(lport->vport));
    + break;
    +
    + case BFI_LPORT_OFFLINE:
    + bfa_cb_lport_offline(bfa->bfad, lport->port_cfg.roles,
    + bfa_vf_get_drv_vf(lport->fabric),
    + (lport->vport == NULL) ? NULL :
    + bfa_vport_get_vpdrv(lport->vport));
    + break;
    +
    + case BFI_LPORT_DELETE:
    + bfa_cb_lport_delete(bfa->bfad, lport->port_cfg.roles,
    + bfa_vf_get_drv_vf(lport->fabric),
    + (lport->vport == NULL) ? NULL :
    + bfa_vport_get_vpdrv(lport->vport));
    + break;
    + }
    +}
    +
    +
    +
    +/**
    + * lport_protected BFA LPORT Protected Functions
    + */
    +
    +/**
    + * Called by rport module when new rports are discovered.
    + */
    +
    +static void
    +bfa_lport_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
    + u32 *dm_len)
    +{
    + if (cfg->fwcfg.num_lports < BFA_LPORT_MIN)
    + cfg->fwcfg.num_lports = BFA_LPORT_MIN;
    + if (cfg->fwcfg.num_lports > BFA_LPORT_MAX)
    + cfg->fwcfg.num_lports = BFA_LPORT_MAX;
    +
    + *km_len += cfg->fwcfg.num_lports * sizeof(struct bfa_lptag_s);
    + *dm_len += cfg->fwcfg.num_lports * BFI_LPORT_PSNLEN;
    +}
    +
    +static void
    +bfa_lport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
    + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
    +{
    + struct bfa_lport_mod_s *mod = BFA_LPORT_MOD(bfa);
    + struct bfa_lptag_s *lptag;
    + int i;
    + u32 psnbufsz;
    +
    + INIT_LIST_HEAD(&mod->lptag_free_q);
    + INIT_LIST_HEAD(&mod->lptag_active_q);
    +
    + lptag = (struct bfa_lptag_s *) bfa_meminfo_kva(meminfo);
    + mod->lptag_list = lptag;
    +
    + mod->num_lptags = cfg->fwcfg.num_lports;
    +
    + bfa_assert(mod->num_lptags
    + && !(mod->num_lptags & (mod->num_lptags - 1)));
    +
    + for (i = 0; i < mod->num_lptags; i++, lptag++) {
    + bfa_os_memset(lptag, 0, sizeof(struct bfa_lptag_s));
    + lptag->lport_tag = i;
    +
    + /**
    + * 0 is reserved for baseport
    + */
    + if (i)
    + list_add_tail(&lptag->qe, &mod->lptag_free_q);
    + }
    +
    + /**
    + * consume memory
    + */
    + bfa_meminfo_kva(meminfo) = (u8 *) lptag;
    +
    + psnbufsz = mod->num_lptags * BFI_LPORT_PSNLEN;
    + mod->psnbase.pa = bfa_meminfo_dma_phys(meminfo);
    + bfa_meminfo_dma_phys(meminfo) += psnbufsz;
    +
    + mod->psnbase.kva = bfa_meminfo_dma_virt(meminfo);
    + bfa_meminfo_dma_virt(meminfo) += psnbufsz;
    +}
    +
    +static void
    +bfa_lport_initdone(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_lport_detach(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_lport_start(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_lport_stop(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_lport_iocdisable(struct bfa_s *bfa)
    +{
    +}
    +
    +void
    +bfa_lport_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
    +{
    + union bfi_lport_i2h_msg_u msg;
    + struct bfa_lport_s *lport;
    +
    + msg.msg = m;
    + bfa_trc(bfa, m->mhdr.msg_id);
    + switch (m->mhdr.msg_id) {
    + case BFI_LPORT_I2H_EVENT:
    + lport = BFA_LPORT_FROM_TAG(bfa,
    + bfa_os_htons(msg.event->lport_tag));
    + lport->pid = msg.event->pid;
    + bfa_lport_event(lport, msg.event->lport_state);
    + break;
    +
    + default:
    + bfa_trc(bfa, m->mhdr.msg_id);
    + bfa_assert(0);
    + }
    +}
    +
    +void
    +bfa_lport_init(struct bfa_lport_s *lport, struct bfa_s *bfa,
    + u16 fabric_tag, struct bfa_lptag_s *lp_tag,
    + struct bfa_port_cfg_s *port_cfg, struct bfa_vport_s *vport)
    +{
    + struct bfa_lport_mod_s *mod = BFA_LPORT_MOD(bfa);
    + u8 *psn;
    +
    + if (lp_tag) {
    + lport->lp_tag = lp_tag;
    + lport->lp_tag->lport = lport;
    + psn = (u8 *)mod->psnbase.kva +
    + (lp_tag->lport_tag * BFI_LPORT_PSNLEN);
    + memcpy((void *)psn, (void *)port_cfg->sym_name.symname,
    + BFI_LPORT_PSNLEN);
    + } else {
    + lport->lp_tag = BFA_LPTAG_FROM_TAG(bfa, 0);
    + lport->lp_tag->lport = lport;
    + }
    +
    + bfa_trc(bfa, fabric_tag);
    + bfa_trc(bfa, lport->lp_tag->lport_tag);
    + lport->fabric_tag = fabric_tag;
    + lport->fabric = bfa_vf_lookup(bfa, fabric_tag);
    + lport->port_cfg.pwwn = port_cfg->pwwn;
    + lport->port_cfg.nwwn = port_cfg->nwwn;
    + lport->port_cfg.roles = port_cfg->roles;
    + bfa_trc(bfa, lport->port_cfg.roles);
    + memcpy(&lport->port_cfg.sym_name, &(port_cfg->sym_name),
    + sizeof(struct bfa_port_symname_s));
    + lport->bfa = bfa;
    + lport->vport = vport;
    + /*TODO*/
    + lport->bfad_port = bfa_cb_port_new(bfa->bfad, lport,
    + port_cfg->roles, lport->fabric->vf_drv,
    + vport ? vport->vport_drv : NULL);
    +}
    +
    +struct bfa_lptag_s *
    +bfa_lport_tag_alloc(struct bfa_lport_mod_s *mod)
    +{
    + struct bfa_lptag_s *lptag;
    +
    + bfa_q_deq(&mod->lptag_free_q, &lptag);
    + if (lptag)
    + list_add_tail(&lptag->qe, &mod->lptag_active_q);
    +
    + return (lptag);
    +}
    +
    +void
    +bfa_lport_lptag_free(struct bfa_lptag_s *lptag)
    +{
    + struct bfa_lport_mod_s *mod = BFA_LPORT_MOD(lptag->lport->bfa);
    +
    + bfa_trc(lptag->lport->bfa, lptag->lport_tag);
    + bfa_assert(bfa_q_is_on_q(&mod->lptag_active_q, lptag));
    + lptag->lport = NULL;
    + list_del(&lptag->qe);
    + list_add_tail(&lptag->qe, &mod->lptag_free_q);
    +}
    +
    +void
    +bfa_lport_msg_init(struct bfa_lport_s *lport, struct bfi_vport_create_req_s *m)
    +{
    + struct bfa_lport_mod_s *mod = BFA_LPORT_MOD(lport->bfa);
    + u16 lport_tag = lport->lp_tag->lport_tag;
    +
    + m->fabric_tag = bfa_os_htons(lport->fabric_tag);
    + m->vport_tag = bfa_os_htons(lport_tag);
    + m->lport_cfg.pwwn = lport->port_cfg.pwwn;
    + m->lport_cfg.nwwn = lport->port_cfg.nwwn;
    + m->lport_cfg.roles = lport->port_cfg.roles;
    +
    + bfa_dma_be_addr_set(m->psn_addr,
    + (mod->psnbase.pa + (lport_tag * BFI_LPORT_PSNLEN)));
    +}
    +
    +bfa_boolean_t
    +bfa_lport_is_initiator(struct bfa_s *bfa, u16 lport_tag)
    +{
    + struct bfa_lport_s *lport;
    +
    + lport = (struct bfa_lport_s *)BFA_LPORT_FROM_TAG(bfa, lport_tag);
    + return(lport->port_cfg.roles & BFA_PORT_ROLE_FCP_IM);
    +}
    +
    +bfa_boolean_t
    +bfa_lport_is_target(struct bfa_s *bfa, u16 lport_tag)
    +{
    + struct bfa_lport_s *lport;
    +
    + lport = (struct bfa_lport_s *)BFA_LPORT_FROM_TAG(bfa, lport_tag);
    + return(lport->port_cfg.roles & BFA_PORT_ROLE_FCP_TM);
    +}
    +
    +
    +
    +/**
    + * lport_api BFA LPORT API
    + */
    +
    +void
    +bfa_cfg_base_port(struct bfa_s *bfa, struct bfa_port_cfg_s *port_cfg)
    +{
    +}
    +
    +/* This should be a Fabric function */
    +struct bfa_lport_s *
    +bfa_get_base_port(struct bfa_s *bfa)
    +{
    + return (&bfa->fabric.bport);
    +}
    +
    +#if 0
    +wwn_t
    +bfa_lport_get_rport(struct bfa_lport_s *port, wwn_t wwn, int index, int nrports,
    + bfa_boolean_t bwwn)
    +{
    + struct list_head *qh, *qe;
    + struct bfa_rport_s *rport = NULL;
    + int i;
    + struct bfa_s *bfa;
    +
    + if (port == NULL || nrports == 0)
    + return (wwn_t)0;
    +
    + bfa = port->bfa;
    + bfa_trc(bfa, (u32) nrports);
    +
    + i = 0;
    + qh = &port->rport_q;
    + qe = bfa_q_first(qh);
    +
    + while ((qe != qh) && (i < nrports)) {
    + rport = (struct bfa_rport_s *)qe;
    + if (bfa_os_ntoh3b(rport->rport_info.pid) > 0xFFF000) {
    + qe = bfa_q_next(qe);
    + bfa_trc(bfa, (u32) rport->rport_info.pwwn);
    + bfa_trc(bfa, rport->rport_info.pid);
    + bfa_trc(bfa, i);
    + continue;
    + }
    +
    + if (bwwn) {
    + if (!memcmp(&wwn, &rport->rport_info.pwwn, 8))
    + break;
    + } else {
    + if (i == index)
    + break;
    + }
    +
    + i++;
    + qe = bfa_q_next(qe);
    + }
    +
    + bfa_trc(bfa, i);
    + if (rport) {
    + return rport->rport_info.pwwn;
    + } else {
    + return (wwn_t) 0;
    + }
    +}
    +#endif
    +
    +void
    +bfa_lport_get_rports(struct bfa_lport_s *port, wwn_t rport_wwns[], int *nrports)
    +{
    +}
    +#if 0
    +void
    +bfa_lport_get_rports(struct bfa_lport_s *port, wwn_t rport_wwns[], int *nrports)
    +{
    + struct list_head *qh, *qe;
    + struct bfa_rport_s *rport = NULL;
    + int i;
    + struct bfa_s *bfa;
    +
    + if (port == NULL || rport_wwns == NULL || *nrports == 0)
    + return;
    +
    + bfa = port->bfa;
    + bfa_trc(bfa, (u32) *nrports);
    +
    + i = 0;
    + qh = &port->rport_q;
    + qe = bfa_q_first(qh);
    +
    + while ((qe != qh) && (i < *nrports)) {
    + rport = (struct bfa_rport_s *) qe;
    + if (bfa_os_ntoh3b(rport->rport_info.pid) > 0xFFF000) {
    + qe = bfa_q_next(qe);
    + bfa_trc(bfa, (u32) rport->rport_info.pwwn);
    + bfa_trc(bfa, rport->rport_info.pid);
    + bfa_trc(bfa, i);
    + continue;
    + }
    +
    + rport_wwns[i] = rport->rport_info.pwwn;
    +
    + i++;
    + qe = bfa_q_next(qe);
    + }
    +
    + bfa_trc(bfa, i);
    + *nrports = i;
    + return;
    +}
    +#endif
    +
    +/* This needs to be obtained from FW */
    +/*
    + * Iterate's through all the rport's in the given port to
    + * determine the maximum operating speed.
    + */
    +#if 0
    +bfa_pport_speed_t
    +bfa_lport_get_rport_max_speed(bfa_lport_t *port)
    +{
    + bfa_q_t *qh, *qe;
    + bfa_rport_t *rport = NULL;
    + bfa_t *bfa;
    + bfa_pport_speed_t max_speed = 0;
    + bfa_pport_attr_t pport_attr;
    + bfa_pport_speed_t pport_speed;
    +
    + if (port == NULL)
    + return 0;
    +
    + bfa = port->bfa;
    +
    + /* Get Physical port's current speed */
    + bfa_pport_get_attr(bfa, &pport_attr);
    + pport_speed = pport_attr.speed;
    + bfa_trc(bfa, pport_speed);
    +
    + qh = &port->rport_q;
    + qe = bfa_q_first(qh);
    +
    + while (qe != qh) {
    + rport = (bfa_rport_t *) qe;
    + if ((bfa_os_ntoh3b(rport->rport_info.pid) > 0xFFF000) ||
    + (bfa_rport_get_state(rport) == BFA_RPORT_OFFLINE)) {
    + qe = bfa_q_next(qe);
    + continue;
    + }
    +
    + if ((rport->rport_info.rpsc_speed == BFA_PPORT_SPEED_8GBPS) ||
    + (rport->rport_info.rpsc_speed > pport_speed)) {
    + max_speed = rport->rport_info.rpsc_speed;
    + break;
    + } else if (rport->rport_info.rpsc_speed > max_speed)
    + max_speed = rport->rport_info.rpsc_speed;
    +
    + qe = bfa_q_next(qe);
    + }
    +
    + bfa_trc(bfa, max_speed);
    + return max_speed;
    +}
    +#endif
    +
    +struct bfa_lport_s *
    +bfa_lport_lookup_port(struct bfa_s *bfa, u16 vf_id, wwn_t lpwwn)
    +{
    + struct bfa_vport_s *vport;
    + struct bfa_fabric_s *vf;
    +
    + bfa_assert(bfa != NULL);
    +
    + bfa_trc(bfa, vf_id);
    + vf = bfa_vf_lookup(bfa, vf_id);
    + if (vf == NULL) {
    + bfa_trc(bfa, vf_id);
    + return (NULL);
    + }
    +
    + if (!lpwwn || (vf->bport.port_cfg.pwwn == lpwwn))
    + return (&vf->bport);
    +
    + vport = bfa_fabric_vport_lookup(vf, lpwwn);
    + if (vport) {
    + bfa_trc(bfa, vport->lport.lp_tag->lport_tag);
    + return (&vport->lport);
    + }
    +
    + return (NULL);
    +}
    +
    +/*
    + * API corresponding to VmWare's NPIV_VPORT_GETINFO.
    + */
    +void
    +bfa_lport_get_info(struct bfa_lport_s *port, struct bfa_port_info_s *port_info)
    +{
    +
    + bfa_trc(port->bfa, port->bfa->fabric.fabric_name);
    +
    + if (port->vport == NULL) {
    + /*
    + * This is a Physical port
    + */
    + port_info->port_type = BFA_PORT_TYPE_PHYSICAL;
    +
    + /*
    + * @todo : need to fix the state & reason
    + */
    + port_info->port_state = 0;
    + port_info->offline_reason = 0;
    +
    + port_info->port_wwn = bfa_lport_get_pwwn(port);
    + port_info->node_wwn = bfa_lport_get_nwwn(port);
    +
    + port_info->max_vports_supp = BFA_MAX_VPORTS_SUPP;
    + port_info->num_vports_inuse =
    + bfa_fabric_vport_count(&port->bfa->fabric);
    + port_info->max_rports_supp = BFA_MAX_RPORTS_SUPP;
    + //port_info->num_rports_inuse = port->num_rports;
    + } else {
    + /*
    + * This is a virtual port
    + */
    + port_info->port_type = BFA_PORT_TYPE_VIRTUAL;
    +
    + /*
    + * @todo : need to fix the state & reason
    + */
    + port_info->port_state = 0;
    + port_info->offline_reason = 0;
    +
    + port_info->port_wwn = bfa_lport_get_pwwn(port);
    + port_info->node_wwn = bfa_lport_get_nwwn(port);
    + }
    +}
    +
    +void
    +bfa_lport_get_stats(struct bfa_lport_s *lport,
    + struct bfa_port_stats_s *port_stats)
    +{
    + /* Send message to FW */
    + return;
    +}
    +
    +void
    +bfa_lport_clear_stats(struct bfa_lport_s *lport)
    +{
    + /* Send message to FW */
    + return;
    +}
    +
    +void
    +bfa_lport_enable_ipfc_roles(struct bfa_lport_s *lport)
    +{
    + /* ??? */
    + lport->port_cfg.roles |= BFA_PORT_ROLE_FCP_IPFC;
    + return;
    +}
    +
    +void
    +bfa_lport_disable_ipfc_roles(struct bfa_lport_s *lport)
    +{
    + /* ??? */
    + lport->port_cfg.roles &= ~BFA_PORT_ROLE_FCP_IPFC;
    + return;
    +}
    +
    +void
    +bfa_lport_get_attr(struct bfa_lport_s *port, struct bfa_port_attr_s *port_attr)
    +{
    + struct bfa_fabric_s *fabric = bfa_vf_lookup(port->bfa,
    + port->fabric_tag);
    +
    + memset(port_attr, 0, sizeof(struct bfa_port_attr_s));
    +
    + port_attr->pid = port->pid;
    + port_attr->port_type = bfa_fabric_port_type(fabric);
    + port_attr->fabric_name = bfa_lport_get_fabric_name(port);
    + port_attr->loopback = bfa_fabric_is_loopback(fabric);
    + port_attr->port_cfg.pwwn = port->port_cfg.pwwn;
    + port_attr->port_cfg.nwwn = port->port_cfg.nwwn;
    + port_attr->port_cfg.roles = port->port_cfg.roles;
    + //port_attr->fabric_ip_addr
    + //port_attr->state = BFA_PORT_ONLINE; TODO
    + memcpy(&port_attr->port_cfg.sym_name, &port->port_cfg.sym_name,
    + sizeof(struct bfa_port_symname_s));
    +}
    +
    +wwn_t bfa_lport_get_nwwn(struct bfa_lport_s *lport)
    +{
    + bfa_assert(lport);
    + return lport->port_cfg.nwwn;
    +}
    +wwn_t bfa_lport_get_pwwn(struct bfa_lport_s *lport)
    +{
    + bfa_assert(lport);
    + return lport->port_cfg.pwwn;
    +}
    +
    +
    +wwn_t bfa_lport_get_fabric_name(struct bfa_lport_s *lport)
    +{
    + struct bfa_fabric_s *fabric = bfa_vf_lookup(lport->bfa, lport->fabric_tag);
    +
    + return fabric->fabric_name;
    +}
    +
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_lport.h patch/drivers/scsi/bfa/bfa_lport.h
    --- orig/drivers/scsi/bfa/bfa_lport.h 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_lport.h 2009-04-01 20:08:47.302868000 -0700
    @@ -0,0 +1,180 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +/**
    + * bfa_lport.h BFA port module public interface
    + */
    +
    +#ifndef __BFA_LPORT_H__
    +#define __BFA_LPORT_H__
    +
    +#include <bfi/bfi_vport.h>
    +#include <bfa_ioc.h>
    +
    +/**
    + * P R I V A T E D E F I N I T I O N S
    + * - Used & visible to BFA RPORT module alone (private)
    + */
    +
    +#define BFA_LPORT_MIN 1
    +#define BFA_LPORT_MAX 256
    +#define BFA_MAX_RPORTS_SUPP 1024
    +#define BFA_MAX_VPORTS_SUPP 255
    +
    +#define bfa_lport_get_fcid(_lport) ((_lport)->pid)
    +
    +struct bfa_lport_s;
    +struct bfa_lptag_s;
    +struct bfad_s;
    +struct bfad_vport_s;
    +struct bfad_vf_s;
    +
    +struct bfa_lport_mod_s {
    + struct bfa_lptag_s *lptag_list; /* list of lport tags list */
    + struct list_head lptag_free_q; /* free lport tags */
    + struct list_head lptag_active_q; /* active lport tags */
    + u16 num_lptags; /* number of lport tags */
    + struct bfa_dma_s psnbase;
    +};
    +
    +/**
    + * P R O T E C T E D D E F I N I T I O N S
    + * - Shared between modules within BFA layer (protected)
    + */
    +
    +struct bfa_lptag_s {
    + struct list_head qe; /* queue element */
    + u16 lport_tag; /* lport tag */
    + struct bfa_lport_s *lport;
    +};
    +
    +
    +struct bfa_lport_s {
    + u16 fabric_tag;
    + struct bfa_fabric_s *fabric;
    + struct bfa_lptag_s *lp_tag;
    + struct bfa_port_cfg_s port_cfg;
    + u32 pid:24;
    + struct bfa_s *bfa;
    + struct bfa_vport_s *vport; /* NULL for base ports */
    + struct bfad_port_s *bfad_port;
    +};
    +
    +#define BFA_LPORT_MOD(__bfa) (&(__bfa)->modules.lport_mod)
    +/**
    + * Convert lport tag to LPORT
    + */
    +#define BFA_LPORT_FROM_TAG(__bfa, _tag) \
    + ((struct bfa_lptag_s *)(BFA_LPORT_MOD(__bfa)->lptag_list + \
    + ((_tag) & (BFA_LPORT_MOD(__bfa)->num_lptags - 1))))->lport
    +
    +#define BFA_LPTAG_FROM_TAG(__bfa, _tag) \
    + BFA_LPORT_MOD(__bfa)->lptag_list + \
    + ((_tag) & (BFA_LPORT_MOD(__bfa)->num_lptags - 1))
    +
    +#define BFA_LPTAG_FROM_LPORT(_lport) _lport->lp_tag
    +
    +void bfa_lport_init(struct bfa_lport_s *lport, struct bfa_s *bfa,
    + u16 fabric_tag, struct bfa_lptag_s *lport_tag,
    + struct bfa_port_cfg_s *port_cfg, struct bfa_vport_s *vport);
    +void bfa_lport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
    +struct bfa_lptag_s *bfa_lport_tag_alloc(struct bfa_lport_mod_s *mod);
    +void bfa_lport_lptag_free(struct bfa_lptag_s *lptag);
    +void bfa_lport_msg_init(struct bfa_lport_s *lport,
    + struct bfi_vport_create_req_s *m);
    +bfa_boolean_t bfa_lport_is_initiator(struct bfa_s *bfa, u16 lport_tag);
    +bfa_boolean_t bfa_lport_is_target(struct bfa_s *bfa, u16 lport_tag);
    +
    +/**
    + * P U B L I C D E F I N I T I O N S
    + * - Shared between BFA layer & Host Drivers (public)
    + */
    +
    +void bfa_lport_get_rports(struct bfa_lport_s *lport,
    + wwn_t rport_wwns[], int *nrports);
    +wwn_t bfa_lport_get_rport(struct bfa_lport_s *port, wwn_t wwn,
    + int index, int nrports, bfa_boolean_t bwwn);
    +struct bfa_lport_s *bfa_lport_lookup_port(struct bfa_s *bfa,
    + u16 vf_id, wwn_t lpwwn);
    +void bfa_lport_get_info(struct bfa_lport_s *lport,
    + struct bfa_port_info_s *port_info);
    +void bfa_lport_get_attr(struct bfa_lport_s *port,
    + struct bfa_port_attr_s *port_attr);
    +void bfa_lport_get_stats(struct bfa_lport_s *lport,
    + struct bfa_port_stats_s *port_stats);
    +void bfa_lport_clear_stats(struct bfa_lport_s *lport);
    +enum bfa_pport_speed bfa_lport_get_rport_max_speed(struct bfa_lport_s *port);
    +void bfa_lport_enable_ipfc_roles(struct bfa_lport_s *lport);
    +void bfa_lport_disable_ipfc_roles(struct bfa_lport_s *lport);
    +wwn_t bfa_lport_get_nwwn(struct bfa_lport_s *lport);
    +wwn_t bfa_lport_get_pwwn(struct bfa_lport_s *lport);
    +
    +wwn_t bfa_lport_get_fabric_name(struct bfa_lport_s *lport);
    +
    +/**
    + * Call from FCS to driver module when a port is deleted. The port
    + * can be a base port or a virtual port with in the base fabric or
    + * a virtual fabric.
    + *
    + * @param[in] bfad - driver instance
    + * @param[in] roles - port roles: IM, TM, IP
    + * @param[in] vf_drv - VF driver instance, NULL if base fabric (no VF)
    + * @param[in] vp_drv - vport driver instance, NULL if base port
    + *
    + * @return None
    + */
    +void bfa_cb_lport_delete(struct bfad_s *bfad, enum bfa_port_role roles,
    + struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv);
    +
    +/**
    + * Notification when port transitions to ONLINE state.
    + *
    + * Online notification is a logical link up for the local port. This
    + * notification is sent after a successfull FLOGI, or a successful
    + * link initialization in proviate-loop or N2N topologies.
    + *
    + * @param[in] bfad - driver instance
    + * @param[in] roles - port roles: IM, TM, IP
    + * @param[in] vf_drv - VF driver instance, NULL if base fabric (no VF)
    + * @param[in] vp_drv - vport driver instance, NULL if base port
    + *
    + * @return None
    + */
    +void bfa_cb_lport_online(struct bfad_s *bfad, enum bfa_port_role roles,
    + struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv);
    +
    +/**
    + * Notification when port transitions to OFFLINE state.
    + *
    + * Offline notification is a logical link down for the local port.
    + *
    + * @param[in] bfad - driver instance
    + * @param[in] roles - port roles: IM, TM, IP
    + * @param[in] vf_drv - VF driver instance, NULL if base fabric (no VF)
    + * @param[in] vp_drv - vport driver instance, NULL if base port
    + *
    + * @return None
    + */
    +void bfa_cb_lport_offline(struct bfad_s *bfad, enum bfa_port_role roles,
    + struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv);
    +struct bfad_port_s *bfa_cb_port_new(struct bfad_s *bfad,
    + struct bfa_lport_s *port,
    + enum bfa_port_role roles,
    + struct bfad_vf_s *vf_drv,
    + struct bfad_vport_s *vp_drv);
    +
    +#endif /* __BFA_LPORT_H__ */
    diff -urpN orig/drivers/scsi/bfa/bfa_lps.c patch/drivers/scsi/bfa/bfa_lps.c
    --- orig/drivers/scsi/bfa/bfa_lps.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_lps.c 2009-04-01 20:08:47.312474000 -0700
    @@ -0,0 +1,742 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#include <bfa.h>
    +#include <bfi/bfi_lps.h>
    +#include <cs/bfa_debug.h>
    +
    +BFA_TRC_FILE(HAL, LPS);
    +BFA_MODULE(lps);
    +
    +#define BFA_LPS_MIN_LPORTS (1)
    +#define BFA_LPS_MAX_LPORTS (256)
    +
    +/**
    + * forward declarations
    + */
    +static void bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len,
    + u32 *dm_len);
    +static void bfa_lps_attach(struct bfa_s *bfa, void *bfad,
    + struct bfa_iocfc_cfg_s *cfg,
    + struct bfa_meminfo_s *meminfo,
    + struct bfa_pcidev_s *pcidev);
    +static void bfa_lps_initdone(struct bfa_s *bfa);
    +static void bfa_lps_detach(struct bfa_s *bfa);
    +static void bfa_lps_start(struct bfa_s *bfa);
    +static void bfa_lps_stop(struct bfa_s *bfa);
    +static void bfa_lps_iocdisable(struct bfa_s *bfa);
    +static void bfa_lps_login_rsp(struct bfa_s *bfa,
    + struct bfi_lps_login_rsp_s *rsp);
    +static void bfa_lps_logout_rsp(struct bfa_s *bfa,
    + struct bfi_lps_logout_rsp_s *rsp);
    +static void bfa_lps_reqq_resume(void *lps_arg);
    +static void bfa_lps_free(struct bfa_lps_s *lps);
    +static void bfa_lps_send_login(struct bfa_lps_s *lps);
    +static void bfa_lps_send_logout(struct bfa_lps_s *lps);
    +static void bfa_lps_login_comp(struct bfa_lps_s *lps);
    +static void bfa_lps_logout_comp(struct bfa_lps_s *lps);
    +
    +
    +/**
    + * lps_pvt BFA LPS private functions
    + */
    +
    +enum bfa_lps_event {
    + BFA_LPS_SM_LOGIN = 1, /* login request from user */
    + BFA_LPS_SM_LOGOUT = 2, /* logout request from user */
    + BFA_LPS_SM_FWRSP = 3, /* f/w response to login/logout */
    + BFA_LPS_SM_RESUME = 4, /* space present in reqq queue */
    + BFA_LPS_SM_DELETE = 5, /* lps delete from user */
    + BFA_LPS_SM_OFFLINE = 6, /* Link is offline */
    +};
    +
    +static void bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event);
    +static void bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event);
    +static void bfa_lps_sm_loginwait(struct bfa_lps_s *lps,
    + enum bfa_lps_event event);
    +static void bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event);
    +static void bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event);
    +static void bfa_lps_sm_logowait(struct bfa_lps_s *lps,
    + enum bfa_lps_event event);
    +
    +/**
    + * Init state -- no login
    + */
    +static void
    +bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event)
    +{
    + bfa_trc(lps->bfa, lps->lp_tag);
    + bfa_trc(lps->bfa, event);
    +
    + switch (event) {
    + case BFA_LPS_SM_LOGIN:
    + if (bfa_reqq_full(lps->bfa, lps->reqq)) {
    + bfa_sm_set_state(lps, bfa_lps_sm_loginwait);
    + bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe);
    + } else {
    + bfa_sm_set_state(lps, bfa_lps_sm_login);
    + bfa_lps_send_login(lps);
    + }
    + break;
    +
    + case BFA_LPS_SM_LOGOUT:
    + bfa_lps_logout_comp(lps);
    + break;
    +
    + case BFA_LPS_SM_DELETE:
    + bfa_lps_free(lps);
    + break;
    +
    + case BFA_LPS_SM_OFFLINE:
    + break;
    +
    + case BFA_LPS_SM_FWRSP:
    + /* Could happen when fabric detects loopback and discards
    + * the lps request. Fw will eventually sent out the timeout
    + * Just ignore
    + */
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * login is in progress -- awaiting response from firmware
    + */
    +static void
    +bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event)
    +{
    + bfa_trc(lps->bfa, lps->lp_tag);
    + bfa_trc(lps->bfa, event);
    +
    + switch (event) {
    + case BFA_LPS_SM_FWRSP:
    + if (lps->status == BFA_STATUS_OK)
    + bfa_sm_set_state(lps, bfa_lps_sm_online);
    + else
    + bfa_sm_set_state(lps, bfa_lps_sm_init);
    + bfa_lps_login_comp(lps);
    + break;
    +
    + case BFA_LPS_SM_OFFLINE:
    + bfa_sm_set_state(lps, bfa_lps_sm_init);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * login pending - awaiting space in request queue
    + */
    +static void
    +bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event event)
    +{
    + bfa_trc(lps->bfa, lps->lp_tag);
    + bfa_trc(lps->bfa, event);
    +
    + switch (event) {
    + case BFA_LPS_SM_RESUME:
    + bfa_sm_set_state(lps, bfa_lps_sm_login);
    + break;
    +
    + case BFA_LPS_SM_OFFLINE:
    + bfa_sm_set_state(lps, bfa_lps_sm_init);
    + bfa_reqq_wcancel(&lps->wqe);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * login complete
    + */
    +static void
    +bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event)
    +{
    + bfa_trc(lps->bfa, lps->lp_tag);
    + bfa_trc(lps->bfa, event);
    +
    + switch (event) {
    + case BFA_LPS_SM_LOGOUT:
    + if (bfa_reqq_full(lps->bfa, lps->reqq)) {
    + bfa_sm_set_state(lps, bfa_lps_sm_logowait);
    + bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe);
    + } else {
    + bfa_sm_set_state(lps, bfa_lps_sm_logout);
    + bfa_lps_send_logout(lps);
    + }
    + break;
    +
    + case BFA_LPS_SM_OFFLINE:
    + case BFA_LPS_SM_DELETE:
    + bfa_sm_set_state(lps, bfa_lps_sm_init);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * logout in progress - awaiting firmware response
    + */
    +static void
    +bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event)
    +{
    + bfa_trc(lps->bfa, lps->lp_tag);
    + bfa_trc(lps->bfa, event);
    +
    + switch (event) {
    + case BFA_LPS_SM_FWRSP:
    + bfa_sm_set_state(lps, bfa_lps_sm_init);
    + bfa_lps_logout_comp(lps);
    + break;
    +
    + case BFA_LPS_SM_OFFLINE:
    + bfa_sm_set_state(lps, bfa_lps_sm_init);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * logout pending -- awaiting space in request queue
    + */
    +static void
    +bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event event)
    +{
    + bfa_trc(lps->bfa, lps->lp_tag);
    + bfa_trc(lps->bfa, event);
    +
    + switch (event) {
    + case BFA_LPS_SM_RESUME:
    + bfa_sm_set_state(lps, bfa_lps_sm_logout);
    + bfa_lps_send_logout(lps);
    + break;
    +
    + case BFA_LPS_SM_OFFLINE:
    + bfa_sm_set_state(lps, bfa_lps_sm_init);
    + bfa_reqq_wcancel(&lps->wqe);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +
    +
    +/**
    + * lps_pvt BFA LPS private functions
    + */
    +
    +/**
    + * return memory requirement
    + */
    +static void
    +bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, u32 *dm_len)
    +{
    + if (cfg->drvcfg.min_cfg)
    + *ndm_len += sizeof(struct bfa_lps_s) * BFA_LPS_MIN_LPORTS;
    + else
    + *ndm_len += sizeof(struct bfa_lps_s) * BFA_LPS_MAX_LPORTS;
    +}
    +
    +/**
    + * bfa module attach at initialization time
    + */
    +static void
    +bfa_lps_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
    + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
    +{
    + struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
    + struct bfa_lps_s *lps;
    + int i;
    +
    + bfa_os_memset(mod, 0, sizeof(struct bfa_lps_mod_s));
    + mod->num_lps = BFA_LPS_MAX_LPORTS;
    + if (cfg->drvcfg.min_cfg)
    + mod->num_lps = BFA_LPS_MIN_LPORTS;
    + else
    + mod->num_lps = BFA_LPS_MAX_LPORTS;
    + mod->lps_arr = lps = (struct bfa_lps_s *) bfa_meminfo_kva(meminfo);
    +
    + bfa_meminfo_kva(meminfo) += mod->num_lps * sizeof(struct bfa_lps_s);
    +
    + INIT_LIST_HEAD(&mod->lps_free_q);
    + INIT_LIST_HEAD(&mod->lps_active_q);
    +
    + for (i = 0; i < mod->num_lps; i++, lps++) {
    + lps->bfa = bfa;
    + lps->lp_tag = (u8) i;
    + lps->reqq = BFA_REQQ_LPS;
    + bfa_reqq_winit(&lps->wqe, bfa_lps_reqq_resume, lps);
    + list_add_tail(&lps->qe, &mod->lps_free_q);
    + }
    +}
    +
    +static void
    +bfa_lps_initdone(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_lps_detach(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_lps_start(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_lps_stop(struct bfa_s *bfa)
    +{
    +}
    +
    +/**
    + * IOC in disabled state -- consider all lps offline
    + */
    +static void
    +bfa_lps_iocdisable(struct bfa_s *bfa)
    +{
    + struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
    + struct bfa_lps_s *lps;
    + struct list_head *qe, *qen;
    +
    + list_for_each_safe(qe, qen, &mod->lps_active_q) {
    + lps = (struct bfa_lps_s *) qe;
    + bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE);
    + }
    +}
    +
    +/**
    + * Firmware login response
    + */
    +static void
    +bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp)
    +{
    + struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
    + struct bfa_lps_s *lps;
    +
    + bfa_assert(rsp->lp_tag < mod->num_lps);
    + lps = BFA_LPS_FROM_TAG(mod, rsp->lp_tag);
    +
    + lps->status = rsp->status;
    + if (rsp->status == BFA_STATUS_OK) {
    + lps->fport = rsp->f_port;
    + lps->npiv_en = rsp->npiv_en;
    + lps->lp_pid = rsp->lp_pid;
    + lps->pr_bbcred = bfa_os_ntohs(rsp->bb_credit);
    + lps->pr_pwwn = rsp->port_name;
    + lps->pr_nwwn = rsp->node_name;
    + lps->auth_req = rsp->auth_req;
    + lps->lp_mac = rsp->lp_mac;
    + lps->brcd_switch = rsp->brcd_switch;
    + lps->fcf_mac = rsp->fcf_mac;
    + }
    + if (rsp->status == BFA_STATUS_FABRIC_RJT) {
    + lps->lsrjt_rsn = rsp->lsrjt_rsn;
    + lps->lsrjt_expl = rsp->lsrjt_expl;
    + }
    +
    + bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP);
    +}
    +
    +/**
    + * Firmware logout response
    + */
    +static void
    +bfa_lps_logout_rsp(struct bfa_s *bfa, struct bfi_lps_logout_rsp_s *rsp)
    +{
    + struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
    + struct bfa_lps_s *lps;
    +
    + bfa_assert(rsp->lp_tag < mod->num_lps);
    + lps = BFA_LPS_FROM_TAG(mod, rsp->lp_tag);
    +
    + bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP);
    +}
    +
    +/**
    + * Space is available in request queue, resume queueing request to firmware.
    + */
    +static void
    +bfa_lps_reqq_resume(void *lps_arg)
    +{
    + struct bfa_lps_s *lps = lps_arg;
    +
    + bfa_sm_send_event(lps, BFA_LPS_SM_RESUME);
    +}
    +
    +/**
    + * lps is freed -- triggered by vport delete
    + */
    +static void
    +bfa_lps_free(struct bfa_lps_s *lps)
    +{
    + struct bfa_lps_mod_s *mod = BFA_LPS_MOD(lps->bfa);
    +
    + list_del(&lps->qe);
    + list_add_tail(&lps->qe, &mod->lps_free_q);
    +}
    +
    +/**
    + * send login request to firmware
    + */
    +static void
    +bfa_lps_send_login(struct bfa_lps_s *lps)
    +{
    + struct bfi_lps_login_req_s *m;
    +
    + m = bfa_reqq_next(lps->bfa, lps->reqq);
    + bfa_assert(m);
    +
    + bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGIN_REQ,
    + bfa_lpuid(lps->bfa));
    +
    + m->lp_tag = lps->lp_tag;
    + m->alpa = lps->alpa;
    + m->pdu_size = bfa_os_htons(lps->pdusz);
    + m->pwwn = lps->pwwn;
    + m->nwwn = lps->nwwn;
    + m->fdisc = lps->fdisc;
    + m->auth_en = lps->auth_en;
    +
    + bfa_reqq_produce(lps->bfa, lps->reqq);
    +}
    +
    +/**
    + * send logout request to firmware
    + */
    +static void
    +bfa_lps_send_logout(struct bfa_lps_s *lps)
    +{
    + struct bfi_lps_logout_req_s *m;
    +
    + m = bfa_reqq_next(lps->bfa, lps->reqq);
    + bfa_assert(m);
    +
    + bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGOUT_REQ,
    + bfa_lpuid(lps->bfa));
    +
    + m->lp_tag = lps->lp_tag;
    + bfa_reqq_produce(lps->bfa, lps->reqq);
    +}
    +
    +/**
    + * Indirect login completion handler for non-fcs
    + */
    +static void
    +bfa_lps_login_comp_cb(void *arg, bfa_boolean_t complete)
    +{
    + struct bfa_lps_s *lps = arg;
    +
    + if (!complete)
    + return;
    +
    + if (lps->fdisc)
    + bfa_cb_lps_fdisc_comp(lps->bfa->bfad, lps->uarg, lps->status);
    + else
    + bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status);
    +}
    +
    +/**
    + * Login completion handler -- direct call for fcs, queue for others
    + */
    +static void
    +bfa_lps_login_comp(struct bfa_lps_s *lps)
    +{
    + if (!bfa_fw_disc_enabled(lps->bfa)) {
    + bfa_cb_queue(lps->bfa, &lps->hcb_qe,
    + bfa_lps_login_comp_cb, lps);
    + return;
    + }
    + if (lps->fdisc)
    + bfa_cb_lps_fdisc_comp(lps->bfa->bfad, lps->uarg, lps->status);
    + else
    + bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status);
    +}
    +
    +/**
    + * Indirect logout completion handler for non-fcs
    + */
    +static void
    +bfa_lps_logout_comp_cb(void *arg, bfa_boolean_t complete)
    +{
    + struct bfa_lps_s *lps = arg;
    +
    + if (!complete)
    + return;
    +
    + if (lps->fdisc)
    + bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg);
    + else
    + bfa_cb_lps_flogo_comp(lps->bfa->bfad, lps->uarg);
    +}
    +
    +/**
    + * Logout completion handler -- direct call for fcs, queue for others
    + */
    +static void
    +bfa_lps_logout_comp(struct bfa_lps_s *lps)
    +{
    + if (!bfa_fw_disc_enabled(lps->bfa)) {
    + bfa_cb_queue(lps->bfa, &lps->hcb_qe,
    + bfa_lps_logout_comp_cb, lps);
    + return;
    + }
    +
    + if (lps->fdisc)
    + bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg);
    + else
    + bfa_cb_lps_flogo_comp(lps->bfa->bfad, lps->uarg);
    +}
    +
    +
    +
    +/**
    + * lps_public BFA LPS public functions
    + */
    +
    +/**
    + * Allocate a lport srvice tag.
    + */
    +struct bfa_lps_s *
    +bfa_lps_alloc(struct bfa_s *bfa)
    +{
    + struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
    + struct bfa_lps_s *lps = NULL;
    +
    + bfa_q_deq(&mod->lps_free_q, &lps);
    +
    + if (lps == NULL)
    + return NULL;
    +
    + list_add_tail(&lps->qe, &mod->lps_active_q);
    +
    + bfa_sm_set_state(lps, bfa_lps_sm_init);
    + return lps;
    +}
    +
    +/**
    + * Free lport service tag. This can be called anytime after an alloc.
    + * No need to wait for any pending login/logout completions.
    + */
    +void
    +bfa_lps_delete(struct bfa_lps_s *lps)
    +{
    + bfa_sm_send_event(lps, BFA_LPS_SM_DELETE);
    +}
    +
    +/**
    + * Initiate a lport login.
    + */
    +void
    +bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, u16 pdusz,
    + wwn_t pwwn, wwn_t nwwn, bfa_boolean_t auth_en)
    +{
    + lps->uarg = uarg;
    + lps->alpa = alpa;
    + lps->pdusz = pdusz;
    + lps->pwwn = pwwn;
    + lps->nwwn = nwwn;
    + lps->fdisc = BFA_FALSE;
    + lps->auth_en = auth_en;
    + bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN);
    +}
    +
    +/**
    + * Initiate a lport fdisc login.
    + */
    +void
    +bfa_lps_fdisc(struct bfa_lps_s *lps, void *uarg, u16 pdusz, wwn_t pwwn,
    + wwn_t nwwn)
    +{
    + lps->uarg = uarg;
    + lps->alpa = 0;
    + lps->pdusz = pdusz;
    + lps->pwwn = pwwn;
    + lps->nwwn = nwwn;
    + lps->fdisc = BFA_TRUE;
    + lps->auth_en = BFA_FALSE;
    + bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN);
    +}
    +
    +/**
    + * Initiate a lport logout (flogi).
    + */
    +void
    +bfa_lps_flogo(struct bfa_lps_s *lps)
    +{
    + bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT);
    +}
    +
    +/**
    + * Initiate a lport FDSIC logout.
    + */
    +void
    +bfa_lps_fdisclogo(struct bfa_lps_s *lps)
    +{
    + bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT);
    +}
    +
    +/**
    + * Discard a pending login request -- should be called only for
    + * link down handling.
    + */
    +void
    +bfa_lps_discard(struct bfa_lps_s *lps)
    +{
    + bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE);
    +}
    +
    +/**
    + * Return lport services tag
    + */
    +u8
    +bfa_lps_get_tag(struct bfa_lps_s *lps)
    +{
    + return lps->lp_tag;
    +}
    +
    +/**
    + * return if fabric login indicates support for NPIV
    + */
    +bfa_boolean_t
    +bfa_lps_is_npiv_en(struct bfa_lps_s *lps)
    +{
    + return lps->npiv_en;
    +}
    +
    +/**
    + * Return TRUE if attached to F-Port, else return FALSE
    + */
    +bfa_boolean_t
    +bfa_lps_is_fport(struct bfa_lps_s *lps)
    +{
    + return lps->fport;
    +}
    +
    +/**
    + * Return TRUE if attached to a Brocade Fabric
    + */
    +bfa_boolean_t
    +bfa_lps_is_brcd_fabric(struct bfa_lps_s *lps)
    +{
    + return lps->brcd_switch;
    +}
    +/**
    + * return TRUE if authentication is required
    + */
    +bfa_boolean_t
    +bfa_lps_is_authreq(struct bfa_lps_s *lps)
    +{
    + return lps->auth_req;
    +}
    +
    +/**
    + * return port id assigned to the lport
    + */
    +u32
    +bfa_lps_get_pid(struct bfa_lps_s *lps)
    +{
    + return lps->lp_pid;
    +}
    +
    +/**
    + * Return bb_credit assigned in FLOGI response
    + */
    +u16
    +bfa_lps_get_peer_bbcredit(struct bfa_lps_s *lps)
    +{
    + return lps->pr_bbcred;
    +}
    +
    +/**
    + * Return peer port name
    + */
    +wwn_t
    +bfa_lps_get_peer_pwwn(struct bfa_lps_s *lps)
    +{
    + return lps->pr_pwwn;
    +}
    +
    +/**
    + * Return peer node name
    + */
    +wwn_t
    +bfa_lps_get_peer_nwwn(struct bfa_lps_s *lps)
    +{
    + return lps->pr_nwwn;
    +}
    +
    +/**
    + * return reason code if login request is rejected
    + */
    +u8
    +bfa_lps_get_lsrjt_rsn(struct bfa_lps_s *lps)
    +{
    + return lps->lsrjt_rsn;
    +}
    +
    +/**
    + * return explanation code if login request is rejected
    + */
    +u8
    +bfa_lps_get_lsrjt_expl(struct bfa_lps_s *lps)
    +{
    + return lps->lsrjt_expl;
    +}
    +
    +
    +/**
    + * LPS firmware message class handler.
    + */
    +void
    +bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
    +{
    + union bfi_lps_i2h_msg_u msg;
    +
    + bfa_trc(bfa, m->mhdr.msg_id);
    + msg.msg = m;
    +
    + switch (m->mhdr.msg_id) {
    + case BFI_LPS_H2I_LOGIN_RSP:
    + bfa_lps_login_rsp(bfa, msg.login_rsp);
    + break;
    +
    + case BFI_LPS_H2I_LOGOUT_RSP:
    + bfa_lps_logout_rsp(bfa, msg.logout_rsp);
    + break;
    +
    + default:
    + bfa_trc(bfa, m->mhdr.msg_id);
    + bfa_assert(0);
    + }
    +}
    +
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_lps_priv.h patch/drivers/scsi/bfa/bfa_lps_priv.h
    --- orig/drivers/scsi/bfa/bfa_lps_priv.h 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_lps_priv.h 2009-04-01 20:08:47.327692000 -0700
    @@ -0,0 +1,38 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#ifndef __BFA_LPS_PRIV_H__
    +#define __BFA_LPS_PRIV_H__
    +
    +#include <bfa_svc.h>
    +
    +struct bfa_lps_mod_s {
    + struct list_head lps_free_q;
    + struct list_head lps_active_q;
    + struct bfa_lps_s *lps_arr;
    + int num_lps;
    +};
    +
    +#define BFA_LPS_MOD(__bfa) (&(__bfa)->modules.lps_mod)
    +#define BFA_LPS_FROM_TAG(__mod, __tag) (&(__mod)->lps_arr[__tag])
    +
    +/*
    + * external functions
    + */
    +void bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
    +
    +#endif /* __BFA_LPS_PRIV_H__ */
    diff -urpN orig/drivers/scsi/bfa/bfa_module.c patch/drivers/scsi/bfa/bfa_module.c
    --- orig/drivers/scsi/bfa/bfa_module.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_module.c 2009-04-01 20:08:47.336330000 -0700
    @@ -0,0 +1,92 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +#include <bfa.h>
    +#include <defs/bfa_defs_pci.h>
    +#include <cs/bfa_debug.h>
    +#include <bfa_iocfc.h>
    +#include <bfa_fabric.h>
    +#include <bfa_lport.h>
    +#include <bfa_vport.h>
    +
    +/**
    + * BFA module list terminated by NULL
    + */
    +struct bfa_module_s *hal_mods[] = {
    + &hal_mod_sgpg,
    + &hal_mod_pport,
    + &hal_mod_fcxp,
    + &hal_mod_lps,
    + &hal_mod_uf,
    + &hal_mod_rport,
    + &hal_mod_fcpim,
    + &hal_mod_lport,
    + &hal_mod_fabric,
    + NULL
    +};
    +
    +/**
    + * Message handlers for various modules.
    + */
    +bfa_isr_func_t bfa_isrs[BFI_MC_MAX] = {
    + bfa_isr_unhandled, /* NONE */
    + bfa_isr_unhandled, /* BFI_MC_IOC */
    + bfa_isr_unhandled, /* BFI_MC_DIAG */
    + bfa_isr_unhandled, /* BFI_MC_FLASH */
    + bfa_isr_unhandled, /* BFI_MC_CEE */
    + bfa_pport_isr, /* BFI_MC_PORT */
    + bfa_isr_unhandled, /* BFI_MC_IOCFC */
    + bfa_isr_unhandled, /* BFI_MC_LL */
    + bfa_uf_isr, /* BFI_MC_UF */
    + bfa_fcxp_isr, /* BFI_MC_FCXP */
    + bfa_lps_isr, /* BFI_MC_LPS */
    + bfa_rport_isr, /* BFI_MC_RPORT */
    + bfa_itnim_isr, /* BFI_MC_ITNIM */
    + bfa_isr_unhandled, /* BFI_MC_IOIM_READ */
    + bfa_isr_unhandled, /* BFI_MC_IOIM_WRITE */
    + bfa_isr_unhandled, /* BFI_MC_IOIM_IO */
    + bfa_ioim_isr, /* BFI_MC_IOIM */
    + bfa_ioim_good_comp_isr, /* BFI_MC_IOIM_IOCOM */
    + bfa_tskim_isr, /* BFI_MC_TSKIM */
    + bfa_isr_unhandled, /* BFI_MC_SBOOT */
    + bfa_isr_unhandled, /* BFI_MC_IPFC */
    + bfa_fabric_isr, /* BFI_MC_FABRIC */
    + bfa_lport_isr, /* BFI_MC_LPORT */
    + bfa_isr_unhandled, /* BFI_MC_ITNTM */
    + bfa_isr_unhandled, /* BFI_MC_IOTM_READ */
    + bfa_isr_unhandled, /* BFI_MC_IOTM_WRITE */
    + bfa_isr_unhandled, /* BFI_MC_IOTM_IO */
    + bfa_isr_unhandled, /* BFI_MC_IOTM_IOCOM */
    + bfa_isr_unhandled, /* BFI_MC_IOTM */
    + bfa_isr_unhandled, /* BFI_MC_TSKTM */
    + bfa_isr_unhandled, /* BFI_MC_SB */
    + bfa_vport_isr, /* BFI_MC_VPORT */
    +};
    +
    +/**
    + * Message handlers for mailbox command classes
    + */
    +bfa_ioc_mbox_mcfunc_t bfa_mbox_isrs[BFI_MC_MAX] = {
    + NULL,
    + NULL, /* BFI_MC_IOC */
    + NULL, /* BFI_MC_DIAG */
    + NULL, /* BFI_MC_FLASH */
    + NULL, /* BFI_MC_CEE */
    + NULL, /* BFI_MC_PORT */
    + bfa_iocfc_isr, /* BFI_MC_IOCFC */
    + NULL,
    +};
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_modules_priv.h patch/drivers/scsi/bfa/bfa_modules_priv.h
    --- orig/drivers/scsi/bfa/bfa_modules_priv.h 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_modules_priv.h 2009-04-01 20:08:47.351013000 -0700
    @@ -0,0 +1,42 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#ifndef __BFA_MODULES_PRIV_H__
    +#define __BFA_MODULES_PRIV_H__
    +
    +#include "bfa_uf_priv.h"
    +#include "bfa_lport.h"
    +#include "bfa_rport.h"
    +#include "bfa_port_priv.h"
    +#include "bfa_fcxp_priv.h"
    +#include "bfa_lps_priv.h"
    +#include "bfa_fcpim.h"
    +//#include "bfa_fcptm.h" /* enable after TM is operational*/
    +
    +struct bfa_modules_s {
    + struct bfa_pport_s pport; /* physical port module */
    + struct bfa_fcxp_mod_s fcxp_mod; /* fcxp module */
    + struct bfa_lps_mod_s lps_mod; /* lps module */
    + struct bfa_uf_mod_s uf_mod; /* unsolicited frame module */
    + struct bfa_rport_mod_s rport_mod; /* remote port module */
    + struct bfa_fcpim_mod_s fcpim_mod; /* FCP initiator module */
    + //struct bfa_fcptm_mod_s fcptm_mod; /* FCP target module */
    + struct bfa_sgpg_mod_s sgpg_mod; /* SG page module */
    + struct bfa_lport_mod_s lport_mod; /* lport_mod */
    +};
    +
    +#endif /* __BFA_MODULES_PRIV_H__ */
    diff -urpN orig/drivers/scsi/bfa/bfa_os_inc.h patch/drivers/scsi/bfa/bfa_os_inc.h
    --- orig/drivers/scsi/bfa/bfa_os_inc.h 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_os_inc.h 2009-04-01 20:08:47.360887000 -0700
    @@ -0,0 +1,197 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +/**
    + * Contains declarations all OS Specific files needed for BFA layer
    + */
    +
    +#ifndef __BFA_OS_INC_H__
    +#define __BFA_OS_INC_H__
    +
    +#ifndef __KERNEL__
    +#include <stdint.h>
    +#else
    +#include <linux/types.h>
    +
    +#include <linux/version.h>
    +#include <linux/pci.h>
    +
    +#include <linux/dma-mapping.h>
    +#define SET_MODULE_VERSION(VER)
    +
    +#include <linux/idr.h>
    +
    +#include <linux/interrupt.h>
    +#include <linux/cdev.h>
    +#include <linux/fs.h>
    +#include <linux/delay.h>
    +#include <linux/vmalloc.h>
    +
    +#include <linux/workqueue.h>
    +
    +#include <scsi/scsi.h>
    +#include <scsi/scsi_host.h>
    +
    +#include <scsi/scsi_tcq.h>
    +#include <scsi/scsi_transport_fc.h>
    +#include <scsi/scsi_transport.h>
    +
    +#define BFA_ERR KERN_ERR
    +#define BFA_WARNING KERN_WARNING
    +#define BFA_NOTICE KERN_NOTICE
    +#define BFA_INFO KERN_INFO
    +#define BFA_DEBUG KERN_DEBUG
    +
    +#define LOG_BFAD_INIT 0x00000001
    +#define LOG_FCP_IO 0x00000002
    +
    +#ifdef DEBUG
    +#define BFA_LOG_TRACE(bfad, level, mask, fmt, arg...) \
    + BFA_LOG(bfad, level, mask, fmt, ## arg)
    +#define BFA_DEV_TRACE(bfad, level, fmt, arg...) \
    + BFA_DEV_PRINTF(bfad, level, fmt, ## arg)
    +#define BFA_TRACE(level, fmt, arg...) \
    + BFA_PRINTF(level, fmt, ## arg)
    +#else
    +#define BFA_LOG_TRACE(bfad, level, mask, fmt, arg...)
    +#define BFA_DEV_TRACE(bfad, level, fmt, arg...)
    +#define BFA_TRACE(level, fmt, arg...)
    +#endif
    +
    +#define BFA_ASSERT(p) do { \
    + if (!(p)) { \
    + printk(KERN_ERR "assert(%s) failed at %s:%d\n", \
    + #p, __FILE__, __LINE__); \
    + BUG(); \
    + } \
    +} while (0)
    +
    +
    +#define BFA_LOG(bfad, level, mask, fmt, arg...) \
    +do { \
    + if (((mask) & (((struct bfad_s *)(bfad))-> \
    + cfg_data[cfg_log_mask])) || (level[1] <= '3')) \
    + dev_printk(level, &(((struct bfad_s *) \
    + (bfad))->pcidev->dev), fmt, ##arg); \
    +} while (0)
    +
    +#ifndef BFA_DEV_PRINTF
    +#define BFA_DEV_PRINTF(bfad, level, fmt, arg...) \
    + dev_printk(level, &(((struct bfad_s *) \
    + (bfad))->pcidev->dev), fmt, ##arg);
    +#endif
    +
    +#define BFA_PRINTF(level, fmt, arg...) \
    + printk(level fmt, ##arg);
    +
    +int bfa_os_MWB(void *);
    +
    +#define bfa_os_mmiowb() mmiowb()
    +
    +#define bfa_swap_3b(_x) \
    + ((((_x) & 0xff) << 16) | \
    + ((_x) & 0x00ff00) | \
    + (((_x) & 0xff0000) >> 16))
    +
    +#define bfa_swap_8b(_x) \
    + ((((_x) & 0xff00000000000000ull) >> 56) \
    + | (((_x) & 0x00ff000000000000ull) >> 40) \
    + | (((_x) & 0x0000ff0000000000ull) >> 24) \
    + | (((_x) & 0x000000ff00000000ull) >> 8) \
    + | (((_x) & 0x00000000ff000000ull) << 8) \
    + | (((_x) & 0x0000000000ff0000ull) << 24) \
    + | (((_x) & 0x000000000000ff00ull) << 40) \
    + | (((_x) & 0x00000000000000ffull) << 56))
    +
    +#define bfa_os_swap32(_x) \
    + ((((_x) & 0xff) << 24) | \
    + (((_x) & 0x0000ff00) << 8) | \
    + (((_x) & 0x00ff0000) >> 8) | \
    + (((_x) & 0xff000000) >> 24))
    +
    +
    +#ifndef __BIGENDIAN
    +#define bfa_os_htons(_x) ((u16)((((_x) & 0xff00) >> 8) | \
    + (((_x) & 0x00ff) << 8)))
    +
    +#define bfa_os_htonl(_x) bfa_os_swap32(_x)
    +#define bfa_os_htonll(_x) bfa_swap_8b(_x)
    +#define bfa_os_hton3b(_x) bfa_swap_3b(_x)
    +
    +#define bfa_os_wtole(_x) (_x)
    +
    +#else
    +
    +#define bfa_os_htons(_x) (_x)
    +#define bfa_os_htonl(_x) (_x)
    +#define bfa_os_hton3b(_x) (_x)
    +#define bfa_os_htonll(_x) (_x)
    +#define bfa_os_wtole(_x) bfa_os_swap32(_x)
    +
    +#endif
    +
    +#define bfa_os_ntohs(_x) bfa_os_htons(_x)
    +#define bfa_os_ntohl(_x) bfa_os_htonl(_x)
    +#define bfa_os_ntohll(_x) bfa_os_htonll(_x)
    +#define bfa_os_ntoh3b(_x) bfa_os_hton3b(_x)
    +
    +#define bfa_os_u32(__pa64) ((__pa64) >> 32)
    +
    +#define bfa_os_memset memset
    +#define bfa_os_memcpy memcpy
    +#define bfa_os_udelay udelay
    +#define bfa_os_vsprintf vsprintf
    +
    +#define bfa_os_addr_t void __iomem *
    +#define bfa_os_panic()
    +
    +#define bfa_os_reg_read(_raddr) \
    + bfa_os_wtole(*((volatile u32 __force *)(_raddr)))
    +#define bfa_os_reg_write(_raddr, _val) \
    + *((volatile u32 __force *)(_raddr)) = bfa_os_wtole((_val))
    +#define bfa_os_mem_read(_raddr, _off) \
    + bfa_os_ntohl(((volatile u32 __force *)(_raddr))[(_off) >> 2])
    +#define bfa_os_mem_write(_raddr, _off, _val) \
    + ((((volatile u32 __force *)(_raddr))[(_off) >> 2]) \
    + = bfa_os_htonl((_val)))
    +
    +#define BFA_TRC_TS(_trcm) \
    + ({ \
    + struct timeval tv; \
    + \
    + do_gettimeofday(&tv); \
    + (tv.tv_sec*1000000+tv.tv_usec); \
    + })
    +
    +struct bfa_log_mod_s;
    +void bfa_os_printf(struct bfa_log_mod_s *log_mod, u32 msg_id,
    + const char *fmt, ...);
    +#endif
    +
    +#define boolean_t int
    +
    +/**
    + * For current time stamp, OS API will fill-in
    + */
    +struct bfa_timeval_s {
    + u32 tv_sec; /* seconds */
    + u32 tv_usec; /* microseconds */
    +};
    +
    +void bfa_os_gettimeofday(struct bfa_timeval_s *tv);
    +
    +#endif /* __BFA_OS_INC_H__ */
    diff -urpN orig/drivers/scsi/bfa/bfa_port.c patch/drivers/scsi/bfa/bfa_port.c
    --- orig/drivers/scsi/bfa/bfa_port.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_port.c 2009-04-01 20:08:47.371181000 -0700
    @@ -0,0 +1,1659 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#include <bfa.h>
    +#include <bfa_svc.h>
    +#include <bfi/bfi_pport.h>
    +#include <cs/bfa_debug.h>
    +#include <aen/bfa_aen.h>
    +#include <cs/bfa_plog.h>
    +#include <aen/bfa_aen_port.h>
    +
    +BFA_TRC_FILE(HAL, PPORT);
    +BFA_MODULE(pport);
    +
    +#define bfa_pport_callback(__pport, __event) do { \
    + if (!bfa_fw_disc_enabled(__pport->bfa)) { \
    + if (__pport->bfa) { \
    + (__pport)->event_cbfn((__pport)->event_cbarg, \
    + (__event)); \
    + } else { \
    + (__pport)->hcb_event = (__event); \
    + bfa_cb_queue((__pport)->bfa, &(__pport)->hcb_qe, \
    + __bfa_cb_port_event, (__pport)); \
    + } \
    + } \
    +} while (0)
    +
    +/*
    + * The port is considered disabled if corresponding physical port or IOC are
    + * disabled explicitly
    + */
    +#define BFA_PORT_IS_OFFLINE(bfa) \
    + ((bfa_pport_is_disabled(bfa) == BFA_TRUE) || \
    + (bfa_ioc_is_disabled(&bfa->ioc) == BFA_TRUE))
    +
    +/*
    + * forward declarations
    + */
    +static bfa_boolean_t bfa_pport_send_enable(struct bfa_pport_s *port);
    +static bfa_boolean_t bfa_pport_send_disable(struct bfa_pport_s *port);
    +static void bfa_pport_update_linkinfo(struct bfa_pport_s *pport);
    +static void bfa_pport_reset_linkinfo(struct bfa_pport_s *pport);
    +static void bfa_pport_set_wwns(struct bfa_pport_s *port);
    +static void __bfa_cb_port_event(void *cbarg, bfa_boolean_t complete);
    +static void __bfa_cb_port_stats(void *cbarg, bfa_boolean_t complete);
    +static void __bfa_cb_port_stats_clr(void *cbarg, bfa_boolean_t complete);
    +static void bfa_port_stats_timeout(void *cbarg);
    +static void bfa_port_stats_clr_timeout(void *cbarg);
    +
    +/**
    + * hal_pport_private
    + */
    +
    +/**
    + * BFA port state machine events
    + */
    +enum bfa_pport_sm_event {
    + BFA_PPORT_SM_START = 1, /* start port state machine */
    + BFA_PPORT_SM_STOP = 2, /* stop port state machine */
    + BFA_PPORT_SM_ENABLE = 3, /* enable port */
    + BFA_PPORT_SM_DISABLE = 4, /* disable port state machine */
    + BFA_PPORT_SM_FWRSP = 5, /* firmware enable/disable rsp */
    + BFA_PPORT_SM_LINKUP = 6, /* firmware linkup event */
    + BFA_PPORT_SM_LINKDOWN = 7, /* firmware linkup down */
    + BFA_PPORT_SM_QRESUME = 8, /* CQ space available */
    + BFA_PPORT_SM_HWFAIL = 9, /* IOC h/w failure */
    +};
    +
    +static void bfa_pport_sm_uninit(struct bfa_pport_s *pport,
    + enum bfa_pport_sm_event event);
    +static void bfa_pport_sm_enabling_qwait(struct bfa_pport_s *pport,
    + enum bfa_pport_sm_event event);
    +static void bfa_pport_sm_enabling(struct bfa_pport_s *pport,
    + enum bfa_pport_sm_event event);
    +static void bfa_pport_sm_linkdown(struct bfa_pport_s *pport,
    + enum bfa_pport_sm_event event);
    +static void bfa_pport_sm_linkup(struct bfa_pport_s *pport,
    + enum bfa_pport_sm_event event);
    +static void bfa_pport_sm_disabling(struct bfa_pport_s *pport,
    + enum bfa_pport_sm_event event);
    +static void bfa_pport_sm_disabling_qwait(struct bfa_pport_s *pport,
    + enum bfa_pport_sm_event event);
    +static void bfa_pport_sm_disabled(struct bfa_pport_s *pport,
    + enum bfa_pport_sm_event event);
    +static void bfa_pport_sm_stopped(struct bfa_pport_s *pport,
    + enum bfa_pport_sm_event event);
    +static void bfa_pport_sm_iocdown(struct bfa_pport_s *pport,
    + enum bfa_pport_sm_event event);
    +static void bfa_pport_sm_iocfail(struct bfa_pport_s *pport,
    + enum bfa_pport_sm_event event);
    +
    +static struct bfa_sm_table_s hal_pport_sm_table[] = {
    + {BFA_SM(bfa_pport_sm_uninit), BFA_PPORT_ST_UNINIT},
    + {BFA_SM(bfa_pport_sm_enabling_qwait), BFA_PPORT_ST_ENABLING_QWAIT},
    + {BFA_SM(bfa_pport_sm_enabling), BFA_PPORT_ST_ENABLING},
    + {BFA_SM(bfa_pport_sm_linkdown), BFA_PPORT_ST_LINKDOWN},
    + {BFA_SM(bfa_pport_sm_linkup), BFA_PPORT_ST_LINKUP},
    + {BFA_SM(bfa_pport_sm_disabling_qwait),
    + BFA_PPORT_ST_DISABLING_QWAIT},
    + {BFA_SM(bfa_pport_sm_disabling), BFA_PPORT_ST_DISABLING},
    + {BFA_SM(bfa_pport_sm_disabled), BFA_PPORT_ST_DISABLED},
    + {BFA_SM(bfa_pport_sm_stopped), BFA_PPORT_ST_STOPPED},
    + {BFA_SM(bfa_pport_sm_iocdown), BFA_PPORT_ST_IOCDOWN},
    + {BFA_SM(bfa_pport_sm_iocfail), BFA_PPORT_ST_IOCDOWN},
    +};
    +
    +static void
    +bfa_pport_aen_post(struct bfa_pport_s *pport, enum bfa_port_aen_event event)
    +{
    + union bfa_aen_data_u aen_data;
    +
    + struct bfa_log_mod_s *logmod = pport->bfa->logm;
    + wwn_t pwwn = pport->pwwn;
    + char *pwwn_ptr = NULL;
    +
    + switch (event) {
    + case BFA_PORT_AEN_ONLINE:
    + bfa_log(logmod, BFA_AEN_PORT_ONLINE, pwwn_ptr);
    + break;
    + case BFA_PORT_AEN_OFFLINE:
    + bfa_log(logmod, BFA_AEN_PORT_OFFLINE, pwwn_ptr);
    + break;
    + case BFA_PORT_AEN_ENABLE:
    + bfa_log(logmod, BFA_AEN_PORT_ENABLE, pwwn_ptr);
    + break;
    + case BFA_PORT_AEN_DISABLE:
    + bfa_log(logmod, BFA_AEN_PORT_DISABLE, pwwn_ptr);
    + break;
    + case BFA_PORT_AEN_DISCONNECT:
    + bfa_log(logmod, BFA_AEN_PORT_DISCONNECT, pwwn_ptr);
    + break;
    + case BFA_PORT_AEN_QOS_NEG:
    + bfa_log(logmod, BFA_AEN_PORT_QOS_NEG, pwwn_ptr);
    + break;
    + default:
    + break;
    + }
    +
    + aen_data.port.pwwn = pwwn;
    +}
    +
    +static void
    +bfa_pport_sm_uninit(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
    +{
    + bfa_trc(pport->bfa, event);
    +
    + switch (event) {
    + case BFA_PPORT_SM_START:
    + /**
    + * Start event after IOC is configured and BFA is started.
    + */
    + if (bfa_pport_send_enable(pport))
    + bfa_sm_set_state(pport, bfa_pport_sm_enabling);
    + else
    + bfa_sm_set_state(pport,
    + bfa_pport_sm_enabling_qwait);
    + break;
    +
    + case BFA_PPORT_SM_ENABLE:
    + /**
    + * Port is persistently configured to be in enabled state. Do
    + * not change state. Port enabling is done when START event is
    + * received.
    + */
    + break;
    +
    + case BFA_PPORT_SM_DISABLE:
    + /**
    + * If a port is persistently configured to be disabled, the
    + * first event will a port disable request.
    + */
    + bfa_sm_set_state(pport, bfa_pport_sm_disabled);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +static void
    +bfa_pport_sm_enabling_qwait(struct bfa_pport_s *pport,
    + enum bfa_pport_sm_event event)
    +{
    + bfa_trc(pport->bfa, event);
    +
    + switch (event) {
    + case BFA_PPORT_SM_QRESUME:
    + bfa_sm_set_state(pport, bfa_pport_sm_enabling);
    + bfa_pport_send_enable(pport);
    + break;
    +
    + case BFA_PPORT_SM_STOP:
    + bfa_reqq_wcancel(&pport->reqq_wait);
    + bfa_sm_set_state(pport, bfa_pport_sm_stopped);
    + break;
    +
    + case BFA_PPORT_SM_ENABLE:
    + /**
    + * Already enable is in progress.
    + */
    + break;
    +
    + case BFA_PPORT_SM_DISABLE:
    + /**
    + * Just send disable request to firmware when room becomes
    + * available in request queue.
    + */
    + bfa_sm_set_state(pport, bfa_pport_sm_disabling_qwait);
    + bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
    + BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
    + bfa_pport_aen_post(pport, BFA_PORT_AEN_DISABLE);
    + break;
    +
    + case BFA_PPORT_SM_LINKUP:
    + case BFA_PPORT_SM_LINKDOWN:
    + /**
    + * Possible to get link events when doing back-to-back
    + * enable/disables.
    + */
    + break;
    +
    + case BFA_PPORT_SM_HWFAIL:
    + bfa_reqq_wcancel(&pport->reqq_wait);
    + bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +static void
    +bfa_pport_sm_enabling(struct bfa_pport_s *pport,
    + enum bfa_pport_sm_event event)
    +{
    + bfa_trc(pport->bfa, event);
    +
    + switch (event) {
    + case BFA_PPORT_SM_FWRSP:
    + case BFA_PPORT_SM_LINKDOWN:
    + bfa_sm_set_state(pport, bfa_pport_sm_linkdown);
    + break;
    +
    + case BFA_PPORT_SM_LINKUP:
    + bfa_pport_update_linkinfo(pport);
    + bfa_sm_set_state(pport, bfa_pport_sm_linkup);
    + if (!bfa_fw_disc_enabled(pport->bfa)) {
    + bfa_assert(pport->event_cbfn);
    + bfa_pport_callback(pport, BFA_PPORT_LINKUP);
    + }
    + break;
    +
    + case BFA_PPORT_SM_ENABLE:
    + /**
    + * Already being enabled.
    + */
    + break;
    +
    + case BFA_PPORT_SM_DISABLE:
    + if (bfa_pport_send_disable(pport))
    + bfa_sm_set_state(pport, bfa_pport_sm_disabling);
    + else
    + bfa_sm_set_state(pport,
    + bfa_pport_sm_disabling_qwait);
    +
    + bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
    + BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
    + bfa_pport_aen_post(pport, BFA_PORT_AEN_DISABLE);
    + break;
    +
    + case BFA_PPORT_SM_STOP:
    + bfa_sm_set_state(pport, bfa_pport_sm_stopped);
    + break;
    +
    + case BFA_PPORT_SM_HWFAIL:
    + bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +static void
    +bfa_pport_sm_linkdown(struct bfa_pport_s *pport,
    + enum bfa_pport_sm_event event)
    +{
    + bfa_trc(pport->bfa, event);
    +
    + switch (event) {
    + case BFA_PPORT_SM_LINKUP:
    + bfa_pport_update_linkinfo(pport);
    + bfa_sm_set_state(pport, bfa_pport_sm_linkup);
    +
    + bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
    + BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkup");
    + if (!bfa_fw_disc_enabled(pport->bfa)) {
    + bfa_assert(pport->event_cbfn);
    + bfa_pport_callback(pport, BFA_PPORT_LINKUP);
    + }
    + bfa_pport_aen_post(pport, BFA_PORT_AEN_ONLINE);
    + /**
    + * If QoS is enabled and it is not online,
    + * Send a separate event.
    + */
    + if ((pport->cfg.qos_enabled) &&
    + (bfa_os_ntohl(pport->qos_attr.state) != BFA_QOS_ONLINE))
    + bfa_pport_aen_post(pport, BFA_PORT_AEN_QOS_NEG);
    +
    + break;
    +
    + case BFA_PPORT_SM_LINKDOWN:
    + /**
    + * Possible to get link down event.
    + */
    + break;
    +
    + case BFA_PPORT_SM_ENABLE:
    + /**
    + * Already enabled.
    + */
    + break;
    +
    + case BFA_PPORT_SM_DISABLE:
    + if (bfa_pport_send_disable(pport))
    + bfa_sm_set_state(pport, bfa_pport_sm_disabling);
    + else
    + bfa_sm_set_state(pport,
    + bfa_pport_sm_disabling_qwait);
    +
    + bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
    + BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
    + bfa_pport_aen_post(pport, BFA_PORT_AEN_DISABLE);
    + break;
    +
    + case BFA_PPORT_SM_STOP:
    + bfa_sm_set_state(pport, bfa_pport_sm_stopped);
    + break;
    +
    + case BFA_PPORT_SM_HWFAIL:
    + bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +static void
    +bfa_pport_sm_linkup(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
    +{
    + bfa_trc(pport->bfa, event);
    +
    + switch (event) {
    + case BFA_PPORT_SM_ENABLE:
    + /**
    + * Already enabled.
    + */
    + break;
    +
    + case BFA_PPORT_SM_DISABLE:
    + if (bfa_pport_send_disable(pport))
    + bfa_sm_set_state(pport, bfa_pport_sm_disabling);
    + else
    + bfa_sm_set_state(pport,
    + bfa_pport_sm_disabling_qwait);
    +
    + bfa_pport_reset_linkinfo(pport);
    + bfa_pport_callback(pport, BFA_PPORT_LINKDOWN);
    + bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
    + BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
    + bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE);
    + bfa_pport_aen_post(pport, BFA_PORT_AEN_DISABLE);
    + break;
    +
    + case BFA_PPORT_SM_LINKDOWN:
    + bfa_sm_set_state(pport, bfa_pport_sm_linkdown);
    + bfa_pport_reset_linkinfo(pport);
    + bfa_pport_callback(pport, BFA_PPORT_LINKDOWN);
    + bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
    + BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkdown");
    + if (BFA_PORT_IS_OFFLINE(pport->bfa)) {
    + bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE);
    + } else {
    + bfa_pport_aen_post(pport, BFA_PORT_AEN_DISCONNECT);
    + }
    + break;
    +
    + case BFA_PPORT_SM_STOP:
    + bfa_sm_set_state(pport, bfa_pport_sm_stopped);
    + bfa_pport_reset_linkinfo(pport);
    + if (BFA_PORT_IS_OFFLINE(pport->bfa)) {
    + bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE);
    + } else {
    + bfa_pport_aen_post(pport, BFA_PORT_AEN_DISCONNECT);
    + }
    + break;
    +
    + case BFA_PPORT_SM_HWFAIL:
    + bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
    + bfa_pport_reset_linkinfo(pport);
    + bfa_pport_callback(pport, BFA_PPORT_LINKDOWN);
    + if (BFA_PORT_IS_OFFLINE(pport->bfa)) {
    + bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE);
    + } else {
    + bfa_pport_aen_post(pport, BFA_PORT_AEN_DISCONNECT);
    + }
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +static void
    +bfa_pport_sm_disabling_qwait(struct bfa_pport_s *pport,
    + enum bfa_pport_sm_event event)
    +{
    + bfa_trc(pport->bfa, event);
    +
    + switch (event) {
    + case BFA_PPORT_SM_QRESUME:
    + bfa_sm_set_state(pport, bfa_pport_sm_disabling);
    + bfa_pport_send_disable(pport);
    + break;
    +
    + case BFA_PPORT_SM_STOP:
    + bfa_sm_set_state(pport, bfa_pport_sm_stopped);
    + bfa_reqq_wcancel(&pport->reqq_wait);
    + break;
    +
    + case BFA_PPORT_SM_ENABLE:
    + /**
    + * Just send enable request to firmware when room becomes
    + * available in request queue.
    + */
    + bfa_sm_set_state(pport, bfa_pport_sm_enabling_qwait);
    + bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
    + BFA_PL_EID_PORT_ENABLE, 0, "Port Enable");
    + bfa_pport_aen_post(pport, BFA_PORT_AEN_ENABLE);
    + break;
    +
    + case BFA_PPORT_SM_DISABLE:
    + /**
    + * Already being disabled.
    + */
    + bfa_sm_set_state(pport, bfa_pport_sm_disabling_qwait);
    + break;
    +
    + case BFA_PPORT_SM_LINKUP:
    + case BFA_PPORT_SM_LINKDOWN:
    + /**
    + * Possible to get link events when doing back-to-back
    + * enable/disables.
    + */
    + break;
    +
    + case BFA_PPORT_SM_HWFAIL:
    + bfa_sm_set_state(pport, bfa_pport_sm_iocfail);
    + bfa_reqq_wcancel(&pport->reqq_wait);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +static void
    +bfa_pport_sm_disabling(struct bfa_pport_s *pport,
    + enum bfa_pport_sm_event event)
    +{
    + bfa_trc(pport->bfa, event);
    +
    + switch (event) {
    + case BFA_PPORT_SM_FWRSP:
    + bfa_sm_set_state(pport, bfa_pport_sm_disabled);
    + break;
    +
    + case BFA_PPORT_SM_DISABLE:
    + /**
    + * Already being disabled.
    + */
    + break;
    +
    + case BFA_PPORT_SM_ENABLE:
    + if (bfa_pport_send_enable(pport))
    + bfa_sm_set_state(pport, bfa_pport_sm_enabling);
    + else
    + bfa_sm_set_state(pport,
    + bfa_pport_sm_enabling_qwait);
    +
    + bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
    + BFA_PL_EID_PORT_ENABLE, 0, "Port Enable");
    + bfa_pport_aen_post(pport, BFA_PORT_AEN_ENABLE);
    + break;
    +
    + case BFA_PPORT_SM_STOP:
    + bfa_sm_set_state(pport, bfa_pport_sm_stopped);
    + break;
    +
    + case BFA_PPORT_SM_LINKUP:
    + case BFA_PPORT_SM_LINKDOWN:
    + /**
    + * Possible to get link events when doing back-to-back
    + * enable/disables.
    + */
    + break;
    +
    + case BFA_PPORT_SM_HWFAIL:
    + bfa_sm_set_state(pport, bfa_pport_sm_iocfail);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +static void
    +bfa_pport_sm_disabled(struct bfa_pport_s *pport,
    + enum bfa_pport_sm_event event)
    +{
    + bfa_trc(pport->bfa, event);
    +
    + switch (event) {
    + case BFA_PPORT_SM_START:
    + /**
    + * Ignore start event for a port that is disabled.
    + */
    + break;
    +
    + case BFA_PPORT_SM_STOP:
    + bfa_sm_set_state(pport, bfa_pport_sm_stopped);
    + break;
    +
    + case BFA_PPORT_SM_ENABLE:
    + if (bfa_pport_send_enable(pport))
    + bfa_sm_set_state(pport, bfa_pport_sm_enabling);
    + else
    + bfa_sm_set_state(pport,
    + bfa_pport_sm_enabling_qwait);
    +
    + bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
    + BFA_PL_EID_PORT_ENABLE, 0, "Port Enable");
    + bfa_pport_aen_post(pport, BFA_PORT_AEN_ENABLE);
    + break;
    +
    + case BFA_PPORT_SM_DISABLE:
    + /**
    + * Already disabled.
    + */
    + break;
    +
    + case BFA_PPORT_SM_HWFAIL:
    + bfa_sm_set_state(pport, bfa_pport_sm_iocfail);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +static void
    +bfa_pport_sm_stopped(struct bfa_pport_s *pport,
    + enum bfa_pport_sm_event event)
    +{
    + bfa_trc(pport->bfa, event);
    +
    + switch (event) {
    + case BFA_PPORT_SM_START:
    + if (bfa_pport_send_enable(pport))
    + bfa_sm_set_state(pport, bfa_pport_sm_enabling);
    + else
    + bfa_sm_set_state(pport,
    + bfa_pport_sm_enabling_qwait);
    + break;
    +
    + default:
    + /**
    + * Ignore all other events.
    + */
    + ;
    + }
    +}
    +
    +/**
    + * Port is enabled. IOC is down/failed.
    + */
    +static void
    +bfa_pport_sm_iocdown(struct bfa_pport_s *pport,
    + enum bfa_pport_sm_event event)
    +{
    + bfa_trc(pport->bfa, event);
    +
    + switch (event) {
    + case BFA_PPORT_SM_START:
    + if (bfa_pport_send_enable(pport))
    + bfa_sm_set_state(pport, bfa_pport_sm_enabling);
    + else
    + bfa_sm_set_state(pport,
    + bfa_pport_sm_enabling_qwait);
    + break;
    +
    + default:
    + /**
    + * Ignore all events.
    + */
    + ;
    + }
    +}
    +
    +/**
    + * Port is disabled. IOC is down/failed.
    + */
    +static void
    +bfa_pport_sm_iocfail(struct bfa_pport_s *pport,
    + enum bfa_pport_sm_event event)
    +{
    + bfa_trc(pport->bfa, event);
    +
    + switch (event) {
    + case BFA_PPORT_SM_START:
    + bfa_sm_set_state(pport, bfa_pport_sm_disabled);
    + break;
    +
    + case BFA_PPORT_SM_ENABLE:
    + bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
    + break;
    +
    + default:
    + /**
    + * Ignore all events.
    + */
    + ;
    + }
    +}
    +
    +
    +
    +/**
    + * hal_pport_private
    + */
    +
    +static void
    +__bfa_cb_port_event(void *cbarg, bfa_boolean_t complete)
    +{
    + struct bfa_pport_s *pport = cbarg;
    +
    + if (complete)
    + pport->event_cbfn(pport->event_cbarg, pport->hcb_event);
    +}
    +
    +#define PPORT_STATS_DMA_SZ (BFA_ROUNDUP(sizeof(struct bfa_pport_stats_s), \
    + BFA_CACHELINE_SZ))
    +
    +static void
    +bfa_pport_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len,
    + u32 *dm_len)
    +{
    + *dm_len += PPORT_STATS_DMA_SZ;
    +}
    +
    +static void
    +bfa_pport_qresume(void *cbarg)
    +{
    + struct bfa_pport_s *port = cbarg;
    +
    + bfa_sm_send_event(port, BFA_PPORT_SM_QRESUME);
    +}
    +
    +static void
    +bfa_pport_mem_claim(struct bfa_pport_s *pport, struct bfa_meminfo_s *meminfo)
    +{
    + u8 *dm_kva;
    + u64 dm_pa;
    +
    + dm_kva = bfa_meminfo_dma_virt(meminfo);
    + dm_pa = bfa_meminfo_dma_phys(meminfo);
    +
    + pport->stats_kva = dm_kva;
    + pport->stats_pa = dm_pa;
    + pport->stats = (struct bfa_pport_stats_s *) dm_kva;
    +
    + dm_kva += PPORT_STATS_DMA_SZ;
    + dm_pa += PPORT_STATS_DMA_SZ;
    +
    + bfa_meminfo_dma_virt(meminfo) = dm_kva;
    + bfa_meminfo_dma_phys(meminfo) = dm_pa;
    +}
    +
    +/**
    + * Memory initialization.
    + */
    +static void
    +bfa_pport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
    + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
    +{
    + struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
    + struct bfa_pport_cfg_s *port_cfg = &pport->cfg;
    +
    + bfa_os_memset(pport, 0, sizeof(struct bfa_pport_s));
    + pport->bfa = bfa;
    +
    + bfa_pport_mem_claim(pport, meminfo);
    +
    + bfa_sm_set_state(pport, bfa_pport_sm_uninit);
    +
    + /**
    + * initialize and set default configuration
    + */
    + port_cfg->topology = BFA_PPORT_TOPOLOGY_P2P;
    + port_cfg->speed = BFA_PPORT_SPEED_AUTO;
    + port_cfg->trunked = BFA_FALSE;
    + port_cfg->maxfrsize = 0;
    +
    + bfa_reqq_winit(&pport->reqq_wait, bfa_pport_qresume, pport);
    +}
    +
    +static void
    +bfa_pport_initdone(struct bfa_s *bfa)
    +{
    + struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
    +
    + /**
    + * Initialize port attributes from IOC hardware data.
    + */
    + bfa_pport_set_wwns(pport);
    + if (pport->cfg.maxfrsize == 0)
    + pport->cfg.maxfrsize = bfa_ioc_maxfrsize(&bfa->ioc);
    + pport->cfg.rx_bbcredit = bfa_ioc_rx_bbcredit(&bfa->ioc);
    + pport->speed_sup = bfa_ioc_speed_sup(&bfa->ioc);
    +
    + bfa_assert(pport->cfg.maxfrsize);
    + bfa_assert(pport->cfg.rx_bbcredit);
    + bfa_assert(pport->speed_sup);
    +}
    +
    +static void
    +bfa_pport_detach(struct bfa_s *bfa)
    +{
    +}
    +
    +/**
    + * Called when IOC is ready.
    + */
    +static void
    +bfa_pport_start(struct bfa_s *bfa)
    +{
    + bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_START);
    +}
    +
    +/**
    + * Called before IOC is stopped.
    + */
    +static void
    +bfa_pport_stop(struct bfa_s *bfa)
    +{
    + bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_STOP);
    +}
    +
    +/**
    + * Called when IOC failure is detected.
    + */
    +static void
    +bfa_pport_iocdisable(struct bfa_s *bfa)
    +{
    + bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_HWFAIL);
    +}
    +
    +static void
    +bfa_pport_update_linkinfo(struct bfa_pport_s *pport)
    +{
    + struct bfi_pport_event_s *pevent = pport->event_arg.i2hmsg.event;
    +
    + pport->speed = pevent->link_state.speed;
    + pport->topology = pevent->link_state.topology;
    +
    + if (pport->topology == BFA_PPORT_TOPOLOGY_LOOP)
    + pport->myalpa =
    + pevent->link_state.tl.loop_info.myalpa;
    +
    + /* QoS Details */
    + pport->qos_attr = pevent->link_state.qos_attr;
    + pport->qos_vc_attr = pevent->link_state.qos_vc_attr;
    +
    + bfa_trc(pport->bfa, pport->speed);
    + bfa_trc(pport->bfa, pport->topology);
    +}
    +
    +static void
    +bfa_pport_reset_linkinfo(struct bfa_pport_s *pport)
    +{
    + pport->speed = BFA_PPORT_SPEED_UNKNOWN;
    + pport->topology = BFA_PPORT_TOPOLOGY_NONE;
    +}
    +
    +/**
    + * Send port enable message to firmware.
    + */
    +static bfa_boolean_t
    +bfa_pport_send_enable(struct bfa_pport_s *port)
    +{
    + struct bfi_pport_enable_req_s *m;
    +
    + /**
    + * Increment message tag before queue check, so that responses to old
    + * requests are discarded.
    + */
    + port->msgtag++;
    +
    + /**
    + * check for room in queue to send request now
    + */
    + m = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
    + if (!m) {
    + bfa_reqq_wait(port->bfa, BFA_REQQ_PORT,
    + &port->reqq_wait);
    + return BFA_FALSE;
    + }
    +
    + bfi_h2i_set(m->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_ENABLE_REQ,
    + bfa_lpuid(port->bfa));
    + m->nwwn = port->nwwn;
    + m->pwwn = port->pwwn;
    + m->port_cfg = port->cfg;
    + m->msgtag = port->msgtag;
    + m->port_cfg.maxfrsize = bfa_os_htons(port->cfg.maxfrsize);
    + bfa_dma_be_addr_set(m->stats_dma_addr, port->stats_pa);
    + bfa_trc(port->bfa, m->stats_dma_addr.a32.addr_lo);
    + bfa_trc(port->bfa, m->stats_dma_addr.a32.addr_hi);
    +
    + /**
    + * queue I/O message to firmware
    + */
    + bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
    + return BFA_TRUE;
    +}
    +
    +/**
    + * Send port disable message to firmware.
    + */
    +static bfa_boolean_t
    +bfa_pport_send_disable(struct bfa_pport_s *port)
    +{
    + bfi_pport_disable_req_t *m;
    +
    + /**
    + * Increment message tag before queue check, so that responses to old
    + * requests are discarded.
    + */
    + port->msgtag++;
    +
    + /**
    + * check for room in queue to send request now
    + */
    + m = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
    + if (!m) {
    + bfa_reqq_wait(port->bfa, BFA_REQQ_PORT,
    + &port->reqq_wait);
    + return BFA_FALSE;
    + }
    +
    + bfi_h2i_set(m->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_DISABLE_REQ,
    + bfa_lpuid(port->bfa));
    + m->msgtag = port->msgtag;
    +
    + /**
    + * queue I/O message to firmware
    + */
    + bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
    +
    + return BFA_TRUE;
    +}
    +
    +static void
    +bfa_pport_set_wwns(struct bfa_pport_s *port)
    +{
    + port->pwwn = bfa_ioc_get_pwwn(&port->bfa->ioc);
    + port->nwwn = bfa_ioc_get_nwwn(&port->bfa->ioc);
    +
    + bfa_trc(port->bfa, port->pwwn);
    + bfa_trc(port->bfa, port->nwwn);
    +}
    +
    +static void
    +bfa_port_send_txcredit(void *port_cbarg)
    +{
    +
    + struct bfa_pport_s *port = port_cbarg;
    + struct bfi_pport_set_svc_params_req_s *m;
    +
    + /**
    + * check for room in queue to send request now
    + */
    + m = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
    + if (!m) {
    + bfa_reqq_winit(&port->svcreq_wait,
    + bfa_port_send_txcredit, port);
    + bfa_reqq_wait(port->bfa, BFA_REQQ_PORT,
    + &port->svcreq_wait);
    + return;
    + }
    +
    + bfi_h2i_set(m->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_SET_SVC_PARAMS_REQ,
    + bfa_lpuid(port->bfa));
    + m->tx_bbcredit = bfa_os_htons((u16)port->cfg.tx_bbcredit);
    +
    + /**
    + * queue I/O message to firmware
    + */
    + bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
    +}
    +
    +
    +
    +/**
    + * hal_pport_public
    + */
    +
    +/**
    + * Firmware message handler.
    + */
    +void
    +bfa_pport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
    +{
    + struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
    + union bfi_pport_i2h_msg_u i2hmsg;
    +
    + i2hmsg.msg = msg;
    + pport->event_arg.i2hmsg = i2hmsg;
    +
    + switch (msg->mhdr.msg_id) {
    + case BFI_PPORT_I2H_ENABLE_RSP:
    + if (pport->msgtag == i2hmsg.enable_rsp->msgtag)
    + bfa_sm_send_event(pport, BFA_PPORT_SM_FWRSP);
    + break;
    +
    + case BFI_PPORT_I2H_DISABLE_RSP:
    + if (pport->msgtag == i2hmsg.enable_rsp->msgtag)
    + bfa_sm_send_event(pport, BFA_PPORT_SM_FWRSP);
    + break;
    +
    + case BFI_PPORT_I2H_EVENT:
    + switch (i2hmsg.event->link_state.linkstate) {
    + case BFA_PPORT_LINKUP:
    + bfa_sm_send_event(pport, BFA_PPORT_SM_LINKUP);
    + break;
    + case BFA_PPORT_LINKDOWN:
    + bfa_sm_send_event(pport, BFA_PPORT_SM_LINKDOWN);
    + break;
    + case BFA_PPORT_TRUNK_LINKDOWN:
    + /** todo: event notification */
    + break;
    + }
    + break;
    +
    + case BFI_PPORT_I2H_GET_STATS_RSP:
    + case BFI_PPORT_I2H_GET_QOS_STATS_RSP:
    + /*
    + * check for timer pop before processing the rsp
    + */
    + if (pport->stats_busy == BFA_FALSE
    + || pport->stats_status == BFA_STATUS_ETIMER)
    + break;
    +
    + bfa_timer_stop(&pport->timer);
    + pport->stats_status = i2hmsg.getstats_rsp->status;
    + bfa_cb_queue(pport->bfa, &pport->hcb_qe, __bfa_cb_port_stats,
    + pport);
    + break;
    + case BFI_PPORT_I2H_CLEAR_STATS_RSP:
    + case BFI_PPORT_I2H_CLEAR_QOS_STATS_RSP:
    + /*
    + * check for timer pop before processing the rsp
    + */
    + if (pport->stats_busy == BFA_FALSE
    + || pport->stats_status == BFA_STATUS_ETIMER)
    + break;
    +
    + bfa_timer_stop(&pport->timer);
    + pport->stats_status = BFA_STATUS_OK;
    + bfa_cb_queue(pport->bfa, &pport->hcb_qe,
    + __bfa_cb_port_stats_clr, pport);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +
    +
    +/**
    + * hal_pport_api
    + */
    +
    +/**
    + * Registered callback for port events.
    + */
    +void
    +bfa_pport_event_register(struct bfa_s *bfa,
    + void (*cbfn) (void *cbarg,
    + bfa_pport_event_t event),
    + void *cbarg)
    +{
    + struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
    +
    + pport->event_cbfn = cbfn;
    + pport->event_cbarg = cbarg;
    +}
    +
    +bfa_status_t
    +bfa_pport_enable(struct bfa_s *bfa)
    +{
    + struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
    +
    + if (pport->diag_busy)
    + return (BFA_STATUS_DIAG_BUSY);
    +
    + bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_ENABLE);
    + return BFA_STATUS_OK;
    +}
    +
    +bfa_status_t
    +bfa_pport_disable(struct bfa_s *bfa)
    +{
    + bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_DISABLE);
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * Configure port speed.
    + */
    +bfa_status_t
    +bfa_pport_cfg_speed(struct bfa_s *bfa, enum bfa_pport_speed speed)
    +{
    + struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
    +
    + bfa_trc(bfa, speed);
    +
    + if ((speed != BFA_PPORT_SPEED_AUTO) && (speed > pport->speed_sup)) {
    + bfa_trc(bfa, pport->speed_sup);
    + return BFA_STATUS_UNSUPP_SPEED;
    + }
    +
    + pport->cfg.speed = speed;
    +
    + return (BFA_STATUS_OK);
    +}
    +
    +/**
    + * Get current speed.
    + */
    +enum bfa_pport_speed
    +bfa_pport_get_speed(struct bfa_s *bfa)
    +{
    + struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
    +
    + return port->speed;
    +}
    +
    +/**
    + * Configure port topology.
    + */
    +bfa_status_t
    +bfa_pport_cfg_topology(struct bfa_s *bfa, enum bfa_pport_topology topology)
    +{
    + struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
    +
    + bfa_trc(bfa, topology);
    + bfa_trc(bfa, pport->cfg.topology);
    +
    + switch (topology) {
    + case BFA_PPORT_TOPOLOGY_P2P:
    + case BFA_PPORT_TOPOLOGY_LOOP:
    + case BFA_PPORT_TOPOLOGY_AUTO:
    + break;
    +
    + default:
    + return BFA_STATUS_EINVAL;
    + }
    +
    + pport->cfg.topology = topology;
    + return (BFA_STATUS_OK);
    +}
    +
    +/**
    + * Get current topology.
    + */
    +enum bfa_pport_topology
    +bfa_pport_get_topology(struct bfa_s *bfa)
    +{
    + struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
    +
    + return port->topology;
    +}
    +
    +bfa_status_t
    +bfa_pport_cfg_hardalpa(struct bfa_s *bfa, u8 alpa)
    +{
    + struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
    +
    + bfa_trc(bfa, alpa);
    + bfa_trc(bfa, pport->cfg.cfg_hardalpa);
    + bfa_trc(bfa, pport->cfg.hardalpa);
    +
    + pport->cfg.cfg_hardalpa = BFA_TRUE;
    + pport->cfg.hardalpa = alpa;
    +
    + return (BFA_STATUS_OK);
    +}
    +
    +bfa_status_t
    +bfa_pport_clr_hardalpa(struct bfa_s *bfa)
    +{
    + struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
    +
    + bfa_trc(bfa, pport->cfg.cfg_hardalpa);
    + bfa_trc(bfa, pport->cfg.hardalpa);
    +
    + pport->cfg.cfg_hardalpa = BFA_FALSE;
    + return (BFA_STATUS_OK);
    +}
    +
    +bfa_boolean_t
    +bfa_pport_get_hardalpa(struct bfa_s *bfa, u8 *alpa)
    +{
    + struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
    +
    + *alpa = port->cfg.hardalpa;
    + return port->cfg.cfg_hardalpa;
    +}
    +
    +u8
    +bfa_pport_get_myalpa(struct bfa_s *bfa)
    +{
    + struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
    +
    + return port->myalpa;
    +}
    +
    +bfa_status_t
    +bfa_pport_cfg_maxfrsize(struct bfa_s *bfa, u16 maxfrsize)
    +{
    + struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
    +
    + bfa_trc(bfa, maxfrsize);
    + bfa_trc(bfa, pport->cfg.maxfrsize);
    +
    + /* with in range */
    + if ((maxfrsize > FC_MAX_PDUSZ) || (maxfrsize < FC_MIN_PDUSZ))
    + return (BFA_STATUS_INVLD_DFSZ);
    +
    + /* power of 2, if not the max frame size of 2112 */
    + if ((maxfrsize != FC_MAX_PDUSZ) && (maxfrsize & (maxfrsize - 1)))
    + return (BFA_STATUS_INVLD_DFSZ);
    +
    + pport->cfg.maxfrsize = maxfrsize;
    + return (BFA_STATUS_OK);
    +}
    +
    +u16
    +bfa_pport_get_maxfrsize(struct bfa_s *bfa)
    +{
    + struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
    +
    + return port->cfg.maxfrsize;
    +}
    +
    +u32
    +bfa_pport_mypid(struct bfa_s *bfa)
    +{
    + struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
    +
    + return port->mypid;
    +}
    +
    +u8
    +bfa_pport_get_rx_bbcredit(struct bfa_s *bfa)
    +{
    + struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
    +
    + return port->cfg.rx_bbcredit;
    +}
    +
    +void
    +bfa_pport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit)
    +{
    + struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
    +
    + port->cfg.tx_bbcredit = (u8)tx_bbcredit;
    + bfa_port_send_txcredit(port);
    +}
    +
    +/**
    + * Get port attributes.
    + */
    +
    +wwn_t
    +bfa_pport_get_wwn(struct bfa_s *bfa, bfa_boolean_t node)
    +{
    + struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
    + if (node)
    + return pport->nwwn;
    + else
    + return pport->pwwn;
    +}
    +
    +void
    +bfa_pport_get_attr(struct bfa_s *bfa, struct bfa_pport_attr_s *attr)
    +{
    + struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
    +
    + bfa_os_memset(attr, 0, sizeof(struct bfa_pport_attr_s));
    +
    + attr->nwwn = pport->nwwn;
    + attr->pwwn = pport->pwwn;
    +
    + bfa_os_memcpy(&attr->pport_cfg, &pport->cfg,
    + sizeof(struct bfa_pport_cfg_s));
    + /* speed attributes */
    + attr->pport_cfg.speed = pport->cfg.speed;
    + attr->speed_supported = pport->speed_sup;
    + attr->speed = pport->speed;
    + attr->cos_supported = FC_CLASS_3;
    +
    + /* topology attributes */
    + attr->pport_cfg.topology = pport->cfg.topology;
    + attr->topology = pport->topology;
    +
    + /* beacon attributes */
    + attr->beacon = pport->beacon;
    + attr->link_e2e_beacon = pport->link_e2e_beacon;
    + attr->plog_enabled = bfa_plog_get_setting(pport->bfa->plog);
    +
    + attr->pport_cfg.path_tov = bfa_fcpim_path_tov_get(bfa);
    + attr->pport_cfg.q_depth = bfa_fcpim_qdepth_get(bfa);
    + attr->port_state = bfa_sm_to_state(hal_pport_sm_table, pport->sm);
    + if (bfa_ioc_is_disabled(&pport->bfa->ioc))
    + attr->port_state = BFA_PPORT_ST_IOCDIS;
    +}
    +
    +static void
    +bfa_port_stats_query(void *cbarg)
    +{
    + struct bfa_pport_s *port = (struct bfa_pport_s *) cbarg;
    + bfi_pport_get_stats_req_t *msg;
    +
    + msg = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
    +
    + if (!msg) {
    + bfa_reqq_winit(&port->stats_reqq_wait,
    + bfa_port_stats_query, port);
    + bfa_reqq_wait(port->bfa, BFA_REQQ_PORT,
    + &port->stats_reqq_wait);
    + return;
    + }
    +
    + bfa_os_memset(msg, 0, sizeof(bfi_pport_get_stats_req_t));
    + bfi_h2i_set(msg->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_GET_STATS_REQ,
    + bfa_lpuid(port->bfa));
    + bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
    +
    + return;
    +}
    +
    +static void
    +bfa_port_stats_clear(void *cbarg)
    +{
    + struct bfa_pport_s *port = (struct bfa_pport_s *) cbarg;
    + bfi_pport_clear_stats_req_t *msg;
    +
    + msg = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
    +
    + if (!msg) {
    + bfa_reqq_winit(&port->stats_reqq_wait,
    + bfa_port_stats_clear, port);
    + bfa_reqq_wait(port->bfa, BFA_REQQ_PORT,
    + &port->stats_reqq_wait);
    + return;
    + }
    +
    + bfa_os_memset(msg, 0, sizeof(bfi_pport_clear_stats_req_t));
    + bfi_h2i_set(msg->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_CLEAR_STATS_REQ,
    + bfa_lpuid(port->bfa));
    + bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
    + return;
    +}
    +
    +static void
    +bfa_port_qos_stats_clear(void *cbarg)
    +{
    + struct bfa_pport_s *port = (struct bfa_pport_s *) cbarg;
    + bfi_pport_clear_qos_stats_req_t *msg;
    +
    + msg = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
    +
    + if (!msg) {
    + bfa_reqq_winit(&port->stats_reqq_wait,
    + bfa_port_qos_stats_clear, port);
    + bfa_reqq_wait(port->bfa, BFA_REQQ_PORT,
    + &port->stats_reqq_wait);
    + return;
    + }
    +
    + bfa_os_memset(msg, 0, sizeof(bfi_pport_clear_qos_stats_req_t));
    + bfi_h2i_set(msg->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_CLEAR_QOS_STATS_REQ,
    + bfa_lpuid(port->bfa));
    + bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
    + return;
    +}
    +
    +static void
    +bfa_pport_stats_swap(struct bfa_pport_stats_s *d, struct bfa_pport_stats_s *s)
    +{
    + u32 *dip = (u32 *) d;
    + u32 *sip = (u32 *) s;
    + int i;
    +
    + /* Do 64 bit fields swap first */
    + for (i = 0; i < ((sizeof(struct bfa_pport_stats_s) -
    + sizeof(struct bfa_qos_stats_s))/sizeof(u32)); i = i + 2) {
    +#ifdef __BIGENDIAN
    + dip[i] = bfa_os_ntohl(sip[i]);
    + dip[i + 1] = bfa_os_ntohl(sip[i + 1]);
    +#else
    + dip[i] = bfa_os_ntohl(sip[i + 1]);
    + dip[i + 1] = bfa_os_ntohl(sip[i]);
    +#endif
    + }
    +
    + /* Now swap the 32 bit fields */
    + for (; i < (sizeof(struct bfa_pport_stats_s)/sizeof(u32)); ++i)
    + dip[i] = bfa_os_ntohl(sip[i]);
    +}
    +
    +static void
    +__bfa_cb_port_stats_clr(void *cbarg, bfa_boolean_t complete)
    +{
    + struct bfa_pport_s *port = cbarg;
    +
    + if (complete) {
    + port->stats_cbfn(port->stats_cbarg, port->stats_status);
    + } else {
    + port->stats_busy = BFA_FALSE;
    + port->stats_status = BFA_STATUS_OK;
    + }
    +}
    +
    +static void
    +bfa_port_stats_clr_timeout(void *cbarg)
    +{
    + struct bfa_pport_s *port = (struct bfa_pport_s *) cbarg;
    +
    + bfa_trc(port->bfa, 0);
    +
    + port->stats_status = BFA_STATUS_ETIMER;
    + bfa_cb_queue(port->bfa, &port->hcb_qe, __bfa_cb_port_stats_clr, port);
    +}
    +
    +static void
    +__bfa_cb_port_stats(void *cbarg, bfa_boolean_t complete)
    +{
    + struct bfa_pport_s *port = cbarg;
    +
    + if (complete) {
    + if (port->stats_status == BFA_STATUS_OK)
    + bfa_pport_stats_swap(port->stats_ret, port->stats);
    + port->stats_cbfn(port->stats_cbarg, port->stats_status);
    + } else {
    + port->stats_busy = BFA_FALSE;
    + port->stats_status = BFA_STATUS_OK;
    + }
    +}
    +
    +static void
    +bfa_port_stats_timeout(void *cbarg)
    +{
    + struct bfa_pport_s *port = (struct bfa_pport_s *) cbarg;
    +
    + bfa_trc(port->bfa, 0);
    +
    + port->stats_status = BFA_STATUS_ETIMER;
    + bfa_cb_queue(port->bfa, &port->hcb_qe, __bfa_cb_port_stats, port);
    +}
    +
    +#define BFA_PORT_STATS_TOV 1000
    +
    +/**
    + * Fetch port attributes.
    + */
    +bfa_status_t
    +bfa_pport_get_stats(struct bfa_s *bfa, struct bfa_pport_stats_s *stats,
    + bfa_cb_pport_t cbfn, void *cbarg)
    +{
    + struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
    +
    + if (port->stats_busy) {
    + bfa_trc(bfa, port->stats_busy);
    + return (BFA_STATUS_DEVBUSY);
    + }
    +
    + port->stats_busy = BFA_TRUE;
    + port->stats_ret = stats;
    + port->stats_cbfn = cbfn;
    + port->stats_cbarg = cbarg;
    +
    + bfa_port_stats_query(port);
    +
    + bfa_timer_start(bfa, &port->timer, bfa_port_stats_timeout, port,
    + BFA_PORT_STATS_TOV);
    + return (BFA_STATUS_OK);
    +}
    +
    +bfa_status_t
    +bfa_pport_clear_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg)
    +{
    + struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
    +
    + if (port->stats_busy) {
    + bfa_trc(bfa, port->stats_busy);
    + return (BFA_STATUS_DEVBUSY);
    + }
    +
    + port->stats_busy = BFA_TRUE;
    + port->stats_cbfn = cbfn;
    + port->stats_cbarg = cbarg;
    +
    + bfa_port_stats_clear(port);
    +
    + bfa_timer_start(bfa, &port->timer, bfa_port_stats_clr_timeout,
    + port, BFA_PORT_STATS_TOV);
    + return (BFA_STATUS_OK);
    +}
    +
    +bfa_status_t
    +bfa_pport_trunk_enable(struct bfa_s *bfa, u8 bitmap)
    +{
    + struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
    +
    + bfa_trc(bfa, bitmap);
    + bfa_trc(bfa, pport->cfg.trunked);
    + bfa_trc(bfa, pport->cfg.trunk_ports);
    +
    + if (!bitmap || (bitmap & (bitmap - 1)))
    + return BFA_STATUS_EINVAL;
    +
    + pport->cfg.trunked = BFA_TRUE;
    + pport->cfg.trunk_ports = bitmap;
    +
    + return BFA_STATUS_OK;
    +}
    +
    +void
    +bfa_pport_qos_get_attr(struct bfa_s *bfa, struct bfa_qos_attr_s *qos_attr)
    +{
    + struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
    +
    + qos_attr->state = bfa_os_ntohl(pport->qos_attr.state);
    + qos_attr->total_bb_cr = bfa_os_ntohl(pport->qos_attr.total_bb_cr);
    +}
    +
    +void
    +bfa_pport_qos_get_vc_attr(struct bfa_s *bfa,
    + struct bfa_qos_vc_attr_s *qos_vc_attr)
    +{
    + struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
    + struct bfa_qos_vc_attr_s *bfa_vc_attr = &pport->qos_vc_attr;
    + u32 i = 0;
    +
    + qos_vc_attr->total_vc_count = bfa_os_ntohs(bfa_vc_attr->total_vc_count);
    + qos_vc_attr->shared_credit = bfa_os_ntohs(bfa_vc_attr->shared_credit);
    + qos_vc_attr->elp_opmode_flags =
    + bfa_os_ntohl(bfa_vc_attr->elp_opmode_flags);
    +
    + /* Individual VC info */
    + while (i < qos_vc_attr->total_vc_count) {
    + qos_vc_attr->vc_info[i].vc_credit =
    + bfa_vc_attr->vc_info[i].vc_credit;
    + qos_vc_attr->vc_info[i].borrow_credit =
    + bfa_vc_attr->vc_info[i].borrow_credit;
    + qos_vc_attr->vc_info[i].priority =
    + bfa_vc_attr->vc_info[i].priority;
    + ++i;
    + }
    +}
    +
    +/**
    + * Fetch QoS Stats.
    + */
    +bfa_status_t
    +bfa_pport_get_qos_stats(struct bfa_s *bfa, struct bfa_pport_stats_s *stats,
    + bfa_cb_pport_t cbfn, void *cbarg)
    +{
    + /* QoS stats is embedded in port stats */
    + return (bfa_pport_get_stats(bfa, stats, cbfn, cbarg));
    +}
    +
    +bfa_status_t
    +bfa_pport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg)
    +{
    + struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
    +
    + if (port->stats_busy) {
    + bfa_trc(bfa, port->stats_busy);
    + return (BFA_STATUS_DEVBUSY);
    + }
    +
    + port->stats_busy = BFA_TRUE;
    + port->stats_cbfn = cbfn;
    + port->stats_cbarg = cbarg;
    +
    + bfa_port_qos_stats_clear(port);
    +
    + bfa_timer_start(bfa, &port->timer, bfa_port_stats_clr_timeout,
    + port, BFA_PORT_STATS_TOV);
    + return (BFA_STATUS_OK);
    +}
    +
    +/**
    + * Fetch port attributes.
    + */
    +bfa_status_t
    +bfa_pport_trunk_disable(struct bfa_s *bfa)
    +{
    + return (BFA_STATUS_OK);
    +}
    +
    +bfa_boolean_t
    +bfa_pport_trunk_query(struct bfa_s *bfa, u32 *bitmap)
    +{
    + struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
    +
    + *bitmap = port->cfg.trunk_ports;
    + return port->cfg.trunked;
    +}
    +
    +bfa_boolean_t
    +bfa_pport_is_disabled(struct bfa_s *bfa)
    +{
    + struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
    +
    + return (bfa_sm_to_state(hal_pport_sm_table, port->sm) ==
    + BFA_PPORT_ST_DISABLED);
    +
    +}
    +
    +bfa_boolean_t
    +bfa_pport_is_ratelim(struct bfa_s *bfa)
    +{
    + struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
    +
    + return(pport->cfg.ratelimit ? BFA_TRUE : BFA_FALSE);
    +
    +}
    +
    +void
    +bfa_pport_cfg_qos(struct bfa_s *bfa, bfa_boolean_t on_off)
    +{
    + struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
    +
    + bfa_trc(bfa, on_off);
    + bfa_trc(bfa, pport->cfg.qos_enabled);
    +
    + pport->cfg.qos_enabled = on_off;
    +}
    +
    +void
    +bfa_pport_cfg_ratelim(struct bfa_s *bfa, bfa_boolean_t on_off)
    +{
    + struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
    +
    + bfa_trc(bfa, on_off);
    + bfa_trc(bfa, pport->cfg.ratelimit);
    +
    + pport->cfg.ratelimit = on_off;
    + if (pport->cfg.trl_def_speed == BFA_PPORT_SPEED_UNKNOWN)
    + pport->cfg.trl_def_speed = BFA_PPORT_SPEED_1GBPS;
    +}
    +
    +/**
    + * Configure default minimum ratelim speed
    + */
    +bfa_status_t
    +bfa_pport_cfg_ratelim_speed(struct bfa_s *bfa, enum bfa_pport_speed speed)
    +{
    + struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
    +
    + bfa_trc(bfa, speed);
    +
    + /* Auto and speeds greater than the supported speed, are invalid */
    + if ((speed == BFA_PPORT_SPEED_AUTO) || (speed > pport->speed_sup)) {
    + bfa_trc(bfa, pport->speed_sup);
    + return BFA_STATUS_UNSUPP_SPEED;
    + }
    +
    + pport->cfg.trl_def_speed = speed;
    +
    + return (BFA_STATUS_OK);
    +}
    +
    +/**
    + * Get default minimum ratelim speed
    + */
    +enum bfa_pport_speed
    +bfa_pport_get_ratelim_speed(struct bfa_s *bfa)
    +{
    + struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
    +
    + bfa_trc(bfa, pport->cfg.trl_def_speed);
    + return(pport->cfg.trl_def_speed);
    +
    +}
    +void
    +bfa_pport_busy(struct bfa_s *bfa, bfa_boolean_t status)
    +{
    + struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
    +
    + bfa_trc(bfa, status);
    + bfa_trc(bfa, pport->diag_busy);
    +
    + pport->diag_busy = status;
    +}
    +
    +void
    +bfa_pport_beacon(struct bfa_s *bfa, bfa_boolean_t beacon,
    + bfa_boolean_t link_e2e_beacon)
    +{
    + struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
    +
    + bfa_trc(bfa, beacon);
    + bfa_trc(bfa, link_e2e_beacon);
    + bfa_trc(bfa, pport->beacon);
    + bfa_trc(bfa, pport->link_e2e_beacon);
    +
    + pport->beacon = beacon;
    + pport->link_e2e_beacon = link_e2e_beacon;
    +}
    +
    +bfa_boolean_t
    +bfa_pport_is_linkup(struct bfa_s *bfa)
    +{
    + return bfa_sm_cmp_state(BFA_PORT_MOD(bfa), bfa_pport_sm_linkup);
    +}
    +
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_port_priv.h patch/drivers/scsi/bfa/bfa_port_priv.h
    --- orig/drivers/scsi/bfa/bfa_port_priv.h 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_port_priv.h 2009-04-01 20:08:47.380363000 -0700
    @@ -0,0 +1,89 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#ifndef __BFA_PORT_PRIV_H__
    +#define __BFA_PORT_PRIV_H__
    +
    +#include <defs/bfa_defs_pport.h>
    +#include <bfi/bfi_pport.h>
    +#include "bfa_intr_priv.h"
    +
    +/**
    + * BFA physical port data structure
    + */
    +struct bfa_pport_s {
    + struct bfa_s *bfa; /* parent BFA instance */
    + bfa_sm_t sm; /* port state machine */
    + wwn_t nwwn; /* node wwn of physical port */
    + wwn_t pwwn; /* port wwn of physical oprt */
    + enum bfa_pport_speed speed_sup;
    + /* supported speeds */
    + enum bfa_pport_speed speed; /* current speed */
    + enum bfa_pport_topology topology; /* current topology */
    + u8 myalpa; /* my ALPA in LOOP topology */
    + u8 rsvd[3];
    + struct bfa_pport_cfg_s cfg; /* current port configuration */
    + struct bfa_qos_attr_s qos_attr; /* QoS Attributes */
    + struct bfa_qos_vc_attr_s qos_vc_attr; /* VC info from ELP */
    + struct bfa_reqq_wait_s reqq_wait;
    + /* to wait for room in reqq */
    + struct bfa_reqq_wait_s svcreq_wait;
    + /* to wait for room in reqq */
    + struct bfa_reqq_wait_s stats_reqq_wait;
    + /* to wait for room in reqq (stats) */
    + void *event_cbarg;
    + void (*event_cbfn) (void *cbarg,
    + bfa_pport_event_t event);
    + union {
    + union bfi_pport_i2h_msg_u i2hmsg;
    + } event_arg;
    + void *bfad; /* BFA driver handle */
    + struct bfa_cb_qe_s hcb_qe; /* BFA callback queue elem */
    + enum bfa_pport_linkstate hcb_event;
    + /* link event for callback */
    + u32 msgtag; /* fimrware msg tag for reply */
    + u8 *stats_kva;
    + u64 stats_pa;
    + struct bfa_pport_stats_s *stats; /* pport stats */
    + u32 mypid : 24;
    + u32 rsvd_b : 8;
    + struct bfa_timer_s timer; /* timer */
    + struct bfa_pport_stats_s *stats_ret;
    + /* driver stats location */
    + bfa_status_t stats_status;
    + /* stats/statsclr status */
    + bfa_boolean_t stats_busy;
    + /* outstanding stats/statsclr */
    + bfa_boolean_t diag_busy;
    + /* diag busy status */
    + bfa_boolean_t beacon;
    + /* port beacon status */
    + bfa_boolean_t link_e2e_beacon;
    + /* link beacon status */
    + bfa_cb_pport_t stats_cbfn;
    + /* driver callback function */
    + void *stats_cbarg;
    + /* *!< user callback arg */
    +};
    +
    +#define BFA_PORT_MOD(__bfa) (&(__bfa)->modules.pport)
    +
    +/*
    + * public functions
    + */
    +void bfa_pport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
    +#endif /* __BFA_PORT_PRIV_H__ */
    diff -urpN orig/drivers/scsi/bfa/bfa_priv.h patch/drivers/scsi/bfa/bfa_priv.h
    --- orig/drivers/scsi/bfa/bfa_priv.h 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_priv.h 2009-04-01 20:08:47.389831000 -0700
    @@ -0,0 +1,122 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#ifndef __BFA_PRIV_H__
    +#define __BFA_PRIV_H__
    +
    +#include "bfa_iocfc.h"
    +#include "bfa_intr_priv.h"
    +#include "bfa_trcmod_priv.h"
    +#include "bfa_modules_priv.h"
    +#include "bfa_fwimg_priv.h"
    +#include <cs/bfa_log.h>
    +#include <bfa_timer.h>
    +#include <bfa_fabric.h>
    +
    +/**
    + * Macro to define a new BFA module
    + */
    +#define BFA_MODULE(__mod) \
    + static void bfa_ ## __mod ## _meminfo( \
    + struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, \
    + u32 *dm_len); \
    + static void bfa_ ## __mod ## _attach(struct bfa_s *bfa, \
    + void *bfad, struct bfa_iocfc_cfg_s *cfg, \
    + struct bfa_meminfo_s *meminfo, \
    + struct bfa_pcidev_s *pcidev); \
    + static void bfa_ ## __mod ## _initdone(struct bfa_s *bfa); \
    + static void bfa_ ## __mod ## _detach(struct bfa_s *bfa); \
    + static void bfa_ ## __mod ## _start(struct bfa_s *bfa); \
    + static void bfa_ ## __mod ## _stop(struct bfa_s *bfa); \
    + static void bfa_ ## __mod ## _iocdisable(struct bfa_s *bfa); \
    + \
    + extern struct bfa_module_s hal_mod_ ## __mod; \
    + struct bfa_module_s hal_mod_ ## __mod = { \
    + bfa_ ## __mod ## _meminfo, \
    + bfa_ ## __mod ## _attach, \
    + bfa_ ## __mod ## _initdone, \
    + bfa_ ## __mod ## _detach, \
    + bfa_ ## __mod ## _start, \
    + bfa_ ## __mod ## _stop, \
    + bfa_ ## __mod ## _iocdisable, \
    + }
    +
    +#define BFA_CACHELINE_SZ (256)
    +
    +/**
    + * Structure used to interact between different BFA sub modules
    + *
    + * Each sub module needs to implement only the entry points relevant to it (and
    + * can leave entry points as NULL)
    + */
    +struct bfa_module_s {
    + void (*meminfo) (struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
    + u32 *dm_len);
    + void (*attach) (struct bfa_s *bfa, void *bfad,
    + struct bfa_iocfc_cfg_s *cfg,
    + struct bfa_meminfo_s *meminfo,
    + struct bfa_pcidev_s *pcidev);
    + void (*initdone) (struct bfa_s *bfa);
    + void (*detach) (struct bfa_s *bfa);
    + void (*start) (struct bfa_s *bfa);
    + void (*stop) (struct bfa_s *bfa);
    + void (*iocdisable) (struct bfa_s *bfa);
    +};
    +
    +extern struct bfa_module_s *hal_mods[];
    +
    +struct bfa_s {
    + void *bfad; /* BFA driver instance */
    + struct bfa_aen_s *aen; /* AEN module */
    + struct bfa_plog_s *plog; /* portlog buffer */
    + struct bfa_log_mod_s *logm; /* driver logging modulen */
    + struct bfa_trc_mod_s *trcmod; /* driver tracing */
    + struct bfa_fabric_s fabric; /* fabric*/
    + struct bfa_driver_info_s driver_info;
    + struct bfa_ioc_s ioc; /* IOC module */
    + struct bfa_iocfc_s iocfc; /* IOCFC module */
    + struct bfa_timer_mod_s timer_mod; /* timer module */
    + struct bfa_modules_s modules; /* BFA modules */
    + struct list_head comp_q; /* pending completions */
    + struct list_head reqq_waitq[BFI_IOC_MAX_CQS];
    +};
    +
    +/**
    + * Macros to get fcs config info given bfa
    + */
    +#define bfa_bport_role(__bfa) \
    + (((struct bfa_s *)__bfa)->iocfc.cfg.drvcfg.bport_role)
    +#define bfa_fw_disc_enabled(__bfa) \
    + (((struct bfa_s *)__bfa)->iocfc.cfg.drvcfg.fw_disc_enabled)
    +
    +extern bfa_isr_func_t bfa_isrs[BFI_MC_MAX];
    +extern bfa_ioc_mbox_mcfunc_t bfa_mbox_isrs[];
    +extern bfa_boolean_t bfa_auto_recover;
    +extern struct bfa_module_s hal_mod_flash;
    +extern struct bfa_module_s hal_mod_fcdiag;
    +extern struct bfa_module_s hal_mod_sgpg;
    +extern struct bfa_module_s hal_mod_pport;
    +extern struct bfa_module_s hal_mod_fcxp;
    +extern struct bfa_module_s hal_mod_lps;
    +extern struct bfa_module_s hal_mod_uf;
    +extern struct bfa_module_s hal_mod_rport;
    +extern struct bfa_module_s hal_mod_fcpim;
    +extern struct bfa_module_s hal_mod_fabric;
    +extern struct bfa_module_s hal_mod_lport;
    +
    +#endif /* __BFA_PRIV_H__ */
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_rport.c patch/drivers/scsi/bfa/bfa_rport.c
    --- orig/drivers/scsi/bfa/bfa_rport.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_rport.c 2009-04-01 20:08:47.398327000 -0700
    @@ -0,0 +1,1142 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#include <bfa.h>
    +#include <bfa_svc.h>
    +#include <bfa_rport.h>
    +#include <bfa_fcpim.h>
    +#include <cs/bfa_debug.h>
    +#include <bfi/bfi_rport.h>
    +#include <bfa_fcpim.h>
    +#include "bfa_intr_priv.h"
    +#include "bfa_lport.h"
    +
    +BFA_TRC_FILE(HAL, RPORT);
    +BFA_MODULE(rport);
    +
    +#define bfa_rport_offline_cb(__rp) do { \
    + bfa_cb_queue((__rp)->bfa, &(__rp)->hcb_qe, \
    + __bfa_cb_rport_offline, (__rp)); \
    +} while (0)
    +
    +/*
    +#define bfa_rport_offline_cb(__rp) do { \
    + fw discovery is enabled in initiator mode \
    + if ((bfa_lport_is_initiator((__rp)->bfa, (__rp)->lport_tag)) \
    + && bfa_fw_disc_enabled((__rp)->bfa)) { \
    + bfa_itnim_offline((__rp)); \
    + bfa is target mode - rport is initiator \
    + } else if (bfa_lport_is_target((__rp)->bfa),(__rp)->lport_tag) { \
    + bfa_itntm_rport_offline((__rp)); \
    + } else { \
    + bfa_cb_queue((__rp)->bfa, &(__rp)->hcb_qe, \
    + __bfa_cb_rport_offline, (__rp)); \
    + } \
    +} while (0)
    +*/
    +
    +#define bfa_rport_online_cb(__rp) do { \
    + bfa_cb_queue((__rp)->bfa, &(__rp)->hcb_qe, \
    + __bfa_cb_rport_online, (__rp)); \
    +} while (0)
    +
    +/*
    + * forward declarations
    + */
    +static struct bfa_rport_s *bfa_rport_alloc(struct bfa_rport_mod_s *rp_mod);
    +static void bfa_rport_free(struct bfa_rport_s *rport);
    +static bfa_boolean_t bfa_rport_send_fwcreate(struct bfa_rport_s *rp);
    +static bfa_boolean_t bfa_rport_send_fwdelete(struct bfa_rport_s *rp);
    +static bfa_boolean_t bfa_rport_send_fwspeed(struct bfa_rport_s *rp);
    +static void __bfa_cb_rport_online(void *cbarg,
    + bfa_boolean_t complete);
    +static void __bfa_cb_rport_offline(void *cbarg,
    + bfa_boolean_t complete);
    +static void bfa_rport_register(struct bfa_rport_s *rp);
    +static bfa_boolean_t bfa_rport_send_cleanup_rsp(struct bfa_rport_s *rp);
    +
    +/**
    + * bfa_rport_sm BFA rport state machine
    + */
    +
    +
    +enum bfa_rport_event {
    + BFA_RPORT_SM_CREATE = 1, /* rport create event */
    + BFA_RPORT_SM_DELETE = 2, /* deleting an existing rport */
    + BFA_RPORT_SM_ONLINE = 3, /* rport is online */
    + BFA_RPORT_SM_OFFLINE = 4, /* rport is offline */
    + BFA_RPORT_SM_FWRSP = 5, /* firmware response */
    + BFA_RPORT_SM_HWFAIL = 6, /* IOC h/w failure */
    + BFA_RPORT_SM_QOS_SCN = 7, /* QoS change notification from fw */
    + BFA_RPORT_SM_SET_SPEED = 8, /* Set Rport Speed */
    +
    + /*
    + * FCS rport related events
    + */
    + BFA_RPORT_SM_ADD = 9, /*! < rport add event from f/w */
    + BFA_RPORT_SM_REMOVE = 10, /*! < rport remove event from f/w */
    + BFA_RPORT_SM_DOWN = 11, /*! < rport down event from f/w */
    + BFA_RPORT_SM_UP = 12, /*! < rport up event from f/w */
    + BFA_RPORT_SM_CLEANUP_DONE = 13, /*! < itnim & io clean up done */
    +};
    +
    +static void bfa_rport_sm_uninit(struct bfa_rport_s *rp,
    + enum bfa_rport_event event);
    +static void bfa_rport_sm_created(struct bfa_rport_s *rp,
    + enum bfa_rport_event event);
    +static void bfa_rport_sm_fwcreate(struct bfa_rport_s *rp,
    + enum bfa_rport_event event);
    +static void bfa_rport_sm_online(struct bfa_rport_s *rp,
    + enum bfa_rport_event event);
    +static void bfa_rport_sm_fwdelete(struct bfa_rport_s *rp,
    + enum bfa_rport_event event);
    +static void bfa_rport_sm_offline(struct bfa_rport_s *rp,
    + enum bfa_rport_event event);
    +static void bfa_rport_sm_deleting(struct bfa_rport_s *rp,
    + enum bfa_rport_event event);
    +static void bfa_rport_sm_offline_pending(struct bfa_rport_s *rp,
    + enum bfa_rport_event event);
    +static void bfa_rport_sm_delete_pending(struct bfa_rport_s *rp,
    + enum bfa_rport_event event);
    +static void bfa_rport_sm_iocdisable(struct bfa_rport_s *rp,
    + enum bfa_rport_event event);
    +
    +/**
    + * Rport SM states for FCS discovery in f/w
    + */
    +static void bfa_rport_sm_up(struct bfa_rport_s *rp,
    + enum bfa_rport_event event);
    +static void bfa_rport_sm_cleanup(struct bfa_rport_s *rp,
    + enum bfa_rport_event event);
    +static void bfa_rport_sm_down(struct bfa_rport_s *rp,
    + enum bfa_rport_event event);
    +
    +/**
    + * Beginning state, only online event expected.
    + */
    +static void
    +bfa_rport_sm_uninit(struct bfa_rport_s *rp, enum bfa_rport_event event)
    +{
    + bfa_trc(rp->bfa, rp->rport_tag);
    + bfa_trc(rp->bfa, event);
    +
    + switch (event) {
    + case BFA_RPORT_SM_CREATE:
    + bfa_stats(rp, sm_un_cr);
    + bfa_sm_set_state(rp, bfa_rport_sm_created);
    + break;
    +
    + case BFA_RPORT_SM_ADD:
    + bfa_sm_set_state(rp, bfa_rport_sm_up);
    + bfa_rport_register(rp);
    + break;
    +
    + default:
    + bfa_stats(rp, sm_un_unexp);
    + bfa_assert(0);
    + }
    +}
    +
    +static void
    +bfa_rport_sm_created(struct bfa_rport_s *rp, enum bfa_rport_event event)
    +{
    + bfa_trc(rp->bfa, rp->rport_tag);
    + bfa_trc(rp->bfa, event);
    +
    + switch (event) {
    + case BFA_RPORT_SM_ONLINE:
    + bfa_stats(rp, sm_cr_on);
    + bfa_sm_set_state(rp, bfa_rport_sm_fwcreate);
    + bfa_rport_send_fwcreate(rp);
    + break;
    +
    + case BFA_RPORT_SM_DELETE:
    + bfa_stats(rp, sm_cr_del);
    + bfa_sm_set_state(rp, bfa_rport_sm_uninit);
    + bfa_rport_free(rp);
    + break;
    +
    + case BFA_RPORT_SM_HWFAIL:
    + bfa_stats(rp, sm_cr_hwf);
    + bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
    + break;
    +
    + default:
    + bfa_stats(rp, sm_cr_unexp);
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Waiting for rport create response from firmware.
    + */
    +static void
    +bfa_rport_sm_fwcreate(struct bfa_rport_s *rp, enum bfa_rport_event event)
    +{
    + bfa_trc(rp->bfa, rp->rport_tag);
    + bfa_trc(rp->bfa, event);
    +
    + switch (event) {
    + case BFA_RPORT_SM_FWRSP:
    + bfa_stats(rp, sm_fwc_rsp);
    + bfa_sm_set_state(rp, bfa_rport_sm_online);
    + bfa_rport_online_cb(rp);
    + break;
    +
    + case BFA_RPORT_SM_DELETE:
    + bfa_stats(rp, sm_fwc_del);
    + bfa_sm_set_state(rp, bfa_rport_sm_delete_pending);
    + break;
    +
    + case BFA_RPORT_SM_OFFLINE:
    + bfa_stats(rp, sm_fwc_off);
    + bfa_sm_set_state(rp, bfa_rport_sm_offline_pending);
    + break;
    +
    + case BFA_RPORT_SM_HWFAIL:
    + bfa_stats(rp, sm_fwc_hwf);
    + bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
    + break;
    +
    + default:
    + bfa_stats(rp, sm_fwc_unexp);
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Online state - normal parking state.
    + */
    +static void
    +bfa_rport_sm_online(struct bfa_rport_s *rp, enum bfa_rport_event event)
    +{
    + struct bfi_rport_qos_scn_s *qos_scn;
    +
    + bfa_trc(rp->bfa, rp->rport_tag);
    + bfa_trc(rp->bfa, event);
    +
    + switch (event) {
    + case BFA_RPORT_SM_OFFLINE:
    + bfa_stats(rp, sm_on_off);
    + bfa_sm_set_state(rp, bfa_rport_sm_fwdelete);
    + bfa_rport_send_fwdelete(rp);
    + break;
    +
    + case BFA_RPORT_SM_DELETE:
    + bfa_stats(rp, sm_on_del);
    + bfa_sm_set_state(rp, bfa_rport_sm_deleting);
    + bfa_rport_send_fwdelete(rp);
    + break;
    +
    + case BFA_RPORT_SM_HWFAIL:
    + bfa_stats(rp, sm_on_hwf);
    + bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
    + break;
    +
    + case BFA_RPORT_SM_SET_SPEED:
    + bfa_rport_send_fwspeed(rp);
    + break;
    +
    + case BFA_RPORT_SM_QOS_SCN:
    + qos_scn = (struct bfi_rport_qos_scn_s *) rp->event_arg.fw_msg;
    + rp->qos_attr = qos_scn->new_qos_attr;
    + bfa_trc(rp->bfa, qos_scn->old_qos_attr.qos_flow_id);
    + bfa_trc(rp->bfa, qos_scn->new_qos_attr.qos_flow_id);
    + bfa_trc(rp->bfa, qos_scn->old_qos_attr.qos_priority);
    + bfa_trc(rp->bfa, qos_scn->new_qos_attr.qos_priority);
    +
    + qos_scn->old_qos_attr.qos_flow_id =
    + bfa_os_ntohl(qos_scn->old_qos_attr.qos_flow_id);
    + qos_scn->new_qos_attr.qos_flow_id =
    + bfa_os_ntohl(qos_scn->new_qos_attr.qos_flow_id);
    + qos_scn->old_qos_attr.qos_priority =
    + bfa_os_ntohl(qos_scn->old_qos_attr.qos_priority);
    + qos_scn->new_qos_attr.qos_priority =
    + bfa_os_ntohl(qos_scn->new_qos_attr.qos_priority);
    +
    + if (qos_scn->old_qos_attr.qos_flow_id !=
    + qos_scn->new_qos_attr.qos_flow_id)
    + bfa_cb_rport_qos_scn_flowid(rp->rport_drv,
    + qos_scn->old_qos_attr,
    + qos_scn->new_qos_attr);
    + if (qos_scn->old_qos_attr.qos_priority !=
    + qos_scn->new_qos_attr.qos_priority)
    + bfa_cb_rport_qos_scn_prio(rp->rport_drv,
    + qos_scn->old_qos_attr,
    + qos_scn->new_qos_attr);
    + break;
    +
    + default:
    + bfa_stats(rp, sm_on_unexp);
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Firmware rport is being deleted - awaiting f/w response.
    + */
    +static void
    +bfa_rport_sm_fwdelete(struct bfa_rport_s *rp, enum bfa_rport_event event)
    +{
    + bfa_trc(rp->bfa, rp->rport_tag);
    + bfa_trc(rp->bfa, event);
    +
    + switch (event) {
    + case BFA_RPORT_SM_FWRSP:
    + bfa_stats(rp, sm_fwd_rsp);
    + bfa_sm_set_state(rp, bfa_rport_sm_offline);
    + bfa_rport_offline_cb(rp);
    + break;
    +
    + case BFA_RPORT_SM_DELETE:
    + bfa_stats(rp, sm_fwd_del);
    + bfa_sm_set_state(rp, bfa_rport_sm_deleting);
    + break;
    +
    + case BFA_RPORT_SM_HWFAIL:
    + bfa_stats(rp, sm_fwd_hwf);
    + bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
    + bfa_rport_offline_cb(rp);
    + break;
    +
    + default:
    + bfa_stats(rp, sm_fwd_unexp);
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Offline state.
    + */
    +static void
    +bfa_rport_sm_offline(struct bfa_rport_s *rp, enum bfa_rport_event event)
    +{
    + bfa_trc(rp->bfa, rp->rport_tag);
    + bfa_trc(rp->bfa, event);
    +
    + switch (event) {
    + case BFA_RPORT_SM_DELETE:
    + bfa_stats(rp, sm_off_del);
    + bfa_sm_set_state(rp, bfa_rport_sm_uninit);
    + bfa_rport_free(rp);
    + break;
    +
    + case BFA_RPORT_SM_ONLINE:
    + bfa_stats(rp, sm_off_on);
    + bfa_sm_set_state(rp, bfa_rport_sm_fwcreate);
    + bfa_rport_send_fwcreate(rp);
    + break;
    +
    + case BFA_RPORT_SM_HWFAIL:
    + bfa_stats(rp, sm_off_hwf);
    + bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
    + break;
    +
    + default:
    + bfa_stats(rp, sm_off_unexp);
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Rport is deleted, waiting for firmware response to delete.
    + */
    +static void
    +bfa_rport_sm_deleting(struct bfa_rport_s *rp, enum bfa_rport_event event)
    +{
    + bfa_trc(rp->bfa, rp->rport_tag);
    + bfa_trc(rp->bfa, event);
    +
    + switch (event) {
    + case BFA_RPORT_SM_FWRSP:
    + bfa_stats(rp, sm_del_fwrsp);
    + bfa_sm_set_state(rp, bfa_rport_sm_uninit);
    + bfa_rport_free(rp);
    + break;
    +
    + case BFA_RPORT_SM_HWFAIL:
    + bfa_stats(rp, sm_del_hwf);
    + bfa_sm_set_state(rp, bfa_rport_sm_uninit);
    + bfa_rport_free(rp);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Waiting for rport create response from firmware. A delete is pending.
    + */
    +static void
    +bfa_rport_sm_delete_pending(struct bfa_rport_s *rp,
    + enum bfa_rport_event event)
    +{
    + bfa_trc(rp->bfa, rp->rport_tag);
    + bfa_trc(rp->bfa, event);
    +
    + switch (event) {
    + case BFA_RPORT_SM_FWRSP:
    + bfa_stats(rp, sm_delp_fwrsp);
    + bfa_sm_set_state(rp, bfa_rport_sm_deleting);
    + bfa_rport_send_fwdelete(rp);
    + break;
    +
    + case BFA_RPORT_SM_HWFAIL:
    + bfa_stats(rp, sm_delp_hwf);
    + bfa_sm_set_state(rp, bfa_rport_sm_uninit);
    + bfa_rport_free(rp);
    + break;
    +
    + default:
    + bfa_stats(rp, sm_delp_unexp);
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Waiting for rport create response from firmware. Rport offline is pending.
    + */
    +static void
    +bfa_rport_sm_offline_pending(struct bfa_rport_s *rp,
    + enum bfa_rport_event event)
    +{
    + bfa_trc(rp->bfa, rp->rport_tag);
    + bfa_trc(rp->bfa, event);
    +
    + switch (event) {
    + case BFA_RPORT_SM_FWRSP:
    + bfa_stats(rp, sm_offp_fwrsp);
    + bfa_sm_set_state(rp, bfa_rport_sm_fwdelete);
    + bfa_rport_send_fwdelete(rp);
    + break;
    +
    + case BFA_RPORT_SM_DELETE:
    + bfa_stats(rp, sm_offp_del);
    + bfa_sm_set_state(rp, bfa_rport_sm_delete_pending);
    + break;
    +
    + case BFA_RPORT_SM_HWFAIL:
    + bfa_stats(rp, sm_offp_hwf);
    + bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
    + break;
    +
    + default:
    + bfa_stats(rp, sm_offp_unexp);
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * IOC h/w failed.
    + */
    +static void
    +bfa_rport_sm_iocdisable(struct bfa_rport_s *rp, enum bfa_rport_event event)
    +{
    + bfa_trc(rp->bfa, rp->rport_tag);
    + bfa_trc(rp->bfa, event);
    +
    + switch (event) {
    + case BFA_RPORT_SM_OFFLINE:
    + bfa_stats(rp, sm_iocd_off);
    + bfa_rport_offline_cb(rp);
    + break;
    +
    + case BFA_RPORT_SM_DELETE:
    + bfa_stats(rp, sm_iocd_del);
    + bfa_sm_set_state(rp, bfa_rport_sm_uninit);
    + bfa_rport_free(rp);
    + break;
    +
    + case BFA_RPORT_SM_ONLINE:
    + bfa_stats(rp, sm_iocd_on);
    + bfa_sm_set_state(rp, bfa_rport_sm_fwcreate);
    + bfa_rport_send_fwcreate(rp);
    + break;
    +
    + case BFA_RPORT_SM_HWFAIL:
    + /* Do nothing */
    + break;
    +
    + default:
    + bfa_stats(rp, sm_iocd_unexp);
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * RPORT States for FCS discovery in f/w
    + */
    +
    +/**
    + * f/w discovered rport & is operational
    + */
    +static void
    +bfa_rport_sm_up(struct bfa_rport_s *rp, enum bfa_rport_event event)
    +{
    + struct bfa_itnim_s *itnim = BFA_ITNIM_FROM_TAG(BFA_FCPIM_MOD(rp->bfa),
    + rp->rport_tag);
    + bfa_boolean_t status;
    +
    + bfa_trc(rp->bfa, rp->rport_tag);
    + bfa_trc(rp->bfa, event);
    + switch (event) {
    +
    + case BFA_RPORT_SM_DOWN:
    + /*
    + * Initiator mode & RP is rpob type
    + * do IO clean up and send rsp to f/w
    + */
    + if (bfa_lport_is_initiator(rp->bfa, rp->lport_tag) &
    + (rp->type)) {
    + bfa_sm_set_state(rp, bfa_rport_sm_cleanup);
    + bfa_itnim_offline(itnim);
    + return;
    + }
    +
    + if (bfa_lport_is_target(rp->bfa, rp->lport_tag)) {
    + bfa_assert(0);
    + /* Target mode
    + bfa_itntm_offline(BFA_ITNTM_FROM_TAG(BFA_FCPTM_MOD(rp->bfa),
    + rp->rport_tag));
    + */
    + return;
    + }
    + /*
    + * rport is rpib type, so no clean up required
    + */
    + bfa_sm_set_state(rp, bfa_rport_sm_down);
    + status = bfa_rport_send_cleanup_rsp(rp);
    + bfa_assert(status == BFA_STATUS_OK);
    + break;
    +
    + case BFA_RPORT_SM_HWFAIL:
    + bfa_stats(rp, sm_cr_hwf);
    + bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
    + break;
    +
    + default:
    + bfa_assert(0);
    + break;
    + }
    +}
    +
    +/**
    + * rport is waiting for itnim clean up to finish
    + */
    +static void
    +bfa_rport_sm_cleanup(struct bfa_rport_s *rp, enum bfa_rport_event event)
    +{
    + bfa_boolean_t status;
    +
    + bfa_trc(rp->bfa, rp->rport_tag);
    + bfa_trc(rp->bfa, event);
    + switch (event) {
    +
    + case BFA_RPORT_SM_CLEANUP_DONE:
    + bfa_sm_set_state(rp, bfa_rport_sm_down);
    + status = bfa_rport_send_cleanup_rsp(rp);
    + bfa_assert(status == BFA_STATUS_OK);
    + break;
    +
    + default:
    + bfa_assert(0);
    + break;
    + }
    +
    +}
    +
    +/**
    + * rport is down - f/w is running either running rport_del timer or
    + * relogin is in progress.
    + */
    +static void
    +bfa_rport_sm_down(struct bfa_rport_s *rp, enum bfa_rport_event event)
    +{
    + bfa_trc(rp->bfa, rp->rport_tag);
    + bfa_trc(rp->bfa, event);
    +
    + switch (event) {
    +
    + case BFA_RPORT_SM_UP:
    + bfa_sm_set_state(rp, bfa_rport_sm_up);
    + break;
    +
    + case BFA_RPORT_SM_REMOVE:
    + bfa_sm_set_state(rp, bfa_rport_sm_uninit);
    + break;
    + default:
    + bfa_assert(0);
    + break;
    + }
    +}
    +
    +
    +
    +/**
    + * bfa_rport_private BFA rport private functions
    + */
    +
    +static void
    +__bfa_cb_rport_online(void *cbarg, bfa_boolean_t complete)
    +{
    + struct bfa_rport_s *rp = cbarg;
    +
    + if (complete)
    + bfa_cb_rport_online(rp->rport_drv);
    +}
    +
    +static void
    +__bfa_cb_rport_offline(void *cbarg, bfa_boolean_t complete)
    +{
    + struct bfa_rport_s *rp = cbarg;
    +
    + if (complete)
    + bfa_cb_rport_offline(rp->rport_drv);
    +}
    +
    +static void
    +bfa_rport_qresume(void *cbarg)
    +{
    + bfa_assert(0);
    +}
    +
    +static void
    +bfa_rport_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
    + u32 *dm_len)
    +{
    + if (cfg->fwcfg.num_rports < BFA_RPORT_MIN)
    + cfg->fwcfg.num_rports = BFA_RPORT_MIN;
    +
    + *km_len += cfg->fwcfg.num_rports * sizeof(struct bfa_rport_s);
    +}
    +
    +static void
    +bfa_rport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
    + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
    +{
    + struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(bfa);
    + struct bfa_rport_s *rp;
    + u16 i;
    +
    + INIT_LIST_HEAD(&mod->rp_free_q);
    + INIT_LIST_HEAD(&mod->rp_active_q);
    +
    + rp = (struct bfa_rport_s *) bfa_meminfo_kva(meminfo);
    + mod->rps_list = rp;
    + mod->num_rports = cfg->fwcfg.num_rports;
    +
    + bfa_assert(mod->num_rports
    + && !(mod->num_rports & (mod->num_rports - 1)));
    +
    + for (i = 0; i < mod->num_rports; i++, rp++) {
    + bfa_os_memset(rp, 0, sizeof(struct bfa_rport_s));
    + rp->bfa = bfa;
    + rp->rport_tag = i;
    + bfa_sm_set_state(rp, bfa_rport_sm_uninit);
    +
    + /**
    + * - is unused
    + */
    + if (i)
    + list_add_tail(&rp->qe, &mod->rp_free_q);
    +
    + bfa_reqq_winit(&rp->reqq_wait, bfa_rport_qresume, rp);
    + }
    +
    + /**
    + * consume memory
    + */
    + bfa_meminfo_kva(meminfo) = (u8 *) rp;
    +}
    +
    +static void
    +bfa_rport_initdone(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_rport_detach(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_rport_start(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_rport_stop(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_rport_iocdisable(struct bfa_s *bfa)
    +{
    + struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(bfa);
    + struct bfa_rport_s *rport;
    + struct list_head *qe, *qen;
    +
    + list_for_each_safe(qe, qen, &mod->rp_active_q) {
    + rport = (struct bfa_rport_s *) qe;
    + bfa_sm_send_event(rport, BFA_RPORT_SM_HWFAIL);
    + }
    +}
    +
    +static struct bfa_rport_s *
    +bfa_rport_alloc(struct bfa_rport_mod_s *mod)
    +{
    + struct bfa_rport_s *rport;
    +
    + bfa_q_deq(&mod->rp_free_q, &rport);
    + if (rport)
    + list_add_tail(&rport->qe, &mod->rp_active_q);
    +
    + return (rport);
    +}
    +
    +static void
    +bfa_rport_free(struct bfa_rport_s *rport)
    +{
    + struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(rport->bfa);
    +
    + bfa_assert(bfa_q_is_on_q(&mod->rp_active_q, rport));
    + list_del(&rport->qe);
    + list_add_tail(&rport->qe, &mod->rp_free_q);
    +}
    +
    +static bfa_boolean_t
    +bfa_rport_send_fwcreate(struct bfa_rport_s *rp)
    +{
    + struct bfi_rport_create_req_s *m;
    +
    + /**
    + * check for room in queue to send request now
    + */
    + m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT);
    + if (!m) {
    + bfa_reqq_wait(rp->bfa, BFA_REQQ_RPORT, &rp->reqq_wait);
    + return BFA_FALSE;
    + }
    +
    + bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_CREATE_REQ,
    + bfa_lpuid(rp->bfa));
    + m->rport_tag = rp->rport_tag;
    + m->max_frmsz = bfa_os_htons(rp->rport_info.maxfrsize);
    + m->pid = rp->rport_info.pid;
    + m->local_pid = rp->rport_info.local_pid;
    + m->fc_class = rp->rport_info.fc_class;
    + m->vf_en = rp->rport_info.vf_en;
    + m->vf_id = rp->rport_info.vf_id;
    + m->cisc = rp->rport_info.cisc;
    +
    + /**
    + * queue I/O message to firmware
    + */
    + bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT);
    + return BFA_TRUE;
    +}
    +
    +static bfa_boolean_t
    +bfa_rport_send_fwdelete(struct bfa_rport_s *rp)
    +{
    + struct bfi_rport_delete_req_s *m;
    +
    + /**
    + * check for room in queue to send request now
    + */
    + m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT);
    + if (!m) {
    + bfa_reqq_wait(rp->bfa, BFA_REQQ_RPORT, &rp->reqq_wait);
    + return BFA_FALSE;
    + }
    +
    + bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_DELETE_REQ,
    + bfa_lpuid(rp->bfa));
    + m->rport_tag = rp->rport_tag;
    +
    + /**
    + * queue I/O message to firmware
    + */
    + bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT);
    + return BFA_TRUE;
    +}
    +
    +static bfa_boolean_t
    +bfa_rport_send_fwspeed(struct bfa_rport_s *rp)
    +{
    + struct bfi_rport_speed_req_s *m;
    +
    + /**
    + * check for room in queue to send request now
    + */
    + m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT);
    + if (!m) {
    + bfa_reqq_wait(rp->bfa, BFA_REQQ_RPORT, &rp->reqq_wait);
    + return BFA_FALSE;
    + }
    +
    + bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_SET_SPEED_REQ,
    + bfa_lpuid(rp->bfa));
    + m->rport_tag = rp->rport_tag;
    + m->speed = bfa_os_htonl(rp->rport_info.rpsc_speed);
    +
    + /**
    + * queue I/O message to firmware
    + */
    + bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT);
    + return BFA_TRUE;
    +}
    +
    +static bfa_boolean_t
    +bfa_rport_send_cleanup_rsp(struct bfa_rport_s *rp)
    +{
    + struct bfi_rport_offline_rsp_s *m;
    +
    + /**
    + * check for room in queue to send request now
    + */
    + m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT);
    + if (!m) {
    + bfa_reqq_wait(rp->bfa, BFA_REQQ_RPORT, &rp->reqq_wait);
    + return BFA_FALSE;
    + }
    +
    + bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_OFFLINE_RSP,
    + bfa_lpuid(rp->bfa));
    + m->rport_tag = rp->rport_tag;
    +
    + /**
    + * queue I/O message to firmware
    + */
    + bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT);
    + return BFA_TRUE;
    +}
    +
    +/**
    + * F/w found a new rport. Register the rport with driver
    + */
    +static void
    +bfa_rport_register(struct bfa_rport_s *rp)
    +{
    + struct bfa_s *bfa = rp->bfa;
    + void *bfad = bfa->bfad;
    + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
    + struct bfad_rport_s *rport_drv;
    + struct bfad_itnim_s *itnim_drv;
    + struct bfa_itnim_s *bfa_itnim;
    +
    + /* allocate driver objects for rport & itnim in initiator mode */
    + if (bfa_lport_is_initiator(bfa, rp->lport_tag)) {
    + bfa_trc(bfa, rp->rport_info.pid);
    + bfa_trc(bfa, rp->rport_tag);
    + bfa_trc(bfa, (unsigned long) rp);
    + /*
    + * Allocate Driver's rport structure
    + */
    + if (bfa_cb_rport_alloc(bfad, rp, &rport_drv) != BFA_STATUS_OK) {
    + bfa_trc(bfa, rp->rport_info.pid);
    + return ;
    + }
    +
    + bfa_trc(bfa, rp->rport_tag);
    + bfa_trc(bfa, (unsigned long) rp);
    + bfa_itnim = BFA_ITNIM_FROM_TAG(fcpim, rp->rport_tag);
    + /*
    + * Allocate Driver's ITNIM structure in advance
    + */
    + bfa_cb_itnim_alloc(bfad, bfa_itnim, &itnim_drv);
    + if (itnim_drv == NULL) {
    + bfa_trc(bfa, rp->rport_info.pid);
    + bfa_cb_rport_free(bfad, &rport_drv);
    + return ;
    + }
    +
    + bfa_itnim->ditn = itnim_drv;
    + rp->rport_drv = rport_drv;
    +
    + /*
    + * allocate bfa itnim instance
    + */
    + bfa_trc(bfa, (unsigned long) bfa);
    + bfa_trc(bfa, rp->rport_tag);
    + bfa_itnim = bfa_itnim_create(bfa, rp, (void *)itnim_drv);
    + bfa_itnim->rport = rp;
    +
    + bfa_assert(bfa_itnim != NULL);
    + if (!bfa_itnim) {
    + bfa_trc(bfa, rp->rport_info.pid);
    + bfa_rport_delete(rp);
    + bfa_cb_rport_free(bfad, &rport_drv);
    + return ;
    + }
    +
    + } else {
    + /* target mode */
    + bfa_assert(bfa_lport_is_target(rp->bfa, rp->lport_tag));
    + bfa_assert(0);
    + }
    +}
    +
    +
    +
    +/**
    + * bfa_rport_public
    + */
    +
    +/**
    + * Rport interrupt processing.
    + */
    +void
    +bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
    +{
    + union bfi_rport_i2h_msg_u msg;
    + struct bfa_rport_s *rp;
    + struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(bfa);
    + u16 rport_tag;
    +
    + bfa_trc(bfa, m->mhdr.msg_id);
    +
    + msg.msg = m;
    +
    + switch (m->mhdr.msg_id) {
    + case BFI_RPORT_I2H_CREATE_RSP:
    + rp = BFA_RPORT_FROM_TAG(bfa, msg.create_rsp->rport_tag);
    + rp->rport_tag = msg.create_rsp->rport_tag;
    + rp->qos_attr = msg.create_rsp->qos_attr;
    + bfa_assert(msg.create_rsp->status == BFA_STATUS_OK);
    + bfa_sm_send_event(rp, BFA_RPORT_SM_FWRSP);
    + break;
    +
    + case BFI_RPORT_I2H_DELETE_RSP:
    + rp = BFA_RPORT_FROM_TAG(bfa, msg.delete_rsp->rport_tag);
    + bfa_assert(msg.delete_rsp->status == BFA_STATUS_OK);
    + bfa_sm_send_event(rp, BFA_RPORT_SM_FWRSP);
    + break;
    +
    + case BFI_RPORT_I2H_QOS_SCN:
    + rp = BFA_RPORT_FROM_TAG(bfa, msg.qos_scn_evt->rport_tag);
    + rp->event_arg.fw_msg = msg.qos_scn_evt;
    + bfa_sm_send_event(rp, BFA_RPORT_SM_QOS_SCN);
    + break;
    +
    + case BFI_RPORT_I2H_ADD:
    + rport_tag = bfa_os_ntohs(msg.add->rport_tag);
    +
    + /*
    + * Rport_tag is already assigned in f/w
    + * get the rport structure and enqueue
    + * the element to active_q
    + */
    + rp = BFA_RPORT_FROM_TAG(bfa, rport_tag);
    + rp = BFA_RPORT_FROM_TAG(bfa, rport_tag);
    +
    + /* assert that this rp is in free_q */
    + bfa_assert(bfa_q_is_on_q(&mod->rp_free_q, rp));
    + /*
    + * dequeue from free_q & enqueue to active_q
    + */
    + list_del(&rp->qe);
    + list_add_tail(&rp->qe, &mod->rp_active_q);
    +
    + /**
    + * initialize rport attributes
    + * move these to bfa_rport_init(rp, msg);
    + */
    + rp->rport_tag = rport_tag;
    + rp->type = msg.add->type;
    + rp->lport_tag = bfa_os_ntohs(msg.add->lport_tag);
    + rp->rport_info.pid = msg.add->rpid;
    + rp->rport_info.pwwn = msg.add->pwwn;
    + rp->rport_info.nwwn = msg.add->nwwn;
    + rp->rport_info.maxfrsize = bfa_os_ntohs(msg.add->max_frmsz);
    + rp->rport_info.vf_id = bfa_os_ntohs(msg.add->vf_id);
    + rp->rport_info.fc_class = msg.add->fc_class;
    + rp->rport_info.cisc = msg.add->cisc;
    + rp->rport_info.vf_en = msg.add->vf_en;
    + rp->rport_info.scsi_function = msg.add->scsi_function;
    + rp->rport_info.rpsc_speed = msg.add->rpsc_speed;
    + rp->rport_info.assigned_speed = msg.add->assigned_speed;
    +
    + bfa_trc(bfa, rp->rport_tag);
    + bfa_sm_send_event(rp, BFA_RPORT_SM_ADD);
    + break;
    +
    + case BFI_RPORT_I2H_REMOVE:
    + rport_tag = bfa_os_ntohs(msg.add->rport_tag);
    + rp = BFA_RPORT_FROM_TAG(bfa, rport_tag);
    +
    + /* assert that this rp is in active_q */
    + bfa_assert(bfa_q_is_on_q(&mod->rp_active_q, rp));
    + /*
    + * dequeue from active_q & enqueue to free_q
    + */
    + list_del(&rp->qe);
    + list_add_tail(&rp->qe, &mod->rp_free_q);
    +
    + bfa_sm_send_event(rp, BFA_RPORT_SM_REMOVE);
    + break;
    +
    + case BFI_RPORT_I2H_OFFLINE:
    + rport_tag = bfa_os_ntohs(msg.add->rport_tag);
    + rp = BFA_RPORT_FROM_TAG(bfa, rport_tag);
    + bfa_sm_send_event(rp, BFA_RPORT_SM_DOWN);
    + break;
    +
    + case BFI_RPORT_I2H_ONLINE:
    + rport_tag = bfa_os_ntohs(msg.add->rport_tag);
    + rp = BFA_RPORT_FROM_TAG(bfa, rport_tag);
    + bfa_sm_send_event(rp, BFA_RPORT_SM_UP);
    + break;
    +
    + default:
    + bfa_trc(bfa, m->mhdr.msg_id);
    + bfa_assert(0);
    + }
    +}
    +
    +
    +
    +/**
    + * bfa_rport_api
    + */
    +
    +struct bfa_rport_s *
    +bfa_rport_create(struct bfa_s *bfa, void *rport_drv)
    +{
    + struct bfa_rport_s *rp;
    +
    + rp = bfa_rport_alloc(BFA_RPORT_MOD(bfa));
    +
    + if (rp == NULL)
    + return (NULL);
    +
    + rp->bfa = bfa;
    + rp->rport_drv = rport_drv;
    + bfa_rport_clear_stats(rp);
    +
    + bfa_assert(bfa_sm_cmp_state(rp, bfa_rport_sm_uninit));
    + bfa_sm_send_event(rp, BFA_RPORT_SM_CREATE);
    +
    + return (rp);
    +}
    +
    +void
    +bfa_rport_delete(struct bfa_rport_s *rport)
    +{
    + bfa_sm_send_event(rport, BFA_RPORT_SM_DELETE);
    +}
    +
    +void
    +bfa_rport_online(struct bfa_rport_s *rport, struct bfa_rport_info_s *rport_info)
    +{
    + bfa_assert(rport_info->maxfrsize != 0);
    +
    + /**
    + * Some JBODs are seen to be not setting PDU size correctly in PLOGI
    + * responses. Default to minimum size.
    + */
    + if (rport_info->maxfrsize == 0) {
    + bfa_trc(rport->bfa, rport->rport_tag);
    + rport_info->maxfrsize = FC_MIN_PDUSZ;
    + }
    +
    + rport->rport_info = *rport_info;
    + bfa_sm_send_event(rport, BFA_RPORT_SM_ONLINE);
    +}
    +
    +void
    +bfa_rport_offline(struct bfa_rport_s *rport)
    +{
    + bfa_sm_send_event(rport, BFA_RPORT_SM_OFFLINE);
    +}
    +
    +void
    +bfa_rport_speed(struct bfa_rport_s *rport, enum bfa_pport_speed speed)
    +{
    + bfa_assert(speed != 0);
    + bfa_assert(speed != BFA_PPORT_SPEED_AUTO);
    +
    + rport->rport_info.rpsc_speed = speed;
    + bfa_sm_send_event(rport, BFA_RPORT_SM_SET_SPEED);
    +}
    +
    +void
    +bfa_rport_get_hal_stats(struct bfa_rport_s *rport,
    + struct bfa_rport_hal_stats_s *stats)
    +{
    + //*stats = rport->stats;
    + memcpy(stats, &rport->stats, sizeof(struct bfa_rport_hal_stats_s ));
    +}
    +
    +void
    +bfa_rport_get_stats(struct bfa_rport_s *rport,
    + struct bfa_rport_stats_s *stats)
    +{
    + //TODO
    +}
    +
    +void
    +bfa_rport_get_qos_attr(struct bfa_rport_s *rport,
    + struct bfa_rport_qos_attr_s *qos_attr)
    +{
    + qos_attr->qos_priority = bfa_os_ntohl(rport->qos_attr.qos_priority);
    + qos_attr->qos_flow_id = bfa_os_ntohl(rport->qos_attr.qos_flow_id);
    +
    +}
    +
    +void
    +bfa_rport_clear_stats(struct bfa_rport_s *rport)
    +{
    + bfa_os_memset(&rport->stats, 0, sizeof(rport->stats));
    +}
    +
    +void
    +bfa_rport_list_in_lport(u16 lport, char *buf)
    +{
    + /*
    + * return list of rports under the given lport
    + */
    +}
    +
    +/**
    + * Callback for itnim_cleanup from itnim module
    + */
    +void
    +bfa_rport_cleanup_cb(struct bfa_s *bfa, struct bfa_rport_s *rport)
    +{
    + bfa_trc(bfa, rport->rport_tag);
    + bfa_sm_send_event(rport, BFA_RPORT_SM_CLEANUP_DONE);
    +}
    +void
    +bfa_rport_get_attr(struct bfa_rport_s *rport, struct bfa_rport_attr_s *attr)
    +{
    +}
    +void
    +bfa_rport_set_del_timeout(u8 rport_tmo)
    +{
    +}
    +struct bfa_rport_s *
    +bfa_rport_lookup(struct bfa_lport_s *port, wwn_t rpwwn)
    +{
    + return NULL;
    +}
    +void
    +bfa_rport_set_speed(struct bfa_rport_s *rport, enum bfa_pport_speed speed)
    +{
    +}
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_rport.h patch/drivers/scsi/bfa/bfa_rport.h
    --- orig/drivers/scsi/bfa/bfa_rport.h 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_rport.h 2009-04-01 20:08:47.407986000 -0700
    @@ -0,0 +1,210 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#ifndef __RPORT_H__
    +#define __RPORT_H__
    +
    +#include <defs/bfa_defs_rport.h>
    +#include <bfa_lport.h>
    +
    +/**
    + * P R I V A T E D E F I N I T I O N S - Used & visible to BFA RPORT module alone (private)
    + */
    +
    +
    +#define BFA_RPORT_MIN 4
    +#define BFA_RPORT_DEF_DEL_TIMEOUT 90 /* in secs */
    +
    +struct bfa_rport_mod_s {
    + struct bfa_rport_s *rps_list; /* list of rports */
    + struct list_head rp_free_q; /* free bfa_rports */
    + struct list_head rp_active_q; /* free bfa_rports */
    + u16 num_rports; /* number of rports */
    +};
    +
    +/**
    + * BFA rport information.
    + */
    +struct bfa_rport_info_s {
    + u16 maxfrsize; /* max rcv pdu size */
    + u32 pid:24, /* remote port ID */
    + rsvd1:8;
    + u32 local_pid:24, /* local port ID */
    + cisc:8; /* CIRO supported */
    + wwn_t pwwn; /* port wwn of rport */
    + wwn_t nwwn; /* node wwn of rport */
    + struct bfa_rport_symname_s psym_name; /* port symbolic name */
    + enum bfa_rport_function scsi_function; /* Initiator/Target */
    + u8 fc_class; /* supported FC classes. fc_cos_t */
    + u8 vf_en; /* virtual fabric enable */
    + u16 vf_id; /* virtual fabric ID */
    + enum bfa_pport_speed rpsc_speed; /* Current Speed from RPSC.
    + * O if RPSC fails
    + */
    + enum bfa_pport_speed assigned_speed; /* speed assigned by user.
    + * Will be used if RPSC is not
    + * supported by rport
    + */
    +};
    +
    +/**
    + * BFA rport data structure
    + */
    +struct bfa_rport_s {
    + struct list_head qe; /* queue element */
    + bfa_sm_t sm; /* state machine */
    + struct bfa_s *bfa; /* backpointer to BFA */
    + void *rport_drv; /* driver rport object */
    + u16 rport_tag; /* rport tag */
    + u16 lport_tag; /* lport tag */
    + u8 type; /* rport type */
    + struct bfa_rport_info_s rport_info; /* rport info from driver */
    + struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */
    + struct bfa_cb_qe_s hcb_qe; /* BFA callback qelem */
    + struct bfa_rport_hal_stats_s stats; /* BFA rport statistics */
    + struct bfa_rport_qos_attr_s qos_attr;
    + union a {
    + bfa_status_t status; /* f/w status */
    + void *fw_msg; /* QoS scn event */
    + } event_arg;
    +};
    +
    +#define BFA_RPORT_FC_COS(_rport) ((_rport)->rport_info.fc_class)
    +
    +#define BFA_RPORT_MOD(__bfa) (&(__bfa)->modules.rport_mod)
    +
    +/**
    + * Convert rport tag to RPORT
    + */
    +#define BFA_RPORT_FROM_TAG(__bfa, _tag) \
    + (BFA_RPORT_MOD(__bfa)->rps_list + \
    + ((_tag) & (BFA_RPORT_MOD(__bfa)->num_rports - 1)))
    +
    +/*
    + * external functions
    + */
    +void bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
    +
    +
    +
    +
    +
    +/**
    + * P R O T E C T E D D E F I N I T I O N S - Shared between modules within BFA layer (protected)
    + */
    +void bfa_rport_cleanup_cb(struct bfa_s *bfa, struct bfa_rport_s *rp);
    +
    +
    +
    +/**
    + * P U B L I C D E F I N I T I O N S - Shared between BFA layer & Host Drivers (public)
    + */
    +
    +/**
    + * bfa rport API functions - exported to drivers
    + */
    +
    +
    +struct bfad_s;
    +struct bfad_rport_s;
    +
    +/*
    + * Used by Solaris
    + */
    +struct bfa_rport_s *bfa_rport_create(struct bfa_s *bfa, void *rport_drv);
    +void bfa_rport_delete(struct bfa_rport_s *rport);
    +void bfa_rport_online(struct bfa_rport_s *rport,
    + struct bfa_rport_info_s *rport_info);
    +void bfa_rport_offline(struct bfa_rport_s *rport);
    +void bfa_rport_speed(struct bfa_rport_s *rport, enum bfa_pport_speed speed);
    +void bfa_cb_rport_qos_scn_flowid(void *rport,
    + struct bfa_rport_qos_attr_s old_qos_attr,
    + struct bfa_rport_qos_attr_s new_qos_attr);
    +void bfa_cb_rport_online(void *rport);
    +void bfa_cb_rport_offline(void *rport);
    +void bfa_cb_rport_qos_scn_prio(void *rport,
    + struct bfa_rport_qos_attr_s old_qos_attr,
    + struct bfa_rport_qos_attr_s new_qos_attr);
    +void bfa_rport_get_qos_attr(struct bfa_rport_s *rport,
    + struct bfa_rport_qos_attr_s *qos_attr);
    +
    +void bfa_rport_list_in_lport(u16 lport_tag,
    + char *buf); /* list of rports under lport */
    +void bfa_rport_get_attr(struct bfa_rport_s *rport,
    + struct bfa_rport_attr_s *attr);
    +void bfa_rport_get_stats(struct bfa_rport_s *rport,
    + struct bfa_rport_stats_s *stats);
    +void bfa_rport_get_hal_stats(struct bfa_rport_s *rport,
    + struct bfa_rport_hal_stats_s *stats);
    +void bfa_rport_clear_stats(struct bfa_rport_s *rport);
    +struct bfa_rport_s *bfa_rport_lookup(struct bfa_lport_s *port, wwn_t rpwwn);
    +struct bfa_rport_s *bfa_rport_lookup_by_nwwn(struct bfa_lport_s *port,
    + wwn_t rnwwn);
    +
    +void bfa__rport_set_del_timeout(u8 rport_tmo);
    +
    +void bfa_rport_set_speed(struct bfa_rport_s *rport,
    + enum bfa_pport_speed speed);
    +void bfa_rport_set_del_timeout(u8 rport_tmo);
    +
    +/*
    + * Callback functions from BFA to driver
    + */
    +
    +/**
    + * Completion callback for bfa_rport_add().
    + *
    + * @param[in] rport_drv - driver instance of rport
    + *
    + * @return None
    + */
    +void bfa_cb_rport_add(struct bfad_rport_s *rport_drv);
    +
    +/**
    + * Completion callback for bfa_rport_remove().
    + *
    + * @param[in] rport_drv - driver instance of rport
    + *
    + * @return None
    + */
    +void bfa_cb_rport_remove(struct bfad_rport_s *rport_drv);
    +
    +/**
    + * Call to allocate a rport instance.
    + *
    + * @param[in] bfad - driver instance
    + * @param[out] rport - BFA instance of rport
    + * @param[out] rport_drv - driver instance of rport
    + *
    + * @retval BFA_STATUS_OK - successfully allocated
    + * @retval BFA_STATUS_ENOMEM - cannot allocate
    + */
    +bfa_status_t bfa_cb_rport_alloc(struct bfad_s *bfad,
    + struct bfa_rport_s *rport,
    + struct bfad_rport_s **rport_drv);
    +
    +/**
    + * Call to free rport memory resources.
    + *
    + * @param[in] bfad - driver instance
    + * @param[in] rport_drv - driver instance of rport
    + *
    + * @return None
    + */
    +void bfa_cb_rport_free(struct bfad_s *bfad, struct bfad_rport_s **rport_drv);
    +
    +#endif /* __RPORT_H__ */
    diff -urpN orig/drivers/scsi/bfa/bfa_sgpg.c patch/drivers/scsi/bfa/bfa_sgpg.c
    --- orig/drivers/scsi/bfa/bfa_sgpg.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_sgpg.c 2009-04-01 20:08:47.415968000 -0700
    @@ -0,0 +1,231 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#include <bfa.h>
    +
    +BFA_TRC_FILE(HAL, SGPG);
    +BFA_MODULE(sgpg);
    +
    +/**
    + * hal_sgpg_mod BFA SGPG Mode module
    + */
    +
    +/**
    + * Compute and return memory needed by FCP(im) module.
    + */
    +static void
    +bfa_sgpg_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
    + u32 *dm_len)
    +{
    + if (cfg->drvcfg.num_sgpgs < BFA_SGPG_MIN)
    + cfg->drvcfg.num_sgpgs = BFA_SGPG_MIN;
    +
    + *km_len += (cfg->drvcfg.num_sgpgs + 1) * sizeof(struct bfa_sgpg_s);
    + *dm_len += (cfg->drvcfg.num_sgpgs + 1) * sizeof(struct bfi_sgpg_s);
    +}
    +
    +
    +static void
    +bfa_sgpg_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
    + struct bfa_meminfo_s *minfo, struct bfa_pcidev_s *pcidev)
    +{
    + struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
    + int i;
    + struct bfa_sgpg_s *hsgpg;
    + struct bfi_sgpg_s *sgpg;
    + u64 align_len;
    +
    + union {
    + u64 pa;
    + union bfi_addr_u addr;
    + } sgpg_pa;
    +
    + INIT_LIST_HEAD(&mod->sgpg_q);
    + INIT_LIST_HEAD(&mod->sgpg_wait_q);
    +
    + bfa_trc(bfa, cfg->drvcfg.num_sgpgs);
    +
    + mod->num_sgpgs = cfg->drvcfg.num_sgpgs;
    + mod->sgpg_arr_pa = bfa_meminfo_dma_phys(minfo);
    + align_len = (BFA_SGPG_ROUNDUP(mod->sgpg_arr_pa) - mod->sgpg_arr_pa);
    + mod->sgpg_arr_pa += align_len;
    + mod->hsgpg_arr = (struct bfa_sgpg_s *) (bfa_meminfo_kva(minfo) +
    + align_len);
    + mod->sgpg_arr = (struct bfi_sgpg_s *) (bfa_meminfo_dma_virt(minfo) +
    + align_len);
    +
    + hsgpg = mod->hsgpg_arr;
    + sgpg = mod->sgpg_arr;
    + sgpg_pa.pa = mod->sgpg_arr_pa;
    + mod->free_sgpgs = mod->num_sgpgs;
    +
    + bfa_assert(!(sgpg_pa.pa & (sizeof(struct bfi_sgpg_s) - 1)));
    +
    + for (i = 0; i < mod->num_sgpgs; i++) {
    + bfa_os_memset(hsgpg, 0, sizeof(*hsgpg));
    + bfa_os_memset(sgpg, 0, sizeof(*sgpg));
    +
    + hsgpg->sgpg = sgpg;
    + hsgpg->sgpg_pa = sgpg_pa.addr;
    + list_add_tail(&hsgpg->qe, &mod->sgpg_q);
    +
    + hsgpg++;
    + sgpg++;
    + sgpg_pa.pa += sizeof(struct bfi_sgpg_s);
    + }
    +
    + bfa_meminfo_kva(minfo) = (u8 *) hsgpg;
    + bfa_meminfo_dma_virt(minfo) = (u8 *) sgpg;
    + bfa_meminfo_dma_phys(minfo) = sgpg_pa.pa;
    +}
    +
    +static void
    +bfa_sgpg_initdone(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_sgpg_detach(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_sgpg_start(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_sgpg_stop(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_sgpg_iocdisable(struct bfa_s *bfa)
    +{
    +}
    +
    +
    +
    +/**
    + * hal_sgpg_public BFA SGPG public functions
    + */
    +
    +bfa_status_t
    +bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpgs)
    +{
    + struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
    + struct bfa_sgpg_s *hsgpg;
    + int i;
    +
    + bfa_trc_fp(bfa, nsgpgs);
    +
    + if (mod->free_sgpgs < nsgpgs)
    + return BFA_STATUS_ENOMEM;
    +
    + for (i = 0; i < nsgpgs; i++) {
    + bfa_q_deq(&mod->sgpg_q, &hsgpg);
    + bfa_assert(hsgpg);
    + list_add_tail(&hsgpg->qe, sgpg_q);
    + }
    +
    + mod->free_sgpgs -= nsgpgs;
    + return BFA_STATUS_OK;
    +}
    +
    +void
    +bfa_sgpg_mfree(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpg)
    +{
    + struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
    + struct bfa_sgpg_wqe_s *wqe;
    +
    + bfa_trc_fp(bfa, nsgpg);
    +
    + mod->free_sgpgs += nsgpg;
    + bfa_assert(mod->free_sgpgs <= mod->num_sgpgs);
    +
    + list_splice_tail_init(sgpg_q, &mod->sgpg_q);
    +
    + if (list_empty(&mod->sgpg_wait_q))
    + return;
    +
    + /**
    + * satisfy as many waiting requests as possible
    + */
    + do {
    + wqe = bfa_q_first(&mod->sgpg_wait_q);
    + if (mod->free_sgpgs < wqe->nsgpg)
    + nsgpg = mod->free_sgpgs;
    + else
    + nsgpg = wqe->nsgpg;
    + bfa_sgpg_malloc(bfa, &wqe->sgpg_q, nsgpg);
    + wqe->nsgpg -= nsgpg;
    + if (wqe->nsgpg == 0) {
    + list_del(&wqe->qe);
    + wqe->cbfn(wqe->cbarg);
    + }
    + } while (mod->free_sgpgs && !list_empty(&mod->sgpg_wait_q));
    +}
    +
    +void
    +bfa_sgpg_wait(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe, int nsgpg)
    +{
    + struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
    +
    + bfa_assert(nsgpg > 0);
    + bfa_assert(nsgpg > mod->free_sgpgs);
    +
    + wqe->nsgpg_total = wqe->nsgpg = nsgpg;
    +
    + /**
    + * allocate any left to this one first
    + */
    + if (mod->free_sgpgs) {
    + /**
    + * no one else is waiting for SGPG
    + */
    + bfa_assert(list_empty(&mod->sgpg_wait_q));
    + list_splice_tail_init(&mod->sgpg_q, &wqe->sgpg_q);
    + wqe->nsgpg -= mod->free_sgpgs;
    + mod->free_sgpgs = 0;
    + }
    +
    + list_add_tail(&wqe->qe, &mod->sgpg_wait_q);
    +}
    +
    +void
    +bfa_sgpg_wcancel(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe)
    +{
    + struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
    +
    + bfa_assert(bfa_q_is_on_q(&mod->sgpg_wait_q, wqe));
    + list_del(&wqe->qe);
    +
    + if (wqe->nsgpg_total != wqe->nsgpg)
    + bfa_sgpg_mfree(bfa, &wqe->sgpg_q,
    + wqe->nsgpg_total - wqe->nsgpg);
    +}
    +
    +void
    +bfa_sgpg_winit(struct bfa_sgpg_wqe_s *wqe, void (*cbfn) (void *cbarg),
    + void *cbarg)
    +{
    + INIT_LIST_HEAD(&wqe->sgpg_q);
    + wqe->cbfn = cbfn;
    + wqe->cbarg = cbarg;
    +}
    +
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_sgpg_priv.h patch/drivers/scsi/bfa/bfa_sgpg_priv.h
    --- orig/drivers/scsi/bfa/bfa_sgpg_priv.h 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_sgpg_priv.h 2009-04-01 20:08:47.423453000 -0700
    @@ -0,0 +1,79 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +/**
    + * hal_sgpg.h BFA SG page module
    + */
    +
    +#ifndef __BFA_SGPG_PRIV_H__
    +#define __BFA_SGPG_PRIV_H__
    +
    +#include <cs/bfa_q.h>
    +
    +#define BFA_SGPG_MIN (32)
    +
    +/**
    + * Alignment macro for SG page allocation
    + */
    +#define BFA_SGPG_ROUNDUP(_l) (((_l) + (sizeof(struct bfi_sgpg_s) - 1)) \
    + & ~(sizeof(struct bfi_sgpg_s) - 1))
    +
    +struct bfa_sgpg_wqe_s {
    + struct list_head qe; /* queue sg page element */
    + int nsgpg; /* pages to be allocated */
    + int nsgpg_total; /* total pages required */
    + void (*cbfn) (void *cbarg);
    + /* callback function */
    + void *cbarg; /* callback arg */
    + struct list_head sgpg_q; /* queue of alloced sgpgs */
    +};
    +
    +struct bfa_sgpg_s {
    + struct list_head qe; /* queue sg page element */
    + struct bfi_sgpg_s *sgpg;/* va of SG page */
    + union bfi_addr_u sgpg_pa;/* pa of SG page */
    +};
    +
    +/**
    + * Given number of SG elements, BFA_SGPG_NPAGE() returns the number of
    + * SG pages required.
    + */
    +#define BFA_SGPG_NPAGE(_nsges) (((_nsges) / BFI_SGPG_DATA_SGES) + 1)
    +
    +struct bfa_sgpg_mod_s {
    + struct bfa_s *bfa;
    + int num_sgpgs; /* number of SG pages */
    + int free_sgpgs; /* number of free SG pages */
    + struct bfa_sgpg_s *hsgpg_arr; /* BFA SG page array */
    + struct bfi_sgpg_s *sgpg_arr; /* actual SG page array */
    + u64 sgpg_arr_pa; /* SG page array DMA addr */
    + struct list_head sgpg_q; /* queue of free SG pages */
    + struct list_head sgpg_wait_q; /* wait queue for SG pages */
    +};
    +#define BFA_SGPG_MOD(__bfa) (&(__bfa)->modules.sgpg_mod)
    +
    +bfa_status_t bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q,
    + int nsgpgs);
    +void bfa_sgpg_mfree(struct bfa_s *bfa, struct list_head *sgpg_q,
    + int nsgpgs);
    +void bfa_sgpg_winit(struct bfa_sgpg_wqe_s *wqe,
    + void (*cbfn) (void *cbarg), void *cbarg);
    +void bfa_sgpg_wait(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe,
    + int nsgpgs);
    +void bfa_sgpg_wcancel(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe);
    +
    +#endif /* __BFA_SGPG_PRIV_H__ */
    diff -urpN orig/drivers/scsi/bfa/bfa_sm.c patch/drivers/scsi/bfa/bfa_sm.c
    --- orig/drivers/scsi/bfa/bfa_sm.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_sm.c 2009-04-01 20:08:47.431274000 -0700
    @@ -0,0 +1,38 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +/**
    + * bfasm.c BFA State machine utility functions
    + */
    +
    +#include <cs/bfa_sm.h>
    +
    +/**
    + * cs_sm_api
    + */
    +
    +int
    +bfa_sm_to_state(struct bfa_sm_table_s *smt, bfa_sm_t sm)
    +{
    + int i = 0;
    +
    + while (smt[i].sm && smt[i].sm != sm)
    + i++;
    + return smt[i].state;
    +}
    +
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_timer.c patch/drivers/scsi/bfa/bfa_timer.c
    --- orig/drivers/scsi/bfa/bfa_timer.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_timer.c 2009-04-01 20:08:47.438816000 -0700
    @@ -0,0 +1,90 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#include <bfa_timer.h>
    +#include <cs/bfa_debug.h>
    +
    +void
    +bfa_timer_init(struct bfa_timer_mod_s *mod)
    +{
    + INIT_LIST_HEAD(&mod->timer_q);
    +}
    +
    +void
    +bfa_timer_beat(struct bfa_timer_mod_s *mod)
    +{
    + struct list_head *qh = &mod->timer_q;
    + struct list_head *qe, *qe_next;
    + struct bfa_timer_s *elem;
    + struct list_head timedout_q;
    +
    + INIT_LIST_HEAD(&timedout_q);
    +
    + qe = bfa_q_next(qh);
    +
    + while (qe != qh) {
    + qe_next = bfa_q_next(qe);
    +
    + elem = (struct bfa_timer_s *) qe;
    + if (elem->timeout <= BFA_TIMER_FREQ) {
    + elem->timeout = 0;
    + list_del(&elem->qe);
    + list_add_tail(&elem->qe, &timedout_q);
    + } else {
    + elem->timeout -= BFA_TIMER_FREQ;
    + }
    +
    + qe = qe_next; /* go to next elem */
    + }
    +
    + /*
    + * Pop all the timeout entries
    + */
    + while (!list_empty(&timedout_q)) {
    + bfa_q_deq(&timedout_q, &elem);
    + elem->timercb(elem->arg);
    + }
    +}
    +
    +/**
    + * Should be called with lock protection
    + */
    +void
    +bfa_timer_begin(struct bfa_timer_mod_s *mod, struct bfa_timer_s *timer,
    + void (*timercb) (void *), void *arg, unsigned int timeout)
    +{
    +
    + bfa_assert(timercb != NULL);
    + bfa_assert(!bfa_q_is_on_q(&mod->timer_q, timer));
    +
    + timer->timeout = timeout;
    + timer->timercb = timercb;
    + timer->arg = arg;
    +
    + list_add_tail(&timer->qe, &mod->timer_q);
    +}
    +
    +/**
    + * Should be called with lock protection
    + */
    +void
    +bfa_timer_stop(struct bfa_timer_s *timer)
    +{
    + bfa_assert(!list_empty(&timer->qe));
    +
    + list_del(&timer->qe);
    +}
    diff -urpN orig/drivers/scsi/bfa/bfa_trcmod_priv.h patch/drivers/scsi/bfa/bfa_trcmod_priv.h
    --- orig/drivers/scsi/bfa/bfa_trcmod_priv.h 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_trcmod_priv.h 2009-04-01 20:08:47.446301000 -0700
    @@ -0,0 +1,65 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +/**
    + * hal_trcmod.h BFA trace modules
    + */
    +
    +#ifndef __BFA_TRCMOD_PRIV_H__
    +#define __BFA_TRCMOD_PRIV_H__
    +
    +#include <cs/bfa_trc.h>
    +
    +/*
    + * !!! Only append to the enums defined here to avoid any versioning
    + * !!! needed between trace utility and driver version
    + */
    +enum {
    + BFA_TRC_HAL_IOC = 1,
    + BFA_TRC_HAL_INTR = 2,
    + BFA_TRC_HAL_FCXP = 3,
    + BFA_TRC_HAL_UF = 4,
    + BFA_TRC_HAL_DIAG = 5,
    + BFA_TRC_HAL_RPORT = 6,
    + BFA_TRC_HAL_FCPIM = 7,
    + BFA_TRC_HAL_IOIM = 8,
    + BFA_TRC_HAL_TSKIM = 9,
    + BFA_TRC_HAL_ITNIM = 10,
    + BFA_TRC_HAL_PPORT = 11,
    + BFA_TRC_HAL_SGPG = 12,
    + BFA_TRC_HAL_FLASH = 13,
    + BFA_TRC_HAL_DEBUG = 14,
    + BFA_TRC_HAL_WWN = 15,
    + BFA_TRC_HAL_FLASH_RAW = 16,
    + BFA_TRC_HAL_SBOOT = 17,
    + BFA_TRC_HAL_SBTEST = 18,
    + BFA_TRC_HAL_IPFC = 19,
    + BFA_TRC_HAL_IOCFC = 20,
    + BFA_TRC_HAL_FCPTM = 21,
    + BFA_TRC_HAL_IOTM = 22,
    + BFA_TRC_HAL_TSKTM = 23,
    + BFA_TRC_HAL_ITNTM = 24,
    + BFA_TRC_HAL_LPS = 25,
    + BFA_TRC_HAL_FCDIAG = 26,
    + BFA_TRC_HAL_LPORT = 27,
    + BFA_TRC_HAL_VPORT = 28,
    + BFA_TRC_HAL_VFAPI = 29,
    + BFA_TRC_HAL_AUTH = 30,
    + BFA_TRC_HAL_FABRIC = 31,
    +};
    +
    +#endif /* __BFA_TRCMOD_PRIV_H__ */
    diff -urpN orig/drivers/scsi/bfa/bfa_tskim.c patch/drivers/scsi/bfa/bfa_tskim.c
    --- orig/drivers/scsi/bfa/bfa_tskim.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_tskim.c 2009-04-01 20:08:47.454638000 -0700
    @@ -0,0 +1,690 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#include <bfa.h>
    +#include <bfa_cb_ioim_macros.h>
    +
    +BFA_TRC_FILE(HAL, TSKIM);
    +
    +/**
    + * task management completion handling
    + */
    +#define bfa_tskim_qcomp(__tskim, __cbfn) do { \
    + bfa_cb_queue((__tskim)->bfa, &(__tskim)->hcb_qe, __cbfn, \
    + (__tskim)); \
    + bfa_tskim_notify_comp(__tskim); \
    +} while (0)
    +
    +#define bfa_tskim_notify_comp(__tskim) do { \
    + if ((__tskim)->notify) \
    + bfa_itnim_tskdone((__tskim)->itnim); \
    +} while (0)
    +
    +/*
    + * forward declarations
    + */
    +static void __bfa_cb_tskim_done(void *cbarg, bfa_boolean_t complete);
    +static void __bfa_cb_tskim_failed(void *cbarg, bfa_boolean_t complete);
    +static bfa_boolean_t bfa_tskim_match_scope(struct bfa_tskim_s *tskim,
    + lun_t lun);
    +static void bfa_tskim_gather_ios(struct bfa_tskim_s *tskim);
    +static void bfa_tskim_cleanp_comp(void *tskim_cbarg);
    +static void bfa_tskim_cleanup_ios(struct bfa_tskim_s *tskim);
    +static bfa_boolean_t bfa_tskim_send(struct bfa_tskim_s *tskim);
    +static bfa_boolean_t bfa_tskim_send_abort(struct bfa_tskim_s *tskim);
    +static void bfa_tskim_iocdisable_ios(struct bfa_tskim_s *tskim);
    +
    +/**
    + * hal_tskim_sm
    + */
    +
    +enum bfa_tskim_event {
    + BFA_TSKIM_SM_START = 1, /* TM command start */
    + BFA_TSKIM_SM_DONE = 2, /* TM completion */
    + BFA_TSKIM_SM_QRESUME = 3, /* resume after qfull */
    + BFA_TSKIM_SM_HWFAIL = 5, /* IOC h/w failure event */
    + BFA_TSKIM_SM_HCB = 6, /* BFA callback completion */
    + BFA_TSKIM_SM_IOS_DONE = 7, /* IO and sub TM completions */
    + BFA_TSKIM_SM_CLEANUP = 8, /* TM cleanup on ITN offline */
    + BFA_TSKIM_SM_CLEANUP_DONE = 9, /* TM abort completion */
    +};
    +
    +static void bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim,
    + enum bfa_tskim_event event);
    +static void bfa_tskim_sm_active(struct bfa_tskim_s *tskim,
    + enum bfa_tskim_event event);
    +static void bfa_tskim_sm_cleanup(struct bfa_tskim_s *tskim,
    + enum bfa_tskim_event event);
    +static void bfa_tskim_sm_iocleanup(struct bfa_tskim_s *tskim,
    + enum bfa_tskim_event event);
    +static void bfa_tskim_sm_qfull(struct bfa_tskim_s *tskim,
    + enum bfa_tskim_event event);
    +static void bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim,
    + enum bfa_tskim_event event);
    +static void bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim,
    + enum bfa_tskim_event event);
    +
    +/**
    + * Task management command beginning state.
    + */
    +static void
    +bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
    +{
    + bfa_trc(tskim->bfa, event);
    +
    + switch (event) {
    + case BFA_TSKIM_SM_START:
    + bfa_sm_set_state(tskim, bfa_tskim_sm_active);
    + bfa_tskim_gather_ios(tskim);
    +
    + /**
    + * If device is offline, do not send TM on wire. Just cleanup
    + * any pending IO requests and complete TM request.
    + */
    + if (!bfa_itnim_is_online(tskim->itnim)) {
    + bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup);
    + tskim->tsk_status = BFI_TSKIM_STS_OK;
    + bfa_tskim_cleanup_ios(tskim);
    + return;
    + }
    +
    + if (!bfa_tskim_send(tskim)) {
    + bfa_sm_set_state(tskim, bfa_tskim_sm_qfull);
    + bfa_reqq_wait(tskim->bfa, tskim->itnim->reqq,
    + &tskim->reqq_wait);
    + }
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * brief
    + * TM command is active, awaiting completion from firmware to
    + * cleanup IO requests in TM scope.
    + */
    +static void
    +bfa_tskim_sm_active(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
    +{
    + bfa_trc(tskim->bfa, event);
    +
    + switch (event) {
    + case BFA_TSKIM_SM_DONE:
    + bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup);
    + bfa_tskim_cleanup_ios(tskim);
    + break;
    +
    + case BFA_TSKIM_SM_CLEANUP:
    + bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup);
    + if (!bfa_tskim_send_abort(tskim)) {
    + bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup_qfull);
    + bfa_reqq_wait(tskim->bfa, tskim->itnim->reqq,
    + &tskim->reqq_wait);
    + }
    + break;
    +
    + case BFA_TSKIM_SM_HWFAIL:
    + bfa_sm_set_state(tskim, bfa_tskim_sm_hcb);
    + bfa_tskim_iocdisable_ios(tskim);
    + bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * An active TM is being cleaned up since ITN is offline. Awaiting cleanup
    + * completion event from firmware.
    + */
    +static void
    +bfa_tskim_sm_cleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
    +{
    + bfa_trc(tskim->bfa, event);
    +
    + switch (event) {
    + case BFA_TSKIM_SM_DONE:
    + /**
    + * Ignore and wait for ABORT completion from firmware.
    + */
    + break;
    +
    + case BFA_TSKIM_SM_CLEANUP_DONE:
    + bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup);
    + bfa_tskim_cleanup_ios(tskim);
    + break;
    +
    + case BFA_TSKIM_SM_HWFAIL:
    + bfa_sm_set_state(tskim, bfa_tskim_sm_hcb);
    + bfa_tskim_iocdisable_ios(tskim);
    + bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +static void
    +bfa_tskim_sm_iocleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
    +{
    + bfa_trc(tskim->bfa, event);
    +
    + switch (event) {
    + case BFA_TSKIM_SM_IOS_DONE:
    + bfa_sm_set_state(tskim, bfa_tskim_sm_hcb);
    + bfa_tskim_qcomp(tskim, __bfa_cb_tskim_done);
    + break;
    +
    + case BFA_TSKIM_SM_CLEANUP:
    + /**
    + * Ignore, TM command completed on wire.
    + * Notify TM conmpletion on IO cleanup completion.
    + */
    + break;
    +
    + case BFA_TSKIM_SM_HWFAIL:
    + bfa_sm_set_state(tskim, bfa_tskim_sm_hcb);
    + bfa_tskim_iocdisable_ios(tskim);
    + bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Task management command is waiting for room in request CQ
    + */
    +static void
    +bfa_tskim_sm_qfull(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
    +{
    + bfa_trc(tskim->bfa, event);
    +
    + switch (event) {
    + case BFA_TSKIM_SM_QRESUME:
    + bfa_sm_set_state(tskim, bfa_tskim_sm_active);
    + bfa_tskim_send(tskim);
    + break;
    +
    + case BFA_TSKIM_SM_CLEANUP:
    + /**
    + * No need to send TM on wire since ITN is offline.
    + */
    + bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup);
    + bfa_reqq_wcancel(&tskim->reqq_wait);
    + bfa_tskim_cleanup_ios(tskim);
    + break;
    +
    + case BFA_TSKIM_SM_HWFAIL:
    + bfa_sm_set_state(tskim, bfa_tskim_sm_hcb);
    + bfa_reqq_wcancel(&tskim->reqq_wait);
    + bfa_tskim_iocdisable_ios(tskim);
    + bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * Task management command is active, awaiting for room in request CQ
    + * to send clean up request.
    + */
    +static void
    +bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim,
    + enum bfa_tskim_event event)
    +{
    + bfa_trc(tskim->bfa, event);
    +
    + switch (event) {
    + case BFA_TSKIM_SM_DONE:
    + bfa_reqq_wcancel(&tskim->reqq_wait);
    + /**
    + *
    + * Fall through !!!
    + */
    +
    + case BFA_TSKIM_SM_QRESUME:
    + bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup);
    + bfa_tskim_send_abort(tskim);
    + break;
    +
    + case BFA_TSKIM_SM_HWFAIL:
    + bfa_sm_set_state(tskim, bfa_tskim_sm_hcb);
    + bfa_reqq_wcancel(&tskim->reqq_wait);
    + bfa_tskim_iocdisable_ios(tskim);
    + bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed);
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +/**
    + * BFA callback is pending
    + */
    +static void
    +bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
    +{
    + bfa_trc(tskim->bfa, event);
    +
    + switch (event) {
    + case BFA_TSKIM_SM_HCB:
    + bfa_sm_set_state(tskim, bfa_tskim_sm_uninit);
    + bfa_tskim_free(tskim);
    + break;
    +
    + case BFA_TSKIM_SM_CLEANUP:
    + bfa_tskim_notify_comp(tskim);
    + break;
    +
    + case BFA_TSKIM_SM_HWFAIL:
    + break;
    +
    + default:
    + bfa_assert(0);
    + }
    +}
    +
    +
    +
    +/**
    + * hal_tskim_private
    + */
    +
    +static void
    +__bfa_cb_tskim_done(void *cbarg, bfa_boolean_t complete)
    +{
    + struct bfa_tskim_s *tskim = cbarg;
    +
    + if (!complete) {
    + bfa_sm_send_event(tskim, BFA_TSKIM_SM_HCB);
    + return;
    + }
    +
    + bfa_stats(tskim->itnim, tm_success);
    + bfa_cb_tskim_done(tskim->bfa->bfad, tskim->dtsk, tskim->tsk_status);
    +}
    +
    +static void
    +__bfa_cb_tskim_failed(void *cbarg, bfa_boolean_t complete)
    +{
    + struct bfa_tskim_s *tskim = cbarg;
    +
    + if (!complete) {
    + bfa_sm_send_event(tskim, BFA_TSKIM_SM_HCB);
    + return;
    + }
    +
    + bfa_stats(tskim->itnim, tm_failures);
    + bfa_cb_tskim_done(tskim->bfa->bfad, tskim->dtsk,
    + BFI_TSKIM_STS_FAILED);
    +}
    +
    +static bfa_boolean_t
    +bfa_tskim_match_scope(struct bfa_tskim_s *tskim, lun_t lun)
    +{
    + switch (tskim->tm_cmnd) {
    + case FCP_TM_TARGET_RESET:
    + return BFA_TRUE;
    +
    + case FCP_TM_ABORT_TASK_SET:
    + case FCP_TM_CLEAR_TASK_SET:
    + case FCP_TM_LUN_RESET:
    + case FCP_TM_CLEAR_ACA:
    + return (tskim->lun == lun);
    +
    + default:
    + bfa_assert(0);
    + }
    +
    + return BFA_FALSE;
    +}
    +
    +/**
    + * Gather affected IO requests and task management commands.
    + */
    +static void
    +bfa_tskim_gather_ios(struct bfa_tskim_s *tskim)
    +{
    + struct bfa_itnim_s *itnim = tskim->itnim;
    + struct bfa_ioim_s *ioim;
    + struct list_head *qe, *qen;
    +
    + INIT_LIST_HEAD(&tskim->io_q);
    +
    + /**
    + * Gather any active IO requests first.
    + */
    + list_for_each_safe(qe, qen, &itnim->io_q) {
    + ioim = (struct bfa_ioim_s *) qe;
    + if (bfa_tskim_match_scope
    + (tskim, bfa_cb_ioim_get_lun(ioim->dio))) {
    + list_del(&ioim->qe);
    + list_add_tail(&ioim->qe, &tskim->io_q);
    + }
    + }
    +
    + /**
    + * Failback any pending IO requests immediately.
    + */
    + list_for_each_safe(qe, qen, &itnim->pending_q) {
    + ioim = (struct bfa_ioim_s *) qe;
    + if (bfa_tskim_match_scope
    + (tskim, bfa_cb_ioim_get_lun(ioim->dio))) {
    + list_del(&ioim->qe);
    + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
    + bfa_ioim_tov(ioim);
    + }
    + }
    +}
    +
    +/**
    + * IO cleanup completion
    + */
    +static void
    +bfa_tskim_cleanp_comp(void *tskim_cbarg)
    +{
    + struct bfa_tskim_s *tskim = tskim_cbarg;
    +
    + bfa_stats(tskim->itnim, tm_io_comps);
    + bfa_sm_send_event(tskim, BFA_TSKIM_SM_IOS_DONE);
    +}
    +
    +/**
    + * Gather affected IO requests and task management commands.
    + */
    +static void
    +bfa_tskim_cleanup_ios(struct bfa_tskim_s *tskim)
    +{
    + struct bfa_ioim_s *ioim;
    + struct list_head *qe, *qen;
    +
    + bfa_wc_init(&tskim->wc, bfa_tskim_cleanp_comp, tskim);
    +
    + list_for_each_safe(qe, qen, &tskim->io_q) {
    + ioim = (struct bfa_ioim_s *) qe;
    + bfa_wc_up(&tskim->wc);
    + bfa_ioim_cleanup_tm(ioim, tskim);
    + }
    +
    + bfa_wc_wait(&tskim->wc);
    +}
    +
    +/**
    + * Send task management request to firmware.
    + */
    +static bfa_boolean_t
    +bfa_tskim_send(struct bfa_tskim_s *tskim)
    +{
    + struct bfa_itnim_s *itnim = tskim->itnim;
    + struct bfi_tskim_req_s *m;
    +
    + /**
    + * check for room in queue to send request now
    + */
    + m = bfa_reqq_next(tskim->bfa, itnim->reqq);
    + if (!m)
    + return BFA_FALSE;
    +
    + /**
    + * build i/o request message next
    + */
    + bfi_h2i_set(m->mh, BFI_MC_TSKIM, BFI_TSKIM_H2I_TM_REQ,
    + bfa_lpuid(tskim->bfa));
    +
    + m->tsk_tag = bfa_os_htons(tskim->tsk_tag);
    + m->itn_fhdl = tskim->itnim->rport->rport_tag;
    + m->t_secs = tskim->tsecs;
    + m->lun = tskim->lun;
    + m->tm_flags = tskim->tm_cmnd;
    +
    + /**
    + * queue I/O message to firmware
    + */
    + bfa_reqq_produce(tskim->bfa, itnim->reqq);
    + return BFA_TRUE;
    +}
    +
    +/**
    + * Send abort request to cleanup an active TM to firmware.
    + */
    +static bfa_boolean_t
    +bfa_tskim_send_abort(struct bfa_tskim_s *tskim)
    +{
    + struct bfa_itnim_s *itnim = tskim->itnim;
    + struct bfi_tskim_abortreq_s *m;
    +
    + /**
    + * check for room in queue to send request now
    + */
    + m = bfa_reqq_next(tskim->bfa, itnim->reqq);
    + if (!m)
    + return BFA_FALSE;
    +
    + /**
    + * build i/o request message next
    + */
    + bfi_h2i_set(m->mh, BFI_MC_TSKIM, BFI_TSKIM_H2I_ABORT_REQ,
    + bfa_lpuid(tskim->bfa));
    +
    + m->tsk_tag = bfa_os_htons(tskim->tsk_tag);
    +
    + /**
    + * queue I/O message to firmware
    + */
    + bfa_reqq_produce(tskim->bfa, itnim->reqq);
    + return BFA_TRUE;
    +}
    +
    +/**
    + * Call to resume task management cmnd waiting for room in request queue.
    + */
    +static void
    +bfa_tskim_qresume(void *cbarg)
    +{
    + struct bfa_tskim_s *tskim = cbarg;
    +
    + bfa_fcpim_stats(tskim->fcpim, qresumes);
    + bfa_stats(tskim->itnim, tm_qresumes);
    + bfa_sm_send_event(tskim, BFA_TSKIM_SM_QRESUME);
    +}
    +
    +/**
    + * Cleanup IOs associated with a task mangement command on IOC failures.
    + */
    +static void
    +bfa_tskim_iocdisable_ios(struct bfa_tskim_s *tskim)
    +{
    + struct bfa_ioim_s *ioim;
    + struct list_head *qe, *qen;
    +
    + list_for_each_safe(qe, qen, &tskim->io_q) {
    + ioim = (struct bfa_ioim_s *) qe;
    + bfa_ioim_iocdisable(ioim);
    + }
    +}
    +
    +
    +
    +/**
    + * hal_tskim_friend
    + */
    +
    +/**
    + * Notification on completions from related ioim.
    + */
    +void
    +bfa_tskim_iodone(struct bfa_tskim_s *tskim)
    +{
    + bfa_wc_down(&tskim->wc);
    +}
    +
    +/**
    + * Handle IOC h/w failure notification from itnim.
    + */
    +void
    +bfa_tskim_iocdisable(struct bfa_tskim_s *tskim)
    +{
    + tskim->notify = BFA_FALSE;
    + bfa_stats(tskim->itnim, tm_iocdowns);
    + bfa_sm_send_event(tskim, BFA_TSKIM_SM_HWFAIL);
    +}
    +
    +/**
    + * Cleanup TM command and associated IOs as part of ITNIM offline.
    + */
    +void
    +bfa_tskim_cleanup(struct bfa_tskim_s *tskim)
    +{
    + tskim->notify = BFA_TRUE;
    + bfa_stats(tskim->itnim, tm_cleanups);
    + bfa_sm_send_event(tskim, BFA_TSKIM_SM_CLEANUP);
    +}
    +
    +/**
    + * Memory allocation and initialization.
    + */
    +void
    +bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
    +{
    + struct bfa_tskim_s *tskim;
    + u16 i;
    +
    + INIT_LIST_HEAD(&fcpim->tskim_free_q);
    +
    + tskim = (struct bfa_tskim_s *) bfa_meminfo_kva(minfo);
    + fcpim->tskim_arr = tskim;
    +
    + for (i = 0; i < fcpim->num_tskim_reqs; i++, tskim++) {
    + /*
    + * initialize TSKIM
    + */
    + bfa_os_memset(tskim, 0, sizeof(struct bfa_tskim_s));
    + tskim->tsk_tag = i;
    + tskim->bfa = fcpim->bfa;
    + tskim->fcpim = fcpim;
    + tskim->notify = BFA_FALSE;
    + bfa_reqq_winit(&tskim->reqq_wait, bfa_tskim_qresume,
    + tskim);
    + bfa_sm_set_state(tskim, bfa_tskim_sm_uninit);
    +
    + list_add_tail(&tskim->qe, &fcpim->tskim_free_q);
    + }
    +
    + bfa_meminfo_kva(minfo) = (u8 *) tskim;
    +}
    +
    +void
    +bfa_tskim_detach(struct bfa_fcpim_mod_s *fcpim)
    +{
    + /**
    + * @todo
    + */
    +}
    +
    +void
    +bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
    +{
    + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
    + struct bfi_tskim_rsp_s *rsp = (struct bfi_tskim_rsp_s *) m;
    + struct bfa_tskim_s *tskim;
    + u16 tsk_tag = bfa_os_ntohs(rsp->tsk_tag);
    +
    + tskim = BFA_TSKIM_FROM_TAG(fcpim, tsk_tag);
    + bfa_assert(tskim->tsk_tag == tsk_tag);
    +
    + tskim->tsk_status = rsp->tsk_status;
    +
    + /**
    + * Firmware sends BFI_TSKIM_STS_ABORTED status for abort
    + * requests. All other statuses are for normal completions.
    + */
    + if (rsp->tsk_status == BFI_TSKIM_STS_ABORTED) {
    + bfa_stats(tskim->itnim, tm_cleanup_comps);
    + bfa_sm_send_event(tskim, BFA_TSKIM_SM_CLEANUP_DONE);
    + } else {
    + bfa_stats(tskim->itnim, tm_fw_rsps);
    + bfa_sm_send_event(tskim, BFA_TSKIM_SM_DONE);
    + }
    +}
    +
    +
    +
    +/**
    + * hal_tskim_api
    + */
    +
    +
    +struct bfa_tskim_s *
    +bfa_tskim_alloc(struct bfa_s *bfa, struct bfad_tskim_s *dtsk)
    +{
    + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
    + struct bfa_tskim_s *tskim;
    +
    + bfa_q_deq(&fcpim->tskim_free_q, &tskim);
    +
    + if (!tskim)
    + bfa_fcpim_stats(fcpim, no_tskims);
    + else
    + tskim->dtsk = dtsk;
    +
    + return tskim;
    +}
    +
    +void
    +bfa_tskim_free(struct bfa_tskim_s *tskim)
    +{
    + bfa_assert(bfa_q_is_on_q_func(&tskim->itnim->tsk_q, &tskim->qe));
    + list_del(&tskim->qe);
    + list_add_tail(&tskim->qe, &tskim->fcpim->tskim_free_q);
    +}
    +
    +/**
    + * Start a task management command.
    + *
    + * @param[in] tskim BFA task management command instance
    + * @param[in] itnim i-t nexus for the task management command
    + * @param[in] lun lun, if applicable
    + * @param[in] tm_cmnd Task management command code.
    + * @param[in] t_secs Timeout in seconds
    + *
    + * @return None.
    + */
    +void
    +bfa_tskim_start(struct bfa_tskim_s *tskim, struct bfa_itnim_s *itnim, lun_t lun,
    + enum fcp_tm_cmnd tm_cmnd, u8 tsecs)
    +{
    + tskim->itnim = itnim;
    + tskim->lun = lun;
    + tskim->tm_cmnd = tm_cmnd;
    + tskim->tsecs = tsecs;
    + tskim->notify = BFA_FALSE;
    + bfa_stats(itnim, tm_cmnds);
    +
    + list_add_tail(&tskim->qe, &itnim->tsk_q);
    + bfa_sm_send_event(tskim, BFA_TSKIM_SM_START);
    +}
    +
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_uf.c patch/drivers/scsi/bfa/bfa_uf.c
    --- orig/drivers/scsi/bfa/bfa_uf.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_uf.c 2009-04-01 20:08:47.463035000 -0700
    @@ -0,0 +1,339 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +/**
    + * bfa_uf.c BFA unsolicited frame receive implementation
    + */
    +
    +#include <bfa.h>
    +#include <bfa_svc.h>
    +#include <bfi/bfi_uf.h>
    +#include <cs/bfa_debug.h>
    +
    +BFA_TRC_FILE(HAL, UF);
    +BFA_MODULE(uf);
    +
    +/*
    + *****************************************************************************
    + * Internal functions
    + *****************************************************************************
    + */
    +static void
    +__bfa_cb_uf_recv(void *cbarg, bfa_boolean_t complete)
    +{
    + struct bfa_uf_s *uf = cbarg;
    + struct bfa_uf_mod_s *ufm = BFA_UF_MOD(uf->bfa);
    +
    + if (complete)
    + ufm->ufrecv(ufm->cbarg, uf);
    +}
    +
    +static void
    +claim_uf_pbs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi)
    +{
    + u32 uf_pb_tot_sz;
    +
    + ufm->uf_pbs_kva = (struct bfa_uf_buf_s *) bfa_meminfo_dma_virt(mi);
    + ufm->uf_pbs_pa = bfa_meminfo_dma_phys(mi);
    + uf_pb_tot_sz = BFA_ROUNDUP((sizeof(struct bfa_uf_buf_s) * ufm->num_ufs),
    + BFA_DMA_ALIGN_SZ);
    +
    + bfa_meminfo_dma_virt(mi) += uf_pb_tot_sz;
    + bfa_meminfo_dma_phys(mi) += uf_pb_tot_sz;
    +
    + bfa_os_memset((void *)ufm->uf_pbs_kva, 0, uf_pb_tot_sz);
    +}
    +
    +static void
    +claim_uf_post_msgs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi)
    +{
    + struct bfi_uf_buf_post_s *uf_bp_msg;
    + struct bfi_sge_s *sge;
    + union bfi_addr_u sga_zero = { {0} };
    + u16 i;
    + u16 buf_len;
    +
    + ufm->uf_buf_posts = (struct bfi_uf_buf_post_s *) bfa_meminfo_kva(mi);
    + uf_bp_msg = ufm->uf_buf_posts;
    +
    + for (i = 0, uf_bp_msg = ufm->uf_buf_posts; i < ufm->num_ufs;
    + i++, uf_bp_msg++) {
    + bfa_os_memset(uf_bp_msg, 0, sizeof(struct bfi_uf_buf_post_s));
    +
    + uf_bp_msg->buf_tag = i;
    + buf_len = sizeof(struct bfa_uf_buf_s);
    + uf_bp_msg->buf_len = bfa_os_htons(buf_len);
    + bfi_h2i_set(uf_bp_msg->mh, BFI_MC_UF, BFI_UF_H2I_BUF_POST,
    + bfa_lpuid(ufm->bfa));
    +
    + sge = uf_bp_msg->sge;
    + sge[0].sg_len = buf_len;
    + sge[0].flags = BFI_SGE_DATA_LAST;
    + bfa_dma_addr_set(sge[0].sga, ufm_pbs_pa(ufm, i));
    + bfa_sge_to_be(sge);
    +
    + sge[1].sg_len = buf_len;
    + sge[1].flags = BFI_SGE_PGDLEN;
    + sge[1].sga = sga_zero;
    + bfa_sge_to_be(&sge[1]);
    + }
    +
    + /**
    + * advance pointer beyond consumed memory
    + */
    + bfa_meminfo_kva(mi) = (u8 *) uf_bp_msg;
    +}
    +
    +static void
    +claim_ufs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi)
    +{
    + u16 i;
    + struct bfa_uf_s *uf;
    +
    + /*
    + * Claim block of memory for UF list
    + */
    + ufm->uf_list = (struct bfa_uf_s *) bfa_meminfo_kva(mi);
    +
    + /*
    + * Initialize UFs and queue it in UF free queue
    + */
    + for (i = 0, uf = ufm->uf_list; i < ufm->num_ufs; i++, uf++) {
    + bfa_os_memset(uf, 0, sizeof(struct bfa_uf_s));
    + uf->bfa = ufm->bfa;
    + uf->uf_tag = i;
    + uf->pb_len = sizeof(struct bfa_uf_buf_s);
    + uf->buf_kva = (void *)&ufm->uf_pbs_kva[i];
    + uf->buf_pa = ufm_pbs_pa(ufm, i);
    + list_add_tail(&uf->qe, &ufm->uf_free_q);
    + }
    +
    + /**
    + * advance memory pointer
    + */
    + bfa_meminfo_kva(mi) = (u8 *) uf;
    +}
    +
    +static void
    +uf_mem_claim(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi)
    +{
    + claim_uf_pbs(ufm, mi);
    + claim_ufs(ufm, mi);
    + claim_uf_post_msgs(ufm, mi);
    +}
    +
    +static void
    +bfa_uf_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, u32 *dm_len)
    +{
    + u32 num_ufs = cfg->fwcfg.num_uf_bufs;
    +
    + /*
    + * dma-able memory for UF posted bufs
    + */
    + *dm_len += BFA_ROUNDUP((sizeof(struct bfa_uf_buf_s) * num_ufs),
    + BFA_DMA_ALIGN_SZ);
    +
    + /*
    + * kernel Virtual memory for UFs and UF buf post msg copies
    + */
    + *ndm_len += sizeof(struct bfa_uf_s) * num_ufs;
    + *ndm_len += sizeof(struct bfi_uf_buf_post_s) * num_ufs;
    +}
    +
    +static void
    +bfa_uf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
    + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
    +{
    + struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa);
    +
    + bfa_os_memset(ufm, 0, sizeof(struct bfa_uf_mod_s));
    + ufm->bfa = bfa;
    + ufm->num_ufs = cfg->fwcfg.num_uf_bufs;
    + INIT_LIST_HEAD(&ufm->uf_free_q);
    + INIT_LIST_HEAD(&ufm->uf_posted_q);
    +
    + uf_mem_claim(ufm, meminfo);
    +}
    +
    +static void
    +bfa_uf_initdone(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_uf_detach(struct bfa_s *bfa)
    +{
    +}
    +
    +static struct bfa_uf_s *
    +bfa_uf_get(struct bfa_uf_mod_s *uf_mod)
    +{
    + struct bfa_uf_s *uf;
    +
    + bfa_q_deq(&uf_mod->uf_free_q, &uf);
    + return (uf);
    +}
    +
    +static void
    +bfa_uf_put(struct bfa_uf_mod_s *uf_mod, struct bfa_uf_s *uf)
    +{
    + list_add_tail(&uf->qe, &uf_mod->uf_free_q);
    +}
    +
    +static void
    +bfa_uf_post(struct bfa_uf_mod_s *ufm, struct bfa_uf_s *uf)
    +{
    + struct bfi_uf_buf_post_s *uf_post_msg;
    +
    + uf_post_msg = bfa_reqq_next(ufm->bfa, BFA_REQQ_FCXP);
    +
    + bfa_os_memcpy(uf_post_msg, &ufm->uf_buf_posts[uf->uf_tag],
    + sizeof(struct bfi_uf_buf_post_s));
    + bfa_reqq_produce(ufm->bfa, BFA_REQQ_FCXP);
    +
    + bfa_trc(ufm->bfa, uf->uf_tag);
    +
    + list_add_tail(&uf->qe, &ufm->uf_posted_q);
    +}
    +
    +static void
    +bfa_uf_post_all(struct bfa_uf_mod_s *uf_mod)
    +{
    + struct bfa_uf_s *uf;
    +
    + while ((uf = bfa_uf_get(uf_mod)) != NULL)
    + bfa_uf_post(uf_mod, uf);
    +}
    +
    +static void
    +uf_recv(struct bfa_s *bfa, struct bfi_uf_frm_rcvd_s *m)
    +{
    + struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa);
    + u16 uf_tag = m->buf_tag;
    + struct bfa_uf_buf_s *uf_buf = &ufm->uf_pbs_kva[uf_tag];
    + struct bfa_uf_s *uf = &ufm->uf_list[uf_tag];
    + u8 *buf = &uf_buf->d[0];
    + struct fchs_s *fchs;
    +
    + m->frm_len = bfa_os_ntohs(m->frm_len);
    + m->xfr_len = bfa_os_ntohs(m->xfr_len);
    +
    + fchs = (struct fchs_s *) uf_buf;
    +
    + list_del(&uf->qe); /* dequeue from posted queue */
    +
    + uf->data_ptr = buf;
    + uf->data_len = m->xfr_len;
    +
    + bfa_assert(uf->data_len >= sizeof(struct fchs_s));
    +
    + if (uf->data_len == sizeof(struct fchs_s)) {
    + bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_UF, BFA_PL_EID_RX,
    + uf->data_len, (struct fchs_s *) buf);
    + } else {
    + u32 pld_w0 = *((u32 *) (buf + sizeof(struct fchs_s)));
    + bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_UF,
    + BFA_PL_EID_RX, uf->data_len,
    + (struct fchs_s *) buf, pld_w0);
    + }
    +
    + bfa_cb_queue(bfa, &uf->hcb_qe, __bfa_cb_uf_recv, uf);
    +}
    +
    +static void
    +bfa_uf_stop(struct bfa_s *bfa)
    +{
    +}
    +
    +static void
    +bfa_uf_iocdisable(struct bfa_s *bfa)
    +{
    + struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa);
    + struct bfa_uf_s *uf;
    + struct list_head *qe, *qen;
    +
    + list_for_each_safe(qe, qen, &ufm->uf_posted_q) {
    + uf = (struct bfa_uf_s *) qe;
    + list_del(&uf->qe);
    + bfa_uf_put(ufm, uf);
    + }
    +}
    +
    +static void
    +bfa_uf_start(struct bfa_s *bfa)
    +{
    + bfa_uf_post_all(BFA_UF_MOD(bfa));
    +}
    +
    +
    +
    +/**
    + * hal_uf_api
    + */
    +
    +/**
    + * Register handler for all unsolicted recieve frames.
    + *
    + * @param[in] bfa BFA instance
    + * @param[in] ufrecv receive handler function
    + * @param[in] cbarg receive handler arg
    + */
    +void
    +bfa_uf_recv_register(struct bfa_s *bfa, bfa_cb_uf_recv_t ufrecv, void *cbarg)
    +{
    + struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa);
    +
    + ufm->ufrecv = ufrecv;
    + ufm->cbarg = cbarg;
    +}
    +
    +/**
    + * Free an unsolicited frame back to BFA.
    + *
    + * @param[in] uf unsolicited frame to be freed
    + *
    + * @return None
    + */
    +void
    +bfa_uf_free(struct bfa_uf_s *uf)
    +{
    + bfa_uf_post(BFA_UF_MOD(uf->bfa), uf);
    +}
    +
    +
    +
    +/**
    + * uf_pub BFA uf module public functions
    + */
    +
    +void
    +bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
    +{
    + bfa_trc(bfa, msg->mhdr.msg_id);
    +
    + switch (msg->mhdr.msg_id) {
    + case BFI_UF_I2H_FRM_RCVD:
    + uf_recv(bfa, (struct bfi_uf_frm_rcvd_s *) msg);
    + break;
    +
    + default:
    + bfa_trc(bfa, msg->mhdr.msg_id);
    + bfa_assert(0);
    + }
    +}
    +
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_uf_priv.h patch/drivers/scsi/bfa/bfa_uf_priv.h
    --- orig/drivers/scsi/bfa/bfa_uf_priv.h 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_uf_priv.h 2009-04-01 20:08:47.470439000 -0700
    @@ -0,0 +1,47 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +#ifndef __BFA_UF_PRIV_H__
    +#define __BFA_UF_PRIV_H__
    +
    +#include <cs/bfa_sm.h>
    +#include <bfa_svc.h>
    +#include <bfi/bfi_uf.h>
    +
    +#define BFA_UF_MIN (4)
    +
    +struct bfa_uf_mod_s {
    + struct bfa_s *bfa; /* back pointer to BFA */
    + struct bfa_uf_s *uf_list; /* array of UFs */
    + u16 num_ufs; /* num unsolicited rx frames */
    + struct list_head uf_free_q; /* free UFs */
    + struct list_head uf_posted_q; /* UFs posted to IOC */
    + struct bfa_uf_buf_s *uf_pbs_kva; /* list UF bufs request pld */
    + u64 uf_pbs_pa; /* phy addr for UF bufs */
    + struct bfi_uf_buf_post_s *uf_buf_posts;
    + /* pre-built UF post msgs */
    + bfa_cb_uf_recv_t ufrecv; /* uf recv handler function */
    + void *cbarg; /* uf receive handler arg */
    +};
    +
    +#define BFA_UF_MOD(__bfa) (&(__bfa)->modules.uf_mod)
    +
    +#define ufm_pbs_pa(_ufmod, _uftag) \
    + ((_ufmod)->uf_pbs_pa + sizeof(struct bfa_uf_buf_s) * (_uftag))
    +
    +void bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
    +
    +#endif /* __BFA_UF_PRIV_H__ */
    diff -urpN orig/drivers/scsi/bfa/bfa_vfapi.c patch/drivers/scsi/bfa/bfa_vfapi.c
    --- orig/drivers/scsi/bfa/bfa_vfapi.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_vfapi.c 2009-04-01 20:08:47.478520000 -0700
    @@ -0,0 +1,319 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +/**
    + * vfapi.c Fabric module implementation.
    + */
    +
    +#include <bfa.h>
    +#include <bfa_fabric.h>
    +#include <bfi/bfi_fabric.h>
    +
    +BFA_TRC_FILE(HAL, VFAPI);
    +
    +/**
    + * vf_api virtual fabrics API
    + */
    +
    +/**
    + * Enable VF mode.
    + *
    + * @param[in] bfa bfa module instance
    + * @param[in] vf_id default vf_id of port, FC_VF_ID_NULL
    + * to use standard default vf_id of 1.
    + *
    + * @retval BFA_STATUS_OK vf mode is enabled
    + * @retval BFA_STATUS_BUSY Port is active. Port must be disabled
    + * before VF mode can be enabled.
    + */
    +bfa_status_t
    +bfa_vf_mode_enable(struct bfa_s *bfa, u16 vf_id)
    +{
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * Disable VF mode.
    + *
    + * @param[in] bfa bfa module instance
    + *
    + * @retval BFA_STATUS_OK vf mode is disabled
    + * @retval BFA_STATUS_BUSY VFs are present and being used. All
    + * VFs must be deleted before disabling
    + * VF mode.
    + */
    +bfa_status_t
    +bfa_vf_mode_disable(struct bfa_s *bfa)
    +{
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * Create a new VF instance.
    + *
    + * A new VF is created using the given VF configuration. A VF is identified
    + * by VF id. No duplicate VF creation is allowed with the same VF id. Once
    + * a VF is created, VF is automatically started after link initialization
    + * and EVFP exchange is completed.
    + *
    + * param[in] vf - bfa vf data structure. Memory is
    + * allocated by caller (driver)
    + * param[in] bfa - bfa module
    + * param[in] vf_cfg - VF configuration
    + * param[in] vf_drv - Opaque handle back to the driver's
    + * virtual vf structure
    + *
    + * retval BFA_STATUS_OK VF creation is successful
    + * retval BFA_STATUS_FAILED VF creation failed
    + * retval BFA_STATUS_EEXIST A VF exists with the given vf_id
    + */
    +bfa_status_t
    +bfa_vf_create(struct bfa_fabric_s *vf, struct bfa_s *bfa, u16 vf_id,
    + struct bfa_port_cfg_s *port_cfg, struct bfad_vf_s *vf_drv)
    +{
    + bfa_trc(bfa, vf_id);
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * Use this function to delete a HAL VF object. VF object should
    + * be stopped before this function call.
    + *
    + * param[in] vf - pointer to struct bfa_fabric_s.
    + *
    + * retval BFA_STATUS_OK On vf deletion success
    + * retval BFA_STATUS_BUSY VF is not in a stopped state
    + * retval BFA_STATUS_INPROGRESS VF deletion in in progress
    + */
    +bfa_status_t
    +bfa_vf_delete(struct bfa_fabric_s *vf)
    +{
    + bfa_trc(vf->bfa, vf->vf_id);
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * Start participation in VF. This triggers login to the virtual fabric.
    + *
    + * param[in] vf - pointer to struct bfa_fabric_s.
    + *
    + * return None
    + */
    +void
    +bfa_vf_start(struct bfa_fabric_s *vf)
    +{
    + struct bfi_fabric_start_req_s req;
    +
    + bfa_trc(vf->bfa, vf->vf_id);
    + req.mh.msg_id = BFI_FABRIC_H2I_START_REQ;
    + req.vf_id = vf->vf_id;
    + bfi_h2i_set(req.mh, BFI_MC_FABRIC, BFI_FABRIC_H2I_START_REQ,
    + bfa_lpuid(vf->bfa));
    + /**
    + * queue I/O message to firmware
    + */
    + bfa_reqq_produce(vf->bfa, vf->reqq);
    +
    +}
    +
    +/**
    + * Logout with the virtual fabric.
    + *
    + * param[in] vf - pointer to struct bfa_fabric_s.
    + *
    + * retval BFA_STATUS_OK On success.
    + * retval BFA_STATUS_INPROGRESS VF is being stopped.
    + */
    +bfa_status_t
    +bfa_vf_stop(struct bfa_fabric_s *vf)
    +{
    + struct bfi_fabric_stop_req_s req;
    + bfa_trc(vf->bfa, vf->vf_id);
    + req.mh.msg_id = BFI_FABRIC_H2I_STOP_REQ;
    + bfi_h2i_set(req.mh, BFI_MC_FABRIC, BFI_FABRIC_H2I_STOP_REQ,
    + bfa_lpuid(vf->bfa));
    + /**
    + * queue I/O message to firmware
    + */
    + bfa_reqq_produce(vf->bfa, vf->reqq);
    +
    + //bfa_cb_vf_stop(vf_drv);
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * Returns attributes of the given VF.
    + *
    + * param[in] vf pointer to struct bfa_fabric_s.
    + * param[out] vf_attr vf attributes returned
    + *
    + * return None
    + */
    +void
    +bfa_vf_get_attr(struct bfa_fabric_s *vf, struct bfa_vf_attr_s *vf_attr)
    +{
    + bfa_trc(vf->bfa, vf->vf_id);
    +}
    +
    +/**
    + * Return statistics associated with the given vf.
    + *
    + * param[in] vf pointer to struct bfa_fabric_s.
    + * param[out] vf_stats vf statistics returned
    + *
    + * @return None
    + */
    +void
    +bfa_vf_get_stats(struct bfa_fabric_s *vf, struct bfa_vf_stats_s *vf_stats)
    +{
    + bfa_os_memcpy(vf_stats, &vf->stats, sizeof(struct bfa_vf_stats_s));
    + return;
    +}
    +
    +void
    +/**
    + * clear statistics associated with the given vf.
    + *
    + * param[in] vf pointer to struct bfa_fabric_s.
    + *
    + * @return None
    + */
    +bfa_vf_clear_stats(struct bfa_fabric_s *vf)
    +{
    + bfa_os_memset(&vf->stats, 0, sizeof(struct bfa_vf_stats_s));
    + return;
    +}
    +
    +/**
    + * Returns bfa vf structure for a given vf_id.
    + *
    + * param[in] vf_id - VF_ID
    + *
    + * return
    + * If lookup succeeds, retuns bfa vf object, otherwise returns NULL
    + */
    +struct bfa_fabric_s *
    +bfa_vf_lookup(struct bfa_s *bfa, u16 vf_id)
    +{
    + struct bfa_fabric_s *vf;
    + struct list_head *qe;
    +
    + bfa_trc(bfa, vf_id);
    + if (vf_id == FC_VF_ID_NULL)
    + return (&bfa->fabric);
    +
    + list_for_each(qe, &bfa->fabric.vf_q) {
    + vf = (struct bfa_fabric_s *) qe;
    + if (vf->vf_id == vf_id)
    + return vf;
    + }
    +
    + return NULL;
    +}
    +
    +/**
    + * Returns driver VF structure for a given bfa vf.
    + *
    + * param[in] vf - pointer to struct bfa_fabric_s
    + *
    + * return Driver VF structure
    + */
    +struct bfad_vf_s *
    +bfa_vf_get_drv_vf(struct bfa_fabric_s *vf)
    +{
    + bfa_assert(vf);
    + bfa_trc(vf->bfa, vf->vf_id);
    + return vf->vf_drv;
    +}
    +
    +/**
    + * Return the list of VFs configured.
    + *
    + * param[in] bfa bfa module instance
    + * param[out] vf_ids returned list of vf_ids
    + * param[in,out] nvfs in:size of vf_ids array,
    + * out:total elements present,
    + * actual elements returned is limited by the size
    + *
    + * return Driver VF structure
    + */
    +void
    +bfa_vf_list(struct bfa_s *bfa, u16 *vf_ids, int *nvfs)
    +{
    + bfa_trc(bfa, *nvfs);
    +}
    +
    +/**
    + * Return the list of all VFs visible from fabric.
    + *
    + * param[in] bfa bfa module instance
    + * param[out] vf_ids returned list of vf_ids
    + * param[in,out] nvfs in:size of vf_ids array,
    + * out:total elements present,
    + * actual elements returned is limited by the size
    + *
    + * return Driver VF structure
    + */
    +void
    +bfa_vf_list_all(struct bfa_s *bfa, u16 *vf_ids, int *nvfs)
    +{
    + bfa_trc(bfa, *nvfs);
    +}
    +
    +/**
    + * Return the list of local logical ports present in the given VF.
    + *
    + * param[in] vf vf for which logical ports are returned
    + * param[out] lpwwn returned logical port wwn list
    + * param[in,out] nlports in:size of lpwwn list;
    + * out:total elements present,
    + * actual elements returned is limited by the size
    + *
    + */
    +void
    +bfa_vf_get_ports(struct bfa_fabric_s *vf, wwn_t lpwwn[], int *nlports)
    +{
    + struct list_head *qe;
    + struct bfa_vport_s *vport;
    + int i;
    + struct bfa_s *bfa;
    +
    + if (vf == NULL || lpwwn == NULL || *nlports == 0)
    + return;
    +
    + bfa = vf->bfa;
    +
    + bfa_trc(bfa, vf->vf_id);
    + bfa_trc(bfa, (u32) *nlports);
    +
    + i = 0;
    + lpwwn[i++] = vf->bport.port_cfg.pwwn;
    +
    + list_for_each(qe, &vf->vport_q) {
    + if (i >= *nlports)
    + break;
    +
    + vport = (struct bfa_vport_s *) qe;
    + lpwwn[i++] = vport->lport.port_cfg.pwwn;
    + }
    +
    + bfa_trc(bfa, i);
    + *nlports = i;
    + return;
    +}
    +
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_vport.c patch/drivers/scsi/bfa/bfa_vport.c
    --- orig/drivers/scsi/bfa/bfa_vport.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_vport.c 2009-04-01 20:08:47.486300000 -0700
    @@ -0,0 +1,327 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +/**
    + * bfa_vport.c Virtual port state machine
    + */
    +
    +#include <bfa.h>
    +#include <bfa_svc.h>
    +#include <bfa_lport.h>
    +#include <bfa_vport.h>
    +#include <bfa_fabric.h>
    +#include <bfi/bfi_vport.h>
    +#include <aen/bfa_aen_lport.h>
    +
    +BFA_TRC_FILE(HAL, VPORT);
    +
    +/*
    + * forward declarations
    + */
    +static bfa_boolean_t bfa_vport_send_fwcreate(struct bfa_vport_s *vport);
    +static bfa_boolean_t bfa_vport_send_fwdelete(struct bfa_vport_s *vport);
    +static void bfa_vport_delete_comp(struct bfa_vport_s *vport);
    +
    +/**
    + * bfa_vport_priv Virtual port private functions
    + */
    +
    +void
    +bfa_vport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
    +{
    + union bfi_vport_i2h_msg_u event;
    + struct bfa_vport_s *vport;
    +
    + event.msg = msg;
    + switch (event.msg->mhdr.msg_id) {
    + case BFI_VPORT_I2H_DELETE_RSP:
    + vport = BFA_VPORT_FROM_TAG(bfa,
    + bfa_os_htons(event.delete_rsp->vport_tag));
    + bfa_assert(event.delete_rsp->status == BFA_STATUS_OK);
    + bfa_vport_delete_comp(vport);
    + break;
    + }
    +}
    +
    +static bfa_boolean_t
    +bfa_vport_send_fwcreate(struct bfa_vport_s *vport)
    +{
    + struct bfa_lport_s *lport = &vport->lport;
    + struct bfa_s *bfa = lport->bfa;
    + struct bfi_vport_create_req_s *m;
    +
    + /**
    + * check for room in queue to send request now
    + */
    + m = bfa_reqq_next(bfa, BFA_REQQ_VPORT);
    + if (!m) {
    + /* TODO
    + bfa_reqq_wait(vport->fabric->bfa, BFA_REQQ_VPORT,
    + &vport->reqq_wait);
    + */
    + return BFA_FALSE;
    + }
    +
    + bfi_h2i_set(m->mh, BFI_MC_VPORT, BFI_VPORT_H2I_CREATE_REQ,
    + bfa_lpuid(bfa));
    + bfa_lport_msg_init(&vport->lport, m);
    + bfa_trc(bfa, m->vport_tag);
    + /**
    + * queue message to firmware
    + */
    + bfa_reqq_produce(bfa, BFA_REQQ_VPORT);
    +
    + return BFA_TRUE;
    +}
    +
    +static bfa_boolean_t
    +bfa_vport_send_fwdelete(struct bfa_vport_s *vport)
    +{
    + struct bfa_lport_s *lport = &vport->lport;
    + struct bfa_s *bfa = lport->bfa;
    + struct bfi_vport_delete_req_s *m;
    +
    + /**
    + * check for room in queue to send request now
    + */
    + m = bfa_reqq_next(bfa, BFA_REQQ_VPORT);
    + if (!m) {
    + // bfa_reqq_wait(vport->fabric->bfa,
    + // vport->reqq, &vport->reqq_wait);
    + return BFA_FALSE;
    + }
    +
    + bfi_h2i_set(m->mh, BFI_MC_VPORT, BFI_VPORT_H2I_DELETE_REQ,
    + bfa_lpuid(bfa));
    +
    + m->fabric_tag = bfa_os_htons(lport->fabric_tag);
    + m->vport_tag = bfa_os_htons(lport->lp_tag->lport_tag);
    + bfa_trc(bfa, m->vport_tag);
    +
    + /**
    + * queue message to firmware
    + */
    + bfa_reqq_produce(bfa, BFA_REQQ_VPORT);
    +
    + return BFA_TRUE;
    +}
    +
    +static void
    +bfa_vport_delete_comp(struct bfa_vport_s *vport)
    +{
    + struct bfa_lport_s *lport = &vport->lport;
    +
    + bfa_trc(lport->bfa, lport->lp_tag->lport_tag);
    + bfa_lport_lptag_free(BFA_LPTAG_FROM_LPORT(lport));
    + bfa_fabric_del_vport(lport->fabric, vport);
    + bfa_cb_vport_delete(vport->vport_drv);
    + bfa_trc(lport->bfa, lport->lp_tag->lport_tag);
    +}
    +
    +
    +
    +/**
    + * bfa_vport_api Virtual port API
    + */
    +
    +/**
    + * Use this function to instantiate a new BFA vport object. This
    + * function will not trigger any HW initialization process (which will be
    + * done in vport_start() call)
    + *
    + * param[in] vport - pointer to bfa_vport_t. This space
    + * needs to be allocated by the driver.
    + * param[in] bfa - BFA instance
    + * param[in] vport_cfg - vport configuration
    + * param[in] vf_id - VF_ID if vport is created within a VF.
    + * FC_VF_ID_NULL to specify base fabric.
    + * param[in] vport_drv - Opaque handle back to the driver's vport
    + * structure
    + *
    + * retval BFA_STATUS_OK - on success.
    + * retval BFA_STATUS_FAILED - on failure.
    + */
    +bfa_status_t
    +bfa_vport_create(struct bfa_vport_s *vport, struct bfa_s *bfa,
    + u16 vf_id, struct bfa_port_cfg_s *vport_cfg,
    + struct bfad_vport_s *vport_drv)
    +{
    + struct bfa_lptag_s *lptag;
    + struct bfa_fabric_s *fabric;
    +
    + if (vport_cfg->pwwn == 0)
    + return (BFA_STATUS_INVALID_WWN);
    +
    + fabric = bfa_vf_lookup(bfa, vf_id);
    +
    + if (bfa_lport_get_pwwn(bfa_fabric_get_bport(fabric)) == vport_cfg->pwwn)
    + return BFA_STATUS_VPORT_WWN_BP;
    +
    + if (bfa_fabric_vport_lookup(fabric, vport_cfg->pwwn) != NULL)
    + return BFA_STATUS_VPORT_EXISTS;
    +
    + if (bfa_fabric_vport_count(fabric) == (BFA_LPORT_MAX-1))
    + return BFA_STATUS_VPORT_MAX;
    +
    + lptag = bfa_lport_tag_alloc(BFA_LPORT_MOD(bfa));
    + if (lptag == NULL)
    + return BFA_STATUS_VPORT_MAX;
    +
    + vport->vport_drv = vport_drv;
    +
    + bfa_lport_init(&vport->lport, bfa, vf_id, lptag, vport_cfg, vport);
    + bfa_trc(bfa, vport->lport.lp_tag->lport_tag);
    + bfa_fabric_add_vport(fabric, vport);
    +
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * Use this function initialize the vport.
    + *
    + * @param[in] vport - pointer to bfa_vport_t.
    + *
    + * @returns None
    + */
    +bfa_status_t
    +bfa_vport_start(struct bfa_vport_s *vport)
    +{
    + bfa_trc(vport->lport.bfa, vport->lport.lp_tag->lport_tag);
    + bfa_vport_send_fwcreate(vport);
    +
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * Use this function quiese the vport object. This function will return
    + * immediately, when the vport is actually stopped, the
    + * bfa_drv_vport_stop_cb() will be called.
    + *
    + * param[in] vport - pointer to bfa_vport_t.
    + *
    + * return None
    + */
    +bfa_status_t
    +bfa_vport_stop(struct bfa_vport_s *vport)
    +{
    + /* Send message to FW to stop vport */
    +
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * Use this function to delete a vport object. Fabric object should
    + * be stopped before this function call.
    + *
    + * param[in] vport - pointer to bfa_vport_t.
    + *
    + * return None
    + */
    +bfa_status_t
    +bfa_vport_delete(struct bfa_vport_s *vport)
    +{
    + bfa_trc(vport->lport.bfa, vport->lport.lp_tag->lport_tag);
    + bfa_vport_send_fwdelete(vport);
    +
    + return BFA_STATUS_OK;
    +}
    +
    +/**
    + * Use this function to get vport's current status info.
    + *
    + * param[in] vport pointer to bfa_vport_t.
    + * param[out] attr pointer to return vport attributes
    + *
    + * return None
    + */
    +void
    +bfa_vport_get_attr(struct bfa_vport_s *vport, struct bfa_vport_attr_s *attr)
    +{
    + struct bfa_fabric_s *fabric = NULL;
    + struct bfa_port_attr_s *port_attr = NULL;
    + if (vport == NULL || attr == NULL)
    + return;
    +
    + fabric = bfa_vf_lookup(vport->lport.bfa, vport->lport.fabric_tag);
    + bfa_os_memset(attr, 0, sizeof(struct bfa_vport_attr_s));
    +
    + port_attr = &attr->port_attr;
    + port_attr->pid = vport->lport.pid;
    + port_attr->port_type = bfa_fabric_port_type(fabric);
    + port_attr->fabric_name = bfa_lport_get_fabric_name(&vport->lport);
    + port_attr->loopback = bfa_fabric_is_loopback(fabric);
    + port_attr->port_cfg.pwwn = vport->lport.port_cfg.pwwn;
    + port_attr->port_cfg.nwwn = vport->lport.port_cfg.nwwn;
    + port_attr->port_cfg.roles = vport->lport.port_cfg.roles;
    + //port_attr->fabric_ip_addr
    + //port_attr->state = BFA_PORT_ONLINE; TODO
    + memcpy(&port_attr->port_cfg.sym_name, &vport->lport.port_cfg.sym_name,
    + sizeof(struct bfa_port_symname_s));
    +
    + attr->vport_state = BFA_FCS_VPORT_ONLINE;//TODO
    +}
    +
    +/**
    + * Use this function to get vport's statistics.
    + *
    + * param[in] vport pointer to bfa_vport_t.
    + * param[out] stats pointer to return vport statistics in
    + *
    + * return None
    + */
    +void
    +bfa_vport_get_stats(struct bfa_vport_s *vport,
    + struct bfa_vport_stats_s *stats)
    +{
    + //*stats = vport->vport_stats;
    + /* Send message to FW to get stats */
    +}
    +
    +/**
    + * Use this function to clear vport's statistics.
    + *
    + * param[in] vport pointer to bfa_vport_t.
    + *
    + * return None
    + */
    +void
    +bfa_vport_clr_stats(struct bfa_vport_s *vport)
    +{
    + /* Send message to FW to clear stats */
    +}
    +
    +struct bfa_vport_s *
    +bfa_vport_lookup(struct bfa_s *bfa, u16 vf_id, wwn_t vpwwn)
    +{
    + struct bfa_vport_s *vport;
    + struct bfa_fabric_s *fabric;
    +
    + bfa_trc(bfa, vf_id);
    + bfa_trc(bfa, vpwwn);
    +
    + fabric = bfa_vf_lookup(bfa, vf_id);
    + if (!fabric) {
    + bfa_trc(bfa, vf_id);
    + return NULL;
    + }
    +
    + vport = bfa_fabric_vport_lookup(fabric, vpwwn);
    + return (vport);
    +}
    +
    +
    +
    diff -urpN orig/drivers/scsi/bfa/bfa_vport.h patch/drivers/scsi/bfa/bfa_vport.h
    --- orig/drivers/scsi/bfa/bfa_vport.h 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/bfa_vport.h 2009-04-01 20:08:47.493511000 -0700
    @@ -0,0 +1,86 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +/**
    + * bfa_fcs_vport.h BFA fcs vport module public interface
    + */
    +
    +#ifndef __BFA_VPORT_H__
    +#define __BFA_VPORT_H__
    +
    +#include <defs/bfa_defs_status.h>
    +#include <defs/bfa_defs_port.h>
    +#include <defs/bfa_defs_vport.h>
    +#include <cs/bfa_q.h>
    +#include <bfa_lport.h>
    +
    +/**
    + * P R I V A T E D E F I N I T I O N S
    + * - Used & visible to BFA RPORT module alone (private)
    + */
    +struct bfa_vport_mod_s {
    +
    +};
    +
    +#define BFA_VPORT_FROM_TAG(__bfa, _tag) \
    + ((struct bfa_lport_s *)BFA_LPORT_FROM_TAG(__bfa, _tag))->vport
    +
    +/**
    + * P R O T E C T E D D E F I N I T I O N S
    + * - Shared between modules within BFA layer (protected)
    + */
    +void bfa_vport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
    +
    +#define bfa_vport_get_vpdrv(vport) vport->vport_drv
    +
    +/**
    + * P U B L I C D E F I N I T I O N S
    + * - Shared between BFA layer & Host Drivers (public)
    + */
    +
    +struct bfa_vport_s {
    + struct list_head qe; /* queue elem */
    + struct bfa_lport_s lport; /* logical port */
    + u8 reqq; /* CQ for requests */
    + struct bfad_vport_s *vport_drv; /* Driver private */
    +};
    +
    +bfa_status_t bfa_vport_create(struct bfa_vport_s *vport,
    + struct bfa_s *bfa, u16 vf_id,
    + struct bfa_port_cfg_s *port_cfg,
    + struct bfad_vport_s *vport_drv);
    +bfa_status_t bfa_vport_delete(struct bfa_vport_s *vport);
    +bfa_status_t bfa_vport_start(struct bfa_vport_s *vport);
    +bfa_status_t bfa_vport_stop(struct bfa_vport_s *vport);
    +void bfa_vport_get_attr(struct bfa_vport_s *vport,
    + struct bfa_vport_attr_s *vport_attr);
    +void bfa_vport_get_stats(struct bfa_vport_s *vport,
    + struct bfa_vport_stats_s *vport_stats);
    +void bfa_vport_clr_stats(struct bfa_vport_s *vport);
    +struct bfa_vport_s *bfa_vport_lookup(struct bfa_s *bfa,
    + u16 vf_id, wwn_t vpwwn);
    +
    +/**
    + * Completion callback for bfa_vport_delete().
    + *
    + * @param[in] vport_drv - driver instance of vport
    + *
    + * @return None
    + */
    +void bfa_cb_vport_delete(struct bfad_vport_s *vport_drv);
    +
    +#endif /* __BFA_VPORT_H__ */
    diff -urpN orig/drivers/scsi/bfa/plog.c patch/drivers/scsi/bfa/plog.c
    --- orig/drivers/scsi/bfa/plog.c 1969-12-31 16:00:00.000000000 -0800
    +++ patch/drivers/scsi/bfa/plog.c 2009-04-01 20:08:47.502818000 -0700
    @@ -0,0 +1,183 @@
    +/*
    + * Copyright (c) 2005-2008 Brocade Communications Systems, Inc.
    + * All rights reserved
    + * www.brocade.com
    + *
    + * Linux driver for Brocade Fibre Channel Host Bus Adapter.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License (GPL) Version 2 as
    + * published by the Free Software Foundation
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + */
    +
    +#include <bfa_os_inc.h>
    +#include <cs/bfa_plog.h>
    +#include <cs/bfa_debug.h>
    +
    +static int
    +plkd_validate_logrec(struct bfa_plog_rec_s *pl_rec)
    +{
    + if ((pl_rec->log_type != BFA_PL_LOG_TYPE_INT)
    + && (pl_rec->log_type != BFA_PL_LOG_TYPE_STRING))
    + return 1;
    +
    + if ((pl_rec->log_type != BFA_PL_LOG_TYPE_INT)
    + && (pl_rec->log_num_ints > BFA_PL_INT_LOG_SZ))
    + return 1;
    +
    + return 0;
    +}
    +
    +static void
    +bfa_plog_add(struct bfa_plog_s *plog, struct bfa_plog_rec_s *pl_rec)
    +{
    + u16 tail;
    + struct bfa_plog_rec_s *pl_recp;
    +
    + if (plog->plog_enabled == 0)
    + return;
    +
    + if (plkd_validate_logrec(pl_rec)) {
    + bfa_assert(0);
    + return;
    + }
    +
    + tail = plog->tail;
    +
    + pl_recp = &(plog->plog_recs[tail]);
    +
    + bfa_os_memcpy(pl_recp, pl_rec, sizeof(struct bfa_plog_rec_s));
    +
    + pl_recp->tv = BFA_TRC_TS(plog);
    + BFA_PL_LOG_REC_INCR(plog->tail);
    +
    + if (plog->head == plog->tail)
    + BFA_PL_LOG_REC_INCR(plog->head);
    +}
    +
    +void
    +bfa_plog_init(struct bfa_plog_s *plog)
    +{
    + bfa_os_memset((char *)plog, 0, sizeof(struct bfa_plog_s));
    +
    + bfa_os_memcpy(plog->plog_sig, BFA_PL_SIG_STR, BFA_PL_SIG_LEN);
    + plog->head = plog->tail = 0;
    + plog->plog_enabled = 1;
    +}
    +
    +void
    +bfa_plog_str(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
    + enum bfa_plog_eid event,
    + u16 misc, char *log_str)
    +{
    + struct bfa_plog_rec_s lp;
    +
    + if (plog->plog_enabled) {
    + bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
    + lp.mid = mid;
    + lp.eid = event;
    + lp.log_type = BFA_PL_LOG_TYPE_STRING;
    + lp.misc = misc;
    + strncpy(lp.log_entry.string_log, log_str,
    + BFA_PL_STRING_LOG_SZ - 1);
    + lp.log_entry.string_log[BFA_PL_STRING_LOG_SZ - 1] = '\0';
    + bfa_plog_add(plog, &lp);
    + }
    +}
    +
    +void
    +bfa_plog_intarr(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
    + enum bfa_plog_eid event,
    + u16 misc, u32 *intarr, u32 num_ints)
    +{
    + struct bfa_plog_rec_s lp;
    + u32 i;
    +
    + if (num_ints > BFA_PL_INT_LOG_SZ)
    + num_ints = BFA_PL_INT_LOG_SZ;
    +
    + if (plog->plog_enabled) {
    + bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
    + lp.mid = mid;
    + lp.eid = event;
    + lp.log_type = BFA_PL_LOG_TYPE_INT;
    + lp.misc = misc;
    +
    + for (i = 0; i < num_ints; i++)
    + lp.log_entry.int_log[i] = intarr[i];
    +
    + lp.log_num_ints = (u8) num_ints;
    +
    + bfa_plog_add(plog, &lp);
    + }
    +}
    +
    +void
    +bfa_plog_fchdr(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
    + enum bfa_plog_eid event,
    + u16 misc, struct fchs_s *fchdr)
    +{
    + struct bfa_plog_rec_s lp;
    + u32 *tmp_int = (u32 *) fchdr;
    + u32 ints[BFA_PL_INT_LOG_SZ];
    +
    + if (plog->plog_enabled) {
    + bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
    +
    + ints[0] = tmp_int[2];
    + ints[1] = tmp_int[3];
    + ints[2] = tmp_int[6];
    +
    + bfa_plog_intarr(plog, mid, event, misc, ints, 3);
    + }
    +}
    +
    +void
    +bfa_plog_fchdr_and_pl(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
    + enum bfa_plog_eid event, u16 misc,
    + struct fchs_s *fchdr, u32 pld_w0)
    +{
    + struct bfa_plog_rec_s lp;
    + u32 *tmp_int = (u32 *) fchdr;
    + u32 ints[BFA_PL_INT_LOG_SZ];
    +
    + if (plog->plog_enabled) {
    + bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
    +
    + ints[0] = tmp_int[2];
    + ints[1] = tmp_int[3];
    + ints[2] = tmp_int[6];
    + ints[3] = pld_w0;
    +
    + bfa_plog_intarr(plog, mid, event, misc, ints, 4);
    + }
    +}
    +
    +void
    +bfa_plog_clear(struct bfa_plog_s *plog)
    +{
    + plog->head = plog->tail = 0;
    +}
    +
    +void
    +bfa_plog_enable(struct bfa_plog_s *plog)
    +{
    + plog->plog_enabled = 1;
    +}
    +
    +void
    +bfa_plog_disable(struct bfa_plog_s *plog)
    +{
    + plog->plog_enabled = 0;
    +}
    +
    +bfa_boolean_t
    +bfa_plog_get_setting(struct bfa_plog_s *plog)
    +{
    + return((bfa_boolean_t)plog->plog_enabled);
    +}

    \
     
     \ /
      Last update: 2009-04-02 05:37    [W:1.119 / U:0.572 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site