s390/qeth: use diag26c to get MAC address on L2

When a s390 guest runs on a z/VM host that's part of a SSI cluster,
it can be migrated to a different host. In this case, the MAC address
it originally obtained on the old host may be re-assigned to a new
guest. This would result in address conflicts between the two guests.

When running as z/VM guest, use the diag26c MAC Service to obtain
a hypervisor-managed MAC address. The MAC Service is SSI-aware, and
won't re-assign the address after the guest is migrated to a new host.

This patch adds support for the z/VM MAC Service on L2 devices.

Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com>
Acked-by: Ursula Braun <ubraun@linux.vnet.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Julian Wiedmann
2017-06-20 16:00:34 +02:00
committed by David S. Miller
parent 1b03047816
commit ec61bd2fd2
3 changed files with 76 additions and 2 deletions

View File

@@ -27,6 +27,9 @@
#include <asm/io.h>
#include <asm/sysinfo.h>
#include <asm/compat.h>
#include <asm/diag.h>
#include <asm/cio.h>
#include <asm/ccwdev.h>
#include "qeth_core.h"
@@ -4773,6 +4776,64 @@ static int qeth_query_card_info(struct qeth_card *card,
(void *)carrier_info);
}
/**
* qeth_vm_request_mac() - Request a hypervisor-managed MAC address
* @card: pointer to a qeth_card
*
* Returns
* 0, if a MAC address has been set for the card's netdevice
* a return code, for various error conditions
*/
int qeth_vm_request_mac(struct qeth_card *card)
{
struct diag26c_mac_resp *response;
struct diag26c_mac_req *request;
struct ccw_dev_id id;
int rc;
QETH_DBF_TEXT(SETUP, 2, "vmreqmac");
if (!card->dev)
return -ENODEV;
request = kzalloc(sizeof(*request), GFP_KERNEL | GFP_DMA);
response = kzalloc(sizeof(*response), GFP_KERNEL | GFP_DMA);
if (!request || !response) {
rc = -ENOMEM;
goto out;
}
ccw_device_get_id(CARD_DDEV(card), &id);
request->resp_buf_len = sizeof(*response);
request->resp_version = DIAG26C_VERSION2;
request->op_code = DIAG26C_GET_MAC;
request->devno = id.devno;
rc = diag26c(request, response, DIAG26C_MAC_SERVICES);
if (rc)
goto out;
if (request->resp_buf_len < sizeof(*response) ||
response->version != request->resp_version) {
rc = -EIO;
QETH_DBF_TEXT(SETUP, 2, "badresp");
QETH_DBF_HEX(SETUP, 2, &request->resp_buf_len,
sizeof(request->resp_buf_len));
} else if (!is_valid_ether_addr(response->mac)) {
rc = -EINVAL;
QETH_DBF_TEXT(SETUP, 2, "badmac");
QETH_DBF_HEX(SETUP, 2, response->mac, ETH_ALEN);
} else {
ether_addr_copy(card->dev->dev_addr, response->mac);
}
out:
kfree(response);
kfree(request);
return rc;
}
EXPORT_SYMBOL_GPL(qeth_vm_request_mac);
static inline int qeth_get_qdio_q_format(struct qeth_card *card)
{
if (card->info.type == QETH_CARD_TYPE_IQD)