// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*/
#include "fnic.h"
#include "fip.h"
#include <linux/etherdevice.h>
#define FIP_FNIC_RESET_WAIT_COUNT 15
/**
* fnic_fcoe_reset_vlans - Free up the list of discovered vlans
* @fnic: Handle to fnic driver instance
*/
void fnic_fcoe_reset_vlans(struct fnic *fnic)
{
unsigned long flags;
struct fcoe_vlan *vlan, *next;
spin_lock_irqsave(&fnic->vlans_lock, flags);
if (!list_empty(&fnic->vlan_list)) {
list_for_each_entry_safe(vlan, next, &fnic->vlan_list, list) {
list_del(&vlan->list);
kfree(vlan);
}
}
spin_unlock_irqrestore(&fnic->vlans_lock, flags);
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
"Reset vlan complete\n");
}
/**
* fnic_fcoe_send_vlan_req - Send FIP vlan request to all FCFs MAC
* @fnic: Handle to fnic driver instance
*/
void fnic_fcoe_send_vlan_req(struct fnic *fnic)
{
uint8_t *frame;
struct fnic_iport_s *iport = &fnic->iport;
struct fnic_stats *fnic_stats = &fnic->fnic_stats;
u64 vlan_tov;
struct fip_vlan_req *pvlan_req;
uint16_t frame_size = sizeof(struct fip_vlan_req);
frame = fdls_alloc_frame(iport);
if (frame == NULL) {
FNIC_FIP_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
"Failed to allocate frame to send VLAN req");
return;
}
fnic_fcoe_reset_vlans(fnic);
fnic->set_vlan(fnic, 0);
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
"set vlan done\n");
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
"got MAC 0x%x:%x:%x:%x:%x:%x\n", iport->hwmac[0],
iport->hwmac[1], iport->hwmac[2], iport->hwmac[3],
iport->hwmac[4], iport->hwmac[5]);
pvlan_req = (struct fip_vlan_req *) frame;
*pvlan_req = (struct fip_vlan_req) {
.eth = {.h_dest = FCOE_ALL_FCFS_MAC,
.h_proto = cpu_to_be16(ETH_P_FIP)},
.fip = {.fip_ver = FIP_VER_ENCAPS(FIP_VER),
.fip_op = cpu_to_be16(FIP_OP_VLAN),
.fip_subcode = FIP_SC_REQ,
.fip_dl_len = cpu_to_be16(FIP_VLAN_REQ_LEN)},
.mac_desc = {.fd_desc = {.fip_dtype = FIP_DT_MAC,
.fip_dlen = 2}}
};
memcpy(pvlan_req->eth.h_source, iport->hwmac, ETH_ALEN);
memcpy(pvlan_req->mac_desc.fd_mac, iport->hwmac, ETH_ALEN);
atomic64_inc(&fnic_stats->vlan_stats.vlan_disc_reqs);
iport->fip.state = FDLS_FIP_VLAN_DISCOVERY_STARTED;
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
"Send VLAN req\n");
fnic_send_fip_frame(iport, frame, frame_size);
vlan_tov = jiffies + msecs_to_jiffies(FCOE_CTLR_FIPVLAN_TOV);
mod_timer(&fnic->retry_fip_timer, round_jiffies(vlan_tov));
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
"fip timer set\n");
}
/**
* fnic_fcoe_process_vlan_resp - Processes the vlan response from one FCF and
* populates VLAN list.
* @fnic: Handle to fnic driver instance
* @fiph: Received FIP frame
*
* Will wait for responses from multiple FCFs until timeout.
*/
void fnic_fcoe_process_vlan_resp(struct fnic *fnic, struct fip_header *fiph)
{
struct fip_vlan_notif *vlan_notif = (struct fip_vlan_notif *)fiph;
struct fnic_stats *fnic_stats = &fnic->fnic_stats;
u16 vid;
int num_vlan = 0;
int cur_desc, desc_len;
struct fcoe_vlan *vlan;
struct fip_vlan_desc *vlan_desc;
unsigned long flags;
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
"fnic 0x%p got vlan resp\n", fnic);
desc_len = be16_to_cpu(vlan_notif->fip.fip_dl_len);
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
"desc_len %d\n", desc_len);
spin_lock_irqsave(&fnic->vlans_lock, flags);