OSDN Git Service

ipmi: Dynamically fetch GUID periodically
authorCorey Minyard <cminyard@mvista.com>
Fri, 1 Sep 2017 20:30:46 +0000 (15:30 -0500)
committerCorey Minyard <cminyard@mvista.com>
Wed, 27 Sep 2017 21:03:45 +0000 (16:03 -0500)
This will catch if the GUID changes.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
drivers/char/ipmi/ipmi_msghandler.c

index 9a6b048..98318b9 100644 (file)
@@ -274,7 +274,8 @@ struct bmc_device {
        unsigned long          dyn_id_expiry;
        struct mutex           dyn_mutex; /* protects id & dyn* fields */
        u8                     guid[16];
-       int                    guid_set;
+       u8                     fetch_guid[16];
+       int                    dyn_guid_set;
        struct kref            usecount;
 };
 #define to_bmc_device(x) container_of((x), struct bmc_device, pdev.dev)
@@ -538,6 +539,8 @@ struct ipmi_smi {
 };
 #define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev)
 
+static void __get_guid(ipmi_smi_t intf);
+
 /**
  * The driver model view of the IPMI messaging driver.
  */
@@ -2198,7 +2201,7 @@ static int bmc_get_device_id(ipmi_smi_t intf, struct bmc_device *bmc,
                             bool *guid_set, u8 *guid)
 {
        int rv = 0;
-       int prev_dyn_id_set;
+       int prev_dyn_id_set, prev_guid_set;
 
        if (!intf) {
                mutex_lock(&bmc->dyn_mutex);
@@ -2230,8 +2233,19 @@ retry_bmc_lock:
        if (bmc->dyn_id_set && time_is_after_jiffies(bmc->dyn_id_expiry))
                goto out;
 
-       prev_dyn_id_set = bmc->dyn_id_set;
+       prev_guid_set = bmc->dyn_guid_set;
+       __get_guid(intf);
+
+       if (bmc->dyn_guid_set)
+               memcpy(bmc->guid, bmc->fetch_guid, 16);
+       else if (prev_guid_set)
+               /*
+                * The guid used to be valid and it failed to fetch,
+                * just use the cached value.
+                */
+               bmc->dyn_guid_set = prev_guid_set;
 
+       prev_dyn_id_set = bmc->dyn_id_set;
        rv = __get_device_id(intf, bmc);
        if (rv)
                goto out;
@@ -2250,9 +2264,9 @@ out:
                *id = bmc->id;
 
        if (guid_set)
-               *guid_set = bmc->guid_set;
+               *guid_set = bmc->dyn_guid_set;
 
-       if (guid && bmc->guid_set)
+       if (guid && bmc->dyn_guid_set)
                memcpy(guid, bmc->guid, 16);
 
        mutex_unlock(&bmc->dyn_mutex);
@@ -2845,7 +2859,7 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum)
         * representing the interfaced BMC already
         */
        mutex_lock(&ipmidriver_mutex);
-       if (bmc->guid_set)
+       if (bmc->dyn_guid_set)
                old_bmc = ipmi_find_bmc_guid(&ipmidriver.driver, bmc->guid);
        else
                old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver.driver,
@@ -2997,9 +3011,10 @@ send_guid_cmd(ipmi_smi_t intf, int chan)
                              -1, 0);
 }
 
-static void
-guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
+static void guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
 {
+       struct bmc_device *bmc = intf->bmc;
+
        if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
            || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE)
            || (msg->msg.cmd != IPMI_GET_DEVICE_GUID_CMD))
@@ -3008,12 +3023,12 @@ guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
 
        if (msg->msg.data[0] != 0) {
                /* Error from getting the GUID, the BMC doesn't have one. */
-               intf->bmc->guid_set = 0;
+               bmc->dyn_guid_set = 0;
                goto out;
        }
 
        if (msg->msg.data_len < 17) {
-               intf->bmc->guid_set = 0;
+               bmc->dyn_guid_set = 0;
                printk(KERN_WARNING PFX
                       "guid_handler: The GUID response from the BMC was too"
                       " short, it was %d but should have been 17.  Assuming"
@@ -3022,24 +3037,34 @@ guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
                goto out;
        }
 
-       memcpy(intf->bmc->guid, msg->msg.data + 1, 16);
-       intf->bmc->guid_set = 1;
+       memcpy(bmc->fetch_guid, msg->msg.data + 1, 16);
+       /*
+        * Make sure the guid data is available before setting
+        * dyn_guid_set.
+        */
+       smp_wmb();
+       bmc->dyn_guid_set = 1;
  out:
        wake_up(&intf->waitq);
 }
 
-static void
-get_guid(ipmi_smi_t intf)
+static void __get_guid(ipmi_smi_t intf)
 {
        int rv;
+       struct bmc_device *bmc = intf->bmc;
 
-       intf->bmc->guid_set = 0x2;
+       bmc->dyn_guid_set = 2;
        intf->null_user_handler = guid_handler;
        rv = send_guid_cmd(intf, 0);
        if (rv)
                /* Send failed, no GUID available. */
-               intf->bmc->guid_set = 0;
-       wait_event(intf->waitq, intf->bmc->guid_set != 2);
+               bmc->dyn_guid_set = 0;
+
+       wait_event(intf->waitq, bmc->dyn_guid_set != 2);
+
+       /* dyn_guid_set makes the guid data available. */
+       smp_rmb();
+
        intf->null_user_handler = NULL;
 }
 
@@ -3254,8 +3279,6 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
        if (rv)
                goto out;
 
-       get_guid(intf);
-
        rv = bmc_get_device_id(intf, NULL, &id, NULL, NULL);
        if (rv) {
                dev_err(si_dev, "Unable to get the device id: %d\n", rv);