/* * 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 #include #include "fcs_lport.h" #include "fcs_rport.h" #include "lport_priv.h" #include "fcs_trcmod.h" #include "fcs_fcxp.h" #include 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); /** * 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_assert(0); } } 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_assert(0); } } 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_assert(0); } } 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_assert(0); } } /* * 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_assert(0); } } 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_assert(0); } } 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_assert(0); } } /* * 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_assert(0); } } 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_assert(0); } } 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_assert(0); } } 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_assert(0); } } /** * 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_pport_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; bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); } 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); }