]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/scsi/bnx2fc/bnx2fc_fcoe.c
Merge tag 'char-misc-4.13-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregk...
[karo-tx-linux.git] / drivers / scsi / bnx2fc / bnx2fc_fcoe.c
index 902722dc4ce3d0d7d1a38d076458a480bc4197ff..6844ba36161638d995f3d5d5135c160fc54bc9ed 100644 (file)
@@ -4,7 +4,8 @@
  * FIP/FCoE packets, listen to link events etc.
  *
  * Copyright (c) 2008-2013 Broadcom Corporation
- * Copyright (c) 2014-2015 QLogic Corporation
+ * Copyright (c) 2014-2016 QLogic Corporation
+ * Copyright (c) 2016-2017 Cavium Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -351,7 +352,7 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp)
                frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1];
                cp = kmap_atomic(skb_frag_page(frag)) + frag->page_offset;
        } else {
-               cp = (struct fcoe_crc_eof *)skb_put(skb, tlen);
+               cp = skb_put(skb, tlen);
        }
 
        memset(cp, 0, sizeof(*cp));
@@ -522,10 +523,12 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
        struct fcoe_crc_eof crc_eof;
        struct fc_frame *fp;
        struct fc_lport *vn_port;
-       struct fcoe_port *port;
+       struct fcoe_port *port, *phys_port;
        u8 *mac = NULL;
        u8 *dest_mac = NULL;
        struct fcoe_hdr *hp;
+       struct bnx2fc_interface *interface;
+       struct fcoe_ctlr *ctlr;
 
        fr = fcoe_dev_from_skb(skb);
        lport = fr->fr_dev;
@@ -561,8 +564,19 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
                return;
        }
 
+       phys_port = lport_priv(lport);
+       interface = phys_port->priv;
+       ctlr = bnx2fc_to_ctlr(interface);
+
        fh = fc_frame_header_get(fp);
 
+       if (ntoh24(&dest_mac[3]) != ntoh24(fh->fh_d_id)) {
+               BNX2FC_HBA_DBG(lport, "FC frame d_id mismatch with MAC %pM.\n",
+                   dest_mac);
+               kfree_skb(skb);
+               return;
+       }
+
        vn_port = fc_vport_id_lookup(lport, ntoh24(fh->fh_d_id));
        if (vn_port) {
                port = lport_priv(vn_port);
@@ -572,6 +586,14 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
                        return;
                }
        }
+       if (ctlr->state) {
+               if (!ether_addr_equal(mac, ctlr->dest_addr)) {
+                       BNX2FC_HBA_DBG(lport, "Wrong source address: mac:%pM dest_addr:%pM.\n",
+                           mac, ctlr->dest_addr);
+                       kfree_skb(skb);
+                       return;
+               }
+       }
        if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA &&
            fh->fh_type == FC_TYPE_FCP) {
                /* Drop FCP data. We dont this in L2 path */
@@ -597,6 +619,18 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
                return;
        }
 
+       /*
+        * If the destination ID from the frame header does not match what we
+        * have on record for lport and the search for a NPIV port came up
+        * empty then this is not addressed to our port so simply drop it.
+        */
+       if (lport->port_id != ntoh24(fh->fh_d_id) && !vn_port) {
+               BNX2FC_HBA_DBG(lport, "Dropping frame due to destination mismatch: lport->port_id=%x fh->d_id=%x.\n",
+                   lport->port_id, ntoh24(fh->fh_d_id));
+               kfree_skb(skb);
+               return;
+       }
+
        stats = per_cpu_ptr(lport->stats, smp_processor_id());
        stats->RxFrames++;
        stats->RxWords += fr_len / FCOE_WORD_TO_BYTE;
