summaryrefslogtreecommitdiff
path: root/kern/ipmi_kcs.patch
diff options
context:
space:
mode:
Diffstat (limited to 'kern/ipmi_kcs.patch')
-rw-r--r--kern/ipmi_kcs.patch1592
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