diff options
author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-07-06 18:04:32 +0200 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-07-06 18:04:32 +0200 |
commit | a7f89980e5b3f4b9a74c70dbc5ffe8aabd28be28 (patch) | |
tree | 41c4deec1fdfbafd7821b4ca7a9772ac0abd92f5 /kern/ipmi_kcs.patch |
Imported Upstream version 2.9.3upstream/2.9.3
Diffstat (limited to 'kern/ipmi_kcs.patch')
-rw-r--r-- | kern/ipmi_kcs.patch | 1592 |
1 files changed, 1592 insertions, 0 deletions
diff --git a/kern/ipmi_kcs.patch b/kern/ipmi_kcs.patch new file mode 100644 index 0000000..15f9a10 --- /dev/null +++ b/kern/ipmi_kcs.patch @@ -0,0 +1,1592 @@ +--- linux-2.4.2-virgin/drivers/char/misc.c Sun Apr 8 18:22:17 2001 ++++ linux-bmc/drivers/char/misc.c Tue Oct 30 17:18:07 2001 +@@ -273,6 +273,9 @@ + #ifdef CONFIG_TOSHIBA + tosh_init(); + #endif ++#ifdef CONFIG_IPMI_KCS ++ ipmi_kcs_init(); ++#endif + if (devfs_register_chrdev(MISC_MAJOR,"misc",&misc_fops)) { + printk("unable to get major %d for misc devices\n", + MISC_MAJOR); +--- linux-2.4.2-virgin/drivers/char/Config.in Sun Apr 8 18:22:22 2001 ++++ linux-bmc/drivers/char/Config.in Tue Oct 30 17:18:07 2001 +@@ -81,6 +81,11 @@ + dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT + fi + ++tristate 'IPMI KCS Interface' CONFIG_IPMI_KCS ++if [ "$CONFIG_IPMI_KCS" != "n" ]; then ++ bool ' BMC watchdog timer support' CONFIG_BMC_WDT ++fi ++ + source drivers/i2c/Config.in + + source drivers/sensors/Config.in +--- linux-2.4.2-virgin/drivers/char/Makefile Sun Apr 8 18:22:17 2001 ++++ linux-bmc/drivers/char/Makefile Tue Oct 30 17:18:08 2001 +@@ -191,6 +191,8 @@ + obj-$(CONFIG_NWBUTTON) += nwbutton.o + obj-$(CONFIG_NWFLASH) += nwflash.o + ++obj-$(CONFIG_IPMI_KCS) += ipmi_kcs.o ++ + # Only one watchdog can succeed. We probe the hardware watchdog + # drivers first, then the softdog driver. This means if your hardware + # watchdog dies or is 'borrowed' for some reason the software watchdog +--- linux-2.4.2-virgin/include/linux/miscdevice.h Sun Apr 8 18:47:26 2001 ++++ linux-bmc/include/linux/miscdevice.h Tue Oct 30 17:32:42 2001 +@@ -31,6 +31,9 @@ + #define SGI_STREAMS_KEYBOARD 150 + /* drivers/sgi/char/usema.c */ + #define SGI_USEMACLONE 151 ++#define IPMI_KCS_MINOR 173 ++#define IPMI_BT_MINOR 210 ++#define IPMI_SMIC_MINOR 211 + + #define TUN_MINOR 200 + +--- /dev/null Fri Mar 23 23:37:44 2001 ++++ linux-bmc/drivers/char/ipmi_kcs.c Tue Oct 30 17:18:07 2001 +@@ -0,0 +1,1211 @@ ++/* ++ * Intelligent Platform Management Interface driver for Linux 2.2.x ++ * ++ * (c) Copyright 2000 San Mehat <nettwerk@valinux.com>, All Rights Reserved. ++ * http://www.valinux.com ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ * ++ * Neither San Mehat nor VA Linux Systems admit liability nor provide ++ * warranty for any of this software. This material is provided ++ * "AS-IS" and at no charge. ++ * ++ * (c) Copyright 1999 San Mehat <nettwerk@valinux.com> ++ * ++ * Release 0.04. - Initial Release ++ * ++ * Release 0.05. - Fixed ring buffer bugs... better buffer handling ++ * ++ * Release 0.06. - Changed polling freq to 1/10 sec ++ * ++ * Release 0.07. - Integrated watchdog commands into IOCTL's and added ++ * support for blinking front panel LED ++ * ++ * Release 0.08. - Sensor read commands added as ioctl ++ * ++ * Release 0.09. - Changed polling freq back to 1 second ++ * - Fixed possible bug where a chip status variable was ++ * not declared volatile. ++ * - Fixed buffer memory leak ++ * - Fixed ioctl return value problem ++ * - Changed architecture so that applications calling ++ * driver ioctl()'s are put to sleep after request ++ * is sent. The reply is handled by the normal ++ * driver polling timer queue and ring buffer ++ * ++ * Release 0.10. - Modified kcs_write routine so once a write is complete ++ * if the interface isn't in a 'READ STATE' it's okay. ++ * ++ * Release 0.12. - Added Intel Nightshade MB fixups since NS boards don't ++ * support pre-timeout NMI support ++ * - FRU download support added ++ * - /proc/ipmi created with fru data and driver status ++ * Release 0.13. - Added ioctl for setting asset tag ++ * - Fixed bug in /proc ++ * - Added asset tag max length field ++ * Release 1.00 - Added intelligent proc reading so that asset tag is ++ * refreshed whenever /proc/ipmi is read ++ * - Code cleanup ++ * - When asset tag is set with data whoes size is < maximum, ++ * pad the rest out with NULLs ++ * Release 1.10 - Fixed SMP bug which was causing command failures when ++ * /proc/ipmi was being read while a command was being ++ * executed (added semaphore) ++ * - Fixed /proc/ipmi so commands only get issued once ++ * Release 1.20 - Removed a bunch of useless warning msgs ++ * Release 1.30 - Added more stringent error checking when ISA state ++ * enters ERROR_STATE ++ * - Added better unexpected OBF handling on transactions ++ * - Explicitly set power sensor state to NO BLINKY on ++ * startup ++ * Release 2.0 - Re-wrote kcs state machine ++ * - Removed high level functions from driver ++ * - removed driver read() and write() capabilities ++ * - /proc/ipmi renamed to /proc/ipmi_kcs ++ * - /proc/ipmi_kcs now contains only BMC info ++ * ++ * Release 2.1 - Added support of watchdog timer through /dev/watchdog ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/smp_lock.h> ++#include <linux/miscdevice.h> ++#include "ipmi_kcs.h" ++#include <linux/malloc.h> ++#include <linux/ioport.h> ++#include <linux/fcntl.h> ++#include <asm/io.h> ++#include <asm/uaccess.h> ++#include <asm/system.h> ++#include <asm/semaphore.h> ++#include <linux/notifier.h> ++#include <linux/reboot.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/timer.h> ++#include <linux/ipmi_ioctls.h> ++#include <linux/pci.h> ++ ++#ifdef CONFIG_PROC_FS ++#include <linux/proc_fs.h> ++#endif ++ ++#ifdef CONFIG_BMC_WDT ++#include <linux/watchdog.h> ++#endif ++ ++/* function prototypes */ ++ ++int ipmi_kcs_init(void); ++ ++static int kcs_open(struct inode *inode, struct file *file); ++static int kcs_release(struct inode *inode, struct file *file); ++static ssize_t kcs_read(struct file *file, char *buf, size_t count, ++ loff_t * ptr); ++static ssize_t kcs_write(struct file *file, const char *buf, size_t count, ++ loff_t * ppos); ++static long long kcs_llseek(struct file *file, long long offset, ++ int origin); ++static int kcs_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg); ++ ++#ifdef CONFIG_BMC_WDT ++static int wdt_is_open; ++static int watchdog_set(int cmd); ++static int watchdog_reset(void); ++static int wdt_open(struct inode *inode, struct file *file); ++static int wdt_release(struct inode *inode, struct file *file); ++static ssize_t wdt_write(struct file *file, const char *buf, size_t count, ++ loff_t * ppos); ++static int wdt_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg); ++ ++static struct file_operations wdt_fops = { ++ owner:THIS_MODULE, ++ write:wdt_write, ++ ioctl:wdt_ioctl, ++ open:wdt_open, ++ release:wdt_release, ++}; ++ ++static struct miscdevice wdt_miscdev = { ++ WATCHDOG_MINOR, ++ "bmc_wdt", ++ &wdt_fops ++}; ++ ++/* module parameters */ ++static int wdt_margin = 60; /* watchdog timer interval in seconds */ ++static int wdt_pre = 1; /* watchdog pre-timeout interval in seconds */ ++static int wdt_action = 0x03; /* Default is no pre-timeout interrupt and power cycle upon timeout */ ++ ++MODULE_PARM(wdt_margin, "i"); ++MODULE_PARM(wdt_pre, "i"); ++MODULE_PARM(wdt_action, "i"); ++ ++#define WATCHDOG_ENABLE 0x01 ++#define WATCHDOG_DISABLE 0x02 ++#endif ++ ++static unsigned char get_kcs_state(void); ++static unsigned char read_kcs_data(void); ++static void write_kcs_data(unsigned char data); ++static void write_kcs_cmd(unsigned char cmd); ++static int is_obf_set(void); ++static int clear_obf(void); ++static int wait_while_ibf(void); ++static int get_deviceid(void); ++static int kcs_do_xfer(BMC_REQUEST * request, int request_len, ++ BMC_RESPONSE * response, int *response_len); ++static int old_kcs_do_xfer(BMC_REQUEST * request, int request_len, ++ BMC_RESPONSE * response, int *response_len); ++static int new_kcs_do_xfer(BMC_REQUEST * request, int request_len, ++ BMC_RESPONSE * response, int *response_len); ++ ++#ifdef CONFIG_PROC_FS ++int ipmi_get_info(char *buf, char **start, off_t fpos, int length, ++ int *eof, void *unused); ++#endif ++ ++/* static globals */ ++static int kcs_refcnt = 0; ++static int driver_major = 2; ++static int driver_minor = 1; ++static int kcs_machine = 0; ++ ++static struct { ++ unsigned int tx_good; ++ unsigned int tx_bad; ++} kcs_stat; ++ ++static DEVICE_ID_RESPONSE dev_id; ++DECLARE_MUTEX(kcs_sem); ++ ++#ifdef CONFIG_PROC_FS ++static struct proc_dir_entry *ipmi_proc_entry; ++#endif ++ ++static struct file_operations kcs_fops = { ++ owner:THIS_MODULE, ++ write:kcs_write, ++ ioctl:kcs_ioctl, ++ open:kcs_open, ++ release:kcs_release, ++ read:kcs_read, ++}; ++ ++static struct miscdevice kcs_miscdev = { ++ IPMI_KCS_MINOR, ++ "ipmi_kcs", ++ &kcs_fops ++}; ++ ++static struct ipmi_driver_info drv_inf; ++ ++/***************/ ++ ++static long long kcs_llseek(struct file *file, long long offset, ++ int origin) ++{ ++ return -ESPIPE; ++} ++ ++static ssize_t kcs_write(struct file *file, const char *buf, size_t count, ++ loff_t * ppos) ++{ ++ return (-ENOSYS); ++} ++ ++static ssize_t kcs_read(struct file *file, char *buf, size_t count, ++ loff_t * ptr) ++{ ++ return (-ENOSYS); ++} ++ ++static int kcs_ioctl(struct inode *inode, ++ struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ switch (cmd) { ++ case IOCTL_IPMI_XFER: ++ { ++ IPMI_XFER user_buffer; ++ int rc; ++ int response_len = sizeof(user_buffer.response); ++ ++ if (!arg) ++ return (-EFAULT); ++ if (copy_from_user ++ ((void *) &user_buffer, (void *) arg, ++ sizeof(IPMI_XFER))) ++ return (-EFAULT); ++ if ((user_buffer.request_len < 2) ++ || (user_buffer.response_len < 3)) ++ return (-EINVAL); ++ ++ rc = kcs_do_xfer((BMC_REQUEST *) & user_buffer. ++ request, user_buffer.request_len, ++ (BMC_RESPONSE *) & user_buffer. ++ response, &response_len); ++ user_buffer.response_len = response_len; ++ copy_to_user((void *) arg, (void *) &user_buffer, ++ sizeof(IPMI_XFER)); ++ return (rc); ++ } ++ case IOCTL_DRIVER_INFO: ++ { ++ struct ipmi_driver_info user_buffer; ++ ++ if (!arg) ++ return (-EFAULT); ++ if (copy_from_user ++ ((void *) &user_buffer, (void *) arg, ++ sizeof(user_buffer))) ++ return (-EFAULT); ++ copy_to_user((void *) arg, (void *) &drv_inf, ++ sizeof(drv_inf)); ++ return (0); ++ } ++ default: ++ return -EINVAL; ++ } ++ return (0); ++} ++ ++static int get_deviceid() ++{ ++ unsigned char request_buffer[MAX_BUFFER_SIZE]; ++ unsigned char response_buffer[MAX_BUFFER_SIZE]; ++ BMC_REQUEST *bmc_req; ++ BMC_RESPONSE *bmc_resp; ++ int rc, response_len; ++ ++ memset(&dev_id, 0, sizeof(DEVICE_ID_RESPONSE)); ++ memset(request_buffer, 0, sizeof(request_buffer)); ++ memset(response_buffer, 0, sizeof(response_buffer)); ++ bmc_req = (BMC_REQUEST *) request_buffer; ++ bmc_resp = (BMC_RESPONSE *) response_buffer; ++ response_len = sizeof(response_buffer); ++ ++ bmc_req->lun = 0; ++ bmc_req->netfn = APP_REQUEST; ++ bmc_req->cmd = 0x01; /* GET_DEVICE_ID */ ++ ++#if defined(__ia64__) ++ rc = new_kcs_do_xfer(bmc_req, 2, bmc_resp, &response_len); ++#else ++ rc = old_kcs_do_xfer(bmc_req, 2, bmc_resp, &response_len); ++#endif ++ if (bmc_resp->cc != 0x00) { ++ printk("[IPMI_KCS] get_deviceid() failed (0x%.2x)\n", ++ bmc_resp->cc); ++ return (-EIO); ++ } ++ memcpy(&dev_id, bmc_resp->data, sizeof(DEVICE_ID_RESPONSE)); ++ return (0); ++} ++ ++static int kcs_open(struct inode *inode, struct file *file) ++{ ++ switch (MINOR(inode->i_rdev)) { ++ case IPMI_KCS_MINOR: ++ { ++ MOD_INC_USE_COUNT; ++ kcs_refcnt++; ++ return 0; ++ } ++ default: ++ return -ENODEV; ++ } ++} ++ ++static int kcs_release(struct inode *inode, struct file *file) ++{ ++ if (MINOR(inode->i_rdev) == IPMI_KCS_MINOR) { ++ kcs_refcnt--; ++ } ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++#ifdef CONFIG_BMC_WDT ++static ssize_t wdt_write(struct file *file, const char *buf, size_t count, ++ loff_t * ppos) ++{ ++ /* Can't seek (pwrite) on this device */ ++ if (ppos != &file->f_pos) ++ return -ESPIPE; ++ ++ /* ++ * Stop and then restart the watchdog timer. ++ */ ++ if (count) { ++ if (watchdog_set(WATCHDOG_DISABLE)) ++ return -EIO; ++ if (watchdog_set(WATCHDOG_ENABLE)) ++ return -EIO; ++ if (watchdog_reset()) ++ return -EIO; ++ return 1; ++ } ++ return 0; ++} ++ ++static int wdt_ioctl(struct inode *inode, ++ struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ static struct watchdog_info ident = { ++ WDIOF_KEEPALIVEPING, 1, "BMC WDT" ++ }; ++ ++ switch (cmd) { ++ case WDIOC_GETSUPPORT: ++ if (copy_to_user ++ ((struct watchdog_info *) arg, &ident, sizeof(ident))) ++ return -EFAULT; ++ break; ++ ++ case WDIOC_GETSTATUS: ++ if (copy_to_user((int *) arg, &wdt_is_open, sizeof(int))) ++ return -EFAULT; ++ break; ++ ++ case WDIOC_KEEPALIVE: ++ if (watchdog_set(WATCHDOG_DISABLE)) ++ return -EIO; ++ if (watchdog_set(WATCHDOG_ENABLE)) ++ return -EIO; ++ if (watchdog_reset()) ++ return -EIO; ++ break; ++ ++ default: ++ return -ENOIOCTLCMD; ++ } ++ return 0; ++} ++ ++static int watchdog_set(int cmd) ++{ ++ unsigned char request_buffer[MAX_BUFFER_SIZE]; ++ unsigned char response_buffer[MAX_BUFFER_SIZE]; ++ BMC_REQUEST *bmc_req; ++ BMC_RESPONSE *bmc_resp; ++ int rc, response_len; ++ SET_WATCHDOG *set; ++ int fixup = 0; ++ ++ memset(request_buffer, 0, sizeof(request_buffer)); ++ memset(response_buffer, 0, sizeof(response_buffer)); ++ bmc_req = (BMC_REQUEST *) request_buffer; ++ bmc_resp = (BMC_RESPONSE *) response_buffer; ++ response_len = sizeof(response_buffer); ++ ++ bmc_req->lun = 0; ++ bmc_req->netfn = APP_REQUEST; ++ bmc_req->cmd = 0x24; /* Set Watchdog Timer */ ++ ++ set = (SET_WATCHDOG *) bmc_req->data; ++ ++ while (1) { ++ set->timer_use = 0x04; ++ ++ set->timeout_action = wdt_action & 0x0F; ++ set->pre_irq = (wdt_action >> 4) & 0x0F; ++ ++ if (cmd == WATCHDOG_DISABLE) { ++ set->timeout_action = 0x00; ++ set->pre_irq = 0x00; ++ } ++ set->pretimeout_interval = wdt_pre; ++ ++ if (fixup) { ++ set->pre_irq = 0x00; ++ set->pretimeout_interval = 0; ++ } ++ ++ set->tuefc_biosfrb2 = 0x00; ++ set->tuefc_biospost = 0x0; ++ set->tuefc_osload = 0x00; ++ set->tuefc_smsos = 0x01; ++ set->initial_count = wdt_margin * 10; ++ ++ rc = kcs_do_xfer(bmc_req, 2 + sizeof(SET_WATCHDOG), ++ bmc_resp, &response_len); ++ ++ if (bmc_resp->cc == 0xcc) { ++ fixup++; ++ if (fixup == 2) { ++ printk ++ ("[IPMI_KCS] Flakey NMI fixup failed\n"); ++ return (-EIO); ++ } ++ printk("[IPMI_KCS] Flakey NMI fixup enabled\n"); ++ continue; ++ } else if (bmc_resp->cc != 0x00) { ++ printk ++ ("[IPMI_KCS] Set watchdog timer failed (rc = 0x%.2x)\n", ++ bmc_resp->cc); ++ return (-EIO); ++ } ++ break; ++ } ++ return (0); ++} ++ ++static int watchdog_reset() ++{ ++ unsigned char request_buffer[MAX_BUFFER_SIZE]; ++ unsigned char response_buffer[MAX_BUFFER_SIZE]; ++ BMC_REQUEST *bmc_req; ++ BMC_RESPONSE *bmc_resp; ++ int rc, response_len; ++ ++ memset(request_buffer, 0, sizeof(request_buffer)); ++ memset(response_buffer, 0, sizeof(response_buffer)); ++ bmc_req = (BMC_REQUEST *) request_buffer; ++ bmc_resp = (BMC_RESPONSE *) response_buffer; ++ response_len = sizeof(response_buffer); ++ ++ bmc_req->lun = 0; ++ bmc_req->netfn = APP_REQUEST; ++ bmc_req->cmd = 0x22; /* Reset Watchdog Timer */ ++ ++ rc = kcs_do_xfer(bmc_req, 2, bmc_resp, &response_len); ++ if (bmc_resp->cc != 0x00) { ++ printk("[IPMI_KCS] Reset Watchdog Timer failed (0x%.2x)\n", ++ bmc_resp->cc); ++ return (-EIO); ++ } ++ return (0); ++} ++ ++static int wdt_open(struct inode *inode, struct file *file) ++{ ++ switch (MINOR(inode->i_rdev)) { ++ case WATCHDOG_MINOR: ++ if (wdt_is_open) ++ return -EBUSY; ++ ++ MOD_INC_USE_COUNT; ++ /* ++ * Activate ++ */ ++ wdt_is_open = 1; ++ if (watchdog_reset()) ++ return -EIO; ++ return 0; ++ default: ++ return -ENODEV; ++ } ++} ++ ++static int wdt_release(struct inode *inode, struct file *file) ++{ ++ lock_kernel(); ++ if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) { ++#ifndef CONFIG_WATCHDOG_NOWAYOUT ++ if (watchdog_set(WATCHDOG_DISABLE)) ++ return -EIO; ++#endif ++ wdt_is_open = 0; ++ MOD_DEC_USE_COUNT; ++ } ++ unlock_kernel(); ++ return 0; ++} ++ ++/* ++ * Notifier for system down ++ */ ++ ++static int wdt_notify_sys(struct notifier_block *this, unsigned long code, ++ void *unused) ++{ ++ if (code == SYS_DOWN || code == SYS_HALT) { ++ /* Turn the timer off */ ++ watchdog_set(WATCHDOG_DISABLE); ++ } ++ return NOTIFY_DONE; ++} ++ ++/* ++ * The BMC needs to learn about soft shutdowns in order to ++ * turn the watchdog timer off. ++ */ ++ ++static struct notifier_block wdt_notifier = { ++ wdt_notify_sys, ++ NULL, ++ 0 ++}; ++#endif ++ ++#ifdef MODULE ++int init_module(void) ++{ ++ return (ipmi_kcs_init()); ++} ++ ++void cleanup_module(void) ++{ ++ printk("[IPMI_KCS] Driver shutting down.\n"); ++#ifdef CONFIG_PROC_FS ++ remove_proc_entry("ipmi_kcs", 0); ++#endif ++ misc_deregister(&kcs_miscdev); ++#ifdef CONFIG_BMC_WDT ++ misc_deregister(&wdt_miscdev); ++ unregister_reboot_notifier(&wdt_notifier); ++#endif ++ release_region(KCS_BASE, 16); ++} ++#endif ++ ++int ipmi_kcs_init() ++{ ++ printk ++ ("IPMI KCS driver (San Mehat nettwerk@valinux.com) v%d.%d at io 0x%x\n", ++ driver_major, driver_minor, KCS_BASE); ++ request_region(KCS_BASE, 16, "ipmi_kcs"); ++ if ((inb_p(KCS_STATUS_REG) == 0xFF) && ++ (inb_p(KCS_DATAIN_REG) == 0xFF)) { ++ printk("--KCS ISA window not present. Driver exiting\n"); ++ release_region(KCS_BASE, 16); ++ return (-ENXIO); ++ } ++ ++ kcs_stat.tx_good = 0; ++ kcs_stat.tx_bad = 0; ++ memset(&drv_inf, 0, sizeof(drv_inf)); ++ strcpy(drv_inf.driver_name, "ipmi_kcs"); ++ drv_inf.major_ver = driver_major; ++ drv_inf.minor_ver = driver_minor; ++ ++ misc_register(&kcs_miscdev); ++#ifdef CONFIG_BMC_WDT ++ misc_register(&wdt_miscdev); ++ register_reboot_notifier(&wdt_notifier); ++#endif ++ get_deviceid(); ++ printk("--BMC version %x.%x, IPMI version %d.%d\n", ++ dev_id.major_firmware_revision, ++ dev_id.minor_firmware_revision, ++ dev_id.ipmi_version_major, dev_id.ipmi_version_minor); ++ if ((dev_id.ipmi_version_major == 0) && ++ (dev_id.ipmi_version_minor == 9)) { ++ printk("--Using legacy KCS state machine\n"); ++ kcs_machine = KCS_LEGACY; ++ drv_inf.flags |= KCS_FLAG_LEGACY; ++ } else { ++ printk("--Using new KCS state machine\n"); ++ kcs_machine = KCS_NEW; ++ } ++ if (!pci_present()) { ++ printk ++ ("--PCIBIOS not present. Unable to determine chipset vendor\n"); ++ drv_inf.flags |= KCS_FLAG_BLINKY; ++ } else { ++ int pci_index = 0; ++ unsigned char pci_bus, pci_device_fn; ++ unsigned short vendor, device; ++ ++ for (; pci_index < 0xff; pci_index++) { ++ if (pcibios_find_class(PCI_CLASS_BRIDGE_HOST << 8, ++ pci_index, ++ &pci_bus, ++ &pci_device_fn) != ++ PCIBIOS_SUCCESSFUL) { ++ break; ++ } ++ pcibios_read_config_word(pci_bus, pci_device_fn, ++ PCI_VENDOR_ID, &vendor); ++ pcibios_read_config_word(pci_bus, pci_device_fn, ++ PCI_DEVICE_ID, &device); ++ drv_inf.mb_chipset_vendor = vendor; ++ drv_inf.mb_chipset_device = device; ++ printk ++ ("--Motherboard Chipset vendor 0x%.4x, device 0x%.4x\n", ++ vendor, device); ++ if ((vendor == 0x8086) && (device == 0x71a0)) { ++ drv_inf.flags |= KCS_FLAG_BLINKY; ++ } ++ } ++ } ++ if (drv_inf.flags & KCS_FLAG_BLINKY) { ++ printk("--Intel Lancewood features enabled\n"); ++ } else ++ printk("--No vendor specific features enabled\n"); ++#ifdef CONFIG_PROC_FS ++ if (!(ipmi_proc_entry = create_proc_entry("ipmi_kcs", 0, 0))) ++ printk(KERN_ERR, ++ "--ERROR: Unable to register /proc/ipmi_kcs\n"); ++ else ++ ipmi_proc_entry->read_proc = ipmi_get_info; ++ ++#endif ++ return (0); ++} ++ ++static int kcs_do_xfer(BMC_REQUEST * request, ++ int request_len, ++ BMC_RESPONSE * response, int *response_len) ++{ ++ int rc = 0; ++ ++ down(&kcs_sem); ++ switch (kcs_machine) { ++ case KCS_LEGACY: ++ { ++ rc = old_kcs_do_xfer(request, request_len, ++ response, response_len); ++ break; ++ } ++ case KCS_NEW: ++ { ++ rc = new_kcs_do_xfer(request, request_len, ++ response, response_len); ++ break; ++ } ++ default: ++ { ++ printk ++ ("[IPMI_KCS] Undefined or bad KCS state machine selected (%d)\n", ++ kcs_machine); ++ get_deviceid(); ++ if ((dev_id.ipmi_version_major == 0) && ++ (dev_id.ipmi_version_minor == 9)) { ++ printk ++ ("Recalibrated to use legacy KCS state machine\n"); ++ kcs_machine = KCS_LEGACY; ++ } else { ++ printk ++ ("Recalibrated to use new KCS state machine\n"); ++ kcs_machine = KCS_NEW; ++ } ++ rc = -EAGAIN; ++ break; ++ } ++ } ++ if (rc == 0) ++ kcs_stat.tx_good++; ++ else ++ kcs_stat.tx_bad++; ++ up(&kcs_sem); ++ return (rc); ++} ++ ++static int new_kcs_do_xfer(BMC_REQUEST * request, ++ int request_len, ++ BMC_RESPONSE * response, int *response_len) ++{ ++ unsigned char *xmit_buffer, *recv_buffer; ++ int i = 0, rc = 0, state = SEND_INIT, bad = 0; ++ ++ xmit_buffer = (unsigned char *) request; ++ recv_buffer = (unsigned char *) response; ++ ++ while (1) { ++ if (state == END) ++ break; ++ else if (bad > 2) { ++ printk ++ ("[IPMI_KCS] Maximum retries exceeded. Aborting transfer\n"); ++ rc = -EIO; ++ break; ++ } ++ switch (state) { ++ case SEND_INIT: ++ { ++ i = 0; ++ state = SEND_START; ++ wait_while_ibf(); ++ if (clear_obf() != 0) { ++ state = ERROR; ++ break; ++ } ++ } ++ case SEND_START: ++ { ++ state = SEND_NEXT; ++ write_kcs_cmd(WRITE_START); ++ wait_while_ibf(); ++ if (get_kcs_state() != KCS_WRITE_STATE) { ++ state = ERROR; ++ break; ++ } ++ } ++ case SEND_NEXT: ++ { ++ if (i == (request_len - 1)) { ++ state = SEND_END; ++ break; ++ } ++ if (get_kcs_state() != KCS_WRITE_STATE) { ++ state = ERROR; ++ break; ++ } ++ write_kcs_data(xmit_buffer[i++]); ++ wait_while_ibf(); ++ if (get_kcs_state() != KCS_WRITE_STATE) { ++ state = ERROR; ++ break; ++ } ++ if (clear_obf() != 0) { ++ state = ERROR; ++ break; ++ } ++ break; ++ } ++ case SEND_END: ++ { ++ write_kcs_cmd(WRITE_END); ++ wait_while_ibf(); ++ if (get_kcs_state() != KCS_WRITE_STATE) { ++ state = ERROR; ++ break; ++ } ++ if (clear_obf() != 0) { ++ state = ERROR; ++ break; ++ } ++ write_kcs_data(xmit_buffer[i++]); ++ wait_while_ibf(); ++ state = RECV_START; ++ } ++ case RECV_START: ++ { ++ switch (get_kcs_state()) { ++ case KCS_ERROR_STATE: ++ { ++ state = ERROR; ++ break; ++ } ++ case KCS_WRITE_STATE: ++ case KCS_IDLE_STATE: ++ { ++ mdelay(BMC_RESPONSE_DELAY); ++ break; ++ } ++ case KCS_READ_STATE: ++ { ++ i = 0; ++ memset(recv_buffer, 0, ++ *response_len); ++ state = RECV_INIT; ++ break; ++ } ++ } ++ break; ++ } ++ case RECV_INIT: ++ { ++ switch (get_kcs_state()) { ++ case KCS_ERROR_STATE: ++ case KCS_WRITE_STATE: ++ { ++ state = ERROR; ++ break; ++ } ++ case KCS_IDLE_STATE: ++ { ++ state = RECV_END; ++ break; ++ } ++ case KCS_READ_STATE: ++ { ++ if (is_obf_set()) ++ state = RECV_NEXT; ++ else ++ mdelay(1); ++ break; ++ } ++ default: ++ { ++ mdelay(1); ++ break; ++ } ++ } ++ break; ++ } ++ case RECV_NEXT: ++ { ++ if (i >= *response_len) { ++ rc = -EOVERFLOW; ++ state = ERROR; ++ break; ++ } ++ recv_buffer[i++] = read_kcs_data(); ++ write_kcs_data(KCS_READ); ++ wait_while_ibf(); ++ state = RECV_INIT2; ++ break; ++ } ++ case RECV_INIT2: ++ { ++ switch (get_kcs_state()) { ++ case KCS_ERROR_STATE: ++ case KCS_WRITE_STATE: ++ { ++ state = ERROR; ++ break; ++ } ++ case KCS_IDLE_STATE: ++ { ++ if (wait_until_obf() == 0) { ++ clear_obf(); ++ state = RECV_END; ++ break; ++ } else { ++ state = ERROR; ++ break; ++ } ++ } ++ case KCS_READ_STATE: ++ { ++ if (wait_until_obf() == 0) ++ state = RECV_NEXT; ++ else ++ state = ERROR; ++ break; ++ } ++ } ++ break; ++ } ++ case RECV_END: ++ { ++ if ((i < MIN_BMC_RESPONSE_SIZE) || ++ (response->netfn != ++ (request->netfn | 0x01)) ++ || (response->cmd != request->cmd)) { ++ mdelay(BMC_RETRY_DELAY); ++ bad++; ++ state = SEND_INIT; ++ printk ++ ("[IPMI_KCS] Request/Response CMD/NETFN mismatch error\n"); ++ ++ printk ++ (" RQcmd/RQnetfn=0x%x/0x%x,RScmd/RSnetfn=0x%x/0x%x\n", ++ request->cmd, request->netfn, ++ response->cmd, ++ response->netfn); ++ break; ++ } ++ ++ *response_len = i; ++ rc = 0; ++ state = END; ++ break; ++ } ++ case ERROR: ++ default: ++ { ++ printk ++ ("[IPMI_KCS] BMC in bad state. Retrying transfer\n"); ++ mdelay(BMC_RETRY_DELAY); ++ bad++; ++ state = SEND_INIT; ++ break; ++ } ++ } ++ } ++ return (rc); ++} ++ ++static int old_kcs_do_xfer(BMC_REQUEST * request, ++ int request_len, ++ BMC_RESPONSE * response, int *response_len) ++{ ++ unsigned char *xmit_buffer, *recv_buffer; ++ int i = 0, rc = 0, state = SEND_INIT, bad = 0; ++ ++ xmit_buffer = (unsigned char *) request; ++ recv_buffer = (unsigned char *) response; ++ ++ while (1) { ++ if (state == END) ++ break; ++ else if (bad > 2) { ++ printk ++ ("[IPMI_KCS] Maximum retries exceeded. Aborting transfer\n"); ++ rc = -EIO; ++ break; ++ } ++ switch (state) { ++ case SEND_INIT: ++ { ++ i = 0; ++ state = SEND_START; ++ wait_while_ibf(); ++ } ++ case SEND_START: ++ { ++ state = SEND_NEXT; ++ write_kcs_cmd(WRITE_START); ++ wait_while_ibf(); ++ } ++ case SEND_NEXT: ++ { ++ if (i == (request_len - 1)) { ++ state = SEND_END; ++ break; ++ } ++ if (get_kcs_state() != KCS_WRITE_STATE) { ++ state = ERROR; ++ break; ++ } ++ write_kcs_data(xmit_buffer[i++]); ++ wait_while_ibf(); ++ break; ++ } ++ case SEND_END: ++ { ++ wait_while_ibf(); ++ write_kcs_cmd(WRITE_END); ++ wait_while_ibf(); ++ if (get_kcs_state() != KCS_WRITE_STATE) { ++ state = ERROR; ++ break; ++ } ++ write_kcs_data(xmit_buffer[i++]); ++ wait_while_ibf(); ++ state = RECV_START; ++ } ++ case RECV_START: ++ { ++ switch (get_kcs_state()) { ++ case KCS_ERROR_STATE: ++ { ++ state = ERROR; ++ break; ++ } ++ case KCS_WRITE_STATE: ++ case KCS_IDLE_STATE: ++ { ++ mdelay(BMC_RESPONSE_DELAY); ++ break; ++ } ++ case KCS_READ_STATE: ++ { ++ i = 0; ++ memset(recv_buffer, 0, ++ *response_len); ++ state = RECV_INIT; ++ break; ++ } ++ } ++ break; ++ } ++ case RECV_INIT: ++ { ++ switch (get_kcs_state()) { ++ case KCS_ERROR_STATE: ++ case KCS_WRITE_STATE: ++ { ++ state = ERROR; ++ break; ++ } ++ case KCS_IDLE_STATE: ++ { ++ state = RECV_END; ++ break; ++ } ++ case KCS_READ_STATE: ++ { ++ if (is_obf_set()) ++ state = RECV_NEXT; ++ else ++ mdelay(1); ++ break; ++ } ++ default: ++ { ++ mdelay(1); ++ break; ++ } ++ } ++ break; ++ } ++ case RECV_NEXT: ++ { ++ if (i >= *response_len) { ++ rc = -EOVERFLOW; ++ state = ERROR; ++ break; ++ } ++ recv_buffer[i++] = read_kcs_data(); ++ wait_while_ibf(); ++ write_kcs_data(KCS_READ); ++ state = RECV_INIT2; ++ break; ++ } ++ case RECV_INIT2: ++ { ++ switch (get_kcs_state()) { ++ case KCS_ERROR_STATE: ++ case KCS_WRITE_STATE: ++ { ++ state = ERROR; ++ break; ++ } ++ case KCS_IDLE_STATE: ++ { ++ state = RECV_END; ++ break; ++ } ++ case KCS_READ_STATE: ++ { ++ if (is_obf_set()) ++ state = RECV_NEXT; ++ break; ++ } ++ } ++ break; ++ } ++ case RECV_END: ++ { ++ if ((i < MIN_BMC_RESPONSE_SIZE) || ++ (response->netfn != ++ (request->netfn | 0x01)) ++ || (response->cmd != request->cmd)) { ++ mdelay(BMC_RETRY_DELAY); ++ bad++; ++ state = SEND_INIT; ++ printk ++ ("[IPMI_KCS] Request/Response CMD/NETFN mismatch error\n"); ++ ++ printk ++ (" RQcmd/RQnetfn=0x%x/0x%x,RScmd/RSnetfn=0x%x/0x%x\n", ++ request->cmd, request->netfn, ++ response->cmd, ++ response->netfn); ++ break; ++ } ++ ++ *response_len = i; ++ rc = 0; ++ state = END; ++ break; ++ } ++ case ERROR: ++ default: ++ { ++ printk ++ ("[IPMI_KCS] BMC in bad state. Retrying transfer\n"); ++ mdelay(BMC_RETRY_DELAY); ++ bad++; ++ state = SEND_INIT; ++ break; ++ } ++ } ++ } ++ return (rc); ++} ++ ++#ifdef CONFIG_PROC_FS ++int ipmi_get_info(char *buf, char **start, off_t fpos, int length, ++ int *eof, void *unused) ++{ ++ char *p; ++ ++ if (get_deviceid() != 0) { ++ printk("[IPMI_KCS] Unable to get device ID\n"); ++ memset(&dev_id, 0, sizeof(dev_id)); ++ } ++ ++ p = buf; ++ p += sprintf(p, "Driver Version\t: %d.%d\n", ++ driver_major, driver_minor); ++ p += sprintf(p, "BMC Version\t: %x.%x\n", ++ dev_id.major_firmware_revision, ++ dev_id.minor_firmware_revision); ++ p += sprintf(p, "IPMI Version\t: %d.%d\n", ++ dev_id.ipmi_version_major, dev_id.ipmi_version_minor); ++ p += sprintf(p, "\nTotal Good Transactions\t: %d\n", ++ kcs_stat.tx_good); ++ p += sprintf(p, "Total Bad Transactions\t: %d\n", kcs_stat.tx_bad); ++ ++ return p - buf; ++} ++#endif ++ ++/* ++ * kcs chip mashing stuff ++ */ ++static int wait_while_ibf() ++{ ++ unsigned char status_byte; ++ ++ status_byte = inb_p(KCS_STATUS_REG); ++ if ((status_byte & KCS_IBF) == 0) ++ return (0); ++ mdelay(KCS_READY_DELAY); ++ status_byte = inb_p(KCS_STATUS_REG); ++ if (status_byte & KCS_IBF) ++ return (-1); ++ return (0); ++} ++ ++static int wait_until_obf() ++{ ++ int retries = 0; ++ ++ while (retries < 2) { ++ if (is_obf_set()) ++ return (0); ++ mdelay(KCS_READY_DELAY); ++ retries++; ++ } ++ return (-ETIMEDOUT); ++} ++ ++static unsigned char get_kcs_state() ++{ ++ unsigned char cs; ++ ++ cs = inb_p(KCS_STATUS_REG); ++ return (cs & KCS_STATE_MASK); ++} ++ ++static unsigned char read_kcs_data() ++{ ++ unsigned char data; ++ ++ data = inb_p(KCS_DATAOUT_REG); ++ return (data); ++} ++ ++static void write_kcs_data(unsigned char data) ++{ ++ outb_p(data, KCS_DATAIN_REG); ++} ++ ++static void write_kcs_cmd(unsigned char cmd) ++{ ++ outb_p(cmd, KCS_COMMAND_REG); ++} ++ ++static int is_obf_set() ++{ ++ unsigned char cs; ++ ++ cs = inb_p(KCS_STATUS_REG); ++ return ((cs & KCS_OBF) == KCS_OBF); ++} ++ ++static int clear_obf() ++{ ++ read_kcs_data(); ++ return (0); ++} +--- /dev/null Fri Mar 23 23:37:44 2001 ++++ linux-bmc/drivers/char/ipmi_kcs.h Tue Oct 30 17:18:07 2001 +@@ -0,0 +1,171 @@ ++/* ++ * Intelligent Platform Management Interface driver for Linux 2.x ++ * ++ * (c) Copyright 1999 San Mehat & VA Linux Systems ++ * 1382 Bordeaux Dr. ++ * Sunnyvale, California ++ * 94089 ++ * ++ * http://www.valinux.com ++ * ++ * This driver is provided under the GNU public license, incorporated ++ * herein by reference. The driver is provided without warranty or ++ * support. ++ * ++ * ++ */ ++ ++#include <linux/config.h> ++ ++#define KCS_LEGACY 1 ++#define KCS_NEW 2 ++ ++#define KCS_READY_DELAY 5 ++#define BMC_RESPONSE_DELAY 5 ++#define BMC_RETRY_DELAY 60 ++ ++#if defined(__ia64__) ++#define KCS_BASE 0x8a2 ++#else ++#define KCS_BASE 0xca2 ++#endif ++#define KCS_STATUS_REG (KCS_BASE + 1) ++#define KCS_COMMAND_REG (KCS_BASE + 1) ++#define KCS_DATAIN_REG (KCS_BASE + 0) ++#define KCS_DATAOUT_REG (KCS_BASE + 0) ++ ++/* State bits based on S1 & S0 below */ ++#define KCS_STATE_MASK 0xC0 ++#define KCS_IDLE_STATE 0x00 ++#define KCS_READ_STATE 0x40 ++#define KCS_WRITE_STATE 0x80 ++#define KCS_ERROR_STATE 0xC0 ++ ++#define KCS_IBF 0x02 ++#define KCS_OBF 0x01 ++#define KCS_SMS_ATN 0x04 ++ ++#define SEND_INIT 1 ++#define SEND_START 2 ++#define SEND_NEXT 3 ++#define SEND_END 4 ++#define RECV_START 5 ++#define RECV_INIT 6 ++#define RECV_NEXT 7 ++#define RECV_INIT2 8 ++#define RECV_END 9 ++#define END 10 ++#define ERROR 0 ++ ++/* SMS Transfer Stream Control Codes */ ++#define GET_STATUS_ABORT 0x60 ++#define WRITE_START 0x61 ++#define WRITE_END 0x62 ++#define KCS_READ 0x68 ++ ++#define MAX_INVALID_RESPONSE_COUNT 2 ++#define MIN_BMC_RESPONSE_SIZE 3 ++#define MAX_IMB_PACKET_SIZE 33 ++#define MAX_BMC_RESPONSE_SIZE (MIN_BMC_RESPONSE_SIZE + MAX_IMB_PACKET_SIZE) ++#define MAX_XFER_LENGTH (MAX_IMB_PACKET_SIZE * 2) ++ ++#define MAX_BUFFER_SIZE 64 ++ ++typedef struct bmc_response ++ { ++ unsigned char lun :2; ++ unsigned char netfn :6; ++ ++ unsigned char cmd; ++ unsigned char cc; ++ unsigned char data[1]; ++ }BMC_RESPONSE; ++ ++typedef struct bmc_request ++ { ++ unsigned char lun :2; ++ unsigned char netfn :6; ++ ++ unsigned char cmd; ++ unsigned char data[1]; ++ }BMC_REQUEST; ++ ++/* GET_DEVICE_ID RESPONSE */ ++typedef struct device_id_response ++ { ++ unsigned char device_id; ++ ++ unsigned char device_revision :4; ++ unsigned char reserved :3; ++ unsigned char provides_sdr :1; ++ ++ unsigned char major_firmware_revision :7; ++ #define NORMAL_OPERATION 0 ++ #define DEVICE_BUSY 1 ++ unsigned char device_available :1; ++ ++ unsigned char minor_firmware_revision; ++ ++ unsigned char ipmi_version_major :4; ++ unsigned char ipmi_version_minor :4; ++ ++ unsigned char supports_sensor_device :1; ++ unsigned char supports_sdr_device :1; ++ unsigned char supports_sel_device :1; ++ unsigned char supports_fru_device :1; ++ unsigned char supports_ipmb_receiver :1; ++ unsigned char supports_ipmb_generator :1; ++ unsigned char supports_bridge :1; ++ unsigned char supports_chassis_device :1; ++ ++ unsigned char manufacturer_id1; ++ unsigned char manufacturer_id2; ++ unsigned char manufacturer_id3; ++ ++ unsigned short product_id; ++ } DEVICE_ID_RESPONSE; ++ ++typedef struct set_watchdog ++ { ++ unsigned char timer_use :3; ++ unsigned char res1 :4; ++ unsigned char dontlog :1; ++ ++ unsigned char timeout_action :3; ++ unsigned char res2 :1; ++ unsigned char pre_irq :3; ++ unsigned char res3 :1; ++ ++ unsigned char pretimeout_interval; ++ ++ unsigned char tuefc_res1 :1; ++ unsigned char tuefc_biosfrb2 :1; ++ unsigned char tuefc_biospost :1; ++ unsigned char tuefc_osload :1; ++ unsigned char tuefc_smsos :1; ++ unsigned char tuefc_oem :1; ++ unsigned char tuefc_res2 :1; ++ unsigned char tuefc_res3 :1; ++ ++ unsigned short initial_count; ++ } SET_WATCHDOG; ++ ++typedef struct get_watchdog_response ++ { ++ unsigned char timer_use :3; ++ unsigned char res1 :3; ++ unsigned char timer_status :1; ++ unsigned char sel_log :1; ++ ++ unsigned char timeout_act :3; ++ unsigned char res2 :1; ++ unsigned char pre_irq_act :3; ++ unsigned char res3 :1; ++ ++ unsigned char pre_timeout __attribute__ ((packed)); ++ ++ unsigned char timer_use_xp __attribute__ ((packed)); ++ ++ unsigned short init_count __attribute__ ((packed)); ++ unsigned short current_count __attribute__ ((packed)); ++ } GET_WATCHDOG_RESPONSE; +--- /dev/null Fri Mar 23 23:37:44 2001 ++++ linux-bmc/include/linux/ipmi_ioctls.h Tue Oct 30 17:18:07 2001 +@@ -0,0 +1,152 @@ ++/* ++ * Intelligent Platform Management Interface driver for Linux 2.x ++ * ++ * (c) Copyright 1999 San Mehat & VA Linux Systems ++ * 1382 Bordeaux Dr. ++ * Sunnyvale, California ++ * 94089 ++ * ++ * http://www.valinux.com ++ * ++ * This driver is provided under the GNU public license, incorporated ++ * herein by reference. The driver is provided without warranty or ++ * support. ++ * ++ * IOCTL definitions for IPMI drivers ++ */ ++ ++/* ++ * Note: The following macros should be used on the IPMI_XFER structure. ++ * DO NOT try to muck with this structure directly.. use the macros ++ * to ensure future compatibility: ++ * ++ * INIT_XFER(IPMI_XFER *); ++ * -- Zero out a IPMI_XFER structure and initialize it for use ++ * ++ * SET_REQUEST_LUN(IPMI_XFER *, unsigned char lun); ++ * -- Set the request packet logical unit ++ * ++ * SET_REQUEST_NETFN(IPMI_XFER *, unsigned char netfn); ++ * -- Set the request packet network function code ++ * ++ * SET_REQUEST_CMD(IPMI_XFER *, unsigned char cmd); ++ * -- Set the request packet IPMI command code ++ * ++ * SET_REQUEST_DATA(IPMI_XFER *, unsigned char *data, int length); ++ * -- Set the request packet optional argument data field ++ * ++ * GET_RESPONSE_LUN(IPMI_XFER *, unsigned char lun); ++ * -- Get the response packet logical unit ++ * ++ * GET_RESPONSE_NETFN(IPMI_XFER *, unsigned char netfn); ++ * -- Get the response packet network function code ++ * ++ * GET_RESPONSE_CMD(IPMI_XFER *, unsigned char cmd); ++ * -- Get the response packet command ++ * ++ * GET_RESPONSE_CC(IPMI_XFER *, unsigned char cc); ++ * -- Get the response packet completion code ++ * ++ * GET_RESPONSE_DATA_LENGTH(IPMI_XFER *, int len); ++ * -- Get the response packet data length ++ * ++ * GET_RESPONSE_DATA(IPMI_XFER *, unsigned char *buffer); ++ * -- Copy the response packet data into local buffer ++ */ ++ ++#ifndef _IPMI_IOCTLS_H ++#define _IPMI_IOCTLS_H ++ ++#define IOCTL_IPMI_XFER 0x01 ++#define IOCTL_DRIVER_INFO 0x02 ++ ++typedef struct ipmi_xfer ++ { ++ unsigned char request[64]; ++ unsigned char response[64]; ++ int request_len; ++ int response_len; ++ } IPMI_XFER; ++ ++struct ipmi_driver_info ++ { ++ char driver_name[64]; /* Name of the driver */ ++ int major_ver; ++ int minor_ver; ++ unsigned short mb_chipset_vendor; /* PCI host bridge vendor tag */ ++ unsigned short mb_chipset_device; /* PCI host bridge vendor device id */ ++ unsigned int flags; /* driver specific flags */ ++ unsigned int reserved; ++ }; ++ ++/* flags definitions for the 'ipmi_kcs' driver */ ++#define KCS_FLAG_BLINKY 0x01 /* Set if blinky works (only on Intel L440GX) */ ++#define KCS_FLAG_LEGACY 0x02 /* Set if using legacy KCS interface ( < IPMI 1.0) */ ++ ++#define INIT_XFER(_xferp) \ ++ memset(_xferp, 0, sizeof(IPMI_XFER)); \ ++ _xferp->request_len = 2; \ ++ _xferp->response_len = sizeof(_xferp->response); ++ ++#define SET_REQUEST_LUN(_xferp, _lun) \ ++ { \ ++ unsigned char _netfn_copy; \ ++ \ ++ _netfn_copy = (_xferp->request[0] & 0xFC); \ ++ _xferp->request[0] = _lun; \ ++ _xferp->request[0]|= _netfn_copy; \ ++ } ++ ++#define SET_REQUEST_NETFN(_xferp, netfn) \ ++ { \ ++ unsigned char __lun_copy; \ ++ \ ++ __lun_copy = (_xferp->request[0] & 0x3); \ ++ _xferp->request[0] = (netfn << 2); \ ++ _xferp->request[0]|= __lun_copy; \ ++ } ++ ++#define SET_REQUEST_CMD(_xferp, _cmd) \ ++ _xferp->request[1] = _cmd; ++ ++#define SET_REQUEST_DATA(_xferp, datap, _len) \ ++ { \ ++ memcpy(&_xferp->request[2], datap, _len); \ ++ _xferp->request_len = (_len + 2); \ ++ } ++ ++#define GET_RESPONSE_LUN(_xferp, _lun) \ ++ _lun = (_xferp->response[0] & 0x3); ++ ++#define GET_RESPONSE_NETFN(_xferp, netfn) \ ++ netfn = ((_xferp->response[0] & 0xFC) >> 2); ++ ++#define GET_RESPONSE_CMD(_xferp, _cmd) \ ++ _cmd = _xferp->response[1]; ++ ++#define GET_RESPONSE_CC(_xferp, cc) \ ++ cc = _xferp->response[2]; ++ ++#define GET_RESPONSE_DATA_LENGTH(_xferp, _len) \ ++ _len = (_xferp->response_len - 3); ++ ++#define GET_RESPONSE_DATA(_xferp, datap) \ ++ memcpy(datap, &_xferp->response[3], (_xferp->response_len -3)); ++ ++/* ++ * The Netfn codes ++ */ ++#define CHASSIS_REQUEST 0x00 ++#define CHASSIS_RESPONSE 0x01 ++#define BRIDGE_REQUEST 0x02 ++#define BRIDGE_RESPONSE 0x03 ++#define SENSOR_REQUEST 0x04 ++#define SENSOR_RESPONSE 0x05 ++#define APP_REQUEST 0x06 ++#define APP_RESPONSE 0x07 ++#define FIRMWARE_REQUEST 0x08 ++#define FIRMWARE_RESPONSE 0x09 ++#define STORAGE_REQUEST 0x0A ++#define STORAGE_RESPONSE 0x0B ++ ++#endif |