linux/drivers/scsi/bfa/fdmi.c
Krishna Gudipati 1c8a4c3749 [SCSI] bfa: Rename pport to fcport in BFA FCS.
Rename pport structures to fcport in BFA FCS, to resolve confusion
about the port structures in the firmware, and make sure the SG page
is setup correctly.

Signed-off-by: Krishna Gudipati <kgudipat@brocade.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
2010-03-07 13:05:10 +05:30

1244 lines
33 KiB
C

/*
* Copyright (c) 2005-2009 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.
*/
/**
* port_api.c BFA FCS port
*/
#include <bfa.h>
#include <bfa_svc.h>
#include "fcs_lport.h"
#include "fcs_rport.h"
#include "lport_priv.h"
#include "fcs_trcmod.h"
#include "fcs_fcxp.h"
#include <fcs/bfa_fcs_fdmi.h>
BFA_TRC_FILE(FCS, FDMI);
#define BFA_FCS_FDMI_CMD_MAX_RETRIES 2
/*
* forward declarations
*/
static void bfa_fcs_port_fdmi_send_rhba(void *fdmi_cbarg,
struct bfa_fcxp_s *fcxp_alloced);
static void bfa_fcs_port_fdmi_send_rprt(void *fdmi_cbarg,
struct bfa_fcxp_s *fcxp_alloced);
static void bfa_fcs_port_fdmi_send_rpa(void *fdmi_cbarg,
struct bfa_fcxp_s *fcxp_alloced);
static void bfa_fcs_port_fdmi_rhba_response(void *fcsarg,
struct bfa_fcxp_s *fcxp,
void *cbarg,
bfa_status_t req_status,
u32 rsp_len,
u32 resid_len,
struct fchs_s *rsp_fchs);
static void bfa_fcs_port_fdmi_rprt_response(void *fcsarg,
struct bfa_fcxp_s *fcxp,
void *cbarg,
bfa_status_t req_status,
u32 rsp_len,
u32 resid_len,
struct fchs_s *rsp_fchs);
static void bfa_fcs_port_fdmi_rpa_response(void *fcsarg,
struct bfa_fcxp_s *fcxp,
void *cbarg,
bfa_status_t req_status,
u32 rsp_len,
u32 resid_len,
struct fchs_s *rsp_fchs);
static void bfa_fcs_port_fdmi_timeout(void *arg);
static u16 bfa_fcs_port_fdmi_build_rhba_pyld(
struct bfa_fcs_port_fdmi_s *fdmi, u8 *pyld);
static u16 bfa_fcs_port_fdmi_build_rprt_pyld(
struct bfa_fcs_port_fdmi_s *fdmi, u8 *pyld);
static u16 bfa_fcs_port_fdmi_build_rpa_pyld(
struct bfa_fcs_port_fdmi_s *fdmi, u8 *pyld);
static u16 bfa_fcs_port_fdmi_build_portattr_block(
struct bfa_fcs_port_fdmi_s *fdmi, u8 *pyld);
static void bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_port_fdmi_s *fdmi,
struct bfa_fcs_fdmi_hba_attr_s *hba_attr);
static void bfa_fcs_fdmi_get_portattr(struct bfa_fcs_port_fdmi_s *fdmi,
struct bfa_fcs_fdmi_port_attr_s *port_attr);
/**
* fcs_fdmi_sm FCS FDMI state machine
*/
/**
* FDMI State Machine events
*/
enum port_fdmi_event {
FDMISM_EVENT_PORT_ONLINE = 1,
FDMISM_EVENT_PORT_OFFLINE = 2,
FDMISM_EVENT_RSP_OK = 4,
FDMISM_EVENT_RSP_ERROR = 5,
FDMISM_EVENT_TIMEOUT = 6,
FDMISM_EVENT_RHBA_SENT = 7,
FDMISM_EVENT_RPRT_SENT = 8,
FDMISM_EVENT_RPA_SENT = 9,
};
static void bfa_fcs_port_fdmi_sm_offline(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event);
static void bfa_fcs_port_fdmi_sm_sending_rhba(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event);
static void bfa_fcs_port_fdmi_sm_rhba(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event);
static void bfa_fcs_port_fdmi_sm_rhba_retry(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event);
static void bfa_fcs_port_fdmi_sm_sending_rprt(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event);
static void bfa_fcs_port_fdmi_sm_rprt(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event);
static void bfa_fcs_port_fdmi_sm_rprt_retry(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event);
static void bfa_fcs_port_fdmi_sm_sending_rpa(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event);
static void bfa_fcs_port_fdmi_sm_rpa(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event);
static void bfa_fcs_port_fdmi_sm_rpa_retry(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event);
static void bfa_fcs_port_fdmi_sm_online(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event);
static void bfa_fcs_port_fdmi_sm_disabled(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event);
/**
* Start in offline state - awaiting MS to send start.
*/
static void
bfa_fcs_port_fdmi_sm_offline(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event)
{
struct bfa_fcs_port_s *port = fdmi->ms->port;
bfa_trc(port->fcs, port->port_cfg.pwwn);
bfa_trc(port->fcs, event);
fdmi->retry_cnt = 0;
switch (event) {
case FDMISM_EVENT_PORT_ONLINE:
if (port->vport) {
/*
* For Vports, register a new port.
*/
bfa_sm_set_state(fdmi,
bfa_fcs_port_fdmi_sm_sending_rprt);
bfa_fcs_port_fdmi_send_rprt(fdmi, NULL);
} else {
/*
* For a base port, we should first register the HBA
* atribute. The HBA attribute also contains the base
* port registration.
*/
bfa_sm_set_state(fdmi,
bfa_fcs_port_fdmi_sm_sending_rhba);
bfa_fcs_port_fdmi_send_rhba(fdmi, NULL);
}
break;
case FDMISM_EVENT_PORT_OFFLINE:
break;
default:
bfa_sm_fault(port->fcs, event);
}
}
static void
bfa_fcs_port_fdmi_sm_sending_rhba(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event)
{
struct bfa_fcs_port_s *port = fdmi->ms->port;
bfa_trc(port->fcs, port->port_cfg.pwwn);
bfa_trc(port->fcs, event);
switch (event) {
case FDMISM_EVENT_RHBA_SENT:
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rhba);
break;
case FDMISM_EVENT_PORT_OFFLINE:
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port),
&fdmi->fcxp_wqe);
break;
default:
bfa_sm_fault(port->fcs, event);
}
}
static void
bfa_fcs_port_fdmi_sm_rhba(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event)
{
struct bfa_fcs_port_s *port = fdmi->ms->port;
bfa_trc(port->fcs, port->port_cfg.pwwn);
bfa_trc(port->fcs, event);
switch (event) {
case FDMISM_EVENT_RSP_ERROR:
/*
* if max retries have not been reached, start timer for a
* delayed retry
*/
if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) {
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rhba_retry);
bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port),
&fdmi->timer, bfa_fcs_port_fdmi_timeout,
fdmi, BFA_FCS_RETRY_TIMEOUT);
} else {
/*
* set state to offline
*/
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
}
break;
case FDMISM_EVENT_RSP_OK:
/*
* Initiate Register Port Attributes
*/
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_sending_rpa);
fdmi->retry_cnt = 0;
bfa_fcs_port_fdmi_send_rpa(fdmi, NULL);
break;
case FDMISM_EVENT_PORT_OFFLINE:
bfa_fcxp_discard(fdmi->fcxp);
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
break;
default:
bfa_sm_fault(port->fcs, event);
}
}
static void
bfa_fcs_port_fdmi_sm_rhba_retry(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event)
{
struct bfa_fcs_port_s *port = fdmi->ms->port;
bfa_trc(port->fcs, port->port_cfg.pwwn);
bfa_trc(port->fcs, event);
switch (event) {
case FDMISM_EVENT_TIMEOUT:
/*
* Retry Timer Expired. Re-send
*/
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_sending_rhba);
bfa_fcs_port_fdmi_send_rhba(fdmi, NULL);
break;
case FDMISM_EVENT_PORT_OFFLINE:
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
bfa_timer_stop(&fdmi->timer);
break;
default:
bfa_sm_fault(port->fcs, event);
}
}
/*
* RPRT : Register Port
*/
static void
bfa_fcs_port_fdmi_sm_sending_rprt(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event)
{
struct bfa_fcs_port_s *port = fdmi->ms->port;
bfa_trc(port->fcs, port->port_cfg.pwwn);
bfa_trc(port->fcs, event);
switch (event) {
case FDMISM_EVENT_RPRT_SENT:
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rprt);
break;
case FDMISM_EVENT_PORT_OFFLINE:
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port),
&fdmi->fcxp_wqe);
break;
default:
bfa_sm_fault(port->fcs, event);
}
}
static void
bfa_fcs_port_fdmi_sm_rprt(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event)
{
struct bfa_fcs_port_s *port = fdmi->ms->port;
bfa_trc(port->fcs, port->port_cfg.pwwn);
bfa_trc(port->fcs, event);
switch (event) {
case FDMISM_EVENT_RSP_ERROR:
/*
* if max retries have not been reached, start timer for a
* delayed retry
*/
if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) {
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rprt_retry);
bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port),
&fdmi->timer, bfa_fcs_port_fdmi_timeout,
fdmi, BFA_FCS_RETRY_TIMEOUT);
} else {
/*
* set state to offline
*/
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
fdmi->retry_cnt = 0;
}
break;
case FDMISM_EVENT_RSP_OK:
fdmi->retry_cnt = 0;
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_online);
break;
case FDMISM_EVENT_PORT_OFFLINE:
bfa_fcxp_discard(fdmi->fcxp);
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
break;
default:
bfa_sm_fault(port->fcs, event);
}
}
static void
bfa_fcs_port_fdmi_sm_rprt_retry(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event)
{
struct bfa_fcs_port_s *port = fdmi->ms->port;
bfa_trc(port->fcs, port->port_cfg.pwwn);
bfa_trc(port->fcs, event);
switch (event) {
case FDMISM_EVENT_TIMEOUT:
/*
* Retry Timer Expired. Re-send
*/
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_sending_rprt);
bfa_fcs_port_fdmi_send_rprt(fdmi, NULL);
break;
case FDMISM_EVENT_PORT_OFFLINE:
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
bfa_timer_stop(&fdmi->timer);
break;
default:
bfa_sm_fault(port->fcs, event);
}
}
/*
* Register Port Attributes
*/
static void
bfa_fcs_port_fdmi_sm_sending_rpa(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event)
{
struct bfa_fcs_port_s *port = fdmi->ms->port;
bfa_trc(port->fcs, port->port_cfg.pwwn);
bfa_trc(port->fcs, event);
switch (event) {
case FDMISM_EVENT_RPA_SENT:
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rpa);
break;
case FDMISM_EVENT_PORT_OFFLINE:
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port),
&fdmi->fcxp_wqe);
break;
default:
bfa_sm_fault(port->fcs, event);
}
}
static void
bfa_fcs_port_fdmi_sm_rpa(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event)
{
struct bfa_fcs_port_s *port = fdmi->ms->port;
bfa_trc(port->fcs, port->port_cfg.pwwn);
bfa_trc(port->fcs, event);
switch (event) {
case FDMISM_EVENT_RSP_ERROR:
/*
* if max retries have not been reached, start timer for a
* delayed retry
*/
if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) {
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rpa_retry);
bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port),
&fdmi->timer, bfa_fcs_port_fdmi_timeout,
fdmi, BFA_FCS_RETRY_TIMEOUT);
} else {
/*
* set state to offline
*/
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
fdmi->retry_cnt = 0;
}
break;
case FDMISM_EVENT_RSP_OK:
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_online);
fdmi->retry_cnt = 0;
break;
case FDMISM_EVENT_PORT_OFFLINE:
bfa_fcxp_discard(fdmi->fcxp);
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
break;
default:
bfa_sm_fault(port->fcs, event);
}
}
static void
bfa_fcs_port_fdmi_sm_rpa_retry(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event)
{
struct bfa_fcs_port_s *port = fdmi->ms->port;
bfa_trc(port->fcs, port->port_cfg.pwwn);
bfa_trc(port->fcs, event);
switch (event) {
case FDMISM_EVENT_TIMEOUT:
/*
* Retry Timer Expired. Re-send
*/
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_sending_rpa);
bfa_fcs_port_fdmi_send_rpa(fdmi, NULL);
break;
case FDMISM_EVENT_PORT_OFFLINE:
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
bfa_timer_stop(&fdmi->timer);
break;
default:
bfa_sm_fault(port->fcs, event);
}
}
static void
bfa_fcs_port_fdmi_sm_online(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event)
{
struct bfa_fcs_port_s *port = fdmi->ms->port;
bfa_trc(port->fcs, port->port_cfg.pwwn);
bfa_trc(port->fcs, event);
switch (event) {
case FDMISM_EVENT_PORT_OFFLINE:
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
break;
default:
bfa_sm_fault(port->fcs, event);
}
}
/**
* FDMI is disabled state.
*/
static void
bfa_fcs_port_fdmi_sm_disabled(struct bfa_fcs_port_fdmi_s *fdmi,
enum port_fdmi_event event)
{
struct bfa_fcs_port_s *port = fdmi->ms->port;
bfa_trc(port->fcs, port->port_cfg.pwwn);
bfa_trc(port->fcs, event);
/* No op State. It can only be enabled at Driver Init. */
}
/**
* RHBA : Register HBA Attributes.
*/
static void
bfa_fcs_port_fdmi_send_rhba(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
{
struct bfa_fcs_port_fdmi_s *fdmi = fdmi_cbarg;
struct bfa_fcs_port_s *port = fdmi->ms->port;
struct fchs_s fchs;
int len, attr_len;
struct bfa_fcxp_s *fcxp;
u8 *pyld;
bfa_trc(port->fcs, port->port_cfg.pwwn);
fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
if (!fcxp) {
bfa_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe,
bfa_fcs_port_fdmi_send_rhba, fdmi);
return;
}
fdmi->fcxp = fcxp;
pyld = bfa_fcxp_get_reqbuf(fcxp);
bfa_os_memset(pyld, 0, FC_MAX_PDUSZ);
len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_port_get_fcid(port),
FDMI_RHBA);
attr_len = bfa_fcs_port_fdmi_build_rhba_pyld(fdmi,
(u8 *) ((struct ct_hdr_s *) pyld + 1));
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, (len + attr_len), &fchs,
bfa_fcs_port_fdmi_rhba_response, (void *)fdmi,
FC_MAX_PDUSZ, FC_RA_TOV);
bfa_sm_send_event(fdmi, FDMISM_EVENT_RHBA_SENT);
}
static u16
bfa_fcs_port_fdmi_build_rhba_pyld(struct bfa_fcs_port_fdmi_s *fdmi,
u8 *pyld)
{
struct bfa_fcs_port_s *port = fdmi->ms->port;
struct bfa_fcs_fdmi_hba_attr_s hba_attr; /* @todo */
struct bfa_fcs_fdmi_hba_attr_s *fcs_hba_attr = &hba_attr; /* @todo */
struct fdmi_rhba_s *rhba = (struct fdmi_rhba_s *) pyld;
struct fdmi_attr_s *attr;
u8 *curr_ptr;
u16 len, count;
/*
* get hba attributes
*/
bfa_fcs_fdmi_get_hbaattr(fdmi, fcs_hba_attr);
rhba->hba_id = bfa_fcs_port_get_pwwn(port);
rhba->port_list.num_ports = bfa_os_htonl(1);
rhba->port_list.port_entry = bfa_fcs_port_get_pwwn(port);
len = sizeof(rhba->hba_id) + sizeof(rhba->port_list);
count = 0;
len += sizeof(rhba->hba_attr_blk.attr_count);
/*
* fill out the invididual entries of the HBA attrib Block
*/
curr_ptr = (u8 *) &rhba->hba_attr_blk.hba_attr;
/*
* Node Name
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_NODENAME);
attr->len = sizeof(wwn_t);
memcpy(attr->value, &bfa_fcs_port_get_nwwn(port), attr->len);
curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
len += attr->len;
count++;
attr->len =
bfa_os_htons(attr->len + sizeof(attr->type) +
sizeof(attr->len));
/*
* Manufacturer
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MANUFACTURER);
attr->len = (u16) strlen(fcs_hba_attr->manufacturer);
memcpy(attr->value, fcs_hba_attr->manufacturer, attr->len);
/* variable fields need to be 4 byte aligned */
attr->len = fc_roundup(attr->len, sizeof(u32));
curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
len += attr->len;
count++;
attr->len =
bfa_os_htons(attr->len + sizeof(attr->type) +
sizeof(attr->len));
/*
* Serial Number
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_SERIALNUM);
attr->len = (u16) strlen(fcs_hba_attr->serial_num);
memcpy(attr->value, fcs_hba_attr->serial_num, attr->len);
/* variable fields need to be 4 byte aligned */
attr->len = fc_roundup(attr->len, sizeof(u32));
curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
len += attr->len;
count++;
attr->len =
bfa_os_htons(attr->len + sizeof(attr->type) +
sizeof(attr->len));
/*
* Model
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MODEL);
attr->len = (u16) strlen(fcs_hba_attr->model);
memcpy(attr->value, fcs_hba_attr->model, attr->len);
/* variable fields need to be 4 byte aligned */
attr->len = fc_roundup(attr->len, sizeof(u32));
curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
len += attr->len;
count++;
attr->len =
bfa_os_htons(attr->len + sizeof(attr->type) +
sizeof(attr->len));
/*
* Model Desc
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MODEL_DESC);
attr->len = (u16) strlen(fcs_hba_attr->model_desc);
memcpy(attr->value, fcs_hba_attr->model_desc, attr->len);
/* variable fields need to be 4 byte aligned */
attr->len = fc_roundup(attr->len, sizeof(u32));
curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
len += attr->len;
count++;
attr->len =
bfa_os_htons(attr->len + sizeof(attr->type) +
sizeof(attr->len));
/*
* H/W Version
*/
if (fcs_hba_attr->hw_version[0] != '\0') {
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_HW_VERSION);
attr->len = (u16) strlen(fcs_hba_attr->hw_version);
memcpy(attr->value, fcs_hba_attr->hw_version, attr->len);
/* variable fields need to be 4 byte aligned */
attr->len = fc_roundup(attr->len, sizeof(u32));
curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
len += attr->len;
count++;
attr->len =
bfa_os_htons(attr->len + sizeof(attr->type) +
sizeof(attr->len));
}
/*
* Driver Version
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_DRIVER_VERSION);
attr->len = (u16) strlen(fcs_hba_attr->driver_version);
memcpy(attr->value, fcs_hba_attr->driver_version, attr->len);
/* variable fields need to be 4 byte aligned */
attr->len = fc_roundup(attr->len, sizeof(u32));
curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
len += attr->len;;
count++;
attr->len =
bfa_os_htons(attr->len + sizeof(attr->type) +
sizeof(attr->len));
/*
* Option Rom Version
*/
if (fcs_hba_attr->option_rom_ver[0] != '\0') {
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_ROM_VERSION);
attr->len = (u16) strlen(fcs_hba_attr->option_rom_ver);
memcpy(attr->value, fcs_hba_attr->option_rom_ver, attr->len);
/* variable fields need to be 4 byte aligned */
attr->len = fc_roundup(attr->len, sizeof(u32));
curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
len += attr->len;
count++;
attr->len =
bfa_os_htons(attr->len + sizeof(attr->type) +
sizeof(attr->len));
}
/*
* f/w Version = driver version
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_FW_VERSION);
attr->len = (u16) strlen(fcs_hba_attr->driver_version);
memcpy(attr->value, fcs_hba_attr->driver_version, attr->len);
/* variable fields need to be 4 byte aligned */
attr->len = fc_roundup(attr->len, sizeof(u32));
curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
len += attr->len;
count++;
attr->len =
bfa_os_htons(attr->len + sizeof(attr->type) +
sizeof(attr->len));
/*
* OS Name
*/
if (fcs_hba_attr->os_name[0] != '\0') {
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_OS_NAME);
attr->len = (u16) strlen(fcs_hba_attr->os_name);
memcpy(attr->value, fcs_hba_attr->os_name, attr->len);
/* variable fields need to be 4 byte aligned */
attr->len = fc_roundup(attr->len, sizeof(u32));
curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
len += attr->len;
count++;
attr->len =
bfa_os_htons(attr->len + sizeof(attr->type) +
sizeof(attr->len));
}
/*
* MAX_CT_PAYLOAD
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MAX_CT);
attr->len = sizeof(fcs_hba_attr->max_ct_pyld);
memcpy(attr->value, &fcs_hba_attr->max_ct_pyld, attr->len);
len += attr->len;
count++;
attr->len =
bfa_os_htons(attr->len + sizeof(attr->type) +
sizeof(attr->len));
/*
* Update size of payload
*/
len += ((sizeof(attr->type) + sizeof(attr->len)) * count);
rhba->hba_attr_blk.attr_count = bfa_os_htonl(count);
return len;
}
static void
bfa_fcs_port_fdmi_rhba_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
void *cbarg, bfa_status_t req_status,
u32 rsp_len, u32 resid_len,
struct fchs_s *rsp_fchs)
{
struct bfa_fcs_port_fdmi_s *fdmi = (struct bfa_fcs_port_fdmi_s *)cbarg;
struct bfa_fcs_port_s *port = fdmi->ms->port;
struct ct_hdr_s *cthdr = NULL;
bfa_trc(port->fcs, port->port_cfg.pwwn);
/*
* Sanity Checks
*/
if (req_status != BFA_STATUS_OK) {
bfa_trc(port->fcs, req_status);
bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
return;
}
cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK);
return;
}
bfa_trc(port->fcs, cthdr->reason_code);
bfa_trc(port->fcs, cthdr->exp_code);
bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
}
/**
* RPRT : Register Port
*/
static void
bfa_fcs_port_fdmi_send_rprt(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
{
struct bfa_fcs_port_fdmi_s *fdmi = fdmi_cbarg;
struct bfa_fcs_port_s *port = fdmi->ms->port;
struct fchs_s fchs;
u16 len, attr_len;
struct bfa_fcxp_s *fcxp;
u8 *pyld;
bfa_trc(port->fcs, port->port_cfg.pwwn);
fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
if (!fcxp) {
bfa_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe,
bfa_fcs_port_fdmi_send_rprt, fdmi);
return;
}
fdmi->fcxp = fcxp;
pyld = bfa_fcxp_get_reqbuf(fcxp);
bfa_os_memset(pyld, 0, FC_MAX_PDUSZ);
len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_port_get_fcid(port),
FDMI_RPRT);
attr_len = bfa_fcs_port_fdmi_build_rprt_pyld(fdmi,
(u8 *) ((struct ct_hdr_s *) pyld + 1));
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len + attr_len, &fchs,
bfa_fcs_port_fdmi_rprt_response, (void *)fdmi,
FC_MAX_PDUSZ, FC_RA_TOV);
bfa_sm_send_event(fdmi, FDMISM_EVENT_RPRT_SENT);
}
/**
* This routine builds Port Attribute Block that used in RPA, RPRT commands.
*/
static u16
bfa_fcs_port_fdmi_build_portattr_block(struct bfa_fcs_port_fdmi_s *fdmi,
u8 *pyld)
{
struct bfa_fcs_fdmi_port_attr_s fcs_port_attr;
struct fdmi_port_attr_s *port_attrib = (struct fdmi_port_attr_s *) pyld;
struct fdmi_attr_s *attr;
u8 *curr_ptr;
u16 len;
u8 count = 0;
/*
* get port attributes
*/
bfa_fcs_fdmi_get_portattr(fdmi, &fcs_port_attr);
len = sizeof(port_attrib->attr_count);
/*
* fill out the invididual entries
*/
curr_ptr = (u8 *) &port_attrib->port_attr;
/*
* FC4 Types
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_FC4_TYPES);
attr->len = sizeof(fcs_port_attr.supp_fc4_types);
memcpy(attr->value, fcs_port_attr.supp_fc4_types, attr->len);
curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
len += attr->len;
++count;
attr->len =
bfa_os_htons(attr->len + sizeof(attr->type) +
sizeof(attr->len));
/*
* Supported Speed
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_SUPP_SPEED);
attr->len = sizeof(fcs_port_attr.supp_speed);
memcpy(attr->value, &fcs_port_attr.supp_speed, attr->len);
curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
len += attr->len;
++count;
attr->len =
bfa_os_htons(attr->len + sizeof(attr->type) +
sizeof(attr->len));
/*
* current Port Speed
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_PORT_SPEED);
attr->len = sizeof(fcs_port_attr.curr_speed);
memcpy(attr->value, &fcs_port_attr.curr_speed, attr->len);
curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
len += attr->len;
++count;
attr->len =
bfa_os_htons(attr->len + sizeof(attr->type) +
sizeof(attr->len));
/*
* max frame size
*/
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_FRAME_SIZE);
attr->len = sizeof(fcs_port_attr.max_frm_size);
memcpy(attr->value, &fcs_port_attr.max_frm_size, attr->len);
curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
len += attr->len;
++count;
attr->len =
bfa_os_htons(attr->len + sizeof(attr->type) +
sizeof(attr->len));
/*
* OS Device Name
*/
if (fcs_port_attr.os_device_name[0] != '\0') {
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_DEV_NAME);
attr->len = (u16) strlen(fcs_port_attr.os_device_name);
memcpy(attr->value, fcs_port_attr.os_device_name, attr->len);
/* variable fields need to be 4 byte aligned */
attr->len = fc_roundup(attr->len, sizeof(u32));
curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
len += attr->len;
++count;
attr->len =
bfa_os_htons(attr->len + sizeof(attr->type) +
sizeof(attr->len));
}
/*
* Host Name
*/
if (fcs_port_attr.host_name[0] != '\0') {
attr = (struct fdmi_attr_s *) curr_ptr;
attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_HOST_NAME);
attr->len = (u16) strlen(fcs_port_attr.host_name);
memcpy(attr->value, fcs_port_attr.host_name, attr->len);
/* variable fields need to be 4 byte aligned */
attr->len = fc_roundup(attr->len, sizeof(u32));
curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
len += attr->len;
++count;
attr->len =
bfa_os_htons(attr->len + sizeof(attr->type) +
sizeof(attr->len));
}
/*
* Update size of payload
*/
port_attrib->attr_count = bfa_os_htonl(count);
len += ((sizeof(attr->type) + sizeof(attr->len)) * count);
return len;
}
static u16
bfa_fcs_port_fdmi_build_rprt_pyld(struct bfa_fcs_port_fdmi_s *fdmi,
u8 *pyld)
{
struct bfa_fcs_port_s *port = fdmi->ms->port;
struct fdmi_rprt_s *rprt = (struct fdmi_rprt_s *) pyld;
u16 len;
rprt->hba_id = bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(port->fcs));
rprt->port_name = bfa_fcs_port_get_pwwn(port);
len = bfa_fcs_port_fdmi_build_portattr_block(fdmi,
(u8 *) &rprt->port_attr_blk);
len += sizeof(rprt->hba_id) + sizeof(rprt->port_name);
return len;
}
static void
bfa_fcs_port_fdmi_rprt_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
void *cbarg, bfa_status_t req_status,
u32 rsp_len, u32 resid_len,
struct fchs_s *rsp_fchs)
{
struct bfa_fcs_port_fdmi_s *fdmi = (struct bfa_fcs_port_fdmi_s *)cbarg;
struct bfa_fcs_port_s *port = fdmi->ms->port;
struct ct_hdr_s *cthdr = NULL;
bfa_trc(port->fcs, port->port_cfg.pwwn);
/*
* Sanity Checks
*/
if (req_status != BFA_STATUS_OK) {
bfa_trc(port->fcs, req_status);
bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
return;
}
cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK);
return;
}
bfa_trc(port->fcs, cthdr->reason_code);
bfa_trc(port->fcs, cthdr->exp_code);
bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
}
/**
* RPA : Register Port Attributes.
*/
static void
bfa_fcs_port_fdmi_send_rpa(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
{
struct bfa_fcs_port_fdmi_s *fdmi = fdmi_cbarg;
struct bfa_fcs_port_s *port = fdmi->ms->port;
struct fchs_s fchs;
u16 len, attr_len;
struct bfa_fcxp_s *fcxp;
u8 *pyld;
bfa_trc(port->fcs, port->port_cfg.pwwn);
fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
if (!fcxp) {
bfa_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe,
bfa_fcs_port_fdmi_send_rpa, fdmi);
return;
}
fdmi->fcxp = fcxp;
pyld = bfa_fcxp_get_reqbuf(fcxp);
bfa_os_memset(pyld, 0, FC_MAX_PDUSZ);
len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_port_get_fcid(port),
FDMI_RPA);
attr_len = bfa_fcs_port_fdmi_build_rpa_pyld(fdmi,
(u8 *) ((struct ct_hdr_s *) pyld + 1));
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len + attr_len, &fchs,
bfa_fcs_port_fdmi_rpa_response, (void *)fdmi,
FC_MAX_PDUSZ, FC_RA_TOV);
bfa_sm_send_event(fdmi, FDMISM_EVENT_RPA_SENT);
}
static u16
bfa_fcs_port_fdmi_build_rpa_pyld(struct bfa_fcs_port_fdmi_s *fdmi,
u8 *pyld)
{
struct bfa_fcs_port_s *port = fdmi->ms->port;
struct fdmi_rpa_s *rpa = (struct fdmi_rpa_s *) pyld;
u16 len;
rpa->port_name = bfa_fcs_port_get_pwwn(port);
len = bfa_fcs_port_fdmi_build_portattr_block(fdmi,
(u8 *) &rpa->port_attr_blk);
len += sizeof(rpa->port_name);
return len;
}
static void
bfa_fcs_port_fdmi_rpa_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
void *cbarg, bfa_status_t req_status,
u32 rsp_len, u32 resid_len,
struct fchs_s *rsp_fchs)
{
struct bfa_fcs_port_fdmi_s *fdmi = (struct bfa_fcs_port_fdmi_s *)cbarg;
struct bfa_fcs_port_s *port = fdmi->ms->port;
struct ct_hdr_s *cthdr = NULL;
bfa_trc(port->fcs, port->port_cfg.pwwn);
/*
* Sanity Checks
*/
if (req_status != BFA_STATUS_OK) {
bfa_trc(port->fcs, req_status);
bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
return;
}
cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK);
return;
}
bfa_trc(port->fcs, cthdr->reason_code);
bfa_trc(port->fcs, cthdr->exp_code);
bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
}
static void
bfa_fcs_port_fdmi_timeout(void *arg)
{
struct bfa_fcs_port_fdmi_s *fdmi = (struct bfa_fcs_port_fdmi_s *)arg;
bfa_sm_send_event(fdmi, FDMISM_EVENT_TIMEOUT);
}
static void
bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_port_fdmi_s *fdmi,
struct bfa_fcs_fdmi_hba_attr_s *hba_attr)
{
struct bfa_fcs_port_s *port = fdmi->ms->port;
struct bfa_fcs_driver_info_s *driver_info = &port->fcs->driver_info;
struct bfa_adapter_attr_s adapter_attr;
bfa_os_memset(hba_attr, 0, sizeof(struct bfa_fcs_fdmi_hba_attr_s));
bfa_os_memset(&adapter_attr, 0, sizeof(struct bfa_adapter_attr_s));
bfa_ioc_get_adapter_attr(&port->fcs->bfa->ioc, &adapter_attr);
strncpy(hba_attr->manufacturer, adapter_attr.manufacturer,
sizeof(adapter_attr.manufacturer));
strncpy(hba_attr->serial_num, adapter_attr.serial_num,
sizeof(adapter_attr.serial_num));
strncpy(hba_attr->model, adapter_attr.model, sizeof(hba_attr->model));
strncpy(hba_attr->model_desc, adapter_attr.model_descr,
sizeof(hba_attr->model_desc));
strncpy(hba_attr->hw_version, adapter_attr.hw_ver,
sizeof(hba_attr->hw_version));
strncpy(hba_attr->driver_version, (char *)driver_info->version,
sizeof(hba_attr->driver_version));
strncpy(hba_attr->option_rom_ver, adapter_attr.optrom_ver,
sizeof(hba_attr->option_rom_ver));
strncpy(hba_attr->fw_version, adapter_attr.fw_ver,
sizeof(hba_attr->fw_version));
strncpy(hba_attr->os_name, driver_info->host_os_name,
sizeof(hba_attr->os_name));
/*
* If there is a patch level, append it to the os name along with a
* separator
*/
if (driver_info->host_os_patch[0] != '\0') {
strncat(hba_attr->os_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
strncat(hba_attr->os_name, driver_info->host_os_patch,
sizeof(driver_info->host_os_patch));
}
hba_attr->max_ct_pyld = bfa_os_htonl(FC_MAX_PDUSZ);
}
static void
bfa_fcs_fdmi_get_portattr(struct bfa_fcs_port_fdmi_s *fdmi,
struct bfa_fcs_fdmi_port_attr_s *port_attr)
{
struct bfa_fcs_port_s *port = fdmi->ms->port;
struct bfa_fcs_driver_info_s *driver_info = &port->fcs->driver_info;
struct bfa_pport_attr_s pport_attr;
bfa_os_memset(port_attr, 0, sizeof(struct bfa_fcs_fdmi_port_attr_s));
/*
* get pport attributes from hal
*/
bfa_fcport_get_attr(port->fcs->bfa, &pport_attr);
/*
* get FC4 type Bitmask
*/
fc_get_fc4type_bitmask(FC_TYPE_FCP, port_attr->supp_fc4_types);
/*
* Supported Speeds
*/
port_attr->supp_speed = bfa_os_htonl(BFA_FCS_FDMI_SUPORTED_SPEEDS);
/*
* Current Speed
*/
port_attr->curr_speed = bfa_os_htonl(pport_attr.speed);
/*
* Max PDU Size.
*/
port_attr->max_frm_size = bfa_os_htonl(FC_MAX_PDUSZ);
/*
* OS device Name
*/
strncpy(port_attr->os_device_name, (char *)driver_info->os_device_name,
sizeof(port_attr->os_device_name));
/*
* Host name
*/
strncpy(port_attr->host_name, (char *)driver_info->host_machine_name,
sizeof(port_attr->host_name));
}
void
bfa_fcs_port_fdmi_init(struct bfa_fcs_port_ms_s *ms)
{
struct bfa_fcs_port_fdmi_s *fdmi = &ms->fdmi;
fdmi->ms = ms;
if (ms->port->fcs->fdmi_enabled)
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
else
bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_disabled);
}
void
bfa_fcs_port_fdmi_offline(struct bfa_fcs_port_ms_s *ms)
{
struct bfa_fcs_port_fdmi_s *fdmi = &ms->fdmi;
fdmi->ms = ms;
bfa_sm_send_event(fdmi, FDMISM_EVENT_PORT_OFFLINE);
}
void
bfa_fcs_port_fdmi_online(struct bfa_fcs_port_ms_s *ms)
{
struct bfa_fcs_port_fdmi_s *fdmi = &ms->fdmi;
fdmi->ms = ms;
bfa_sm_send_event(fdmi, FDMISM_EVENT_PORT_ONLINE);
}