On 06/12/2017 12:35 PM, Thomas Falcon wrote: > The IBM vNIC protocol provides support for the user to initiate > a failover from the client LPAR in case the current backing infrastructure > is deemed inadequate or in an error state. > > Support for two H_VIOCTL sub-commands for vNIC devices are required > to implement this function. These commands are H_GET_SESSION_TOKEN > and H_SESSION_ERR_DETECTED. > > "[H_GET_SESSION_TOKEN] is used to obtain a session token from a VNIC client > adapter. This token is opaque to the caller and is intended to be used in > tandem with the SESSION_ERROR_DETECTED vioctl subfunction." > > "[H_SESSION_ERR_DETECTED] is used to report that the currently active > backing device for a VNIC client adapter is behaving poorly, and that > the hypervisor should attempt to fail over to a different backing device, > if one is available." > > To provide tools access to this functionality the vNIC driver creates a > sysfs file that, when written to, will send a request to pHyp to failover > to a different backing device. > > Signed-off-by: Thomas Falcon <tlfal...@linux.vnet.ibm.com>
Reviewed-by: Nathan Fontenot <nf...@linux.vnet.ibm.com> > --- > arch/powerpc/include/asm/hvcall.h | 2 ++ > drivers/net/ethernet/ibm/ibmvnic.c | 46 > ++++++++++++++++++++++++++++++++++++++ > 2 files changed, 48 insertions(+) > > diff --git a/arch/powerpc/include/asm/hvcall.h > b/arch/powerpc/include/asm/hvcall.h > index d73755f..57d38b5 100644 > --- a/arch/powerpc/include/asm/hvcall.h > +++ b/arch/powerpc/include/asm/hvcall.h > @@ -295,6 +295,8 @@ > #define H_DISABLE_ALL_VIO_INTS 0x0A > #define H_DISABLE_VIO_INTERRUPT 0x0B > #define H_ENABLE_VIO_INTERRUPT 0x0C > +#define H_GET_SESSION_TOKEN 0x19 > +#define H_SESSION_ERR_DETECTED 0x1A > > > /* Platform specific hcalls, used by KVM */ > diff --git a/drivers/net/ethernet/ibm/ibmvnic.c > b/drivers/net/ethernet/ibm/ibmvnic.c > index 7d84e20..fd3ef30 100644 > --- a/drivers/net/ethernet/ibm/ibmvnic.c > +++ b/drivers/net/ethernet/ibm/ibmvnic.c > @@ -3656,6 +3656,8 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter) > return rc; > } > > +static struct device_attribute dev_attr_failover; > + > static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) > { > struct ibmvnic_adapter *adapter; > @@ -3712,9 +3714,16 @@ static int ibmvnic_probe(struct vio_dev *dev, const > struct vio_device_id *id) > > netdev->mtu = adapter->req_mtu - ETH_HLEN; > > + rc = device_create_file(&dev->dev, &dev_attr_failover); > + if (rc) { > + free_netdev(netdev); > + return rc; > + } > + > rc = register_netdev(netdev); > if (rc) { > dev_err(&dev->dev, "failed to register netdev rc=%d\n", rc); > + device_remove_file(&dev->dev, &dev_attr_failover); > free_netdev(netdev); > return rc; > } > @@ -3740,12 +3749,49 @@ static int ibmvnic_remove(struct vio_dev *dev) > adapter->state = VNIC_REMOVED; > > mutex_unlock(&adapter->reset_lock); > + device_remove_file(&dev->dev, &dev_attr_failover); > free_netdev(netdev); > dev_set_drvdata(&dev->dev, NULL); > > return 0; > } > > +static ssize_t failover_store(struct device *dev, struct device_attribute > *attr, > + const char *buf, size_t count) > +{ > + struct net_device *netdev = dev_get_drvdata(dev); > + struct ibmvnic_adapter *adapter = netdev_priv(netdev); > + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; > + __be64 session_token; > + long rc; > + > + if (!sysfs_streq(buf, "1")) > + return -EINVAL; > + > + rc = plpar_hcall(H_VIOCTL, retbuf, adapter->vdev->unit_address, > + H_GET_SESSION_TOKEN, 0, 0, 0); > + if (rc) { > + netdev_err(netdev, "Couldn't retrieve session token, rc %ld\n", > + rc); > + return -EINVAL; > + } > + > + session_token = (__be64)retbuf[0]; > + netdev_dbg(netdev, "Initiating client failover, session id %llx\n", > + be64_to_cpu(session_token)); > + rc = plpar_hcall_norets(H_VIOCTL, adapter->vdev->unit_address, > + H_SESSION_ERR_DETECTED, session_token, 0, 0); > + if (rc) { > + netdev_err(netdev, "Client initiated failover failed, rc %ld\n", > + rc); > + return -EINVAL; > + } > + > + return count; > +} > + > +static DEVICE_ATTR(failover, 0200, NULL, failover_store); > + > static unsigned long ibmvnic_get_desired_dma(struct vio_dev *vdev) > { > struct net_device *netdev = dev_get_drvdata(&vdev->dev); >