ipmi.c (167950) | ipmi.c (182322) |
---|---|
1/*- 2 * Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 11 unchanged lines hidden (view full) --- 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 11 unchanged lines hidden (view full) --- 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> |
28__FBSDID("$FreeBSD: head/sys/dev/ipmi/ipmi.c 167950 2007-03-27 21:03:37Z n_hibma $"); | 28__FBSDID("$FreeBSD: head/sys/dev/ipmi/ipmi.c 182322 2008-08-28 02:13:53Z jhb $"); |
29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/bus.h> 33#include <sys/condvar.h> 34#include <sys/conf.h> 35#include <sys/kernel.h> 36#include <sys/malloc.h> --- 16 unchanged lines hidden (view full) --- 53static int ipmi_ipmb_checksum(u_char, int); 54static int ipmi_ipmb_send_message(device_t, u_char, u_char, u_char, 55 u_char, u_char, int) 56#endif 57 58static d_ioctl_t ipmi_ioctl; 59static d_poll_t ipmi_poll; 60static d_open_t ipmi_open; | 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/bus.h> 33#include <sys/condvar.h> 34#include <sys/conf.h> 35#include <sys/kernel.h> 36#include <sys/malloc.h> --- 16 unchanged lines hidden (view full) --- 53static int ipmi_ipmb_checksum(u_char, int); 54static int ipmi_ipmb_send_message(device_t, u_char, u_char, u_char, 55 u_char, u_char, int) 56#endif 57 58static d_ioctl_t ipmi_ioctl; 59static d_poll_t ipmi_poll; 60static d_open_t ipmi_open; |
61static d_close_t ipmi_close; | 61static void ipmi_dtor(void *arg); |
62 63int ipmi_attached = 0; 64 | 62 63int ipmi_attached = 0; 64 |
65#define IPMI_MINOR 0 66 | |
67static int on = 1; 68SYSCTL_NODE(_hw, OID_AUTO, ipmi, CTLFLAG_RD, 0, "IPMI driver parameters"); 69SYSCTL_INT(_hw_ipmi, OID_AUTO, on, CTLFLAG_RW, 70 &on, 0, ""); 71 72static struct cdevsw ipmi_cdevsw = { 73 .d_version = D_VERSION, 74 .d_open = ipmi_open, | 65static int on = 1; 66SYSCTL_NODE(_hw, OID_AUTO, ipmi, CTLFLAG_RD, 0, "IPMI driver parameters"); 67SYSCTL_INT(_hw_ipmi, OID_AUTO, on, CTLFLAG_RW, 68 &on, 0, ""); 69 70static struct cdevsw ipmi_cdevsw = { 71 .d_version = D_VERSION, 72 .d_open = ipmi_open, |
75 .d_close = ipmi_close, | |
76 .d_ioctl = ipmi_ioctl, 77 .d_poll = ipmi_poll, 78 .d_name = "ipmi", 79}; 80 81MALLOC_DEFINE(M_IPMI, "ipmi", "ipmi"); 82 83static int 84ipmi_open(struct cdev *cdev, int flags, int fmt, struct thread *td) 85{ 86 struct ipmi_device *dev; 87 struct ipmi_softc *sc; | 73 .d_ioctl = ipmi_ioctl, 74 .d_poll = ipmi_poll, 75 .d_name = "ipmi", 76}; 77 78MALLOC_DEFINE(M_IPMI, "ipmi", "ipmi"); 79 80static int 81ipmi_open(struct cdev *cdev, int flags, int fmt, struct thread *td) 82{ 83 struct ipmi_device *dev; 84 struct ipmi_softc *sc; |
85 int error; |
|
88 89 if (!on) 90 return (ENOENT); 91 | 86 87 if (!on) 88 return (ENOENT); 89 |
92 dev = cdev->si_drv1; 93 sc = dev->ipmi_softc; 94 IPMI_LOCK(sc); 95 if (dev->ipmi_open) { 96 IPMI_UNLOCK(sc); 97 return (EBUSY); | 90 /* Initialize the per file descriptor data. */ 91 dev = malloc(sizeof(struct ipmi_device), M_IPMI, M_WAITOK | M_ZERO); 92 error = devfs_set_cdevpriv(dev, ipmi_dtor); 93 if (error) { 94 free(dev, M_IPMI); 95 return (error); |
98 } | 96 } |
99 dev->ipmi_open = 1; | 97 98 sc = cdev->si_drv1; 99 TAILQ_INIT(&dev->ipmi_completed_requests); 100 dev->ipmi_address = IPMI_BMC_SLAVE_ADDR; 101 dev->ipmi_lun = IPMI_BMC_SMS_LUN; 102 dev->ipmi_softc = sc; 103 IPMI_LOCK(sc); 104 sc->ipmi_opened++; |
100 IPMI_UNLOCK(sc); 101 102 return (0); 103} 104 105static int 106ipmi_poll(struct cdev *cdev, int poll_events, struct thread *td) 107{ 108 struct ipmi_device *dev; 109 struct ipmi_softc *sc; 110 int revents = 0; 111 | 105 IPMI_UNLOCK(sc); 106 107 return (0); 108} 109 110static int 111ipmi_poll(struct cdev *cdev, int poll_events, struct thread *td) 112{ 113 struct ipmi_device *dev; 114 struct ipmi_softc *sc; 115 int revents = 0; 116 |
112 dev = cdev->si_drv1; 113 sc = dev->ipmi_softc; | 117 if (devfs_get_cdevpriv((void **)&dev)) 118 return (0); |
114 | 119 |
120 sc = cdev->si_drv1; |
|
115 IPMI_LOCK(sc); 116 if (poll_events & (POLLIN | POLLRDNORM)) { 117 if (!TAILQ_EMPTY(&dev->ipmi_completed_requests)) 118 revents |= poll_events & (POLLIN | POLLRDNORM); 119 if (dev->ipmi_requests == 0) 120 revents |= POLLERR; 121 } 122 --- 14 unchanged lines hidden (view full) --- 137 while (!TAILQ_EMPTY(&dev->ipmi_completed_requests)) { 138 req = TAILQ_FIRST(&dev->ipmi_completed_requests); 139 TAILQ_REMOVE(&dev->ipmi_completed_requests, req, ir_link); 140 dev->ipmi_requests--; 141 ipmi_free_request(req); 142 } 143} 144 | 121 IPMI_LOCK(sc); 122 if (poll_events & (POLLIN | POLLRDNORM)) { 123 if (!TAILQ_EMPTY(&dev->ipmi_completed_requests)) 124 revents |= poll_events & (POLLIN | POLLRDNORM); 125 if (dev->ipmi_requests == 0) 126 revents |= POLLERR; 127 } 128 --- 14 unchanged lines hidden (view full) --- 143 while (!TAILQ_EMPTY(&dev->ipmi_completed_requests)) { 144 req = TAILQ_FIRST(&dev->ipmi_completed_requests); 145 TAILQ_REMOVE(&dev->ipmi_completed_requests, req, ir_link); 146 dev->ipmi_requests--; 147 ipmi_free_request(req); 148 } 149} 150 |
145static int 146ipmi_close(struct cdev *cdev, int flags, int fmt, struct thread *td) | 151static void 152ipmi_dtor(void *arg) |
147{ 148 struct ipmi_request *req, *nreq; 149 struct ipmi_device *dev; 150 struct ipmi_softc *sc; | 153{ 154 struct ipmi_request *req, *nreq; 155 struct ipmi_device *dev; 156 struct ipmi_softc *sc; |
151#ifdef CLONING 152 int bit; 153#endif | |
154 | 157 |
155 dev = cdev->si_drv1; | 158 dev = arg; |
156 sc = dev->ipmi_softc; 157 158 IPMI_LOCK(sc); 159 if (dev->ipmi_requests) { 160 /* Throw away any pending requests for this device. */ 161 TAILQ_FOREACH_SAFE(req, &sc->ipmi_pending_requests, ir_link, 162 nreq) { 163 if (req->ir_owner == dev) { --- 13 unchanged lines hidden (view full) --- 177 */ 178 dev->ipmi_closing = 1; 179 while (dev->ipmi_requests > 0) { 180 msleep(&dev->ipmi_requests, &sc->ipmi_lock, PWAIT, 181 "ipmidrain", 0); 182 ipmi_purge_completed_requests(dev); 183 } 184 } | 159 sc = dev->ipmi_softc; 160 161 IPMI_LOCK(sc); 162 if (dev->ipmi_requests) { 163 /* Throw away any pending requests for this device. */ 164 TAILQ_FOREACH_SAFE(req, &sc->ipmi_pending_requests, ir_link, 165 nreq) { 166 if (req->ir_owner == dev) { --- 13 unchanged lines hidden (view full) --- 180 */ 181 dev->ipmi_closing = 1; 182 while (dev->ipmi_requests > 0) { 183 msleep(&dev->ipmi_requests, &sc->ipmi_lock, PWAIT, 184 "ipmidrain", 0); 185 ipmi_purge_completed_requests(dev); 186 } 187 } |
185 186#ifdef CLONING 187 /* Detach this sub-device from the main driver. */ 188 bit = minor(cdev) % 32; 189 sc->ipmi_cdev_mask &= ~(1 << bit); 190 TAILQ_REMOVE(&sc->ipmi_cdevs, dev, ipmi_link); | 188 sc->ipmi_opened--; |
191 IPMI_UNLOCK(sc); 192 193 /* Cleanup. */ | 189 IPMI_UNLOCK(sc); 190 191 /* Cleanup. */ |
194 cdev->si_drv1 = NULL; | |
195 free(dev, M_IPMI); | 192 free(dev, M_IPMI); |
196 destroy_dev(cdev); 197#else 198 dev->ipmi_open = 0; 199 IPMI_UNLOCK(sc); 200#endif 201 202 return (0); | |
203} 204 205#ifdef IPMB 206static int 207ipmi_ipmb_checksum(u_char *data, int len) 208{ 209 u_char sum = 0; 210 --- 92 unchanged lines hidden (view full) --- 303 struct ipmi_recv32 *recv32 = (struct ipmi_recv32 *)data; 304 union { 305 struct ipmi_req req; 306 struct ipmi_recv recv; 307 } thunk32; 308#endif 309 int error, len; 310 | 193} 194 195#ifdef IPMB 196static int 197ipmi_ipmb_checksum(u_char *data, int len) 198{ 199 u_char sum = 0; 200 --- 92 unchanged lines hidden (view full) --- 293 struct ipmi_recv32 *recv32 = (struct ipmi_recv32 *)data; 294 union { 295 struct ipmi_req req; 296 struct ipmi_recv recv; 297 } thunk32; 298#endif 299 int error, len; 300 |
311 dev = cdev->si_drv1; 312 sc = dev->ipmi_softc; | 301 error = devfs_get_cdevpriv((void **)&dev); 302 if (error) 303 return (error); |
313 | 304 |
305 sc = cdev->si_drv1; 306 |
|
314#ifdef IPMICTL_SEND_COMMAND_32 315 /* Convert 32-bit structures to native. */ 316 switch (cmd) { 317 case IPMICTL_SEND_COMMAND_32: 318 req = &thunk32.req; 319 req->addr = PTRIN(req32->addr); 320 req->addr_len = req32->addr_len; 321 req->msgid = req32->msgid; --- 332 unchanged lines hidden (view full) --- 654 timeout = ((uint64_t)1 << cmd) / 1800000000; 655 ipmi_set_watchdog(sc, timeout); 656 *error = 0; 657 } else { 658 ipmi_set_watchdog(sc, 0); 659 } 660} 661 | 307#ifdef IPMICTL_SEND_COMMAND_32 308 /* Convert 32-bit structures to native. */ 309 switch (cmd) { 310 case IPMICTL_SEND_COMMAND_32: 311 req = &thunk32.req; 312 req->addr = PTRIN(req32->addr); 313 req->addr_len = req32->addr_len; 314 req->msgid = req32->msgid; --- 332 unchanged lines hidden (view full) --- 647 timeout = ((uint64_t)1 << cmd) / 1800000000; 648 ipmi_set_watchdog(sc, timeout); 649 *error = 0; 650 } else { 651 ipmi_set_watchdog(sc, 0); 652 } 653} 654 |
662#ifdef CLONING | |
663static void | 655static void |
664ipmi_clone(void *arg, struct ucred *cred, char *name, int namelen, 665 struct cdev **cdev) 666{ 667 struct ipmi_softc *sc = arg; 668 struct ipmi_device *dev; 669 int minor, unit; 670 671 if (*cdev != NULL) 672 return; 673 674 if (strcmp(name, device_get_nameunit(sc->ipmi_dev)) != 0) 675 return; 676 677 dev = malloc(sizeof(struct ipmi_device), M_IPMI, M_WAITOK | M_ZERO); 678 679 /* Reserve a sub-device. */ 680 IPMI_LOCK(sc); 681 minor = ffs(~(sc->ipmi_cdev_mask & 0xffff)); 682 if (minor == 0 || !sc->ipmi_cloning) { 683 IPMI_UNLOCK(sc); 684 free(dev, M_IPMI); 685 return; 686 } 687 minor--; 688 sc->ipmi_cdev_mask |= (1 << minor); 689 TAILQ_INSERT_TAIL(&sc->ipmi_cdevs, dev, ipmi_link); 690 IPMI_UNLOCK(sc); 691 692 /* Initialize the device. */ 693 TAILQ_INIT(&dev->ipmi_completed_requests); 694 dev->ipmi_softc = sc; 695 dev->ipmi_address = IPMI_BMC_SLAVE_ADDR; 696 dev->ipmi_lun = IPMI_BMC_SMS_LUN; 697 unit = device_get_unit(sc->ipmi_dev); 698 dev->ipmi_cdev = make_dev_cred(&ipmi_cdevsw, unit * 32 + minor, cred, 699 UID_ROOT, GID_OPERATOR, 0660, "ipmi%d.%d", unit, minor); 700 if (dev->ipmi_cdev == NULL) { 701 IPMI_LOCK(sc); 702 sc->ipmi_cdev_mask &= ~(1 << minor); 703 TAILQ_REMOVE(&sc->ipmi_cdevs, dev, ipmi_link); 704 IPMI_UNLOCK(sc); 705 free(dev, M_IPMI); 706 return; 707 } 708 dev->ipmi_cdev->si_drv1 = dev; 709 *cdev = dev->ipmi_cdev; 710 dev_ref(*cdev); 711} 712#endif 713 714static void | |
715ipmi_startup(void *arg) 716{ 717 struct ipmi_softc *sc = arg; 718 struct ipmi_request *req; 719 device_t dev; 720 int error, i; 721 722 config_intrhook_disestablish(&sc->ipmi_ich); 723 dev = sc->ipmi_dev; 724 725 /* Initialize interface-independent state. */ 726 mtx_init(&sc->ipmi_lock, device_get_nameunit(dev), "ipmi", MTX_DEF); 727 cv_init(&sc->ipmi_request_added, "ipmireq"); 728 TAILQ_INIT(&sc->ipmi_pending_requests); | 656ipmi_startup(void *arg) 657{ 658 struct ipmi_softc *sc = arg; 659 struct ipmi_request *req; 660 device_t dev; 661 int error, i; 662 663 config_intrhook_disestablish(&sc->ipmi_ich); 664 dev = sc->ipmi_dev; 665 666 /* Initialize interface-independent state. */ 667 mtx_init(&sc->ipmi_lock, device_get_nameunit(dev), "ipmi", MTX_DEF); 668 cv_init(&sc->ipmi_request_added, "ipmireq"); 669 TAILQ_INIT(&sc->ipmi_pending_requests); |
729#ifdef CLONING 730 TAILQ_INIT(&sc->ipmi_cdevs); 731#endif | |
732 733 /* Initialize interface-dependent state. */ 734 error = sc->ipmi_startup(sc); 735 if (error) { 736 device_printf(dev, "Failed to initialize interface: %d\n", 737 error); 738 return; 739 } --- 70 unchanged lines hidden (view full) --- 810 if (req->ir_compcode == 0x00) { 811 device_printf(dev, "Attached watchdog\n"); 812 /* register the watchdog event handler */ 813 sc->ipmi_watchdog_tag = EVENTHANDLER_REGISTER(watchdog_list, 814 ipmi_wd_event, sc, 0); 815 } 816 ipmi_free_request(req); 817 | 670 671 /* Initialize interface-dependent state. */ 672 error = sc->ipmi_startup(sc); 673 if (error) { 674 device_printf(dev, "Failed to initialize interface: %d\n", 675 error); 676 return; 677 } --- 70 unchanged lines hidden (view full) --- 748 if (req->ir_compcode == 0x00) { 749 device_printf(dev, "Attached watchdog\n"); 750 /* register the watchdog event handler */ 751 sc->ipmi_watchdog_tag = EVENTHANDLER_REGISTER(watchdog_list, 752 ipmi_wd_event, sc, 0); 753 } 754 ipmi_free_request(req); 755 |
818#ifdef CLONING 819 sc->ipmi_cloning = 1; 820 sc->ipmi_clone_tag = EVENTHANDLER_REGISTER(dev_clone, ipmi_clone, sc, 821 1000); 822#else 823 /* Initialize the device. */ 824 TAILQ_INIT(&sc->ipmi_idev.ipmi_completed_requests); 825 sc->ipmi_idev.ipmi_softc = sc; 826 sc->ipmi_idev.ipmi_address = IPMI_BMC_SLAVE_ADDR; 827 sc->ipmi_idev.ipmi_lun = IPMI_BMC_SMS_LUN; 828 sc->ipmi_idev.ipmi_cdev = make_dev(&ipmi_cdevsw, device_get_unit(dev), | 756 sc->ipmi_cdev = make_dev(&ipmi_cdevsw, device_get_unit(dev), |
829 UID_ROOT, GID_OPERATOR, 0660, "ipmi%d", device_get_unit(dev)); | 757 UID_ROOT, GID_OPERATOR, 0660, "ipmi%d", device_get_unit(dev)); |
830 if (sc->ipmi_idev.ipmi_cdev == NULL) { | 758 if (sc->ipmi_cdev == NULL) { |
831 device_printf(dev, "Failed to create cdev\n"); 832 return; 833 } | 759 device_printf(dev, "Failed to create cdev\n"); 760 return; 761 } |
834 sc->ipmi_idev.ipmi_cdev->si_drv1 = &sc->ipmi_idev; 835#endif | 762 sc->ipmi_cdev->si_drv1 = sc; |
836} 837 838int 839ipmi_attach(device_t dev) 840{ 841 struct ipmi_softc *sc = device_get_softc(dev); 842 int error; 843 --- 22 unchanged lines hidden (view full) --- 866ipmi_detach(device_t dev) 867{ 868 struct ipmi_softc *sc; 869 870 sc = device_get_softc(dev); 871 872 /* Fail if there are any open handles. */ 873 IPMI_LOCK(sc); | 763} 764 765int 766ipmi_attach(device_t dev) 767{ 768 struct ipmi_softc *sc = device_get_softc(dev); 769 int error; 770 --- 22 unchanged lines hidden (view full) --- 793ipmi_detach(device_t dev) 794{ 795 struct ipmi_softc *sc; 796 797 sc = device_get_softc(dev); 798 799 /* Fail if there are any open handles. */ 800 IPMI_LOCK(sc); |
874#ifdef CLONING 875 if (!TAILQ_EMPTY(&sc->ipmi_cdevs)) { | 801 if (sc->ipmi_opened) { |
876 IPMI_UNLOCK(sc); 877 return (EBUSY); 878 } | 802 IPMI_UNLOCK(sc); 803 return (EBUSY); 804 } |
879 880 /* Turn off cloning. */ 881 sc->ipmi_cloning = 0; | |
882 IPMI_UNLOCK(sc); | 805 IPMI_UNLOCK(sc); |
806 if (sc->ipmi_cdev) 807 destroy_dev(sc->ipmi_cdev); |
|
883 | 808 |
884 if (sc->ipmi_clone_tag) 885 EVENTHANDLER_DEREGISTER(dev_clone, sc->ipmi_clone_tag); 886#else 887 if (sc->ipmi_idev.ipmi_open) { 888 IPMI_UNLOCK(sc); 889 return (EBUSY); 890 } 891 IPMI_UNLOCK(sc); 892 if (sc->ipmi_idev.ipmi_cdev) 893 destroy_dev(sc->ipmi_idev.ipmi_cdev); 894#endif 895 | |
896 /* Detach from watchdog handling and turn off watchdog. */ 897 if (sc->ipmi_watchdog_tag) { 898 EVENTHANDLER_DEREGISTER(watchdog_list, sc->ipmi_watchdog_tag); 899 ipmi_set_watchdog(sc, 0); 900 } 901 902 /* XXX: should use shutdown callout I think. */ 903 /* If the backend uses a kthread, shut it down. */ --- 90 unchanged lines hidden --- | 809 /* Detach from watchdog handling and turn off watchdog. */ 810 if (sc->ipmi_watchdog_tag) { 811 EVENTHANDLER_DEREGISTER(watchdog_list, sc->ipmi_watchdog_tag); 812 ipmi_set_watchdog(sc, 0); 813 } 814 815 /* XXX: should use shutdown callout I think. */ 816 /* If the backend uses a kthread, shut it down. */ --- 90 unchanged lines hidden --- |