aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c205
1 files changed, 190 insertions, 15 deletions
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index f42459a27b19..9157a9e17c36 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -159,6 +159,9 @@ static struct proc_dir_entry *proc_ipmi_root;
159 */ 159 */
160#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME)) 160#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME))
161 161
162/* How long should we cache dynamic device IDs? */
163#define IPMI_DYN_DEV_ID_EXPIRY (10 * HZ)
164
162/* 165/*
163 * The main "user" data structure. 166 * The main "user" data structure.
164 */ 167 */
@@ -264,8 +267,12 @@ struct ipmi_proc_entry {
264 267
265struct bmc_device { 268struct bmc_device {
266 struct platform_device pdev; 269 struct platform_device pdev;
267 struct ipmi_device_id id;
268 struct list_head intfs; 270 struct list_head intfs;
271 struct ipmi_device_id id;
272 struct ipmi_device_id fetch_id;
273 int dyn_id_set;
274 unsigned long dyn_id_expiry;
275 struct mutex dyn_mutex; /* protects id & dyn* fields */
269 unsigned char guid[16]; 276 unsigned char guid[16];
270 int guid_set; 277 int guid_set;
271 struct kref usecount; 278 struct kref usecount;
@@ -402,6 +409,13 @@ struct ipmi_smi {
402 /* Used for wake ups at startup. */ 409 /* Used for wake ups at startup. */
403 wait_queue_head_t waitq; 410 wait_queue_head_t waitq;
404 411
412 /*
413 * Prevents the interface from being unregistered when the
414 * interface is used by being looked up through the BMC
415 * structure.
416 */
417 struct mutex bmc_reg_mutex;
418
405 struct bmc_device *bmc; 419 struct bmc_device *bmc;
406 bool bmc_registered; 420 bool bmc_registered;
407 struct list_head bmc_link; 421 struct list_head bmc_link;
@@ -491,6 +505,11 @@ struct ipmi_smi {
491 * interface comes in with a NULL user, call this routine with 505 * interface comes in with a NULL user, call this routine with
492 * it. Note that the message will still be freed by the 506 * it. Note that the message will still be freed by the
493 * caller. This only works on the system interface. 507 * caller. This only works on the system interface.
508 *
509 * The only user outside of initialization an panic handling is
510 * the dynamic device id fetching, so no mutex is currently
511 * required on this. If more users come along, some sort of
512 * mutex will be required.
494 */ 513 */
495 void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg); 514 void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg);
496 515
@@ -2081,14 +2100,158 @@ int ipmi_request_supply_msgs(ipmi_user_t user,
2081} 2100}
2082EXPORT_SYMBOL(ipmi_request_supply_msgs); 2101EXPORT_SYMBOL(ipmi_request_supply_msgs);
2083 2102
2103static void bmc_device_id_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
2104{
2105 int rv;
2106
2107 if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2108 || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE)
2109 || (msg->msg.cmd != IPMI_GET_DEVICE_ID_CMD)) {
2110 pr_warn(PFX "invalid device_id msg: addr_type=%d netfn=%x cmd=%x\n",
2111 msg->addr.addr_type, msg->msg.netfn, msg->msg.cmd);
2112 return;
2113 }
2114
2115 rv = ipmi_demangle_device_id(msg->msg.netfn, msg->msg.cmd,
2116 msg->msg.data, msg->msg.data_len, &intf->bmc->fetch_id);
2117 if (rv) {
2118 pr_warn(PFX "device id demangle failed: %d\n", rv);
2119 intf->bmc->dyn_id_set = 0;
2120 } else {
2121 /*
2122 * Make sure the id data is available before setting
2123 * dyn_id_set.
2124 */
2125 smp_wmb();
2126 intf->bmc->dyn_id_set = 1;
2127 }
2128
2129 wake_up(&intf->waitq);
2130}
2131
2132static int
2133send_get_device_id_cmd(ipmi_smi_t intf)
2134{
2135 struct ipmi_system_interface_addr si;
2136 struct kernel_ipmi_msg msg;
2137
2138 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2139 si.channel = IPMI_BMC_CHANNEL;
2140 si.lun = 0;
2141
2142 msg.netfn = IPMI_NETFN_APP_REQUEST;
2143 msg.cmd = IPMI_GET_DEVICE_ID_CMD;
2144 msg.data = NULL;
2145 msg.data_len = 0;
2146
2147 return i_ipmi_request(NULL,
2148 intf,
2149 (struct ipmi_addr *) &si,
2150 0,
2151 &msg,
2152 intf,
2153 NULL,
2154 NULL,
2155 0,
2156 intf->channels[0].address,
2157 intf->channels[0].lun,
2158 -1, 0);
2159}
2160
2161static int __get_device_id(ipmi_smi_t intf, struct bmc_device *bmc)
2162{
2163 int rv;
2164
2165 bmc->dyn_id_set = 2;
2166
2167 intf->null_user_handler = bmc_device_id_handler;
2168
2169 rv = send_get_device_id_cmd(intf);
2170 if (rv)
2171 return rv;
2172
2173 wait_event(intf->waitq, bmc->dyn_id_set != 2);
2174
2175 if (!bmc->dyn_id_set)
2176 rv = -EIO; /* Something went wrong in the fetch. */
2177
2178 /* dyn_id_set makes the id data available. */
2179 smp_rmb();
2180
2181 intf->null_user_handler = NULL;
2182
2183 return rv;
2184}
2185
2186/*
2187 * Fetch the device id for the bmc/interface. You must pass in either
2188 * bmc or intf, this code will get the other one. If the data has
2189 * been recently fetched, this will just use the cached data. Otherwise
2190 * it will run a new fetch.
2191 *
2192 * Except for the first time this is called (in ipmi_register_smi()),
2193 * this will always return good data;
2194 */
2084static int bmc_get_device_id(ipmi_smi_t intf, struct bmc_device *bmc, 2195static int bmc_get_device_id(ipmi_smi_t intf, struct bmc_device *bmc,
2085 struct ipmi_device_id *id) 2196 struct ipmi_device_id *id)
2086{ 2197{
2087 if (!bmc) 2198 int rv = 0;
2199 int prev_dyn_id_set;
2200
2201 if (!intf) {
2202 mutex_lock(&bmc->dyn_mutex);
2203retry_bmc_lock:
2204 if (list_empty(&bmc->intfs)) {
2205 mutex_unlock(&bmc->dyn_mutex);
2206 return -ENOENT;
2207 }
2208 intf = list_first_entry(&bmc->intfs, struct ipmi_smi,
2209 bmc_link);
2210 kref_get(&intf->refcount);
2211 mutex_unlock(&bmc->dyn_mutex);
2212 mutex_lock(&intf->bmc_reg_mutex);
2213 mutex_lock(&bmc->dyn_mutex);
2214 if (intf != list_first_entry(&bmc->intfs, struct ipmi_smi,
2215 bmc_link)) {
2216 mutex_unlock(&intf->bmc_reg_mutex);
2217 kref_put(&intf->refcount, intf_free);
2218 goto retry_bmc_lock;
2219 }
2220 } else {
2221 mutex_lock(&intf->bmc_reg_mutex);
2088 bmc = intf->bmc; 2222 bmc = intf->bmc;
2223 mutex_lock(&bmc->dyn_mutex);
2224 kref_get(&intf->refcount);
2225 }
2089 2226
2090 *id = bmc->id; 2227 /* If we have a valid and current ID, just return that. */
2091 return 0; 2228 if (bmc->dyn_id_set && time_is_after_jiffies(bmc->dyn_id_expiry))
2229 goto out;
2230
2231 prev_dyn_id_set = bmc->dyn_id_set;
2232
2233 rv = __get_device_id(intf, bmc);
2234 if (rv)
2235 goto out;
2236
2237 memcpy(&bmc->id, &bmc->fetch_id, sizeof(bmc->id));
2238
2239 bmc->dyn_id_expiry = jiffies + IPMI_DYN_DEV_ID_EXPIRY;
2240
2241out:
2242 if (rv && prev_dyn_id_set) {
2243 rv = 0; /* Ignore failures if we have previous data. */
2244 bmc->dyn_id_set = prev_dyn_id_set;
2245 }
2246
2247 if (id)
2248 *id = bmc->id;
2249
2250 mutex_unlock(&bmc->dyn_mutex);
2251 mutex_unlock(&intf->bmc_reg_mutex);
2252
2253 kref_put(&intf->refcount, intf_free);
2254 return rv;
2092} 2255}
2093 2256
2094#ifdef CONFIG_PROC_FS 2257#ifdef CONFIG_PROC_FS
@@ -2615,17 +2778,23 @@ static void ipmi_bmc_unregister(ipmi_smi_t intf)
2615 if (!intf->bmc_registered) 2778 if (!intf->bmc_registered)
2616 return; 2779 return;
2617 2780
2781 mutex_lock(&intf->bmc_reg_mutex);
2782
2618 sysfs_remove_link(&intf->si_dev->kobj, "bmc"); 2783 sysfs_remove_link(&intf->si_dev->kobj, "bmc");
2619 sysfs_remove_link(&bmc->pdev.dev.kobj, intf->my_dev_name); 2784 sysfs_remove_link(&bmc->pdev.dev.kobj, intf->my_dev_name);
2620 kfree(intf->my_dev_name); 2785 kfree(intf->my_dev_name);
2621 intf->my_dev_name = NULL; 2786 intf->my_dev_name = NULL;
2622 2787
2623 mutex_lock(&ipmidriver_mutex); 2788 mutex_lock(&bmc->dyn_mutex);
2624 list_del(&intf->bmc_link); 2789 list_del(&intf->bmc_link);
2790 mutex_unlock(&bmc->dyn_mutex);
2625 intf->bmc = NULL; 2791 intf->bmc = NULL;
2792 mutex_lock(&ipmidriver_mutex);
2626 kref_put(&bmc->usecount, cleanup_bmc_device); 2793 kref_put(&bmc->usecount, cleanup_bmc_device);
2627 mutex_unlock(&ipmidriver_mutex); 2794 mutex_unlock(&ipmidriver_mutex);
2628 intf->bmc_registered = false; 2795 intf->bmc_registered = false;
2796
2797 mutex_unlock(&intf->bmc_reg_mutex);
2629} 2798}
2630 2799
2631static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) 2800static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum)
@@ -2653,11 +2822,11 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum)
2653 */ 2822 */
2654 if (old_bmc) { 2823 if (old_bmc) {
2655 kfree(bmc); 2824 kfree(bmc);
2656 mutex_lock(&ipmidriver_mutex); 2825 bmc = old_bmc;
2657 intf->bmc = old_bmc; 2826 intf->bmc = old_bmc;
2827 mutex_lock(&bmc->dyn_mutex);
2658 list_add_tail(&intf->bmc_link, &bmc->intfs); 2828 list_add_tail(&intf->bmc_link, &bmc->intfs);
2659 mutex_unlock(&ipmidriver_mutex); 2829 mutex_unlock(&bmc->dyn_mutex);
2660 bmc = old_bmc;
2661 2830
2662 printk(KERN_INFO 2831 printk(KERN_INFO
2663 "ipmi: interfacing existing BMC (man_id: 0x%6.6x," 2832 "ipmi: interfacing existing BMC (man_id: 0x%6.6x,"
@@ -2677,10 +2846,12 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum)
2677 bmc->pdev.dev.type = &bmc_device_type; 2846 bmc->pdev.dev.type = &bmc_device_type;
2678 kref_init(&bmc->usecount); 2847 kref_init(&bmc->usecount);
2679 2848
2680 rv = platform_device_register(&bmc->pdev); 2849 intf->bmc = bmc;
2681 mutex_lock(&ipmidriver_mutex); 2850 mutex_lock(&bmc->dyn_mutex);
2682 list_add_tail(&intf->bmc_link, &bmc->intfs); 2851 list_add_tail(&intf->bmc_link, &bmc->intfs);
2683 mutex_unlock(&ipmidriver_mutex); 2852 mutex_unlock(&bmc->dyn_mutex);
2853
2854 rv = platform_device_register(&bmc->pdev);
2684 if (rv) { 2855 if (rv) {
2685 printk(KERN_ERR 2856 printk(KERN_ERR
2686 "ipmi_msghandler:" 2857 "ipmi_msghandler:"
@@ -2743,18 +2914,20 @@ out_unlink1:
2743 sysfs_remove_link(&intf->si_dev->kobj, "bmc"); 2914 sysfs_remove_link(&intf->si_dev->kobj, "bmc");
2744 2915
2745out_put_bmc: 2916out_put_bmc:
2746 mutex_lock(&ipmidriver_mutex); 2917 mutex_lock(&bmc->dyn_mutex);
2747 list_del(&intf->bmc_link); 2918 list_del(&intf->bmc_link);
2919 mutex_unlock(&bmc->dyn_mutex);
2748 intf->bmc = NULL; 2920 intf->bmc = NULL;
2921 mutex_lock(&ipmidriver_mutex);
2749 kref_put(&bmc->usecount, cleanup_bmc_device); 2922 kref_put(&bmc->usecount, cleanup_bmc_device);
2750 mutex_unlock(&ipmidriver_mutex); 2923 mutex_unlock(&ipmidriver_mutex);
2751 goto out; 2924 goto out;
2752 2925
2753out_list_del: 2926out_list_del:
2754 mutex_lock(&ipmidriver_mutex); 2927 mutex_lock(&bmc->dyn_mutex);
2755 list_del(&intf->bmc_link); 2928 list_del(&intf->bmc_link);
2929 mutex_unlock(&bmc->dyn_mutex);
2756 intf->bmc = NULL; 2930 intf->bmc = NULL;
2757 mutex_unlock(&ipmidriver_mutex);
2758 put_device(&bmc->pdev.dev); 2931 put_device(&bmc->pdev.dev);
2759 goto out; 2932 goto out;
2760} 2933}
@@ -2976,9 +3149,11 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
2976 return -ENOMEM; 3149 return -ENOMEM;
2977 } 3150 }
2978 INIT_LIST_HEAD(&intf->bmc->intfs); 3151 INIT_LIST_HEAD(&intf->bmc->intfs);
3152 mutex_init(&intf->bmc->dyn_mutex);
3153 INIT_LIST_HEAD(&intf->bmc_link);
3154 mutex_init(&intf->bmc_reg_mutex);
2979 intf->intf_num = -1; /* Mark it invalid for now. */ 3155 intf->intf_num = -1; /* Mark it invalid for now. */
2980 kref_init(&intf->refcount); 3156 kref_init(&intf->refcount);
2981 intf->bmc->id = *device_id;
2982 intf->si_dev = si_dev; 3157 intf->si_dev = si_dev;
2983 for (j = 0; j < IPMI_MAX_CHANNELS; j++) { 3158 for (j = 0; j < IPMI_MAX_CHANNELS; j++) {
2984 intf->channels[j].address = IPMI_BMC_SLAVE_ADDR; 3159 intf->channels[j].address = IPMI_BMC_SLAVE_ADDR;