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 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; |
61static void ipmi_dtor(void *arg); |
62 63int ipmi_attached = 0; 64 |
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, |
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; |
86 87 if (!on) 88 return (ENOENT); 89 |
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); |
96 } |
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++; |
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 |
117 if (devfs_get_cdevpriv((void **)&dev)) 118 return (0); |
119 |
120 sc = cdev->si_drv1; |
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 |
151static void 152ipmi_dtor(void *arg) |
153{ 154 struct ipmi_request *req, *nreq; 155 struct ipmi_device *dev; 156 struct ipmi_softc *sc; |
157 |
158 dev = arg; |
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 } |
188 sc->ipmi_opened--; |
189 IPMI_UNLOCK(sc); 190 191 /* Cleanup. */ |
192 free(dev, M_IPMI); |
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 |
301 error = devfs_get_cdevpriv((void **)&dev); 302 if (error) 303 return (error); |
304 |
305 sc = cdev->si_drv1; 306 |
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 |
655static void |
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); |
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 |
756 sc->ipmi_cdev = make_dev(&ipmi_cdevsw, device_get_unit(dev), |
757 UID_ROOT, GID_OPERATOR, 0660, "ipmi%d", device_get_unit(dev)); |
758 if (sc->ipmi_cdev == NULL) { |
759 device_printf(dev, "Failed to create cdev\n"); 760 return; 761 } |
762 sc->ipmi_cdev->si_drv1 = 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); |
801 if (sc->ipmi_opened) { |
802 IPMI_UNLOCK(sc); 803 return (EBUSY); 804 } |
805 IPMI_UNLOCK(sc); |
806 if (sc->ipmi_cdev) 807 destroy_dev(sc->ipmi_cdev); |
808 |
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 --- |