diff options
-rw-r--r-- | drivers/char/ipmi/ipmi_devintf.c | 48 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_msghandler.c | 552 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_poweroff.c | 2 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_si_intf.c | 114 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_watchdog.c | 2 | ||||
-rw-r--r-- | include/linux/ipmi.h | 3 | ||||
-rw-r--r-- | include/linux/ipmi_msgdefs.h | 1 | ||||
-rw-r--r-- | include/linux/ipmi_smi.h | 47 |
8 files changed, 712 insertions, 57 deletions
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index 7c0684deea06..932feedda262 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c | |||
@@ -90,7 +90,7 @@ static unsigned int ipmi_poll(struct file *file, poll_table *wait) | |||
90 | 90 | ||
91 | spin_lock_irqsave(&priv->recv_msg_lock, flags); | 91 | spin_lock_irqsave(&priv->recv_msg_lock, flags); |
92 | 92 | ||
93 | if (! list_empty(&(priv->recv_msgs))) | 93 | if (!list_empty(&(priv->recv_msgs))) |
94 | mask |= (POLLIN | POLLRDNORM); | 94 | mask |= (POLLIN | POLLRDNORM); |
95 | 95 | ||
96 | spin_unlock_irqrestore(&priv->recv_msg_lock, flags); | 96 | spin_unlock_irqrestore(&priv->recv_msg_lock, flags); |
@@ -789,21 +789,53 @@ MODULE_PARM_DESC(ipmi_major, "Sets the major number of the IPMI device. By" | |||
789 | " interface. Other values will set the major device number" | 789 | " interface. Other values will set the major device number" |
790 | " to that value."); | 790 | " to that value."); |
791 | 791 | ||
792 | /* Keep track of the devices that are registered. */ | ||
793 | struct ipmi_reg_list { | ||
794 | dev_t dev; | ||
795 | struct list_head link; | ||
796 | }; | ||
797 | static LIST_HEAD(reg_list); | ||
798 | static DEFINE_MUTEX(reg_list_mutex); | ||
799 | |||
792 | static struct class *ipmi_class; | 800 | static struct class *ipmi_class; |
793 | 801 | ||
794 | static void ipmi_new_smi(int if_num) | 802 | static void ipmi_new_smi(int if_num, struct device *device) |
795 | { | 803 | { |
796 | dev_t dev = MKDEV(ipmi_major, if_num); | 804 | dev_t dev = MKDEV(ipmi_major, if_num); |
805 | struct ipmi_reg_list *entry; | ||
797 | 806 | ||
798 | devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, | 807 | devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, |
799 | "ipmidev/%d", if_num); | 808 | "ipmidev/%d", if_num); |
800 | 809 | ||
801 | class_device_create(ipmi_class, NULL, dev, NULL, "ipmi%d", if_num); | 810 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
811 | if (!entry) { | ||
812 | printk(KERN_ERR "ipmi_devintf: Unable to create the" | ||
813 | " ipmi class device link\n"); | ||
814 | return; | ||
815 | } | ||
816 | entry->dev = dev; | ||
817 | |||
818 | mutex_lock(®_list_mutex); | ||
819 | class_device_create(ipmi_class, NULL, dev, device, "ipmi%d", if_num); | ||
820 | list_add(&entry->link, ®_list); | ||
821 | mutex_unlock(®_list_mutex); | ||
802 | } | 822 | } |
803 | 823 | ||
804 | static void ipmi_smi_gone(int if_num) | 824 | static void ipmi_smi_gone(int if_num) |
805 | { | 825 | { |
806 | class_device_destroy(ipmi_class, MKDEV(ipmi_major, if_num)); | 826 | dev_t dev = MKDEV(ipmi_major, if_num); |
827 | struct ipmi_reg_list *entry; | ||
828 | |||
829 | mutex_lock(®_list_mutex); | ||
830 | list_for_each_entry(entry, ®_list, link) { | ||
831 | if (entry->dev == dev) { | ||
832 | list_del(&entry->link); | ||
833 | kfree(entry); | ||
834 | break; | ||
835 | } | ||
836 | } | ||
837 | class_device_destroy(ipmi_class, dev); | ||
838 | mutex_unlock(®_list_mutex); | ||
807 | devfs_remove("ipmidev/%d", if_num); | 839 | devfs_remove("ipmidev/%d", if_num); |
808 | } | 840 | } |
809 | 841 | ||
@@ -856,6 +888,14 @@ module_init(init_ipmi_devintf); | |||
856 | 888 | ||
857 | static __exit void cleanup_ipmi(void) | 889 | static __exit void cleanup_ipmi(void) |
858 | { | 890 | { |
891 | struct ipmi_reg_list *entry, *entry2; | ||
892 | mutex_lock(®_list_mutex); | ||
893 | list_for_each_entry_safe(entry, entry2, ®_list, link) { | ||
894 | list_del(&entry->link); | ||
895 | class_device_destroy(ipmi_class, entry->dev); | ||
896 | kfree(entry); | ||
897 | } | ||
898 | mutex_unlock(®_list_mutex); | ||
859 | class_destroy(ipmi_class); | 899 | class_destroy(ipmi_class); |
860 | ipmi_smi_watcher_unregister(&smi_watcher); | 900 | ipmi_smi_watcher_unregister(&smi_watcher); |
861 | devfs_remove(DEVICE_NAME); | 901 | devfs_remove(DEVICE_NAME); |
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index abd4c5118a1b..f553b7a86841 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c | |||
@@ -162,6 +162,28 @@ struct ipmi_proc_entry | |||
162 | }; | 162 | }; |
163 | #endif | 163 | #endif |
164 | 164 | ||
165 | struct bmc_device | ||
166 | { | ||
167 | struct platform_device *dev; | ||
168 | struct ipmi_device_id id; | ||
169 | unsigned char guid[16]; | ||
170 | int guid_set; | ||
171 | |||
172 | struct kref refcount; | ||
173 | |||
174 | /* bmc device attributes */ | ||
175 | struct device_attribute device_id_attr; | ||
176 | struct device_attribute provides_dev_sdrs_attr; | ||
177 | struct device_attribute revision_attr; | ||
178 | struct device_attribute firmware_rev_attr; | ||
179 | struct device_attribute version_attr; | ||
180 | struct device_attribute add_dev_support_attr; | ||
181 | struct device_attribute manufacturer_id_attr; | ||
182 | struct device_attribute product_id_attr; | ||
183 | struct device_attribute guid_attr; | ||
184 | struct device_attribute aux_firmware_rev_attr; | ||
185 | }; | ||
186 | |||
165 | #define IPMI_IPMB_NUM_SEQ 64 | 187 | #define IPMI_IPMB_NUM_SEQ 64 |
166 | #define IPMI_MAX_CHANNELS 16 | 188 | #define IPMI_MAX_CHANNELS 16 |
167 | struct ipmi_smi | 189 | struct ipmi_smi |
@@ -178,9 +200,8 @@ struct ipmi_smi | |||
178 | /* Used for wake ups at startup. */ | 200 | /* Used for wake ups at startup. */ |
179 | wait_queue_head_t waitq; | 201 | wait_queue_head_t waitq; |
180 | 202 | ||
181 | /* The IPMI version of the BMC on the other end. */ | 203 | struct bmc_device *bmc; |
182 | unsigned char version_major; | 204 | char *my_dev_name; |
183 | unsigned char version_minor; | ||
184 | 205 | ||
185 | /* This is the lower-layer's sender routine. */ | 206 | /* This is the lower-layer's sender routine. */ |
186 | struct ipmi_smi_handlers *handlers; | 207 | struct ipmi_smi_handlers *handlers; |
@@ -194,6 +215,9 @@ struct ipmi_smi | |||
194 | struct ipmi_proc_entry *proc_entries; | 215 | struct ipmi_proc_entry *proc_entries; |
195 | #endif | 216 | #endif |
196 | 217 | ||
218 | /* Driver-model device for the system interface. */ | ||
219 | struct device *si_dev; | ||
220 | |||
197 | /* A table of sequence numbers for this interface. We use the | 221 | /* A table of sequence numbers for this interface. We use the |
198 | sequence numbers for IPMB messages that go out of the | 222 | sequence numbers for IPMB messages that go out of the |
199 | interface to match them up with their responses. A routine | 223 | interface to match them up with their responses. A routine |
@@ -312,6 +336,7 @@ struct ipmi_smi | |||
312 | /* Events that were received with the proper format. */ | 336 | /* Events that were received with the proper format. */ |
313 | unsigned int events; | 337 | unsigned int events; |
314 | }; | 338 | }; |
339 | #define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev) | ||
315 | 340 | ||
316 | /* Used to mark an interface entry that cannot be used but is not a | 341 | /* Used to mark an interface entry that cannot be used but is not a |
317 | * free entry, either, primarily used at creation and deletion time so | 342 | * free entry, either, primarily used at creation and deletion time so |
@@ -320,6 +345,15 @@ struct ipmi_smi | |||
320 | #define IPMI_INVALID_INTERFACE(i) (((i) == NULL) \ | 345 | #define IPMI_INVALID_INTERFACE(i) (((i) == NULL) \ |
321 | || (i == IPMI_INVALID_INTERFACE_ENTRY)) | 346 | || (i == IPMI_INVALID_INTERFACE_ENTRY)) |
322 | 347 | ||
348 | /** | ||
349 | * The driver model view of the IPMI messaging driver. | ||
350 | */ | ||
351 | static struct device_driver ipmidriver = { | ||
352 | .name = "ipmi", | ||
353 | .bus = &platform_bus_type | ||
354 | }; | ||
355 | static DEFINE_MUTEX(ipmidriver_mutex); | ||
356 | |||
323 | #define MAX_IPMI_INTERFACES 4 | 357 | #define MAX_IPMI_INTERFACES 4 |
324 | static ipmi_smi_t ipmi_interfaces[MAX_IPMI_INTERFACES]; | 358 | static ipmi_smi_t ipmi_interfaces[MAX_IPMI_INTERFACES]; |
325 | 359 | ||
@@ -393,7 +427,7 @@ int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher) | |||
393 | if (IPMI_INVALID_INTERFACE(intf)) | 427 | if (IPMI_INVALID_INTERFACE(intf)) |
394 | continue; | 428 | continue; |
395 | spin_unlock_irqrestore(&interfaces_lock, flags); | 429 | spin_unlock_irqrestore(&interfaces_lock, flags); |
396 | watcher->new_smi(i); | 430 | watcher->new_smi(i, intf->si_dev); |
397 | spin_lock_irqsave(&interfaces_lock, flags); | 431 | spin_lock_irqsave(&interfaces_lock, flags); |
398 | } | 432 | } |
399 | spin_unlock_irqrestore(&interfaces_lock, flags); | 433 | spin_unlock_irqrestore(&interfaces_lock, flags); |
@@ -409,14 +443,14 @@ int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher) | |||
409 | } | 443 | } |
410 | 444 | ||
411 | static void | 445 | static void |
412 | call_smi_watchers(int i) | 446 | call_smi_watchers(int i, struct device *dev) |
413 | { | 447 | { |
414 | struct ipmi_smi_watcher *w; | 448 | struct ipmi_smi_watcher *w; |
415 | 449 | ||
416 | down_read(&smi_watchers_sem); | 450 | down_read(&smi_watchers_sem); |
417 | list_for_each_entry(w, &smi_watchers, link) { | 451 | list_for_each_entry(w, &smi_watchers, link) { |
418 | if (try_module_get(w->owner)) { | 452 | if (try_module_get(w->owner)) { |
419 | w->new_smi(i); | 453 | w->new_smi(i, dev); |
420 | module_put(w->owner); | 454 | module_put(w->owner); |
421 | } | 455 | } |
422 | } | 456 | } |
@@ -844,8 +878,8 @@ void ipmi_get_version(ipmi_user_t user, | |||
844 | unsigned char *major, | 878 | unsigned char *major, |
845 | unsigned char *minor) | 879 | unsigned char *minor) |
846 | { | 880 | { |
847 | *major = user->intf->version_major; | 881 | *major = ipmi_version_major(&user->intf->bmc->id); |
848 | *minor = user->intf->version_minor; | 882 | *minor = ipmi_version_minor(&user->intf->bmc->id); |
849 | } | 883 | } |
850 | 884 | ||
851 | int ipmi_set_my_address(ipmi_user_t user, | 885 | int ipmi_set_my_address(ipmi_user_t user, |
@@ -1553,7 +1587,8 @@ static int version_file_read_proc(char *page, char **start, off_t off, | |||
1553 | ipmi_smi_t intf = data; | 1587 | ipmi_smi_t intf = data; |
1554 | 1588 | ||
1555 | return sprintf(out, "%d.%d\n", | 1589 | return sprintf(out, "%d.%d\n", |
1556 | intf->version_major, intf->version_minor); | 1590 | ipmi_version_major(&intf->bmc->id), |
1591 | ipmi_version_minor(&intf->bmc->id)); | ||
1557 | } | 1592 | } |
1558 | 1593 | ||
1559 | static int stat_file_read_proc(char *page, char **start, off_t off, | 1594 | static int stat_file_read_proc(char *page, char **start, off_t off, |
@@ -1712,6 +1747,470 @@ static void remove_proc_entries(ipmi_smi_t smi) | |||
1712 | #endif /* CONFIG_PROC_FS */ | 1747 | #endif /* CONFIG_PROC_FS */ |
1713 | } | 1748 | } |
1714 | 1749 | ||
1750 | static int __find_bmc_guid(struct device *dev, void *data) | ||
1751 | { | ||
1752 | unsigned char *id = data; | ||
1753 | struct bmc_device *bmc = dev_get_drvdata(dev); | ||
1754 | return memcmp(bmc->guid, id, 16) == 0; | ||
1755 | } | ||
1756 | |||
1757 | static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv, | ||
1758 | unsigned char *guid) | ||
1759 | { | ||
1760 | struct device *dev; | ||
1761 | |||
1762 | dev = driver_find_device(drv, NULL, guid, __find_bmc_guid); | ||
1763 | if (dev) | ||
1764 | return dev_get_drvdata(dev); | ||
1765 | else | ||
1766 | return NULL; | ||
1767 | } | ||
1768 | |||
1769 | struct prod_dev_id { | ||
1770 | unsigned int product_id; | ||
1771 | unsigned char device_id; | ||
1772 | }; | ||
1773 | |||
1774 | static int __find_bmc_prod_dev_id(struct device *dev, void *data) | ||
1775 | { | ||
1776 | struct prod_dev_id *id = data; | ||
1777 | struct bmc_device *bmc = dev_get_drvdata(dev); | ||
1778 | |||
1779 | return (bmc->id.product_id == id->product_id | ||
1780 | && bmc->id.product_id == id->product_id | ||
1781 | && bmc->id.device_id == id->device_id); | ||
1782 | } | ||
1783 | |||
1784 | static struct bmc_device *ipmi_find_bmc_prod_dev_id( | ||
1785 | struct device_driver *drv, | ||
1786 | unsigned char product_id, unsigned char device_id) | ||
1787 | { | ||
1788 | struct prod_dev_id id = { | ||
1789 | .product_id = product_id, | ||
1790 | .device_id = device_id, | ||
1791 | }; | ||
1792 | struct device *dev; | ||
1793 | |||
1794 | dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id); | ||
1795 | if (dev) | ||
1796 | return dev_get_drvdata(dev); | ||
1797 | else | ||
1798 | return NULL; | ||
1799 | } | ||
1800 | |||
1801 | static ssize_t device_id_show(struct device *dev, | ||
1802 | struct device_attribute *attr, | ||
1803 | char *buf) | ||
1804 | { | ||
1805 | struct bmc_device *bmc = dev_get_drvdata(dev); | ||
1806 | |||
1807 | return snprintf(buf, 10, "%u\n", bmc->id.device_id); | ||
1808 | } | ||
1809 | |||
1810 | static ssize_t provides_dev_sdrs_show(struct device *dev, | ||
1811 | struct device_attribute *attr, | ||
1812 | char *buf) | ||
1813 | { | ||
1814 | struct bmc_device *bmc = dev_get_drvdata(dev); | ||
1815 | |||
1816 | return snprintf(buf, 10, "%u\n", | ||
1817 | bmc->id.device_revision && 0x80 >> 7); | ||
1818 | } | ||
1819 | |||
1820 | static ssize_t revision_show(struct device *dev, struct device_attribute *attr, | ||
1821 | char *buf) | ||
1822 | { | ||
1823 | struct bmc_device *bmc = dev_get_drvdata(dev); | ||
1824 | |||
1825 | return snprintf(buf, 20, "%u\n", | ||
1826 | bmc->id.device_revision && 0x0F); | ||
1827 | } | ||
1828 | |||
1829 | static ssize_t firmware_rev_show(struct device *dev, | ||
1830 | struct device_attribute *attr, | ||
1831 | char *buf) | ||
1832 | { | ||
1833 | struct bmc_device *bmc = dev_get_drvdata(dev); | ||
1834 | |||
1835 | return snprintf(buf, 20, "%u.%x\n", bmc->id.firmware_revision_1, | ||
1836 | bmc->id.firmware_revision_2); | ||
1837 | } | ||
1838 | |||
1839 | static ssize_t ipmi_version_show(struct device *dev, | ||
1840 | struct device_attribute *attr, | ||
1841 | char *buf) | ||
1842 | { | ||
1843 | struct bmc_device *bmc = dev_get_drvdata(dev); | ||
1844 | |||
1845 | return snprintf(buf, 20, "%u.%u\n", | ||
1846 | ipmi_version_major(&bmc->id), | ||
1847 | ipmi_version_minor(&bmc->id)); | ||
1848 | } | ||
1849 | |||
1850 | static ssize_t add_dev_support_show(struct device *dev, | ||
1851 | struct device_attribute *attr, | ||
1852 | char *buf) | ||
1853 | { | ||
1854 | struct bmc_device *bmc = dev_get_drvdata(dev); | ||
1855 | |||
1856 | return snprintf(buf, 10, "0x%02x\n", | ||
1857 | bmc->id.additional_device_support); | ||
1858 | } | ||
1859 | |||
1860 | static ssize_t manufacturer_id_show(struct device *dev, | ||
1861 | struct device_attribute *attr, | ||
1862 | char *buf) | ||
1863 | { | ||
1864 | struct bmc_device *bmc = dev_get_drvdata(dev); | ||
1865 | |||
1866 | return snprintf(buf, 20, "0x%6.6x\n", bmc->id.manufacturer_id); | ||
1867 | } | ||
1868 | |||
1869 | static ssize_t product_id_show(struct device *dev, | ||
1870 | struct device_attribute *attr, | ||
1871 | char *buf) | ||
1872 | { | ||
1873 | struct bmc_device *bmc = dev_get_drvdata(dev); | ||
1874 | |||
1875 | return snprintf(buf, 10, "0x%4.4x\n", bmc->id.product_id); | ||
1876 | } | ||
1877 | |||
1878 | static ssize_t aux_firmware_rev_show(struct device *dev, | ||
1879 | struct device_attribute *attr, | ||
1880 | char *buf) | ||
1881 | { | ||
1882 | struct bmc_device *bmc = dev_get_drvdata(dev); | ||
1883 | |||
1884 | return snprintf(buf, 21, "0x%02x 0x%02x 0x%02x 0x%02x\n", | ||
1885 | bmc->id.aux_firmware_revision[3], | ||
1886 | bmc->id.aux_firmware_revision[2], | ||
1887 | bmc->id.aux_firmware_revision[1], | ||
1888 | bmc->id.aux_firmware_revision[0]); | ||
1889 | } | ||
1890 | |||
1891 | static ssize_t guid_show(struct device *dev, struct device_attribute *attr, | ||
1892 | char *buf) | ||
1893 | { | ||
1894 | struct bmc_device *bmc = dev_get_drvdata(dev); | ||
1895 | |||
1896 | return snprintf(buf, 100, "%Lx%Lx\n", | ||
1897 | (long long) bmc->guid[0], | ||
1898 | (long long) bmc->guid[8]); | ||
1899 | } | ||
1900 | |||
1901 | static void | ||
1902 | cleanup_bmc_device(struct kref *ref) | ||
1903 | { | ||
1904 | struct bmc_device *bmc; | ||
1905 | |||
1906 | bmc = container_of(ref, struct bmc_device, refcount); | ||
1907 | |||
1908 | device_remove_file(&bmc->dev->dev, | ||
1909 | &bmc->device_id_attr); | ||
1910 | device_remove_file(&bmc->dev->dev, | ||
1911 | &bmc->provides_dev_sdrs_attr); | ||
1912 | device_remove_file(&bmc->dev->dev, | ||
1913 | &bmc->revision_attr); | ||
1914 | device_remove_file(&bmc->dev->dev, | ||
1915 | &bmc->firmware_rev_attr); | ||
1916 | device_remove_file(&bmc->dev->dev, | ||
1917 | &bmc->version_attr); | ||
1918 | device_remove_file(&bmc->dev->dev, | ||
1919 | &bmc->add_dev_support_attr); | ||
1920 | device_remove_file(&bmc->dev->dev, | ||
1921 | &bmc->manufacturer_id_attr); | ||
1922 | device_remove_file(&bmc->dev->dev, | ||
1923 | &bmc->product_id_attr); | ||
1924 | if (bmc->id.aux_firmware_revision_set) | ||
1925 | device_remove_file(&bmc->dev->dev, | ||
1926 | &bmc->aux_firmware_rev_attr); | ||
1927 | if (bmc->guid_set) | ||
1928 | device_remove_file(&bmc->dev->dev, | ||
1929 | &bmc->guid_attr); | ||
1930 | platform_device_unregister(bmc->dev); | ||
1931 | kfree(bmc); | ||
1932 | } | ||
1933 | |||
1934 | static void ipmi_bmc_unregister(ipmi_smi_t intf) | ||
1935 | { | ||
1936 | struct bmc_device *bmc = intf->bmc; | ||
1937 | |||
1938 | sysfs_remove_link(&intf->si_dev->kobj, "bmc"); | ||
1939 | if (intf->my_dev_name) { | ||
1940 | sysfs_remove_link(&bmc->dev->dev.kobj, intf->my_dev_name); | ||
1941 | kfree(intf->my_dev_name); | ||
1942 | intf->my_dev_name = NULL; | ||
1943 | } | ||
1944 | |||
1945 | mutex_lock(&ipmidriver_mutex); | ||
1946 | kref_put(&bmc->refcount, cleanup_bmc_device); | ||
1947 | mutex_unlock(&ipmidriver_mutex); | ||
1948 | } | ||
1949 | |||
1950 | static int ipmi_bmc_register(ipmi_smi_t intf) | ||
1951 | { | ||
1952 | int rv; | ||
1953 | struct bmc_device *bmc = intf->bmc; | ||
1954 | struct bmc_device *old_bmc; | ||
1955 | int size; | ||
1956 | char dummy[1]; | ||
1957 | |||
1958 | mutex_lock(&ipmidriver_mutex); | ||
1959 | |||
1960 | /* | ||
1961 | * Try to find if there is an bmc_device struct | ||
1962 | * representing the interfaced BMC already | ||
1963 | */ | ||
1964 | if (bmc->guid_set) | ||
1965 | old_bmc = ipmi_find_bmc_guid(&ipmidriver, bmc->guid); | ||
1966 | else | ||
1967 | old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver, | ||
1968 | bmc->id.product_id, | ||
1969 | bmc->id.device_id); | ||
1970 | |||
1971 | /* | ||
1972 | * If there is already an bmc_device, free the new one, | ||
1973 | * otherwise register the new BMC device | ||
1974 | */ | ||
1975 | if (old_bmc) { | ||
1976 | kfree(bmc); | ||
1977 | intf->bmc = old_bmc; | ||
1978 | bmc = old_bmc; | ||
1979 | |||
1980 | kref_get(&bmc->refcount); | ||
1981 | mutex_unlock(&ipmidriver_mutex); | ||
1982 | |||
1983 | printk(KERN_INFO | ||
1984 | "ipmi: interfacing existing BMC (man_id: 0x%6.6x," | ||
1985 | " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n", | ||
1986 | bmc->id.manufacturer_id, | ||
1987 | bmc->id.product_id, | ||
1988 | bmc->id.device_id); | ||
1989 | } else { | ||
1990 | bmc->dev = platform_device_alloc("ipmi_bmc", | ||
1991 | bmc->id.device_id); | ||
1992 | if (! bmc->dev) { | ||
1993 | printk(KERN_ERR | ||
1994 | "ipmi_msghandler:" | ||
1995 | " Unable to allocate platform device\n"); | ||
1996 | return -ENOMEM; | ||
1997 | } | ||
1998 | bmc->dev->dev.driver = &ipmidriver; | ||
1999 | dev_set_drvdata(&bmc->dev->dev, bmc); | ||
2000 | kref_init(&bmc->refcount); | ||
2001 | |||
2002 | rv = platform_device_register(bmc->dev); | ||
2003 | mutex_unlock(&ipmidriver_mutex); | ||
2004 | if (rv) { | ||
2005 | printk(KERN_ERR | ||
2006 | "ipmi_msghandler:" | ||
2007 | " Unable to register bmc device: %d\n", | ||
2008 | rv); | ||
2009 | /* Don't go to out_err, you can only do that if | ||
2010 | the device is registered already. */ | ||
2011 | return rv; | ||
2012 | } | ||
2013 | |||
2014 | bmc->device_id_attr.attr.name = "device_id"; | ||
2015 | bmc->device_id_attr.attr.owner = THIS_MODULE; | ||
2016 | bmc->device_id_attr.attr.mode = S_IRUGO; | ||
2017 | bmc->device_id_attr.show = device_id_show; | ||
2018 | |||
2019 | bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs"; | ||
2020 | bmc->provides_dev_sdrs_attr.attr.owner = THIS_MODULE; | ||
2021 | bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO; | ||
2022 | bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show; | ||
2023 | |||
2024 | |||
2025 | bmc->revision_attr.attr.name = "revision"; | ||
2026 | bmc->revision_attr.attr.owner = THIS_MODULE; | ||
2027 | bmc->revision_attr.attr.mode = S_IRUGO; | ||
2028 | bmc->revision_attr.show = revision_show; | ||
2029 | |||
2030 | bmc->firmware_rev_attr.attr.name = "firmware_revision"; | ||
2031 | bmc->firmware_rev_attr.attr.owner = THIS_MODULE; | ||
2032 | bmc->firmware_rev_attr.attr.mode = S_IRUGO; | ||
2033 | bmc->firmware_rev_attr.show = firmware_rev_show; | ||
2034 | |||
2035 | bmc->version_attr.attr.name = "ipmi_version"; | ||
2036 | bmc->version_attr.attr.owner = THIS_MODULE; | ||
2037 | bmc->version_attr.attr.mode = S_IRUGO; | ||
2038 | bmc->version_attr.show = ipmi_version_show; | ||
2039 | |||
2040 | bmc->add_dev_support_attr.attr.name | ||
2041 | = "additional_device_support"; | ||
2042 | bmc->add_dev_support_attr.attr.owner = THIS_MODULE; | ||
2043 | bmc->add_dev_support_attr.attr.mode = S_IRUGO; | ||
2044 | bmc->add_dev_support_attr.show = add_dev_support_show; | ||
2045 | |||
2046 | bmc->manufacturer_id_attr.attr.name = "manufacturer_id"; | ||
2047 | bmc->manufacturer_id_attr.attr.owner = THIS_MODULE; | ||
2048 | bmc->manufacturer_id_attr.attr.mode = S_IRUGO; | ||
2049 | bmc->manufacturer_id_attr.show = manufacturer_id_show; | ||
2050 | |||
2051 | bmc->product_id_attr.attr.name = "product_id"; | ||
2052 | bmc->product_id_attr.attr.owner = THIS_MODULE; | ||
2053 | bmc->product_id_attr.attr.mode = S_IRUGO; | ||
2054 | bmc->product_id_attr.show = product_id_show; | ||
2055 | |||
2056 | bmc->guid_attr.attr.name = "guid"; | ||
2057 | bmc->guid_attr.attr.owner = THIS_MODULE; | ||
2058 | bmc->guid_attr.attr.mode = S_IRUGO; | ||
2059 | bmc->guid_attr.show = guid_show; | ||
2060 | |||
2061 | bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision"; | ||
2062 | bmc->aux_firmware_rev_attr.attr.owner = THIS_MODULE; | ||
2063 | bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO; | ||
2064 | bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show; | ||
2065 | |||
2066 | device_create_file(&bmc->dev->dev, | ||
2067 | &bmc->device_id_attr); | ||
2068 | device_create_file(&bmc->dev->dev, | ||
2069 | &bmc->provides_dev_sdrs_attr); | ||
2070 | device_create_file(&bmc->dev->dev, | ||
2071 | &bmc->revision_attr); | ||
2072 | device_create_file(&bmc->dev->dev, | ||
2073 | &bmc->firmware_rev_attr); | ||
2074 | device_create_file(&bmc->dev->dev, | ||
2075 | &bmc->version_attr); | ||
2076 | device_create_file(&bmc->dev->dev, | ||
2077 | &bmc->add_dev_support_attr); | ||
2078 | device_create_file(&bmc->dev->dev, | ||
2079 | &bmc->manufacturer_id_attr); | ||
2080 | device_create_file(&bmc->dev->dev, | ||
2081 | &bmc->product_id_attr); | ||
2082 | if (bmc->id.aux_firmware_revision_set) | ||
2083 | device_create_file(&bmc->dev->dev, | ||
2084 | &bmc->aux_firmware_rev_attr); | ||
2085 | if (bmc->guid_set) | ||
2086 | device_create_file(&bmc->dev->dev, | ||
2087 | &bmc->guid_attr); | ||
2088 | |||
2089 | printk(KERN_INFO | ||
2090 | "ipmi: Found new BMC (man_id: 0x%6.6x, " | ||
2091 | " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n", | ||
2092 | bmc->id.manufacturer_id, | ||
2093 | bmc->id.product_id, | ||
2094 | bmc->id.device_id); | ||
2095 | } | ||
2096 | |||
2097 | /* | ||
2098 | * create symlink from system interface device to bmc device | ||
2099 | * and back. | ||
2100 | */ | ||
2101 | rv = sysfs_create_link(&intf->si_dev->kobj, | ||
2102 | &bmc->dev->dev.kobj, "bmc"); | ||
2103 | if (rv) { | ||
2104 | printk(KERN_ERR | ||
2105 | "ipmi_msghandler: Unable to create bmc symlink: %d\n", | ||
2106 | rv); | ||
2107 | goto out_err; | ||
2108 | } | ||
2109 | |||
2110 | size = snprintf(dummy, 0, "ipmi%d", intf->intf_num); | ||
2111 | intf->my_dev_name = kmalloc(size+1, GFP_KERNEL); | ||
2112 | if (!intf->my_dev_name) { | ||
2113 | rv = -ENOMEM; | ||
2114 | printk(KERN_ERR | ||
2115 | "ipmi_msghandler: allocate link from BMC: %d\n", | ||
2116 | rv); | ||
2117 | goto out_err; | ||
2118 | } | ||
2119 | snprintf(intf->my_dev_name, size+1, "ipmi%d", intf->intf_num); | ||
2120 | |||
2121 | rv = sysfs_create_link(&bmc->dev->dev.kobj, &intf->si_dev->kobj, | ||
2122 | intf->my_dev_name); | ||
2123 | if (rv) { | ||
2124 | kfree(intf->my_dev_name); | ||
2125 | intf->my_dev_name = NULL; | ||
2126 | printk(KERN_ERR | ||
2127 | "ipmi_msghandler:" | ||
2128 | " Unable to create symlink to bmc: %d\n", | ||
2129 | rv); | ||
2130 | goto out_err; | ||
2131 | } | ||
2132 | |||
2133 | return 0; | ||
2134 | |||
2135 | out_err: | ||
2136 | ipmi_bmc_unregister(intf); | ||
2137 | return rv; | ||
2138 | } | ||
2139 | |||
2140 | static int | ||
2141 | send_guid_cmd(ipmi_smi_t intf, int chan) | ||
2142 | { | ||
2143 | struct kernel_ipmi_msg msg; | ||
2144 | struct ipmi_system_interface_addr si; | ||
2145 | |||
2146 | si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; | ||
2147 | si.channel = IPMI_BMC_CHANNEL; | ||
2148 | si.lun = 0; | ||
2149 | |||
2150 | msg.netfn = IPMI_NETFN_APP_REQUEST; | ||
2151 | msg.cmd = IPMI_GET_DEVICE_GUID_CMD; | ||
2152 | msg.data = NULL; | ||
2153 | msg.data_len = 0; | ||
2154 | return i_ipmi_request(NULL, | ||
2155 | intf, | ||
2156 | (struct ipmi_addr *) &si, | ||
2157 | 0, | ||
2158 | &msg, | ||
2159 | intf, | ||
2160 | NULL, | ||
2161 | NULL, | ||
2162 | 0, | ||
2163 | intf->channels[0].address, | ||
2164 | intf->channels[0].lun, | ||
2165 | -1, 0); | ||
2166 | } | ||
2167 | |||
2168 | static void | ||
2169 | guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) | ||
2170 | { | ||
2171 | if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE) | ||
2172 | || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE) | ||
2173 | || (msg->msg.cmd != IPMI_GET_DEVICE_GUID_CMD)) | ||
2174 | /* Not for me */ | ||
2175 | return; | ||
2176 | |||
2177 | if (msg->msg.data[0] != 0) { | ||
2178 | /* Error from getting the GUID, the BMC doesn't have one. */ | ||
2179 | intf->bmc->guid_set = 0; | ||
2180 | goto out; | ||
2181 | } | ||
2182 | |||
2183 | if (msg->msg.data_len < 17) { | ||
2184 | intf->bmc->guid_set = 0; | ||
2185 | printk(KERN_WARNING PFX | ||
2186 | "guid_handler: The GUID response from the BMC was too" | ||
2187 | " short, it was %d but should have been 17. Assuming" | ||
2188 | " GUID is not available.\n", | ||
2189 | msg->msg.data_len); | ||
2190 | goto out; | ||
2191 | } | ||
2192 | |||
2193 | memcpy(intf->bmc->guid, msg->msg.data, 16); | ||
2194 | intf->bmc->guid_set = 1; | ||
2195 | out: | ||
2196 | wake_up(&intf->waitq); | ||
2197 | } | ||
2198 | |||
2199 | static void | ||
2200 | get_guid(ipmi_smi_t intf) | ||
2201 | { | ||
2202 | int rv; | ||
2203 | |||
2204 | intf->bmc->guid_set = 0x2; | ||
2205 | intf->null_user_handler = guid_handler; | ||
2206 | rv = send_guid_cmd(intf, 0); | ||
2207 | if (rv) | ||
2208 | /* Send failed, no GUID available. */ | ||
2209 | intf->bmc->guid_set = 0; | ||
2210 | wait_event(intf->waitq, intf->bmc->guid_set != 2); | ||
2211 | intf->null_user_handler = NULL; | ||
2212 | } | ||
2213 | |||
1715 | static int | 2214 | static int |
1716 | send_channel_info_cmd(ipmi_smi_t intf, int chan) | 2215 | send_channel_info_cmd(ipmi_smi_t intf, int chan) |
1717 | { | 2216 | { |
@@ -1804,8 +2303,8 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) | |||
1804 | 2303 | ||
1805 | int ipmi_register_smi(struct ipmi_smi_handlers *handlers, | 2304 | int ipmi_register_smi(struct ipmi_smi_handlers *handlers, |
1806 | void *send_info, | 2305 | void *send_info, |
1807 | unsigned char version_major, | 2306 | struct ipmi_device_id *device_id, |
1808 | unsigned char version_minor, | 2307 | struct device *si_dev, |
1809 | unsigned char slave_addr, | 2308 | unsigned char slave_addr, |
1810 | ipmi_smi_t *new_intf) | 2309 | ipmi_smi_t *new_intf) |
1811 | { | 2310 | { |
@@ -1813,7 +2312,11 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, | |||
1813 | int rv; | 2312 | int rv; |
1814 | ipmi_smi_t intf; | 2313 | ipmi_smi_t intf; |
1815 | unsigned long flags; | 2314 | unsigned long flags; |
2315 | int version_major; | ||
2316 | int version_minor; | ||
1816 | 2317 | ||
2318 | version_major = ipmi_version_major(device_id); | ||
2319 | version_minor = ipmi_version_minor(device_id); | ||
1817 | 2320 | ||
1818 | /* Make sure the driver is actually initialized, this handles | 2321 | /* Make sure the driver is actually initialized, this handles |
1819 | problems with initialization order. */ | 2322 | problems with initialization order. */ |
@@ -1831,10 +2334,15 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, | |||
1831 | if (!intf) | 2334 | if (!intf) |
1832 | return -ENOMEM; | 2335 | return -ENOMEM; |
1833 | memset(intf, 0, sizeof(*intf)); | 2336 | memset(intf, 0, sizeof(*intf)); |
2337 | intf->bmc = kzalloc(sizeof(*intf->bmc), GFP_KERNEL); | ||
2338 | if (!intf->bmc) { | ||
2339 | kfree(intf); | ||
2340 | return -ENOMEM; | ||
2341 | } | ||
1834 | intf->intf_num = -1; | 2342 | intf->intf_num = -1; |
1835 | kref_init(&intf->refcount); | 2343 | kref_init(&intf->refcount); |
1836 | intf->version_major = version_major; | 2344 | intf->bmc->id = *device_id; |
1837 | intf->version_minor = version_minor; | 2345 | intf->si_dev = si_dev; |
1838 | for (j = 0; j < IPMI_MAX_CHANNELS; j++) { | 2346 | for (j = 0; j < IPMI_MAX_CHANNELS; j++) { |
1839 | intf->channels[j].address = IPMI_BMC_SLAVE_ADDR; | 2347 | intf->channels[j].address = IPMI_BMC_SLAVE_ADDR; |
1840 | intf->channels[j].lun = 2; | 2348 | intf->channels[j].lun = 2; |
@@ -1884,6 +2392,8 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, | |||
1884 | caller before sending any messages with it. */ | 2392 | caller before sending any messages with it. */ |
1885 | *new_intf = intf; | 2393 | *new_intf = intf; |
1886 | 2394 | ||
2395 | get_guid(intf); | ||
2396 | |||
1887 | if ((version_major > 1) | 2397 | if ((version_major > 1) |
1888 | || ((version_major == 1) && (version_minor >= 5))) | 2398 | || ((version_major == 1) && (version_minor >= 5))) |
1889 | { | 2399 | { |
@@ -1898,6 +2408,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, | |||
1898 | /* Wait for the channel info to be read. */ | 2408 | /* Wait for the channel info to be read. */ |
1899 | wait_event(intf->waitq, | 2409 | wait_event(intf->waitq, |
1900 | intf->curr_channel >= IPMI_MAX_CHANNELS); | 2410 | intf->curr_channel >= IPMI_MAX_CHANNELS); |
2411 | intf->null_user_handler = NULL; | ||
1901 | } else { | 2412 | } else { |
1902 | /* Assume a single IPMB channel at zero. */ | 2413 | /* Assume a single IPMB channel at zero. */ |
1903 | intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB; | 2414 | intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB; |
@@ -1907,6 +2418,8 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, | |||
1907 | if (rv == 0) | 2418 | if (rv == 0) |
1908 | rv = add_proc_entries(intf, i); | 2419 | rv = add_proc_entries(intf, i); |
1909 | 2420 | ||
2421 | rv = ipmi_bmc_register(intf); | ||
2422 | |||
1910 | out: | 2423 | out: |
1911 | if (rv) { | 2424 | if (rv) { |
1912 | if (intf->proc_dir) | 2425 | if (intf->proc_dir) |
@@ -1921,7 +2434,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, | |||
1921 | spin_lock_irqsave(&interfaces_lock, flags); | 2434 | spin_lock_irqsave(&interfaces_lock, flags); |
1922 | ipmi_interfaces[i] = intf; | 2435 | ipmi_interfaces[i] = intf; |
1923 | spin_unlock_irqrestore(&interfaces_lock, flags); | 2436 | spin_unlock_irqrestore(&interfaces_lock, flags); |
1924 | call_smi_watchers(i); | 2437 | call_smi_watchers(i, intf->si_dev); |
1925 | } | 2438 | } |
1926 | 2439 | ||
1927 | return rv; | 2440 | return rv; |
@@ -1933,6 +2446,8 @@ int ipmi_unregister_smi(ipmi_smi_t intf) | |||
1933 | struct ipmi_smi_watcher *w; | 2446 | struct ipmi_smi_watcher *w; |
1934 | unsigned long flags; | 2447 | unsigned long flags; |
1935 | 2448 | ||
2449 | ipmi_bmc_unregister(intf); | ||
2450 | |||
1936 | spin_lock_irqsave(&interfaces_lock, flags); | 2451 | spin_lock_irqsave(&interfaces_lock, flags); |
1937 | for (i = 0; i < MAX_IPMI_INTERFACES; i++) { | 2452 | for (i = 0; i < MAX_IPMI_INTERFACES; i++) { |
1938 | if (ipmi_interfaces[i] == intf) { | 2453 | if (ipmi_interfaces[i] == intf) { |
@@ -3196,10 +3711,17 @@ static struct notifier_block panic_block = { | |||
3196 | static int ipmi_init_msghandler(void) | 3711 | static int ipmi_init_msghandler(void) |
3197 | { | 3712 | { |
3198 | int i; | 3713 | int i; |
3714 | int rv; | ||
3199 | 3715 | ||
3200 | if (initialized) | 3716 | if (initialized) |
3201 | return 0; | 3717 | return 0; |
3202 | 3718 | ||
3719 | rv = driver_register(&ipmidriver); | ||
3720 | if (rv) { | ||
3721 | printk(KERN_ERR PFX "Could not register IPMI driver\n"); | ||
3722 | return rv; | ||
3723 | } | ||
3724 | |||
3203 | printk(KERN_INFO "ipmi message handler version " | 3725 | printk(KERN_INFO "ipmi message handler version " |
3204 | IPMI_DRIVER_VERSION "\n"); | 3726 | IPMI_DRIVER_VERSION "\n"); |
3205 | 3727 | ||
@@ -3256,6 +3778,8 @@ static __exit void cleanup_ipmi(void) | |||
3256 | remove_proc_entry(proc_ipmi_root->name, &proc_root); | 3778 | remove_proc_entry(proc_ipmi_root->name, &proc_root); |
3257 | #endif /* CONFIG_PROC_FS */ | 3779 | #endif /* CONFIG_PROC_FS */ |
3258 | 3780 | ||
3781 | driver_unregister(&ipmidriver); | ||
3782 | |||
3259 | initialized = 0; | 3783 | initialized = 0; |
3260 | 3784 | ||
3261 | /* Check for buffer leaks. */ | 3785 | /* Check for buffer leaks. */ |
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index e8ed26b77d4c..786a2802ca34 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c | |||
@@ -464,7 +464,7 @@ static void ipmi_poweroff_function (void) | |||
464 | 464 | ||
465 | /* Wait for an IPMI interface to be installed, the first one installed | 465 | /* Wait for an IPMI interface to be installed, the first one installed |
466 | will be grabbed by this code and used to perform the powerdown. */ | 466 | will be grabbed by this code and used to perform the powerdown. */ |
467 | static void ipmi_po_new_smi(int if_num) | 467 | static void ipmi_po_new_smi(int if_num, struct device *device) |
468 | { | 468 | { |
469 | struct ipmi_system_interface_addr smi_addr; | 469 | struct ipmi_system_interface_addr smi_addr; |
470 | struct kernel_ipmi_msg send_msg; | 470 | struct kernel_ipmi_msg send_msg; |
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index f3b3b23c5330..12f858dc9994 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c | |||
@@ -112,20 +112,13 @@ enum si_type { | |||
112 | }; | 112 | }; |
113 | static char *si_to_str[] = { "KCS", "SMIC", "BT" }; | 113 | static char *si_to_str[] = { "KCS", "SMIC", "BT" }; |
114 | 114 | ||
115 | struct ipmi_device_id { | 115 | #define DEVICE_NAME "ipmi_si" |
116 | unsigned char device_id; | 116 | |
117 | unsigned char device_revision; | 117 | static struct device_driver ipmi_driver = |
118 | unsigned char firmware_revision_1; | 118 | { |
119 | unsigned char firmware_revision_2; | 119 | .name = DEVICE_NAME, |
120 | unsigned char ipmi_version; | 120 | .bus = &platform_bus_type |
121 | unsigned char additional_device_support; | 121 | }; |
122 | unsigned char manufacturer_id[3]; | ||
123 | unsigned char product_id[2]; | ||
124 | unsigned char aux_firmware_revision[4]; | ||
125 | } __attribute__((packed)); | ||
126 | |||
127 | #define ipmi_version_major(v) ((v)->ipmi_version & 0xf) | ||
128 | #define ipmi_version_minor(v) ((v)->ipmi_version >> 4) | ||
129 | 122 | ||
130 | struct smi_info | 123 | struct smi_info |
131 | { | 124 | { |
@@ -208,8 +201,17 @@ struct smi_info | |||
208 | interrupts. */ | 201 | interrupts. */ |
209 | int interrupt_disabled; | 202 | int interrupt_disabled; |
210 | 203 | ||
204 | /* From the get device id response... */ | ||
211 | struct ipmi_device_id device_id; | 205 | struct ipmi_device_id device_id; |
212 | 206 | ||
207 | /* Driver model stuff. */ | ||
208 | struct device *dev; | ||
209 | struct platform_device *pdev; | ||
210 | |||
211 | /* True if we allocated the device, false if it came from | ||
212 | * someplace else (like PCI). */ | ||
213 | int dev_registered; | ||
214 | |||
213 | /* Slave address, could be reported from DMI. */ | 215 | /* Slave address, could be reported from DMI. */ |
214 | unsigned char slave_addr; | 216 | unsigned char slave_addr; |
215 | 217 | ||
@@ -987,8 +989,6 @@ static LIST_HEAD(smi_infos); | |||
987 | static DECLARE_MUTEX(smi_infos_lock); | 989 | static DECLARE_MUTEX(smi_infos_lock); |
988 | static int smi_num; /* Used to sequence the SMIs */ | 990 | static int smi_num; /* Used to sequence the SMIs */ |
989 | 991 | ||
990 | #define DEVICE_NAME "ipmi_si" | ||
991 | |||
992 | #define DEFAULT_REGSPACING 1 | 992 | #define DEFAULT_REGSPACING 1 |
993 | 993 | ||
994 | static int si_trydefaults = 1; | 994 | static int si_trydefaults = 1; |
@@ -1164,7 +1164,6 @@ static void port_cleanup(struct smi_info *info) | |||
1164 | 1164 | ||
1165 | release_region (addr, mapsize); | 1165 | release_region (addr, mapsize); |
1166 | } | 1166 | } |
1167 | kfree(info); | ||
1168 | } | 1167 | } |
1169 | 1168 | ||
1170 | static int port_setup(struct smi_info *info) | 1169 | static int port_setup(struct smi_info *info) |
@@ -1273,7 +1272,6 @@ static void mem_cleanup(struct smi_info *info) | |||
1273 | 1272 | ||
1274 | release_mem_region(addr, mapsize); | 1273 | release_mem_region(addr, mapsize); |
1275 | } | 1274 | } |
1276 | kfree(info); | ||
1277 | } | 1275 | } |
1278 | 1276 | ||
1279 | static int mem_setup(struct smi_info *info) | 1277 | static int mem_setup(struct smi_info *info) |
@@ -1858,6 +1856,8 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, | |||
1858 | if (info->irq) | 1856 | if (info->irq) |
1859 | info->irq_setup = std_irq_setup; | 1857 | info->irq_setup = std_irq_setup; |
1860 | 1858 | ||
1859 | info->dev = &pdev->dev; | ||
1860 | |||
1861 | return try_smi_init(info); | 1861 | return try_smi_init(info); |
1862 | } | 1862 | } |
1863 | 1863 | ||
@@ -1898,11 +1898,11 @@ static struct pci_driver ipmi_pci_driver = { | |||
1898 | 1898 | ||
1899 | static int try_get_dev_id(struct smi_info *smi_info) | 1899 | static int try_get_dev_id(struct smi_info *smi_info) |
1900 | { | 1900 | { |
1901 | unsigned char msg[2]; | 1901 | unsigned char msg[2]; |
1902 | unsigned char *resp; | 1902 | unsigned char *resp; |
1903 | unsigned long resp_len; | 1903 | unsigned long resp_len; |
1904 | enum si_sm_result smi_result; | 1904 | enum si_sm_result smi_result; |
1905 | int rv = 0; | 1905 | int rv = 0; |
1906 | 1906 | ||
1907 | resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL); | 1907 | resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL); |
1908 | if (!resp) | 1908 | if (!resp) |
@@ -1941,7 +1941,7 @@ static int try_get_dev_id(struct smi_info *smi_info) | |||
1941 | /* Otherwise, we got some data. */ | 1941 | /* Otherwise, we got some data. */ |
1942 | resp_len = smi_info->handlers->get_result(smi_info->si_sm, | 1942 | resp_len = smi_info->handlers->get_result(smi_info->si_sm, |
1943 | resp, IPMI_MAX_MSG_LENGTH); | 1943 | resp, IPMI_MAX_MSG_LENGTH); |
1944 | if (resp_len < 6) { | 1944 | if (resp_len < 14) { |
1945 | /* That's odd, it should be longer. */ | 1945 | /* That's odd, it should be longer. */ |
1946 | rv = -EINVAL; | 1946 | rv = -EINVAL; |
1947 | goto out; | 1947 | goto out; |
@@ -1954,8 +1954,7 @@ static int try_get_dev_id(struct smi_info *smi_info) | |||
1954 | } | 1954 | } |
1955 | 1955 | ||
1956 | /* Record info from the get device id, in case we need it. */ | 1956 | /* Record info from the get device id, in case we need it. */ |
1957 | memcpy(&smi_info->device_id, &resp[3], | 1957 | ipmi_demangle_device_id(resp+3, resp_len-3, &smi_info->device_id); |
1958 | min_t(unsigned long, resp_len-3, sizeof(smi_info->device_id))); | ||
1959 | 1958 | ||
1960 | out: | 1959 | out: |
1961 | kfree(resp); | 1960 | kfree(resp); |
@@ -2058,15 +2057,14 @@ static int oem_data_avail_to_receive_msg_avail(struct smi_info *smi_info) | |||
2058 | #define DELL_POWEREDGE_8G_BMC_DEVICE_ID 0x20 | 2057 | #define DELL_POWEREDGE_8G_BMC_DEVICE_ID 0x20 |
2059 | #define DELL_POWEREDGE_8G_BMC_DEVICE_REV 0x80 | 2058 | #define DELL_POWEREDGE_8G_BMC_DEVICE_REV 0x80 |
2060 | #define DELL_POWEREDGE_8G_BMC_IPMI_VERSION 0x51 | 2059 | #define DELL_POWEREDGE_8G_BMC_IPMI_VERSION 0x51 |
2061 | #define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00} | 2060 | #define DELL_IANA_MFR_ID 0x0002a2 |
2062 | static void setup_dell_poweredge_oem_data_handler(struct smi_info *smi_info) | 2061 | static void setup_dell_poweredge_oem_data_handler(struct smi_info *smi_info) |
2063 | { | 2062 | { |
2064 | struct ipmi_device_id *id = &smi_info->device_id; | 2063 | struct ipmi_device_id *id = &smi_info->device_id; |
2065 | const char mfr[3]=DELL_IANA_MFR_ID; | 2064 | if (id->manufacturer_id == DELL_IANA_MFR_ID) { |
2066 | if (!memcmp(mfr, id->manufacturer_id, sizeof(mfr))) { | ||
2067 | if (id->device_id == DELL_POWEREDGE_8G_BMC_DEVICE_ID && | 2065 | if (id->device_id == DELL_POWEREDGE_8G_BMC_DEVICE_ID && |
2068 | id->device_revision == DELL_POWEREDGE_8G_BMC_DEVICE_REV && | 2066 | id->device_revision == DELL_POWEREDGE_8G_BMC_DEVICE_REV && |
2069 | id->ipmi_version == DELL_POWEREDGE_8G_BMC_IPMI_VERSION) { | 2067 | id->ipmi_version == DELL_POWEREDGE_8G_BMC_IPMI_VERSION) { |
2070 | smi_info->oem_data_avail_handler = | 2068 | smi_info->oem_data_avail_handler = |
2071 | oem_data_avail_to_receive_msg_avail; | 2069 | oem_data_avail_to_receive_msg_avail; |
2072 | } | 2070 | } |
@@ -2138,8 +2136,7 @@ static void | |||
2138 | setup_dell_poweredge_bt_xaction_handler(struct smi_info *smi_info) | 2136 | setup_dell_poweredge_bt_xaction_handler(struct smi_info *smi_info) |
2139 | { | 2137 | { |
2140 | struct ipmi_device_id *id = &smi_info->device_id; | 2138 | struct ipmi_device_id *id = &smi_info->device_id; |
2141 | const char mfr[3]=DELL_IANA_MFR_ID; | 2139 | if (id->manufacturer_id == DELL_IANA_MFR_ID && |
2142 | if (!memcmp(mfr, id->manufacturer_id, sizeof(mfr)) && | ||
2143 | smi_info->si_type == SI_BT) | 2140 | smi_info->si_type == SI_BT) |
2144 | register_xaction_notifier(&dell_poweredge_bt_xaction_notifier); | 2141 | register_xaction_notifier(&dell_poweredge_bt_xaction_notifier); |
2145 | } | 2142 | } |
@@ -2358,10 +2355,36 @@ static int try_smi_init(struct smi_info *new_smi) | |||
2358 | new_smi->thread = kthread_run(ipmi_thread, new_smi, | 2355 | new_smi->thread = kthread_run(ipmi_thread, new_smi, |
2359 | "kipmi%d", new_smi->intf_num); | 2356 | "kipmi%d", new_smi->intf_num); |
2360 | 2357 | ||
2358 | if (!new_smi->dev) { | ||
2359 | /* If we don't already have a device from something | ||
2360 | * else (like PCI), then register a new one. */ | ||
2361 | new_smi->pdev = platform_device_alloc("ipmi_si", | ||
2362 | new_smi->intf_num); | ||
2363 | if (rv) { | ||
2364 | printk(KERN_ERR | ||
2365 | "ipmi_si_intf:" | ||
2366 | " Unable to allocate platform device\n"); | ||
2367 | goto out_err_stop_timer; | ||
2368 | } | ||
2369 | new_smi->dev = &new_smi->pdev->dev; | ||
2370 | new_smi->dev->driver = &ipmi_driver; | ||
2371 | |||
2372 | rv = platform_device_register(new_smi->pdev); | ||
2373 | if (rv) { | ||
2374 | printk(KERN_ERR | ||
2375 | "ipmi_si_intf:" | ||
2376 | " Unable to register system interface device:" | ||
2377 | " %d\n", | ||
2378 | rv); | ||
2379 | goto out_err_stop_timer; | ||
2380 | } | ||
2381 | new_smi->dev_registered = 1; | ||
2382 | } | ||
2383 | |||
2361 | rv = ipmi_register_smi(&handlers, | 2384 | rv = ipmi_register_smi(&handlers, |
2362 | new_smi, | 2385 | new_smi, |
2363 | ipmi_version_major(&new_smi->device_id), | 2386 | &new_smi->device_id, |
2364 | ipmi_version_minor(&new_smi->device_id), | 2387 | new_smi->dev, |
2365 | new_smi->slave_addr, | 2388 | new_smi->slave_addr, |
2366 | &(new_smi->intf)); | 2389 | &(new_smi->intf)); |
2367 | if (rv) { | 2390 | if (rv) { |
@@ -2425,6 +2448,11 @@ static int try_smi_init(struct smi_info *new_smi) | |||
2425 | if (new_smi->io_cleanup) | 2448 | if (new_smi->io_cleanup) |
2426 | new_smi->io_cleanup(new_smi); | 2449 | new_smi->io_cleanup(new_smi); |
2427 | 2450 | ||
2451 | if (new_smi->dev_registered) | ||
2452 | platform_device_unregister(new_smi->pdev); | ||
2453 | |||
2454 | kfree(new_smi); | ||
2455 | |||
2428 | up(&smi_infos_lock); | 2456 | up(&smi_infos_lock); |
2429 | 2457 | ||
2430 | return rv; | 2458 | return rv; |
@@ -2434,11 +2462,22 @@ static __devinit int init_ipmi_si(void) | |||
2434 | { | 2462 | { |
2435 | int i; | 2463 | int i; |
2436 | char *str; | 2464 | char *str; |
2465 | int rv; | ||
2437 | 2466 | ||
2438 | if (initialized) | 2467 | if (initialized) |
2439 | return 0; | 2468 | return 0; |
2440 | initialized = 1; | 2469 | initialized = 1; |
2441 | 2470 | ||
2471 | /* Register the device drivers. */ | ||
2472 | rv = driver_register(&ipmi_driver); | ||
2473 | if (rv) { | ||
2474 | printk(KERN_ERR | ||
2475 | "init_ipmi_si: Unable to register driver: %d\n", | ||
2476 | rv); | ||
2477 | return rv; | ||
2478 | } | ||
2479 | |||
2480 | |||
2442 | /* Parse out the si_type string into its components. */ | 2481 | /* Parse out the si_type string into its components. */ |
2443 | str = si_type_str; | 2482 | str = si_type_str; |
2444 | if (*str != '\0') { | 2483 | if (*str != '\0') { |
@@ -2549,6 +2588,11 @@ static void __devexit cleanup_one_si(struct smi_info *to_clean) | |||
2549 | to_clean->addr_source_cleanup(to_clean); | 2588 | to_clean->addr_source_cleanup(to_clean); |
2550 | if (to_clean->io_cleanup) | 2589 | if (to_clean->io_cleanup) |
2551 | to_clean->io_cleanup(to_clean); | 2590 | to_clean->io_cleanup(to_clean); |
2591 | |||
2592 | if (to_clean->dev_registered) | ||
2593 | platform_device_unregister(to_clean->pdev); | ||
2594 | |||
2595 | kfree(to_clean); | ||
2552 | } | 2596 | } |
2553 | 2597 | ||
2554 | static __exit void cleanup_ipmi_si(void) | 2598 | static __exit void cleanup_ipmi_si(void) |
@@ -2566,6 +2610,8 @@ static __exit void cleanup_ipmi_si(void) | |||
2566 | list_for_each_entry_safe(e, tmp_e, &smi_infos, link) | 2610 | list_for_each_entry_safe(e, tmp_e, &smi_infos, link) |
2567 | cleanup_one_si(e); | 2611 | cleanup_one_si(e); |
2568 | up(&smi_infos_lock); | 2612 | up(&smi_infos_lock); |
2613 | |||
2614 | driver_unregister(&ipmi_driver); | ||
2569 | } | 2615 | } |
2570 | module_exit(cleanup_ipmi_si); | 2616 | module_exit(cleanup_ipmi_si); |
2571 | 2617 | ||
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 1f3159eb1ede..616539310d9a 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c | |||
@@ -996,7 +996,7 @@ static struct notifier_block wdog_panic_notifier = { | |||
996 | }; | 996 | }; |
997 | 997 | ||
998 | 998 | ||
999 | static void ipmi_new_smi(int if_num) | 999 | static void ipmi_new_smi(int if_num, struct device *device) |
1000 | { | 1000 | { |
1001 | ipmi_register_watchdog(if_num); | 1001 | ipmi_register_watchdog(if_num); |
1002 | } | 1002 | } |
diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h index d6276e60b3bf..0a84b56935c2 100644 --- a/include/linux/ipmi.h +++ b/include/linux/ipmi.h | |||
@@ -36,6 +36,7 @@ | |||
36 | 36 | ||
37 | #include <linux/ipmi_msgdefs.h> | 37 | #include <linux/ipmi_msgdefs.h> |
38 | #include <linux/compiler.h> | 38 | #include <linux/compiler.h> |
39 | #include <linux/device.h> | ||
39 | 40 | ||
40 | /* | 41 | /* |
41 | * This file describes an interface to an IPMI driver. You have to | 42 | * This file describes an interface to an IPMI driver. You have to |
@@ -397,7 +398,7 @@ struct ipmi_smi_watcher | |||
397 | the watcher list. So you can add and remove users from the | 398 | the watcher list. So you can add and remove users from the |
398 | IPMI interface, send messages, etc., but you cannot add | 399 | IPMI interface, send messages, etc., but you cannot add |
399 | or remove SMI watchers or SMI interfaces. */ | 400 | or remove SMI watchers or SMI interfaces. */ |
400 | void (*new_smi)(int if_num); | 401 | void (*new_smi)(int if_num, struct device *dev); |
401 | void (*smi_gone)(int if_num); | 402 | void (*smi_gone)(int if_num); |
402 | }; | 403 | }; |
403 | 404 | ||
diff --git a/include/linux/ipmi_msgdefs.h b/include/linux/ipmi_msgdefs.h index 03bc64dc2ec1..22f5e2afda4f 100644 --- a/include/linux/ipmi_msgdefs.h +++ b/include/linux/ipmi_msgdefs.h | |||
@@ -47,6 +47,7 @@ | |||
47 | #define IPMI_NETFN_APP_RESPONSE 0x07 | 47 | #define IPMI_NETFN_APP_RESPONSE 0x07 |
48 | #define IPMI_GET_DEVICE_ID_CMD 0x01 | 48 | #define IPMI_GET_DEVICE_ID_CMD 0x01 |
49 | #define IPMI_CLEAR_MSG_FLAGS_CMD 0x30 | 49 | #define IPMI_CLEAR_MSG_FLAGS_CMD 0x30 |
50 | #define IPMI_GET_DEVICE_GUID_CMD 0x08 | ||
50 | #define IPMI_GET_MSG_FLAGS_CMD 0x31 | 51 | #define IPMI_GET_MSG_FLAGS_CMD 0x31 |
51 | #define IPMI_SEND_MSG_CMD 0x34 | 52 | #define IPMI_SEND_MSG_CMD 0x34 |
52 | #define IPMI_GET_MSG_CMD 0x33 | 53 | #define IPMI_GET_MSG_CMD 0x33 |
diff --git a/include/linux/ipmi_smi.h b/include/linux/ipmi_smi.h index e36ee157ad67..53571288a9fc 100644 --- a/include/linux/ipmi_smi.h +++ b/include/linux/ipmi_smi.h | |||
@@ -37,6 +37,9 @@ | |||
37 | #include <linux/ipmi_msgdefs.h> | 37 | #include <linux/ipmi_msgdefs.h> |
38 | #include <linux/proc_fs.h> | 38 | #include <linux/proc_fs.h> |
39 | #include <linux/module.h> | 39 | #include <linux/module.h> |
40 | #include <linux/device.h> | ||
41 | #include <linux/platform_device.h> | ||
42 | #include <linux/ipmi_smi.h> | ||
40 | 43 | ||
41 | /* This files describes the interface for IPMI system management interface | 44 | /* This files describes the interface for IPMI system management interface |
42 | drivers to bind into the IPMI message handler. */ | 45 | drivers to bind into the IPMI message handler. */ |
@@ -113,12 +116,52 @@ struct ipmi_smi_handlers | |||
113 | void (*dec_usecount)(void *send_info); | 116 | void (*dec_usecount)(void *send_info); |
114 | }; | 117 | }; |
115 | 118 | ||
119 | struct ipmi_device_id { | ||
120 | unsigned char device_id; | ||
121 | unsigned char device_revision; | ||
122 | unsigned char firmware_revision_1; | ||
123 | unsigned char firmware_revision_2; | ||
124 | unsigned char ipmi_version; | ||
125 | unsigned char additional_device_support; | ||
126 | unsigned int manufacturer_id; | ||
127 | unsigned int product_id; | ||
128 | unsigned char aux_firmware_revision[4]; | ||
129 | unsigned int aux_firmware_revision_set : 1; | ||
130 | }; | ||
131 | |||
132 | #define ipmi_version_major(v) ((v)->ipmi_version & 0xf) | ||
133 | #define ipmi_version_minor(v) ((v)->ipmi_version >> 4) | ||
134 | |||
135 | /* Take a pointer to a raw data buffer and a length and extract device | ||
136 | id information from it. The first byte of data must point to the | ||
137 | byte from the get device id response after the completion code. | ||
138 | The caller is responsible for making sure the length is at least | ||
139 | 11 and the command completed without error. */ | ||
140 | static inline void ipmi_demangle_device_id(unsigned char *data, | ||
141 | unsigned int data_len, | ||
142 | struct ipmi_device_id *id) | ||
143 | { | ||
144 | id->device_id = data[0]; | ||
145 | id->device_revision = data[1]; | ||
146 | id->firmware_revision_1 = data[2]; | ||
147 | id->firmware_revision_2 = data[3]; | ||
148 | id->ipmi_version = data[4]; | ||
149 | id->additional_device_support = data[5]; | ||
150 | id->manufacturer_id = data[6] | (data[7] << 8) | (data[8] << 16); | ||
151 | id->product_id = data[9] | (data[10] << 8); | ||
152 | if (data_len >= 15) { | ||
153 | memcpy(id->aux_firmware_revision, data+11, 4); | ||
154 | id->aux_firmware_revision_set = 1; | ||
155 | } else | ||
156 | id->aux_firmware_revision_set = 0; | ||
157 | } | ||
158 | |||
116 | /* Add a low-level interface to the IPMI driver. Note that if the | 159 | /* Add a low-level interface to the IPMI driver. Note that if the |
117 | interface doesn't know its slave address, it should pass in zero. */ | 160 | interface doesn't know its slave address, it should pass in zero. */ |
118 | int ipmi_register_smi(struct ipmi_smi_handlers *handlers, | 161 | int ipmi_register_smi(struct ipmi_smi_handlers *handlers, |
119 | void *send_info, | 162 | void *send_info, |
120 | unsigned char version_major, | 163 | struct ipmi_device_id *device_id, |
121 | unsigned char version_minor, | 164 | struct device *dev, |
122 | unsigned char slave_addr, | 165 | unsigned char slave_addr, |
123 | ipmi_smi_t *intf); | 166 | ipmi_smi_t *intf); |
124 | 167 | ||