if (!is_zero_ether_addr(fc->ctlr.data_src_addr))
                dev_unicast_delete(fc->real_dev,
                                   fc->ctlr.data_src_addr, ETH_ALEN);
+       if (fc->ctlr.spma)
+               dev_unicast_delete(fc->real_dev,
+                                  fc->ctlr.ctl_src_addr, ETH_ALEN);
        dev_mc_delete(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0);
        rtnl_unlock();
 }
        u64 wwnn, wwpn;
        struct fcoe_softc *fc;
        u8 flogi_maddr[ETH_ALEN];
+       struct netdev_hw_addr *ha;
 
        /* Setup lport private data to point to fcoe softc */
        fc = lport_priv(lp);
        skb_queue_head_init(&fc->fcoe_pending_queue);
        fc->fcoe_pending_queue_active = 0;
 
+       /* look for SAN MAC address, if multiple SAN MACs exist, only
+        * use the first one for SPMA */
+       rcu_read_lock();
+       for_each_dev_addr(netdev, ha) {
+               if ((ha->type == NETDEV_HW_ADDR_T_SAN) &&
+                   (is_valid_ether_addr(fc->ctlr.ctl_src_addr))) {
+                       memcpy(fc->ctlr.ctl_src_addr, ha->addr, ETH_ALEN);
+                       fc->ctlr.spma = 1;
+                       break;
+               }
+       }
+       rcu_read_unlock();
+
        /* setup Source Mac Address */
-       memcpy(fc->ctlr.ctl_src_addr, fc->real_dev->dev_addr,
-              fc->real_dev->addr_len);
+       if (!fc->ctlr.spma)
+               memcpy(fc->ctlr.ctl_src_addr, fc->real_dev->dev_addr,
+                      fc->real_dev->addr_len);
 
        wwnn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 1, 0);
        fc_set_wwnn(lp, wwnn);
        rtnl_lock();
        memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN);
        dev_unicast_add(fc->real_dev, flogi_maddr, ETH_ALEN);
+       if (fc->ctlr.spma)
+               dev_unicast_add(fc->real_dev, fc->ctlr.ctl_src_addr, ETH_ALEN);
        rtnl_unlock();
 
        /*
 
        sol->fip.fip_subcode = FIP_SC_SOL;
        sol->fip.fip_dl_len = htons(sizeof(sol->desc) / FIP_BPW);
        sol->fip.fip_flags = htons(FIP_FL_FPMA);
+       if (fip->spma)
+               sol->fip.fip_flags |= htons(FIP_FL_SPMA);
 
        sol->desc.mac.fd_desc.fip_dtype = FIP_DT_MAC;
        sol->desc.mac.fd_desc.fip_dlen = sizeof(sol->desc.mac) / FIP_BPW;
        kal->fip.fip_dl_len = htons((sizeof(kal->mac) +
                                    ports * sizeof(*vn)) / FIP_BPW);
        kal->fip.fip_flags = htons(FIP_FL_FPMA);
+       if (fip->spma)
+               kal->fip.fip_flags |= htons(FIP_FL_SPMA);
 
        kal->mac.fd_desc.fip_dtype = FIP_DT_MAC;
        kal->mac.fd_desc.fip_dlen = sizeof(kal->mac) / FIP_BPW;
        cap->fip.fip_subcode = FIP_SC_REQ;
        cap->fip.fip_dl_len = htons((dlen + sizeof(*mac)) / FIP_BPW);
        cap->fip.fip_flags = htons(FIP_FL_FPMA);
+       if (fip->spma)
+               cap->fip.fip_flags |= htons(FIP_FL_SPMA);
 
        cap->encaps.fd_desc.fip_dtype = dtype;
        cap->encaps.fd_desc.fip_dlen = dlen / FIP_BPW;
        memset(mac, 0, sizeof(mac));
        mac->fd_desc.fip_dtype = FIP_DT_MAC;
        mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW;
-       if (dtype != ELS_FLOGI)
+       if (dtype != FIP_DT_FLOGI)
                memcpy(mac->fd_mac, fip->data_src_addr, ETH_ALEN);
+       else if (fip->spma)
+               memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN);
 
        skb->protocol = htons(ETH_P_802_3);
        skb_reset_mac_header(skb);
 
  * @link:      current link status for libfc.
  * @last_link: last link state reported to libfc.
  * @map_dest:  use the FC_MAP mode for destination MAC addresses.
+ * @spma:      supports SPMA server-provided MACs mode
  * @dest_addr: MAC address of the selected FC forwarder.
  * @ctl_src_addr: the native MAC address of our local port.
  * @data_src_addr: the assigned MAC address for the local port after FLOGI.
        u8 link;
        u8 last_link;
        u8 map_dest;
+       u8 spma;
        u8 dest_addr[ETH_ALEN];
        u8 ctl_src_addr[ETH_ALEN];
        u8 data_src_addr[ETH_ALEN];