linux/drivers/char/ipmi/ipmi_devintf.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * ipmi_devintf.c
   4 *
   5 * Linux device interface for the IPMI message handler.
   6 *
   7 * Author: MontaVista Software, Inc.
   8 *         Corey Minyard <minyard@mvista.com>
   9 *         source@mvista.com
  10 *
  11 * Copyright 2002 MontaVista Software Inc.
  12 */
  13
  14#include <linux/module.h>
  15#include <linux/moduleparam.h>
  16#include <linux/errno.h>
  17#include <linux/poll.h>
  18#include <linux/sched.h>
  19#include <linux/spinlock.h>
  20#include <linux/slab.h>
  21#include <linux/ipmi.h>
  22#include <linux/mutex.h>
  23#include <linux/init.h>
  24#include <linux/device.h>
  25#include <linux/compat.h>
  26
  27struct ipmi_file_private
  28{
  29        ipmi_user_t          user;
  30        spinlock_t           recv_msg_lock;
  31        struct list_head     recv_msgs;
  32        struct file          *file;
  33        struct fasync_struct *fasync_queue;
  34        wait_queue_head_t    wait;
  35        struct mutex         recv_mutex;
  36        int                  default_retries;
  37        unsigned int         default_retry_time_ms;
  38};
  39
  40static DEFINE_MUTEX(ipmi_mutex);
  41static void file_receive_handler(struct ipmi_recv_msg *msg,
  42                                 void                 *handler_data)
  43{
  44        struct ipmi_file_private *priv = handler_data;
  45        int                      was_empty;
  46        unsigned long            flags;
  47
  48        spin_lock_irqsave(&(priv->recv_msg_lock), flags);
  49
  50        was_empty = list_empty(&(priv->recv_msgs));
  51        list_add_tail(&(msg->link), &(priv->recv_msgs));
  52
  53        if (was_empty) {
  54                wake_up_interruptible(&priv->wait);
  55                kill_fasync(&priv->fasync_queue, SIGIO, POLL_IN);
  56        }
  57
  58        spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
  59}
  60
  61static __poll_t ipmi_poll(struct file *file, poll_table *wait)
  62{
  63        struct ipmi_file_private *priv = file->private_data;
  64        __poll_t             mask = 0;
  65        unsigned long            flags;
  66
  67        poll_wait(file, &priv->wait, wait);
  68
  69        spin_lock_irqsave(&priv->recv_msg_lock, flags);
  70
  71        if (!list_empty(&(priv->recv_msgs)))
  72                mask |= (EPOLLIN | EPOLLRDNORM);
  73
  74        spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
  75
  76        return mask;
  77}
  78
  79static int ipmi_fasync(int fd, struct file *file, int on)
  80{
  81        struct ipmi_file_private *priv = file->private_data;
  82        int                      result;
  83
  84        mutex_lock(&ipmi_mutex); /* could race against open() otherwise */
  85        result = fasync_helper(fd, file, on, &priv->fasync_queue);
  86        mutex_unlock(&ipmi_mutex);
  87
  88        return (result);
  89}
  90
  91static const struct ipmi_user_hndl ipmi_hndlrs =
  92{
  93        .ipmi_recv_hndl = file_receive_handler,
  94};
  95
  96static int ipmi_open(struct inode *inode, struct file *file)
  97{
  98        int                      if_num = iminor(inode);
  99        int                      rv;
 100        struct ipmi_file_private *priv;
 101
 102
 103        priv = kmalloc(sizeof(*priv), GFP_KERNEL);
 104        if (!priv)
 105                return -ENOMEM;
 106
 107        mutex_lock(&ipmi_mutex);
 108        priv->file = file;
 109
 110        rv = ipmi_create_user(if_num,
 111                              &ipmi_hndlrs,
 112                              priv,
 113                              &(priv->user));
 114        if (rv) {
 115                kfree(priv);
 116                goto out;
 117        }
 118
 119        file->private_data = priv;
 120
 121        spin_lock_init(&(priv->recv_msg_lock));
 122        INIT_LIST_HEAD(&(priv->recv_msgs));
 123        init_waitqueue_head(&priv->wait);
 124        priv->fasync_queue = NULL;
 125        mutex_init(&priv->recv_mutex);
 126
 127        /* Use the low-level defaults. */
 128        priv->default_retries = -1;
 129        priv->default_retry_time_ms = 0;
 130
 131out:
 132        mutex_unlock(&ipmi_mutex);
 133        return rv;
 134}
 135
 136static int ipmi_release(struct inode *inode, struct file *file)
 137{
 138        struct ipmi_file_private *priv = file->private_data;
 139        int                      rv;
 140        struct  ipmi_recv_msg *msg, *next;
 141
 142        rv = ipmi_destroy_user(priv->user);
 143        if (rv)
 144                return rv;
 145
 146        list_for_each_entry_safe(msg, next, &priv->recv_msgs, link)
 147                ipmi_free_recv_msg(msg);
 148
 149
 150        kfree(priv);
 151
 152        return 0;
 153}
 154
 155static int handle_send_req(ipmi_user_t     user,
 156                           struct ipmi_req *req,
 157                           int             retries,
 158                           unsigned int    retry_time_ms)
 159{
 160        int              rv;
 161        struct ipmi_addr addr;
 162        struct kernel_ipmi_msg msg;
 163
 164        if (req->addr_len > sizeof(struct ipmi_addr))
 165                return -EINVAL;
 166
 167        if (copy_from_user(&addr, req->addr, req->addr_len))
 168                return -EFAULT;
 169
 170        msg.netfn = req->msg.netfn;
 171        msg.cmd = req->msg.cmd;
 172        msg.data_len = req->msg.data_len;
 173        msg.data = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
 174        if (!msg.data)
 175                return -ENOMEM;
 176
 177        /* From here out we cannot return, we must jump to "out" for
 178           error exits to free msgdata. */
 179
 180        rv = ipmi_validate_addr(&addr, req->addr_len);
 181        if (rv)
 182                goto out;
 183
 184        if (req->msg.data != NULL) {
 185                if (req->msg.data_len > IPMI_MAX_MSG_LENGTH) {
 186                        rv = -EMSGSIZE;
 187                        goto out;
 188                }
 189
 190                if (copy_from_user(msg.data,
 191                                   req->msg.data,
 192                                   req->msg.data_len))
 193                {
 194                        rv = -EFAULT;
 195                        goto out;
 196                }
 197        } else {
 198                msg.data_len = 0;
 199        }
 200
 201        rv = ipmi_request_settime(user,
 202                                  &addr,
 203                                  req->msgid,
 204                                  &msg,
 205                                  NULL,
 206                                  0,
 207                                  retries,
 208                                  retry_time_ms);
 209 out:
 210        kfree(msg.data);
 211        return rv;
 212}
 213
 214static int handle_recv(struct ipmi_file_private *priv,
 215                        bool trunc, struct ipmi_recv *rsp,
 216                        int (*copyout)(struct ipmi_recv *, void __user *),
 217                        void __user *to)
 218{
 219        int              addr_len;
 220        struct list_head *entry;
 221        struct ipmi_recv_msg  *msg;
 222        unsigned long    flags;
 223        int rv = 0;
 224
 225        /* We claim a mutex because we don't want two
 226           users getting something from the queue at a time.
 227           Since we have to release the spinlock before we can
 228           copy the data to the user, it's possible another
 229           user will grab something from the queue, too.  Then
 230           the messages might get out of order if something
 231           fails and the message gets put back onto the
 232           queue.  This mutex prevents that problem. */
 233        mutex_lock(&priv->recv_mutex);
 234
 235        /* Grab the message off the list. */
 236        spin_lock_irqsave(&(priv->recv_msg_lock), flags);
 237        if (list_empty(&(priv->recv_msgs))) {
 238                spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
 239                rv = -EAGAIN;
 240                goto recv_err;
 241        }
 242        entry = priv->recv_msgs.next;
 243        msg = list_entry(entry, struct ipmi_recv_msg, link);
 244        list_del(entry);
 245        spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
 246
 247        addr_len = ipmi_addr_length(msg->addr.addr_type);
 248        if (rsp->addr_len < addr_len)
 249        {
 250                rv = -EINVAL;
 251                goto recv_putback_on_err;
 252        }
 253
 254        if (copy_to_user(rsp->addr, &(msg->addr), addr_len)) {
 255                rv = -EFAULT;
 256                goto recv_putback_on_err;
 257        }
 258        rsp->addr_len = addr_len;
 259
 260        rsp->recv_type = msg->recv_type;
 261        rsp->msgid = msg->msgid;
 262        rsp->msg.netfn = msg->msg.netfn;
 263        rsp->msg.cmd = msg->msg.cmd;
 264
 265        if (msg->msg.data_len > 0) {
 266                if (rsp->msg.data_len < msg->msg.data_len) {
 267                        rv = -EMSGSIZE;
 268                        if (trunc)
 269                                msg->msg.data_len = rsp->msg.data_len;
 270                        else
 271                                goto recv_putback_on_err;
 272                }
 273
 274                if (copy_to_user(rsp->msg.data,
 275                                 msg->msg.data,
 276                                 msg->msg.data_len))
 277                {
 278                        rv = -EFAULT;
 279                        goto recv_putback_on_err;
 280                }
 281                rsp->msg.data_len = msg->msg.data_len;
 282        } else {
 283                rsp->msg.data_len = 0;
 284        }
 285
 286        rv = copyout(rsp, to);
 287        if (rv)
 288                goto recv_putback_on_err;
 289
 290        mutex_unlock(&priv->recv_mutex);
 291        ipmi_free_recv_msg(msg);
 292        return 0;
 293
 294recv_putback_on_err:
 295        /* If we got an error, put the message back onto
 296           the head of the queue. */
 297        spin_lock_irqsave(&(priv->recv_msg_lock), flags);
 298        list_add(entry, &(priv->recv_msgs));
 299        spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
 300recv_err:
 301        mutex_unlock(&priv->recv_mutex);
 302        return rv;
 303}
 304
 305static int copyout_recv(struct ipmi_recv *rsp, void __user *to)
 306{
 307        return copy_to_user(to, rsp, sizeof(struct ipmi_recv)) ? -EFAULT : 0;
 308}
 309
 310static int ipmi_ioctl(struct file   *file,
 311                      unsigned int  cmd,
 312                      unsigned long data)
 313{
 314        int                      rv = -EINVAL;
 315        struct ipmi_file_private *priv = file->private_data;
 316        void __user *arg = (void __user *)data;
 317
 318        switch (cmd) 
 319        {
 320        case IPMICTL_SEND_COMMAND:
 321        {
 322                struct ipmi_req req;
 323
 324                if (copy_from_user(&req, arg, sizeof(req))) {
 325                        rv = -EFAULT;
 326                        break;
 327                }
 328
 329                rv = handle_send_req(priv->user,
 330                                     &req,
 331                                     priv->default_retries,
 332                                     priv->default_retry_time_ms);
 333                break;
 334        }
 335
 336        case IPMICTL_SEND_COMMAND_SETTIME:
 337        {
 338                struct ipmi_req_settime req;
 339
 340                if (copy_from_user(&req, arg, sizeof(req))) {
 341                        rv = -EFAULT;
 342                        break;
 343                }
 344
 345                rv = handle_send_req(priv->user,
 346                                     &req.req,
 347                                     req.retries,
 348                                     req.retry_time_ms);
 349                break;
 350        }
 351
 352        case IPMICTL_RECEIVE_MSG:
 353        case IPMICTL_RECEIVE_MSG_TRUNC:
 354        {
 355                struct ipmi_recv      rsp;
 356
 357                if (copy_from_user(&rsp, arg, sizeof(rsp)))
 358                        rv = -EFAULT;
 359                else
 360                        rv = handle_recv(priv, cmd == IPMICTL_RECEIVE_MSG_TRUNC,
 361                                         &rsp, copyout_recv, arg);
 362                break;
 363        }
 364
 365        case IPMICTL_REGISTER_FOR_CMD:
 366        {
 367                struct ipmi_cmdspec val;
 368
 369                if (copy_from_user(&val, arg, sizeof(val))) {
 370                        rv = -EFAULT;
 371                        break;
 372                }
 373
 374                rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd,
 375                                           IPMI_CHAN_ALL);
 376                break;
 377        }
 378
 379        case IPMICTL_UNREGISTER_FOR_CMD:
 380        {
 381                struct ipmi_cmdspec   val;
 382
 383                if (copy_from_user(&val, arg, sizeof(val))) {
 384                        rv = -EFAULT;
 385                        break;
 386                }
 387
 388                rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd,
 389                                             IPMI_CHAN_ALL);
 390                break;
 391        }
 392
 393        case IPMICTL_REGISTER_FOR_CMD_CHANS:
 394        {
 395                struct ipmi_cmdspec_chans val;
 396
 397                if (copy_from_user(&val, arg, sizeof(val))) {
 398                        rv = -EFAULT;
 399                        break;
 400                }
 401
 402                rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd,
 403                                           val.chans);
 404                break;
 405        }
 406
 407        case IPMICTL_UNREGISTER_FOR_CMD_CHANS:
 408        {
 409                struct ipmi_cmdspec_chans val;
 410
 411                if (copy_from_user(&val, arg, sizeof(val))) {
 412                        rv = -EFAULT;
 413                        break;
 414                }
 415
 416                rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd,
 417                                             val.chans);
 418                break;
 419        }
 420
 421        case IPMICTL_SET_GETS_EVENTS_CMD:
 422        {
 423                int val;
 424
 425                if (copy_from_user(&val, arg, sizeof(val))) {
 426                        rv = -EFAULT;
 427                        break;
 428                }
 429
 430                rv = ipmi_set_gets_events(priv->user, val);
 431                break;
 432        }
 433
 434        /* The next four are legacy, not per-channel. */
 435        case IPMICTL_SET_MY_ADDRESS_CMD:
 436        {
 437                unsigned int val;
 438
 439                if (copy_from_user(&val, arg, sizeof(val))) {
 440                        rv = -EFAULT;
 441                        break;
 442                }
 443
 444                rv = ipmi_set_my_address(priv->user, 0, val);
 445                break;
 446        }
 447
 448        case IPMICTL_GET_MY_ADDRESS_CMD:
 449        {
 450                unsigned int  val;
 451                unsigned char rval;
 452
 453                rv = ipmi_get_my_address(priv->user, 0, &rval);
 454                if (rv)
 455                        break;
 456
 457                val = rval;
 458
 459                if (copy_to_user(arg, &val, sizeof(val))) {
 460                        rv = -EFAULT;
 461                        break;
 462                }
 463                break;
 464        }
 465
 466        case IPMICTL_SET_MY_LUN_CMD:
 467        {
 468                unsigned int val;
 469
 470                if (copy_from_user(&val, arg, sizeof(val))) {
 471                        rv = -EFAULT;
 472                        break;
 473                }
 474
 475                rv = ipmi_set_my_LUN(priv->user, 0, val);
 476                break;
 477        }
 478
 479        case IPMICTL_GET_MY_LUN_CMD:
 480        {
 481                unsigned int  val;
 482                unsigned char rval;
 483
 484                rv = ipmi_get_my_LUN(priv->user, 0, &rval);
 485                if (rv)
 486                        break;
 487
 488                val = rval;
 489
 490                if (copy_to_user(arg, &val, sizeof(val))) {
 491                        rv = -EFAULT;
 492                        break;
 493                }
 494                break;
 495        }
 496
 497        case IPMICTL_SET_MY_CHANNEL_ADDRESS_CMD:
 498        {
 499                struct ipmi_channel_lun_address_set val;
 500
 501                if (copy_from_user(&val, arg, sizeof(val))) {
 502                        rv = -EFAULT;
 503                        break;
 504                }
 505
 506                return ipmi_set_my_address(priv->user, val.channel, val.value);
 507                break;
 508        }
 509
 510        case IPMICTL_GET_MY_CHANNEL_ADDRESS_CMD:
 511        {
 512                struct ipmi_channel_lun_address_set val;
 513
 514                if (copy_from_user(&val, arg, sizeof(val))) {
 515                        rv = -EFAULT;
 516                        break;
 517                }
 518
 519                rv = ipmi_get_my_address(priv->user, val.channel, &val.value);
 520                if (rv)
 521                        break;
 522
 523                if (copy_to_user(arg, &val, sizeof(val))) {
 524                        rv = -EFAULT;
 525                        break;
 526                }
 527                break;
 528        }
 529
 530        case IPMICTL_SET_MY_CHANNEL_LUN_CMD:
 531        {
 532                struct ipmi_channel_lun_address_set val;
 533
 534                if (copy_from_user(&val, arg, sizeof(val))) {
 535                        rv = -EFAULT;
 536                        break;
 537                }
 538
 539                rv = ipmi_set_my_LUN(priv->user, val.channel, val.value);
 540                break;
 541        }
 542
 543        case IPMICTL_GET_MY_CHANNEL_LUN_CMD:
 544        {
 545                struct ipmi_channel_lun_address_set val;
 546
 547                if (copy_from_user(&val, arg, sizeof(val))) {
 548                        rv = -EFAULT;
 549                        break;
 550                }
 551
 552                rv = ipmi_get_my_LUN(priv->user, val.channel, &val.value);
 553                if (rv)
 554                        break;
 555
 556                if (copy_to_user(arg, &val, sizeof(val))) {
 557                        rv = -EFAULT;
 558                        break;
 559                }
 560                break;
 561        }
 562
 563        case IPMICTL_SET_TIMING_PARMS_CMD:
 564        {
 565                struct ipmi_timing_parms parms;
 566
 567                if (copy_from_user(&parms, arg, sizeof(parms))) {
 568                        rv = -EFAULT;
 569                        break;
 570                }
 571
 572                priv->default_retries = parms.retries;
 573                priv->default_retry_time_ms = parms.retry_time_ms;
 574                rv = 0;
 575                break;
 576        }
 577
 578        case IPMICTL_GET_TIMING_PARMS_CMD:
 579        {
 580                struct ipmi_timing_parms parms;
 581
 582                parms.retries = priv->default_retries;
 583                parms.retry_time_ms = priv->default_retry_time_ms;
 584
 585                if (copy_to_user(arg, &parms, sizeof(parms))) {
 586                        rv = -EFAULT;
 587                        break;
 588                }
 589
 590                rv = 0;
 591                break;
 592        }
 593
 594        case IPMICTL_GET_MAINTENANCE_MODE_CMD:
 595        {
 596                int mode;
 597
 598                mode = ipmi_get_maintenance_mode(priv->user);
 599                if (copy_to_user(arg, &mode, sizeof(mode))) {
 600                        rv = -EFAULT;
 601                        break;
 602                }
 603                rv = 0;
 604                break;
 605        }
 606
 607        case IPMICTL_SET_MAINTENANCE_MODE_CMD:
 608        {
 609                int mode;
 610
 611                if (copy_from_user(&mode, arg, sizeof(mode))) {
 612                        rv = -EFAULT;
 613                        break;
 614                }
 615                rv = ipmi_set_maintenance_mode(priv->user, mode);
 616                break;
 617        }
 618        }
 619  
 620        return rv;
 621}
 622
 623/*
 624 * Note: it doesn't make sense to take the BKL here but
 625 *       not in compat_ipmi_ioctl. -arnd
 626 */
 627static long ipmi_unlocked_ioctl(struct file   *file,
 628                                unsigned int  cmd,
 629                                unsigned long data)
 630{
 631        int ret;
 632
 633        mutex_lock(&ipmi_mutex);
 634        ret = ipmi_ioctl(file, cmd, data);
 635        mutex_unlock(&ipmi_mutex);
 636
 637        return ret;
 638}
 639
 640#ifdef CONFIG_COMPAT
 641
 642/*
 643 * The following code contains code for supporting 32-bit compatible
 644 * ioctls on 64-bit kernels.  This allows running 32-bit apps on the
 645 * 64-bit kernel
 646 */
 647#define COMPAT_IPMICTL_SEND_COMMAND     \
 648        _IOR(IPMI_IOC_MAGIC, 13, struct compat_ipmi_req)
 649#define COMPAT_IPMICTL_SEND_COMMAND_SETTIME     \
 650        _IOR(IPMI_IOC_MAGIC, 21, struct compat_ipmi_req_settime)
 651#define COMPAT_IPMICTL_RECEIVE_MSG      \
 652        _IOWR(IPMI_IOC_MAGIC, 12, struct compat_ipmi_recv)
 653#define COMPAT_IPMICTL_RECEIVE_MSG_TRUNC        \
 654        _IOWR(IPMI_IOC_MAGIC, 11, struct compat_ipmi_recv)
 655
 656struct compat_ipmi_msg {
 657        u8              netfn;
 658        u8              cmd;
 659        u16             data_len;
 660        compat_uptr_t   data;
 661};
 662
 663struct compat_ipmi_req {
 664        compat_uptr_t           addr;
 665        compat_uint_t           addr_len;
 666        compat_long_t           msgid;
 667        struct compat_ipmi_msg  msg;
 668};
 669
 670struct compat_ipmi_recv {
 671        compat_int_t            recv_type;
 672        compat_uptr_t           addr;
 673        compat_uint_t           addr_len;
 674        compat_long_t           msgid;
 675        struct compat_ipmi_msg  msg;
 676};
 677
 678struct compat_ipmi_req_settime {
 679        struct compat_ipmi_req  req;
 680        compat_int_t            retries;
 681        compat_uint_t           retry_time_ms;
 682};
 683
 684/*
 685 * Define some helper functions for copying IPMI data
 686 */
 687static void get_compat_ipmi_msg(struct ipmi_msg *p64,
 688                                struct compat_ipmi_msg *p32)
 689{
 690        p64->netfn = p32->netfn;
 691        p64->cmd = p32->cmd;
 692        p64->data_len = p32->data_len;
 693        p64->data = compat_ptr(p32->data);
 694}
 695
 696static void get_compat_ipmi_req(struct ipmi_req *p64,
 697                                struct compat_ipmi_req *p32)
 698{
 699        p64->addr = compat_ptr(p32->addr);
 700        p64->addr_len = p32->addr_len;
 701        p64->msgid = p32->msgid;
 702        get_compat_ipmi_msg(&p64->msg, &p32->msg);
 703}
 704
 705static void get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
 706                struct compat_ipmi_req_settime *p32)
 707{
 708        get_compat_ipmi_req(&p64->req, &p32->req);
 709        p64->retries = p32->retries;
 710        p64->retry_time_ms = p32->retry_time_ms;
 711}
 712
 713static void get_compat_ipmi_recv(struct ipmi_recv *p64,
 714                                 struct compat_ipmi_recv *p32)
 715{
 716        memset(p64, 0, sizeof(struct ipmi_recv));
 717        p64->recv_type = p32->recv_type;
 718        p64->addr = compat_ptr(p32->addr);
 719        p64->addr_len = p32->addr_len;
 720        p64->msgid = p32->msgid;
 721        get_compat_ipmi_msg(&p64->msg, &p32->msg);
 722}
 723
 724static int copyout_recv32(struct ipmi_recv *p64, void __user *to)
 725{
 726        struct compat_ipmi_recv v32;
 727        memset(&v32, 0, sizeof(struct compat_ipmi_recv));
 728        v32.recv_type = p64->recv_type;
 729        v32.addr = ptr_to_compat(p64->addr);
 730        v32.addr_len = p64->addr_len;
 731        v32.msgid = p64->msgid;
 732        v32.msg.netfn = p64->msg.netfn;
 733        v32.msg.cmd = p64->msg.cmd;
 734        v32.msg.data_len = p64->msg.data_len;
 735        v32.msg.data = ptr_to_compat(p64->msg.data);
 736        return copy_to_user(to, &v32, sizeof(v32)) ? -EFAULT : 0;
 737}
 738
 739/*
 740 * Handle compatibility ioctls
 741 */
 742static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
 743                              unsigned long arg)
 744{
 745        struct ipmi_file_private *priv = filep->private_data;
 746
 747        switch(cmd) {
 748        case COMPAT_IPMICTL_SEND_COMMAND:
 749        {
 750                struct ipmi_req rp;
 751                struct compat_ipmi_req r32;
 752
 753                if (copy_from_user(&r32, compat_ptr(arg), sizeof(r32)))
 754                        return -EFAULT;
 755
 756                get_compat_ipmi_req(&rp, &r32);
 757
 758                return handle_send_req(priv->user, &rp,
 759                                priv->default_retries,
 760                                priv->default_retry_time_ms);
 761        }
 762        case COMPAT_IPMICTL_SEND_COMMAND_SETTIME:
 763        {
 764                struct ipmi_req_settime sp;
 765                struct compat_ipmi_req_settime sp32;
 766
 767                if (copy_from_user(&sp32, compat_ptr(arg), sizeof(sp32)))
 768                        return -EFAULT;
 769
 770                get_compat_ipmi_req_settime(&sp, &sp32);
 771
 772                return handle_send_req(priv->user, &sp.req,
 773                                sp.retries, sp.retry_time_ms);
 774        }
 775        case COMPAT_IPMICTL_RECEIVE_MSG:
 776        case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC:
 777        {
 778                struct ipmi_recv   recv64;
 779                struct compat_ipmi_recv recv32;
 780
 781                if (copy_from_user(&recv32, compat_ptr(arg), sizeof(recv32)))
 782                        return -EFAULT;
 783
 784                get_compat_ipmi_recv(&recv64, &recv32);
 785
 786                return handle_recv(priv,
 787                                 cmd == COMPAT_IPMICTL_RECEIVE_MSG_TRUNC,
 788                                 &recv64, copyout_recv32, compat_ptr(arg));
 789        }
 790        default:
 791                return ipmi_ioctl(filep, cmd, arg);
 792        }
 793}
 794
 795static long unlocked_compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
 796                                       unsigned long arg)
 797{
 798        int ret;
 799
 800        mutex_lock(&ipmi_mutex);
 801        ret = compat_ipmi_ioctl(filep, cmd, arg);
 802        mutex_unlock(&ipmi_mutex);
 803
 804        return ret;
 805}
 806#endif
 807
 808static const struct file_operations ipmi_fops = {
 809        .owner          = THIS_MODULE,
 810        .unlocked_ioctl = ipmi_unlocked_ioctl,
 811#ifdef CONFIG_COMPAT
 812        .compat_ioctl   = unlocked_compat_ipmi_ioctl,
 813#endif
 814        .open           = ipmi_open,
 815        .release        = ipmi_release,
 816        .fasync         = ipmi_fasync,
 817        .poll           = ipmi_poll,
 818        .llseek         = noop_llseek,
 819};
 820
 821#define DEVICE_NAME     "ipmidev"
 822
 823static int ipmi_major;
 824module_param(ipmi_major, int, 0);
 825MODULE_PARM_DESC(ipmi_major, "Sets the major number of the IPMI device.  By"
 826                 " default, or if you set it to zero, it will choose the next"
 827                 " available device.  Setting it to -1 will disable the"
 828                 " interface.  Other values will set the major device number"
 829                 " to that value.");
 830
 831/* Keep track of the devices that are registered. */
 832struct ipmi_reg_list {
 833        dev_t            dev;
 834        struct list_head link;
 835};
 836static LIST_HEAD(reg_list);
 837static DEFINE_MUTEX(reg_list_mutex);
 838
 839static struct class *ipmi_class;
 840
 841static void ipmi_new_smi(int if_num, struct device *device)
 842{
 843        dev_t dev = MKDEV(ipmi_major, if_num);
 844        struct ipmi_reg_list *entry;
 845
 846        entry = kmalloc(sizeof(*entry), GFP_KERNEL);
 847        if (!entry) {
 848                printk(KERN_ERR "ipmi_devintf: Unable to create the"
 849                       " ipmi class device link\n");
 850                return;
 851        }
 852        entry->dev = dev;
 853
 854        mutex_lock(&reg_list_mutex);
 855        device_create(ipmi_class, device, dev, NULL, "ipmi%d", if_num);
 856        list_add(&entry->link, &reg_list);
 857        mutex_unlock(&reg_list_mutex);
 858}
 859
 860static void ipmi_smi_gone(int if_num)
 861{
 862        dev_t dev = MKDEV(ipmi_major, if_num);
 863        struct ipmi_reg_list *entry;
 864
 865        mutex_lock(&reg_list_mutex);
 866        list_for_each_entry(entry, &reg_list, link) {
 867                if (entry->dev == dev) {
 868                        list_del(&entry->link);
 869                        kfree(entry);
 870                        break;
 871                }
 872        }
 873        device_destroy(ipmi_class, dev);
 874        mutex_unlock(&reg_list_mutex);
 875}
 876
 877static struct ipmi_smi_watcher smi_watcher =
 878{
 879        .owner    = THIS_MODULE,
 880        .new_smi  = ipmi_new_smi,
 881        .smi_gone = ipmi_smi_gone,
 882};
 883
 884static int __init init_ipmi_devintf(void)
 885{
 886        int rv;
 887
 888        if (ipmi_major < 0)
 889                return -EINVAL;
 890
 891        printk(KERN_INFO "ipmi device interface\n");
 892
 893        ipmi_class = class_create(THIS_MODULE, "ipmi");
 894        if (IS_ERR(ipmi_class)) {
 895                printk(KERN_ERR "ipmi: can't register device class\n");
 896                return PTR_ERR(ipmi_class);
 897        }
 898
 899        rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops);
 900        if (rv < 0) {
 901                class_destroy(ipmi_class);
 902                printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major);
 903                return rv;
 904        }
 905
 906        if (ipmi_major == 0) {
 907                ipmi_major = rv;
 908        }
 909
 910        rv = ipmi_smi_watcher_register(&smi_watcher);
 911        if (rv) {
 912                unregister_chrdev(ipmi_major, DEVICE_NAME);
 913                class_destroy(ipmi_class);
 914                printk(KERN_WARNING "ipmi: can't register smi watcher\n");
 915                return rv;
 916        }
 917
 918        return 0;
 919}
 920module_init(init_ipmi_devintf);
 921
 922static void __exit cleanup_ipmi(void)
 923{
 924        struct ipmi_reg_list *entry, *entry2;
 925        mutex_lock(&reg_list_mutex);
 926        list_for_each_entry_safe(entry, entry2, &reg_list, link) {
 927                list_del(&entry->link);
 928                device_destroy(ipmi_class, entry->dev);
 929                kfree(entry);
 930        }
 931        mutex_unlock(&reg_list_mutex);
 932        class_destroy(ipmi_class);
 933        ipmi_smi_watcher_unregister(&smi_watcher);
 934        unregister_chrdev(ipmi_major, DEVICE_NAME);
 935}
 936module_exit(cleanup_ipmi);
 937
 938MODULE_LICENSE("GPL");
 939MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
 940MODULE_DESCRIPTION("Linux device interface for the IPMI message handler.");
 941