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