diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 04f500571d49e99d19283e9481afd787d055a9cb..f2d16127bd0ac34ea962609ff3a354c55fb8f68b 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -238,6 +238,9 @@ void fcoe_netdev_cleanup(struct fcoe_softc *fc)
 	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();
 }
@@ -257,6 +260,7 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)
 	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);
@@ -313,9 +317,23 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)
 	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);
@@ -331,6 +349,8 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)
 	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();
 
 	/*
diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c
index f410f4abb548988cccf68816cdefbc5e78f3e3e0..444a06bdb70b1ef9742d5ca1ab0272cb7a107093 100644
--- a/drivers/scsi/fcoe/libfcoe.c
+++ b/drivers/scsi/fcoe/libfcoe.c
@@ -198,6 +198,8 @@ static void fcoe_ctlr_solicit(struct fcoe_ctlr *fip, struct fcoe_fcf *fcf)
 	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;
@@ -350,6 +352,8 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, int ports, u8 *sa)
 	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;
@@ -413,6 +417,8 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip,
 	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;
@@ -421,8 +427,10 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip,
 	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);
diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h
index 666cc131732ee3cfc7715a6568dabcd57a1e42e2..b2410605b740ed99633992f0d6b2294260c7707b 100644
--- a/include/scsi/libfcoe.h
+++ b/include/scsi/libfcoe.h
@@ -73,6 +73,7 @@ enum fip_state {
  * @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.
@@ -104,6 +105,7 @@ struct fcoe_ctlr {
 	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];