@@ -2105,6 +2139,9 @@ static uint bnx2fc_npiv_create_vports(struct fc_lport *lport,
 {
        struct fc_vport_identifiers vpid;
        uint i, created = 0;
+       u64 wwnn = 0;
+       char wwpn_str[32];
+       char wwnn_str[32];
 
        if (npiv_tbl->count > MAX_NPIV_ENTRIES) {
                BNX2FC_HBA_DBG(lport, "Exceeded count max of npiv table\n");
@@ -2123,11 +2160,23 @@ static uint bnx2fc_npiv_create_vports(struct fc_lport *lport,
        vpid.disable = false;
 
        for (i = 0; i < npiv_tbl->count; i++) {
-               vpid.node_name = wwn_to_u64(npiv_tbl->wwnn[i]);
+               wwnn = wwn_to_u64(npiv_tbl->wwnn[i]);
+               if (wwnn == 0) {
+                       /*
+                        * If we get a 0 element from for the WWNN then assume
+                        * the WWNN should be the same as the physical port.
+                        */
+                       wwnn = lport->wwnn;
+               }
+               vpid.node_name = wwnn;
                vpid.port_name = wwn_to_u64(npiv_tbl->wwpn[i]);
                scnprintf(vpid.symbolic_name, sizeof(vpid.symbolic_name),
                    "NPIV[%u]:%016llx-%016llx",
                    created, vpid.port_name, vpid.node_name);
+               fcoe_wwn_to_str(vpid.node_name, wwnn_str, sizeof(wwnn_str));
+               fcoe_wwn_to_str(vpid.port_name, wwpn_str, sizeof(wwpn_str));
+               BNX2FC_HBA_DBG(lport, "Creating vport %s:%s.\n", wwnn_str,
+                   wwpn_str);
                if (fc_vport_create(lport->host, 0, &vpid))
                        created++;
                else
@@ -2524,6 +2573,11 @@ static void bnx2fc_ulp_exit(struct cnic_dev *dev)
        bnx2fc_hba_destroy(hba);
 }
 
+static void bnx2fc_rport_terminate_io(struct fc_rport *rport)
+{
+       /* This is a no-op */
+}
+
 /**
  * bnx2fc_fcoe_reset - Resets the fcoe
  *
@@ -2570,12 +2624,11 @@ static struct fcoe_transport bnx2fc_transport = {
 };
 
 /**
- * bnx2fc_percpu_thread_create - Create a receive thread for an
- *                              online CPU
+ * bnx2fc_cpu_online - Create a receive thread for an  online CPU
  *
  * @cpu: cpu index for the online cpu
  */
-static void bnx2fc_percpu_thread_create(unsigned int cpu)
+static int bnx2fc_cpu_online(unsigned int cpu)
 {
        struct bnx2fc_percpu_s *p;
        struct task_struct *thread;
@@ -2585,15 +2638,17 @@ static void bnx2fc_percpu_thread_create(unsigned int cpu)
        thread = kthread_create_on_node(bnx2fc_percpu_io_thread,
                                        (void *)p, cpu_to_node(cpu),
                                        "bnx2fc_thread/%d", cpu);
+       if (IS_ERR(thread))
+               return PTR_ERR(thread);
+
        /* bind thread to the cpu */
-       if (likely(!IS_ERR(thread))) {
-               kthread_bind(thread, cpu);
-               p->iothread = thread;
-               wake_up_process(thread);
-       }
+       kthread_bind(thread, cpu);
+       p->iothread = thread;
+       wake_up_process(thread);
+       return 0;
 }
 
-static void bnx2fc_percpu_thread_destroy(unsigned int cpu)
+static int bnx2fc_cpu_offline(unsigned int cpu)
 {
        struct bnx2fc_percpu_s *p;
        struct task_struct *thread;
@@ -2607,7 +2662,6 @@ static void bnx2fc_percpu_thread_destroy(unsigned int cpu)
        thread = p->iothread;
        p->iothread = NULL;
 
-
        /* Free all work in the list */
        list_for_each_entry_safe(work, tmp, &p->work_list, list) {
                list_del_init(&work->list);
@@ -2619,20 +2673,6 @@ static void bnx2fc_percpu_thread_destroy(unsigned int cpu)
 
        if (thread)
                kthread_stop(thread);
-}
-
-
-static int bnx2fc_cpu_online(unsigned int cpu)
-{
-       printk(PFX "CPU %x online: Create Rx thread\n", cpu);
-       bnx2fc_percpu_thread_create(cpu);
-       return 0;
-}
-
-static int bnx2fc_cpu_dead(unsigned int cpu)
-{
-       printk(PFX "CPU %x offline: Remove Rx thread\n", cpu);
-       bnx2fc_percpu_thread_destroy(cpu);
        return 0;
 }
 
@@ -2707,30 +2747,16 @@ static int __init bnx2fc_mod_init(void)
                spin_lock_init(&p->fp_work_lock);
        }
 
-       get_online_cpus();
-
-       for_each_online_cpu(cpu)
-               bnx2fc_percpu_thread_create(cpu);
-
-       rc = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
-                                      "scsi/bnx2fc:online",
-                                      bnx2fc_cpu_online, NULL);
+       rc = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "scsi/bnx2fc:online",
+                              bnx2fc_cpu_online, bnx2fc_cpu_offline);
        if (rc < 0)
-               goto stop_threads;
+               goto stop_thread;
        bnx2fc_online_state = rc;
 
-       cpuhp_setup_state_nocalls(CPUHP_SCSI_BNX2FC_DEAD, "scsi/bnx2fc:dead",
-                                 NULL, bnx2fc_cpu_dead);
-       put_online_cpus();
-
        cnic_register_driver(CNIC_ULP_FCOE, &bnx2fc_cnic_cb);
-
        return 0;
 
-stop_threads:
-       for_each_online_cpu(cpu)
-               bnx2fc_percpu_thread_destroy(cpu);
-       put_online_cpus();
+stop_thread:
        kthread_stop(l2_thread);
 free_wq:
        destroy_workqueue(bnx2fc_wq);
@@ -2749,7 +2775,6 @@ static void __exit bnx2fc_mod_exit(void)
        struct fcoe_percpu_s *bg;
        struct task_struct *l2_thread;
        struct sk_buff *skb;
-       unsigned int cpu = 0;
 
        /*
         * NOTE: Since cnic calls register_driver routine rtnl_lock,
@@ -2790,16 +2815,7 @@ static void __exit bnx2fc_mod_exit(void)
        if (l2_thread)
                kthread_stop(l2_thread);
 
-       get_online_cpus();
-       /* Destroy per cpu threads */
-       for_each_online_cpu(cpu) {
-               bnx2fc_percpu_thread_destroy(cpu);
-       }
-
-       cpuhp_remove_state_nocalls(bnx2fc_online_state);
-       cpuhp_remove_state_nocalls(CPUHP_SCSI_BNX2FC_DEAD);
-
-       put_online_cpus();
+       cpuhp_remove_state(bnx2fc_online_state);
 
        destroy_workqueue(bnx2fc_wq);
        /*
@@ -2860,7 +2876,7 @@ static struct fc_function_template bnx2fc_transport_function = {
 
        .issue_fc_host_lip = bnx2fc_fcoe_reset,
 
-       .terminate_rport_io = fc_rport_terminate_io,
+       .terminate_rport_io = bnx2fc_rport_terminate_io,
 
        .vport_create = bnx2fc_vport_create,
        .vport_delete = bnx2fc_vport_destroy,