1*61d8658bSDupuis, Chad /* 2*61d8658bSDupuis, Chad * QLogic FCoE Offload Driver 3*61d8658bSDupuis, Chad * Copyright (c) 2016 Cavium Inc. 4*61d8658bSDupuis, Chad * 5*61d8658bSDupuis, Chad * This software is available under the terms of the GNU General Public License 6*61d8658bSDupuis, Chad * (GPL) Version 2, available from the file COPYING in the main directory of 7*61d8658bSDupuis, Chad * this source tree. 8*61d8658bSDupuis, Chad */ 9*61d8658bSDupuis, Chad #include <linux/if_ether.h> 10*61d8658bSDupuis, Chad #include <linux/if_vlan.h> 11*61d8658bSDupuis, Chad #include "qedf.h" 12*61d8658bSDupuis, Chad 13*61d8658bSDupuis, Chad extern const struct qed_fcoe_ops *qed_ops; 14*61d8658bSDupuis, Chad /* 15*61d8658bSDupuis, Chad * FIP VLAN functions that will eventually move to libfcoe. 16*61d8658bSDupuis, Chad */ 17*61d8658bSDupuis, Chad 18*61d8658bSDupuis, Chad void qedf_fcoe_send_vlan_req(struct qedf_ctx *qedf) 19*61d8658bSDupuis, Chad { 20*61d8658bSDupuis, Chad struct sk_buff *skb; 21*61d8658bSDupuis, Chad char *eth_fr; 22*61d8658bSDupuis, Chad int fr_len; 23*61d8658bSDupuis, Chad struct fip_vlan *vlan; 24*61d8658bSDupuis, Chad #define MY_FIP_ALL_FCF_MACS ((__u8[6]) { 1, 0x10, 0x18, 1, 0, 2 }) 25*61d8658bSDupuis, Chad static u8 my_fcoe_all_fcfs[ETH_ALEN] = MY_FIP_ALL_FCF_MACS; 26*61d8658bSDupuis, Chad 27*61d8658bSDupuis, Chad skb = dev_alloc_skb(sizeof(struct fip_vlan)); 28*61d8658bSDupuis, Chad if (!skb) 29*61d8658bSDupuis, Chad return; 30*61d8658bSDupuis, Chad 31*61d8658bSDupuis, Chad fr_len = sizeof(*vlan); 32*61d8658bSDupuis, Chad eth_fr = (char *)skb->data; 33*61d8658bSDupuis, Chad vlan = (struct fip_vlan *)eth_fr; 34*61d8658bSDupuis, Chad 35*61d8658bSDupuis, Chad memset(vlan, 0, sizeof(*vlan)); 36*61d8658bSDupuis, Chad ether_addr_copy(vlan->eth.h_source, qedf->mac); 37*61d8658bSDupuis, Chad ether_addr_copy(vlan->eth.h_dest, my_fcoe_all_fcfs); 38*61d8658bSDupuis, Chad vlan->eth.h_proto = htons(ETH_P_FIP); 39*61d8658bSDupuis, Chad 40*61d8658bSDupuis, Chad vlan->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER); 41*61d8658bSDupuis, Chad vlan->fip.fip_op = htons(FIP_OP_VLAN); 42*61d8658bSDupuis, Chad vlan->fip.fip_subcode = FIP_SC_VL_REQ; 43*61d8658bSDupuis, Chad vlan->fip.fip_dl_len = htons(sizeof(vlan->desc) / FIP_BPW); 44*61d8658bSDupuis, Chad 45*61d8658bSDupuis, Chad vlan->desc.mac.fd_desc.fip_dtype = FIP_DT_MAC; 46*61d8658bSDupuis, Chad vlan->desc.mac.fd_desc.fip_dlen = sizeof(vlan->desc.mac) / FIP_BPW; 47*61d8658bSDupuis, Chad ether_addr_copy(vlan->desc.mac.fd_mac, qedf->mac); 48*61d8658bSDupuis, Chad 49*61d8658bSDupuis, Chad vlan->desc.wwnn.fd_desc.fip_dtype = FIP_DT_NAME; 50*61d8658bSDupuis, Chad vlan->desc.wwnn.fd_desc.fip_dlen = sizeof(vlan->desc.wwnn) / FIP_BPW; 51*61d8658bSDupuis, Chad put_unaligned_be64(qedf->lport->wwnn, &vlan->desc.wwnn.fd_wwn); 52*61d8658bSDupuis, Chad 53*61d8658bSDupuis, Chad skb_put(skb, sizeof(*vlan)); 54*61d8658bSDupuis, Chad skb->protocol = htons(ETH_P_FIP); 55*61d8658bSDupuis, Chad skb_reset_mac_header(skb); 56*61d8658bSDupuis, Chad skb_reset_network_header(skb); 57*61d8658bSDupuis, Chad 58*61d8658bSDupuis, Chad QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "Sending FIP VLAN " 59*61d8658bSDupuis, Chad "request."); 60*61d8658bSDupuis, Chad 61*61d8658bSDupuis, Chad if (atomic_read(&qedf->link_state) != QEDF_LINK_UP) { 62*61d8658bSDupuis, Chad QEDF_WARN(&(qedf->dbg_ctx), "Cannot send vlan request " 63*61d8658bSDupuis, Chad "because link is not up.\n"); 64*61d8658bSDupuis, Chad 65*61d8658bSDupuis, Chad kfree_skb(skb); 66*61d8658bSDupuis, Chad return; 67*61d8658bSDupuis, Chad } 68*61d8658bSDupuis, Chad qed_ops->ll2->start_xmit(qedf->cdev, skb); 69*61d8658bSDupuis, Chad } 70*61d8658bSDupuis, Chad 71*61d8658bSDupuis, Chad static void qedf_fcoe_process_vlan_resp(struct qedf_ctx *qedf, 72*61d8658bSDupuis, Chad struct sk_buff *skb) 73*61d8658bSDupuis, Chad { 74*61d8658bSDupuis, Chad struct fip_header *fiph; 75*61d8658bSDupuis, Chad struct fip_desc *desc; 76*61d8658bSDupuis, Chad u16 vid = 0; 77*61d8658bSDupuis, Chad ssize_t rlen; 78*61d8658bSDupuis, Chad size_t dlen; 79*61d8658bSDupuis, Chad 80*61d8658bSDupuis, Chad fiph = (struct fip_header *)(((void *)skb->data) + 2 * ETH_ALEN + 2); 81*61d8658bSDupuis, Chad 82*61d8658bSDupuis, Chad rlen = ntohs(fiph->fip_dl_len) * 4; 83*61d8658bSDupuis, Chad desc = (struct fip_desc *)(fiph + 1); 84*61d8658bSDupuis, Chad while (rlen > 0) { 85*61d8658bSDupuis, Chad dlen = desc->fip_dlen * FIP_BPW; 86*61d8658bSDupuis, Chad switch (desc->fip_dtype) { 87*61d8658bSDupuis, Chad case FIP_DT_VLAN: 88*61d8658bSDupuis, Chad vid = ntohs(((struct fip_vlan_desc *)desc)->fd_vlan); 89*61d8658bSDupuis, Chad break; 90*61d8658bSDupuis, Chad } 91*61d8658bSDupuis, Chad desc = (struct fip_desc *)((char *)desc + dlen); 92*61d8658bSDupuis, Chad rlen -= dlen; 93*61d8658bSDupuis, Chad } 94*61d8658bSDupuis, Chad 95*61d8658bSDupuis, Chad QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "VLAN response, " 96*61d8658bSDupuis, Chad "vid=0x%x.\n", vid); 97*61d8658bSDupuis, Chad 98*61d8658bSDupuis, Chad if (vid > 0 && qedf->vlan_id != vid) { 99*61d8658bSDupuis, Chad qedf_set_vlan_id(qedf, vid); 100*61d8658bSDupuis, Chad 101*61d8658bSDupuis, Chad /* Inform waiter that it's ok to call fcoe_ctlr_link up() */ 102*61d8658bSDupuis, Chad complete(&qedf->fipvlan_compl); 103*61d8658bSDupuis, Chad } 104*61d8658bSDupuis, Chad } 105*61d8658bSDupuis, Chad 106*61d8658bSDupuis, Chad void qedf_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) 107*61d8658bSDupuis, Chad { 108*61d8658bSDupuis, Chad struct qedf_ctx *qedf = container_of(fip, struct qedf_ctx, ctlr); 109*61d8658bSDupuis, Chad struct ethhdr *eth_hdr; 110*61d8658bSDupuis, Chad struct vlan_ethhdr *vlan_hdr; 111*61d8658bSDupuis, Chad struct fip_header *fiph; 112*61d8658bSDupuis, Chad u16 op, vlan_tci = 0; 113*61d8658bSDupuis, Chad u8 sub; 114*61d8658bSDupuis, Chad 115*61d8658bSDupuis, Chad if (!test_bit(QEDF_LL2_STARTED, &qedf->flags)) { 116*61d8658bSDupuis, Chad QEDF_WARN(&(qedf->dbg_ctx), "LL2 not started\n"); 117*61d8658bSDupuis, Chad kfree_skb(skb); 118*61d8658bSDupuis, Chad return; 119*61d8658bSDupuis, Chad } 120*61d8658bSDupuis, Chad 121*61d8658bSDupuis, Chad fiph = (struct fip_header *) ((void *)skb->data + 2 * ETH_ALEN + 2); 122*61d8658bSDupuis, Chad eth_hdr = (struct ethhdr *)skb_mac_header(skb); 123*61d8658bSDupuis, Chad op = ntohs(fiph->fip_op); 124*61d8658bSDupuis, Chad sub = fiph->fip_subcode; 125*61d8658bSDupuis, Chad 126*61d8658bSDupuis, Chad if (!qedf->vlan_hw_insert) { 127*61d8658bSDupuis, Chad vlan_hdr = (struct vlan_ethhdr *)skb_push(skb, sizeof(*vlan_hdr) 128*61d8658bSDupuis, Chad - sizeof(*eth_hdr)); 129*61d8658bSDupuis, Chad memcpy(vlan_hdr, eth_hdr, 2 * ETH_ALEN); 130*61d8658bSDupuis, Chad vlan_hdr->h_vlan_proto = htons(ETH_P_8021Q); 131*61d8658bSDupuis, Chad vlan_hdr->h_vlan_encapsulated_proto = eth_hdr->h_proto; 132*61d8658bSDupuis, Chad vlan_hdr->h_vlan_TCI = vlan_tci = htons(qedf->vlan_id); 133*61d8658bSDupuis, Chad } 134*61d8658bSDupuis, Chad 135*61d8658bSDupuis, Chad /* Update eth_hdr since we added a VLAN tag */ 136*61d8658bSDupuis, Chad eth_hdr = (struct ethhdr *)skb_mac_header(skb); 137*61d8658bSDupuis, Chad 138*61d8658bSDupuis, Chad QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, "FIP frame send: " 139*61d8658bSDupuis, Chad "dest=%pM op=%x sub=%x vlan=%04x.", eth_hdr->h_dest, op, sub, 140*61d8658bSDupuis, Chad ntohs(vlan_tci)); 141*61d8658bSDupuis, Chad if (qedf_dump_frames) 142*61d8658bSDupuis, Chad print_hex_dump(KERN_WARNING, "fip ", DUMP_PREFIX_OFFSET, 16, 1, 143*61d8658bSDupuis, Chad skb->data, skb->len, false); 144*61d8658bSDupuis, Chad 145*61d8658bSDupuis, Chad qed_ops->ll2->start_xmit(qedf->cdev, skb); 146*61d8658bSDupuis, Chad } 147*61d8658bSDupuis, Chad 148*61d8658bSDupuis, Chad /* Process incoming FIP frames. */ 149*61d8658bSDupuis, Chad void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb) 150*61d8658bSDupuis, Chad { 151*61d8658bSDupuis, Chad struct ethhdr *eth_hdr; 152*61d8658bSDupuis, Chad struct fip_header *fiph; 153*61d8658bSDupuis, Chad struct fip_desc *desc; 154*61d8658bSDupuis, Chad struct fip_mac_desc *mp; 155*61d8658bSDupuis, Chad struct fip_wwn_desc *wp; 156*61d8658bSDupuis, Chad struct fip_vn_desc *vp; 157*61d8658bSDupuis, Chad size_t rlen, dlen; 158*61d8658bSDupuis, Chad uint32_t cvl_port_id; 159*61d8658bSDupuis, Chad __u8 cvl_mac[ETH_ALEN]; 160*61d8658bSDupuis, Chad u16 op; 161*61d8658bSDupuis, Chad u8 sub; 162*61d8658bSDupuis, Chad 163*61d8658bSDupuis, Chad eth_hdr = (struct ethhdr *)skb_mac_header(skb); 164*61d8658bSDupuis, Chad fiph = (struct fip_header *) ((void *)skb->data + 2 * ETH_ALEN + 2); 165*61d8658bSDupuis, Chad op = ntohs(fiph->fip_op); 166*61d8658bSDupuis, Chad sub = fiph->fip_subcode; 167*61d8658bSDupuis, Chad 168*61d8658bSDupuis, Chad QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, "FIP frame received: " 169*61d8658bSDupuis, Chad "skb=%p fiph=%p source=%pM op=%x sub=%x", skb, fiph, 170*61d8658bSDupuis, Chad eth_hdr->h_source, op, sub); 171*61d8658bSDupuis, Chad if (qedf_dump_frames) 172*61d8658bSDupuis, Chad print_hex_dump(KERN_WARNING, "fip ", DUMP_PREFIX_OFFSET, 16, 1, 173*61d8658bSDupuis, Chad skb->data, skb->len, false); 174*61d8658bSDupuis, Chad 175*61d8658bSDupuis, Chad /* Handle FIP VLAN resp in the driver */ 176*61d8658bSDupuis, Chad if (op == FIP_OP_VLAN && sub == FIP_SC_VL_NOTE) { 177*61d8658bSDupuis, Chad qedf_fcoe_process_vlan_resp(qedf, skb); 178*61d8658bSDupuis, Chad qedf->vlan_hw_insert = 0; 179*61d8658bSDupuis, Chad kfree_skb(skb); 180*61d8658bSDupuis, Chad } else if (op == FIP_OP_CTRL && sub == FIP_SC_CLR_VLINK) { 181*61d8658bSDupuis, Chad QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "Clear virtual " 182*61d8658bSDupuis, Chad "link received.\n"); 183*61d8658bSDupuis, Chad 184*61d8658bSDupuis, Chad /* Check that an FCF has been selected by fcoe */ 185*61d8658bSDupuis, Chad if (qedf->ctlr.sel_fcf == NULL) { 186*61d8658bSDupuis, Chad QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, 187*61d8658bSDupuis, Chad "Dropping CVL since FCF has not been selected " 188*61d8658bSDupuis, Chad "yet."); 189*61d8658bSDupuis, Chad return; 190*61d8658bSDupuis, Chad } 191*61d8658bSDupuis, Chad 192*61d8658bSDupuis, Chad cvl_port_id = 0; 193*61d8658bSDupuis, Chad memset(cvl_mac, 0, ETH_ALEN); 194*61d8658bSDupuis, Chad /* 195*61d8658bSDupuis, Chad * We need to loop through the CVL descriptors to determine 196*61d8658bSDupuis, Chad * if we want to reset the fcoe link 197*61d8658bSDupuis, Chad */ 198*61d8658bSDupuis, Chad rlen = ntohs(fiph->fip_dl_len) * FIP_BPW; 199*61d8658bSDupuis, Chad desc = (struct fip_desc *)(fiph + 1); 200*61d8658bSDupuis, Chad while (rlen >= sizeof(*desc)) { 201*61d8658bSDupuis, Chad dlen = desc->fip_dlen * FIP_BPW; 202*61d8658bSDupuis, Chad switch (desc->fip_dtype) { 203*61d8658bSDupuis, Chad case FIP_DT_MAC: 204*61d8658bSDupuis, Chad mp = (struct fip_mac_desc *)desc; 205*61d8658bSDupuis, Chad QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, 206*61d8658bSDupuis, Chad "fd_mac=%pM.\n", __func__, mp->fd_mac); 207*61d8658bSDupuis, Chad ether_addr_copy(cvl_mac, mp->fd_mac); 208*61d8658bSDupuis, Chad break; 209*61d8658bSDupuis, Chad case FIP_DT_NAME: 210*61d8658bSDupuis, Chad wp = (struct fip_wwn_desc *)desc; 211*61d8658bSDupuis, Chad QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, 212*61d8658bSDupuis, Chad "fc_wwpn=%016llx.\n", 213*61d8658bSDupuis, Chad get_unaligned_be64(&wp->fd_wwn)); 214*61d8658bSDupuis, Chad break; 215*61d8658bSDupuis, Chad case FIP_DT_VN_ID: 216*61d8658bSDupuis, Chad vp = (struct fip_vn_desc *)desc; 217*61d8658bSDupuis, Chad QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, 218*61d8658bSDupuis, Chad "fd_fc_id=%x.\n", ntoh24(vp->fd_fc_id)); 219*61d8658bSDupuis, Chad cvl_port_id = ntoh24(vp->fd_fc_id); 220*61d8658bSDupuis, Chad break; 221*61d8658bSDupuis, Chad default: 222*61d8658bSDupuis, Chad /* Ignore anything else */ 223*61d8658bSDupuis, Chad break; 224*61d8658bSDupuis, Chad } 225*61d8658bSDupuis, Chad desc = (struct fip_desc *)((char *)desc + dlen); 226*61d8658bSDupuis, Chad rlen -= dlen; 227*61d8658bSDupuis, Chad } 228*61d8658bSDupuis, Chad 229*61d8658bSDupuis, Chad QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, 230*61d8658bSDupuis, Chad "cvl_port_id=%06x cvl_mac=%pM.\n", cvl_port_id, 231*61d8658bSDupuis, Chad cvl_mac); 232*61d8658bSDupuis, Chad if (cvl_port_id == qedf->lport->port_id && 233*61d8658bSDupuis, Chad ether_addr_equal(cvl_mac, 234*61d8658bSDupuis, Chad qedf->ctlr.sel_fcf->fcf_mac)) { 235*61d8658bSDupuis, Chad fcoe_ctlr_link_down(&qedf->ctlr); 236*61d8658bSDupuis, Chad qedf_wait_for_upload(qedf); 237*61d8658bSDupuis, Chad fcoe_ctlr_link_up(&qedf->ctlr); 238*61d8658bSDupuis, Chad } 239*61d8658bSDupuis, Chad kfree_skb(skb); 240*61d8658bSDupuis, Chad } else { 241*61d8658bSDupuis, Chad /* Everything else is handled by libfcoe */ 242*61d8658bSDupuis, Chad __skb_pull(skb, ETH_HLEN); 243*61d8658bSDupuis, Chad fcoe_ctlr_recv(&qedf->ctlr, skb); 244*61d8658bSDupuis, Chad } 245*61d8658bSDupuis, Chad } 246*61d8658bSDupuis, Chad 247*61d8658bSDupuis, Chad void qedf_update_src_mac(struct fc_lport *lport, u8 *addr) 248*61d8658bSDupuis, Chad { 249*61d8658bSDupuis, Chad struct qedf_ctx *qedf = lport_priv(lport); 250*61d8658bSDupuis, Chad 251*61d8658bSDupuis, Chad QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, 252*61d8658bSDupuis, Chad "Setting data_src_addr=%pM.\n", addr); 253*61d8658bSDupuis, Chad ether_addr_copy(qedf->data_src_addr, addr); 254*61d8658bSDupuis, Chad } 255*61d8658bSDupuis, Chad 256*61d8658bSDupuis, Chad u8 *qedf_get_src_mac(struct fc_lport *lport) 257*61d8658bSDupuis, Chad { 258*61d8658bSDupuis, Chad u8 mac[ETH_ALEN]; 259*61d8658bSDupuis, Chad u8 port_id[3]; 260*61d8658bSDupuis, Chad struct qedf_ctx *qedf = lport_priv(lport); 261*61d8658bSDupuis, Chad 262*61d8658bSDupuis, Chad /* We need to use the lport port_id to create the data_src_addr */ 263*61d8658bSDupuis, Chad if (is_zero_ether_addr(qedf->data_src_addr)) { 264*61d8658bSDupuis, Chad hton24(port_id, lport->port_id); 265*61d8658bSDupuis, Chad fc_fcoe_set_mac(mac, port_id); 266*61d8658bSDupuis, Chad qedf->ctlr.update_mac(lport, mac); 267*61d8658bSDupuis, Chad } 268*61d8658bSDupuis, Chad return qedf->data_src_addr; 269*61d8658bSDupuis, Chad } 270