N: Stephen Rothwell
E: Stephen.Rothwell@canb.auug.org.au
+W: http://www.canb.auug.org.au/~sfr
+P: 1024/BD8C7805 CD A4 9D 01 10 6E 7E 3B 91 88 FA D9 C8 40 AA 02
D: Boot/setup/build work for setup > 2K
D: Author, APM driver
-S: 59 Bugden Avenue
-S: Gowrie ACT 2904
+S: 66 Maltby Circuit
+S: Wanniassa ACT 2903
S: Australia
N: Gerard Roudier
as well. APM, which is primarily of use in laptops, provides access to
battery status information and may help to conserve battery power. The
support files can be found in
-ftp://tsx-11.mit.edu/pub/linux/packages/laptops/apm/apmd-2.4.tar.gz
+http://www.worldvisions.ca/~apenwarr/apmd/
iBCS and Dosemu
===============
S: Maintained
APM DRIVER
-P: Rik Faith & Stephen Rothwell
-M: faith@cs.unc.edu, Stephen.Rothwell@canb.auug.org.au
+P: Stephen Rothwell
+M: Stephen.Rothwell@canb.auug.org.au
L: linux-laptop@vger.rutgers.edu
S: Maintained
# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_NET_ISA is not set
-CONFIG_NET_EISA=y
+CONFIG_NET_PCI=y
# CONFIG_APRICOT is not set
CONFIG_DE4X5=y
# CONFIG_DEC_ELCP is not set
# CONFIG_UMISC is not set
# CONFIG_QIC02_TAPE is not set
# CONFIG_FTAPE is not set
-# CONFIG_APM is not set
# CONFIG_WATCHDOG is not set
# CONFIG_RTC is not set
! March 1993/June 1994 (Christoph.Niemann@linux.org)
!
! add APM BIOS checking by Stephen Rothwell, May 1994
-! (Stephen.Rothwell@pd.necisa.oz.au)
+! (Stephen.Rothwell@canb.auug.org.au)
!
! High load stuff, initrd support and position independency
! by Hans Lermen & Werner Almesberger, February 1996
#ifdef CONFIG_APM
! check for APM BIOS
- ! NOTE: DS is pointing to the bootsector
+ ! NOTE: DS is pointing to the boot sector
!
mov [64],#0 ! version == 0 means no APM BIOS
bool 'Handle buggy SMP BIOSes with bad MTRR setup' CONFIG_MTRR
fi
+bool 'Advanced Power Management BIOS support' CONFIG_APM
+if [ "$CONFIG_APM" = "y" ]; then
+ bool ' Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND
+ bool ' Enable PM at boot time' CONFIG_APM_DO_ENABLE
+ bool ' Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE
+ bool ' Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK
+ bool ' Power off on shutdown' CONFIG_APM_POWER_OFF
+ bool ' Ignore multiple suspend' CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
+fi
+
endmenu
source drivers/block/Config.in
O_TARGET := kernel.o
O_OBJS := process.o signal.o entry.o traps.o irq.o vm86.o bios32.o \
ptrace.o ioport.o ldt.o setup.o time.o sys_i386.o ksyms.o
+OX_OBJS :=
+
+ifdef CONFIG_APM
+OX_OBJS += apm.o
+endif
ifdef SMP
--- /dev/null
+/* -*- linux-c -*-
+ * APM BIOS driver for Linux
+ * Copyright 1994-1999 Stephen Rothwell
+ * (Stephen.Rothwell@canb.auug.org.au)
+ * Development of this driver was funded by NEC Australia P/L
+ * and NEC Corporation
+ *
+ * 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, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * October 1995, Rik Faith (faith@cs.unc.edu):
+ * Minor enhancements and updates (to the patch set) for 1.3.x
+ * Documentation
+ * January 1996, Rik Faith (faith@cs.unc.edu):
+ * Make /proc/apm easy to format (bump driver version)
+ * March 1996, Rik Faith (faith@cs.unc.edu):
+ * Prohibit APM BIOS calls unless apm_enabled.
+ * (Thanks to Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de>)
+ * April 1996, Stephen Rothwell (Stephen.Rothwell@canb.auug.org.au)
+ * Version 1.0 and 1.1
+ * May 1996, Version 1.2
+ *
+ * History:
+ * 0.6b: first version in official kernel, Linux 1.3.46
+ * 0.7: changed /proc/apm format, Linux 1.3.58
+ * 0.8: fixed gcc 2.7.[12] compilation problems, Linux 1.3.59
+ * 0.9: only call bios if bios is present, Linux 1.3.72
+ * 1.0: use fixed device number, consolidate /proc/apm into this file,
+ * Linux 1.3.85
+ * 1.1: support user-space standby and suspend, power off after system
+ * halted, Linux 1.3.98
+ * 1.2: When resetting RTC after resume, take care so that the time
+ * is only incorrect by 30-60mS (vs. 1S previously) (Gabor J. Toth
+ * <jtoth@princeton.edu>); improve interaction between
+ * screen-blanking and gpm (Stephen Rothwell); Linux 1.99.4
+ * 1.2a: Fix OOPs on power off with no APM BIOS
+ * Jan Echternach <echter@informatik.uni-rostock.de>
+ *
+ * Reference:
+ *
+ * Intel Corporation, Microsoft Corporation. Advanced Power Management
+ * (APM) BIOS Interface Specification, Revision 1.1, September 1993.
+ * Intel Order Number 241704-001. Microsoft Part Number 781-110-X01.
+ *
+ * [This document is available free from Intel by calling 800.628.8686 (fax
+ * 916.356.6100) or 800.548.4725; or via anonymous ftp from
+ * ftp://ftp.intel.com/pub/IAL/software_specs/apmv11.doc. It is also
+ * available from Microsoft by calling 206.882.8080.]
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/timer.h>
+#include <linux/fcntl.h>
+#include <linux/malloc.h>
+#include <linux/linkage.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#endif
+#include <linux/miscdevice.h>
+#include <linux/apm_bios.h>
+
+static struct symbol_table apm_syms = {
+#include <linux/symtab_begin.h>
+ X(apm_register_callback),
+ X(apm_unregister_callback),
+#include <linux/symtab_end.h>
+};
+
+extern unsigned long get_cmos_time(void);
+
+/*
+ * The apm_bios device is one of the misc char devices.
+ * This is its minor number.
+ */
+#define APM_MINOR_DEV 134
+
+/* Configurable options:
+ *
+ * CONFIG_APM_IGNORE_USER_SUSPEND: define to ignore USER SUSPEND requests.
+ * This is necessary on the NEC Versa M series, which generates these when
+ * resuming from SYSTEM SUSPEND. However, enabling this on other laptops
+ * will cause the laptop to generate a CRITICAL SUSPEND when an appropriate
+ * USER SUSPEND is ignored -- this may prevent the APM driver from updating
+ * the system time on a RESUME.
+ *
+ * CONFIG_APM_DO_ENABLE: enable APM features at boot time. From page 36 of
+ * the specification: "When disabled, the APM BIOS does not automatically
+ * power manage devices, enter the Standby State, enter the Suspend State,
+ * or take power saving steps in response to CPU Idle calls." This driver
+ * will make CPU Idle calls when Linux is idle (unless this feature is
+ * turned off -- see below). This should always save battery power, but
+ * more complicated APM features will be dependent on your BIOS
+ * implementation. You may need to turn this option off if your computer
+ * hangs at boot time when using APM support, or if it beeps continuously
+ * instead of suspending. Turn this off if you have a NEC UltraLite Versa
+ * 33/C or a Toshiba T400CDT. This is off by default since most machines
+ * do fine without this feature.
+ *
+ * CONFIG_APM_CPU_IDLE: enable calls to APM CPU Idle/CPU Busy inside the
+ * idle loop. On some machines, this can activate improved power savings,
+ * such as a slowed CPU clock rate, when the machine is idle. These idle
+ * call is made after the idle loop has run for some length of time (e.g.,
+ * 333 mS). On some machines, this will cause a hang at boot time or
+ * whenever the CPU becomes idle.
+ *
+ * CONFIG_APM_DISPLAY_BLANK: enable console blanking using the APM. Some
+ * laptops can use this to turn of the LCD backlight when the VC screen
+ * blanker blanks the screen. Note that this is only used by the VC screen
+ * blanker, and probably won't turn off the backlight when using X11. Some
+ * problems have been reported when using this option with gpm (if you'd
+ * like to debug this, please do so).
+ *
+ * CONFIG_APM_IGNORE_MULTIPLE_SUSPEND: The IBM TP560 bios seems to insist
+ * on returning multiple suspend/standby events whenever one occurs. We
+ * really only need one at a time, so just ignore any beyond the first.
+ * This is probably safe on most laptops.
+ *
+ * If you are debugging the APM support for your laptop, note that code for
+ * all of these options is contained in this file, so you can #define or
+ * #undef these on the next line to avoid recompiling the whole kernel.
+ *
+ */
+
+/* KNOWN PROBLEM MACHINES:
+ *
+ * U: TI 4000M TravelMate: BIOS is *NOT* APM compliant
+ * [Confirmed by TI representative]
+ * U: ACER 486DX4/75: uses dseg 0040, in violation of APM specification
+ * [Confirmed by BIOS disassembly]
+ * P: Toshiba 1950S: battery life information only gets updated after resume
+ *
+ * Legend: U = unusable with APM patches
+ * P = partially usable with APM patches
+ */
+
+/*
+ * Define to have debug messages.
+ */
+#undef APM_DEBUG
+
+/*
+ * Define to always call the APM BIOS busy routine even if the clock was
+ * not slowed by the idle routine.
+ */
+#define ALWAYS_CALL_BUSY
+
+/*
+ * Define to disable interrupts in APM BIOS calls (the CPU Idle BIOS call
+ * should turn interrupts on before it does a 'hlt').
+ */
+#define APM_NOINTS
+
+/*
+ * Define to make the APM BIOS calls zero all data segment registers (do
+ * that if an incorrect BIOS implementation will cause a kernel panic if it
+ * tries to write to arbitrary memory).
+ */
+#define APM_ZERO_SEGS
+
+/*
+ * Define to make all set_limit calls use 64k limits. The APM 1.1 BIOS is
+ * supposed to provide limit information that it recognizes. Many machines
+ * do this correctly, but many others do not restrict themselves to their
+ * claimed limit. When this happens, they will cause a segmentation
+ * violation in the kernel at boot time. Most BIOS's, however, will
+ * respect a 64k limit, so we use that. If you want to be pedantic and
+ * hold your BIOS to its claims, then undefine this.
+ */
+#define APM_RELAX_SEGMENTS
+
+/*
+ * Need to poll the APM BIOS every second
+ */
+#define APM_CHECK_TIMEOUT (HZ)
+
+/*
+ * These are the actual BIOS calls in assembler. Depending on
+ * APM_ZERO_SEGS and APM_NOINTS, we are being really paranoid here! Not
+ * only are interrupts disabled, but all the segment registers (except SS)
+ * are saved and zeroed this means that if the BIOS tries to reference any
+ * data without explicitly loading the segment registers, the kernel will
+ * fault immediately rather than have some unforeseen circumstances for the
+ * rest of the kernel. And it will be very obvious! :-) Doing this
+ * depends on CS referring to the same physical memory as DS so that DS can
+ * be zeroed before the call. Unfortunately, we can't do anything about the
+ * stack segment/pointer. Also, we tell the compiler that everything could
+ * change.
+ */
+#ifdef APM_NOINTS
+# define APM_DO_CLI "cli\n\t"
+#else
+# define APM_DO_CLI
+#endif
+#ifdef APM_ZERO_SEGS
+# define APM_DO_ZERO_SEGS \
+ "pushl %%ds\n\t" \
+ "pushl %%es\n\t" \
+ "pushl %%fs\n\t" \
+ "pushl %%gs\n\t" \
+ "xorl %%edx, %%edx\n\t" \
+ "mov %%dx, %%ds\n\t" \
+ "mov %%dx, %%es\n\t" \
+ "mov %%dx, %%fs\n\t" \
+ "mov %%dx, %%gs\n\t"
+# define APM_DO_RESTORE_SEGS \
+ "popl %%gs\n\t" \
+ "popl %%fs\n\t" \
+ "popl %%es\n\t" \
+ "popl %%ds\n\t"
+#else
+# define APM_DO_ZERO_SEGS
+# define APM_DO_RESTORE_SEGS
+#endif
+
+#define APM_BIOS_CALL(error_reg) \
+ __asm__ __volatile__( \
+ APM_DO_ZERO_SEGS \
+ "pushfl\n\t" \
+ APM_DO_CLI \
+ "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" \
+ "setc %%" # error_reg "\n\t" \
+ "popfl\n\t" \
+ APM_DO_RESTORE_SEGS
+#define APM_BIOS_CALL_END \
+ : "ax", "bx", "cx", "dx", "si", "di", "bp", "memory")
+
+#ifdef CONFIG_APM_CPU_IDLE
+#define APM_SET_CPU_IDLE(error) \
+ APM_BIOS_CALL(al) \
+ : "=a" (error) \
+ : "a" (0x5305) \
+ APM_BIOS_CALL_END
+#endif
+
+#define APM_SET_CPU_BUSY(error) \
+ APM_BIOS_CALL(al) \
+ : "=a" (error) \
+ : "a" (0x5306) \
+ APM_BIOS_CALL_END
+
+#define APM_SET_POWER_STATE(state, error) \
+ APM_BIOS_CALL(al) \
+ : "=a" (error) \
+ : "a" (0x5307), "b" (0x0001), "c" (state) \
+ APM_BIOS_CALL_END
+
+#ifdef CONFIG_APM_DISPLAY_BLANK
+#define APM_SET_DISPLAY_POWER_STATE(state, error) \
+ APM_BIOS_CALL(al) \
+ : "=a" (error) \
+ : "a" (0x5307), "b" (0x01ff), "c" (state) \
+ APM_BIOS_CALL_END
+#endif
+
+#ifdef CONFIG_APM_DO_ENABLE
+#define APM_ENABLE_POWER_MANAGEMENT(device, error) \
+ APM_BIOS_CALL(al) \
+ : "=a" (error) \
+ : "a" (0x5308), "b" (device), "c" (1) \
+ APM_BIOS_CALL_END
+#endif
+
+#define APM_GET_POWER_STATUS(bx, cx, dx, error) \
+ APM_BIOS_CALL(al) \
+ : "=a" (error), "=b" (bx), "=c" (cx), "=d" (dx) \
+ : "a" (0x530a), "b" (1) \
+ APM_BIOS_CALL_END
+
+#define APM_GET_EVENT(event, error) \
+ APM_BIOS_CALL(al) \
+ : "=a" (error), "=b" (event) \
+ : "a" (0x530b) \
+ APM_BIOS_CALL_END
+
+#define APM_DRIVER_VERSION(ver, ax, error) \
+ APM_BIOS_CALL(bl) \
+ : "=a" (ax), "=b" (error) \
+ : "a" (0x530e), "b" (0), "c" (ver) \
+ APM_BIOS_CALL_END
+
+#define APM_ENGAGE_POWER_MANAGEMENT(device, error) \
+ APM_BIOS_CALL(al) \
+ : "=a" (error) \
+ : "a" (0x530f), "b" (device), "c" (1) \
+ APM_BIOS_CALL_END
+
+/*
+ * Forward declarations
+ */
+static void suspend(void);
+static void standby(void);
+static void set_time(void);
+
+static void check_events(void);
+static void do_apm_timer(unsigned long);
+
+static int do_open(struct inode *, struct file *);
+static void do_release(struct inode *, struct file *);
+static int do_read(struct inode *, struct file *, char *, int);
+static int do_select(struct inode *, struct file *, int,
+ select_table *);
+static int do_ioctl(struct inode *, struct file *, u_int, u_long);
+
+#ifdef CONFIG_PROC_FS
+static int apm_get_info(char *, char **, off_t, int, int);
+#endif
+
+extern int apm_register_callback(int (*)(apm_event_t));
+extern void apm_unregister_callback(int (*)(apm_event_t));
+
+/*
+ * Local variables
+ */
+static asmlinkage struct {
+ unsigned long offset;
+ unsigned short segment;
+} apm_bios_entry;
+static int apm_enabled = 0;
+#ifdef CONFIG_APM_CPU_IDLE
+static int clock_slowed = 0;
+#endif
+static int suspends_pending = 0;
+static int standbys_pending = 0;
+#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
+static int waiting_for_resume = 0;
+#endif
+
+static long clock_cmos_diff;
+static int got_clock_diff = 0;
+
+static struct wait_queue * process_list = NULL;
+static struct apm_bios_struct * user_list = NULL;
+
+static struct timer_list apm_timer;
+
+static char driver_version[] = "1.2";/* no spaces */
+
+#ifdef APM_DEBUG
+static char * apm_event_name[] = {
+ "system standby",
+ "system suspend",
+ "normal resume",
+ "critical resume",
+ "low battery",
+ "power status change",
+ "update time",
+ "critical suspend",
+ "user standby",
+ "user suspend",
+ "system standby resume"
+};
+#define NR_APM_EVENT_NAME \
+ (sizeof(apm_event_name) / sizeof(apm_event_name[0]))
+#endif
+
+static struct file_operations apm_bios_fops = {
+ NULL, /* lseek */
+ do_read,
+ NULL, /* write */
+ NULL, /* readdir */
+ do_select,
+ do_ioctl,
+ NULL, /* mmap */
+ do_open,
+ do_release,
+ NULL, /* fsync */
+ NULL /* fasync */
+};
+
+static struct miscdevice apm_device = {
+ APM_MINOR_DEV,
+ "apm",
+ &apm_bios_fops
+};
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry apm_proc_entry = {
+ 0, 3, "apm", S_IFREG | S_IRUGO, 1, 0, 0, 0, 0, apm_get_info
+};
+#endif
+
+typedef struct callback_list_t {
+ int (* callback)(apm_event_t);
+ struct callback_list_t * next;
+} callback_list_t;
+
+static callback_list_t * callback_list = NULL;
+
+typedef struct lookup_t {
+ int key;
+ char * msg;
+} lookup_t;
+
+static const lookup_t error_table[] = {
+/* N/A { APM_SUCCESS, "Operation succeeded" }, */
+ { APM_DISABLED, "Power management disabled" },
+ { APM_CONNECTED, "Real mode interface already connected" },
+ { APM_NOT_CONNECTED, "Interface not connected" },
+ { APM_16_CONNECTED, "16 bit interface already connected" },
+/* N/A { APM_16_UNSUPPORTED, "16 bit interface not supported" }, */
+ { APM_32_CONNECTED, "32 bit interface already connected" },
+ { APM_32_UNSUPPORTED, "32 bit interface not supported" },
+ { APM_BAD_DEVICE, "Unrecognized device ID" },
+ { APM_BAD_PARAM, "Parameter out of range" },
+ { APM_NOT_ENGAGED, "Interface not engaged" },
+ { APM_BAD_STATE, "Unable to enter requested state" },
+/* N/A { APM_NO_EVENTS, "No events pending" }, */
+ { APM_NOT_PRESENT, "No APM present" }
+};
+#define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t))
+
+static int apm_driver_version(u_short *val)
+{
+ u_short error;
+
+ APM_DRIVER_VERSION(*val, *val, error);
+
+ if (error & 0xff)
+ return (*val >> 8);
+ return APM_SUCCESS;
+}
+
+static int apm_get_event(apm_event_t *event)
+{
+ u_short error;
+
+ APM_GET_EVENT(*event, error);
+ if (error & 0xff)
+ return (error >> 8);
+ return APM_SUCCESS;
+}
+
+static int apm_set_power_state(u_short state)
+{
+ u_short error;
+
+ APM_SET_POWER_STATE(state, error);
+ if (error & 0xff)
+ return (error >> 8);
+ return APM_SUCCESS;
+}
+
+#ifdef CONFIG_APM_POWER_OFF
+void apm_power_off(void)
+{
+ if (apm_enabled)
+ (void) apm_set_power_state(APM_STATE_OFF);
+}
+#endif
+
+#ifdef CONFIG_APM_DISPLAY_BLANK
+/* Called by apm_display_blank and apm_display_unblank when apm_enabled. */
+static int apm_set_display_power_state(u_short state)
+{
+ u_short error;
+
+ APM_SET_DISPLAY_POWER_STATE(state, error);
+ if (error & 0xff)
+ return (error >> 8);
+ return APM_SUCCESS;
+}
+#endif
+
+#ifdef CONFIG_APM_DO_ENABLE
+/* Called by apm_setup if apm_enabled will be true. */
+static int apm_enable_power_management(void)
+{
+ u_short error;
+
+ APM_ENABLE_POWER_MANAGEMENT((apm_bios_info.version > 0x100)
+ ? 0x0001 : 0xffff,
+ error);
+ if (error & 0xff)
+ return (error >> 8);
+ return APM_SUCCESS;
+}
+#endif
+
+static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
+{
+ u_short error;
+
+ APM_GET_POWER_STATUS(*status, *bat, *life, error);
+ if (error & 0xff)
+ return (error >> 8);
+ return APM_SUCCESS;
+}
+
+static int apm_engage_power_management(u_short device)
+{
+ u_short error;
+
+ APM_ENGAGE_POWER_MANAGEMENT(device, error);
+ if (error & 0xff)
+ return (error >> 8);
+ return APM_SUCCESS;
+}
+
+static void apm_error(char *str, int err)
+{
+ int i;
+
+ for (i = 0; i < ERROR_COUNT; i++)
+ if (error_table[i].key == err) break;
+ if (i < ERROR_COUNT)
+ printk("apm_bios: %s: %s\n", str, error_table[i].msg);
+ else
+ printk("apm_bios: %s: unknown error code %#2.2x\n", str, err);
+}
+
+/* Called from console driver -- must make sure apm_enabled. */
+int apm_display_blank(void)
+{
+#ifdef CONFIG_APM_DISPLAY_BLANK
+ int error;
+
+ if (!apm_enabled)
+ return 0;
+ error = apm_set_display_power_state(APM_STATE_STANDBY);
+ if (error == APM_SUCCESS)
+ return 1;
+ apm_error("set display standby", error);
+#endif
+ return 0;
+}
+
+/* Called from console driver -- must make sure apm_enabled. */
+int apm_display_unblank(void)
+{
+#ifdef CONFIG_APM_DISPLAY_BLANK
+ int error;
+
+ if (!apm_enabled)
+ return 0;
+ error = apm_set_display_power_state(APM_STATE_READY);
+ if (error == APM_SUCCESS)
+ return 1;
+ apm_error("set display ready", error);
+#endif
+ return 0;
+}
+
+int apm_register_callback(int (*callback)(apm_event_t))
+{
+ callback_list_t * new;
+
+ new = kmalloc(sizeof(callback_list_t), GFP_KERNEL);
+ if (new == NULL)
+ return -ENOMEM;
+ new->callback = callback;
+ new->next = callback_list;
+ callback_list = new;
+ return 0;
+}
+
+void apm_unregister_callback(int (*callback)(apm_event_t))
+{
+ callback_list_t ** ptr;
+ callback_list_t * old;
+
+ ptr = &callback_list;
+ for (ptr = &callback_list; *ptr != NULL; ptr = &(*ptr)->next)
+ if ((*ptr)->callback == callback)
+ break;
+ old = *ptr;
+ *ptr = old->next;
+ kfree_s(old, sizeof(callback_list_t));
+}
+
+static int queue_empty(struct apm_bios_struct * as)
+{
+ return as->event_head == as->event_tail;
+}
+
+static apm_event_t get_queued_event(struct apm_bios_struct * as)
+{
+ as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
+ return as->events[as->event_tail];
+}
+
+static int queue_event(apm_event_t event, struct apm_bios_struct *sender)
+{
+ struct apm_bios_struct * as;
+
+ if (user_list == NULL)
+ return 0;
+ for (as = user_list; as != NULL; as = as->next) {
+ if (as == sender)
+ continue;
+ as->event_head = (as->event_head + 1) % APM_MAX_EVENTS;
+ if (as->event_head == as->event_tail) {
+ static int notified;
+
+ if (notified == 0) {
+ printk( "apm_bios: an event queue overflowed\n" );
+ notified = 1;
+ }
+ as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
+ }
+ as->events[as->event_head] = event;
+ if (!as->suser)
+ continue;
+ switch (event) {
+ case APM_SYS_SUSPEND:
+ case APM_USER_SUSPEND:
+ as->suspends_pending++;
+ suspends_pending++;
+ break;
+
+ case APM_SYS_STANDBY:
+ case APM_USER_STANDBY:
+ as->standbys_pending++;
+ standbys_pending++;
+ break;
+ }
+ }
+ wake_up_interruptible(&process_list);
+ return 1;
+}
+
+static void set_time(void)
+{
+ unsigned long flags;
+
+ if (!got_clock_diff) /* Don't know time zone, can't set clock */
+ return;
+
+ save_flags(flags);
+ cli();
+ CURRENT_TIME = get_cmos_time() + clock_cmos_diff;
+ restore_flags(flags);
+}
+
+static void suspend(void)
+{
+ unsigned long flags;
+ int err;
+
+ /* Estimate time zone so that set_time can
+ update the clock */
+ save_flags(flags);
+ clock_cmos_diff = -get_cmos_time();
+ cli();
+ clock_cmos_diff += CURRENT_TIME;
+ got_clock_diff = 1;
+ restore_flags(flags);
+
+ err = apm_set_power_state(APM_STATE_SUSPEND);
+ if (err)
+ apm_error("suspend", err);
+ set_time();
+}
+
+static void standby(void)
+{
+ int err;
+
+ err = apm_set_power_state(APM_STATE_STANDBY);
+ if (err)
+ apm_error("standby", err);
+}
+
+static apm_event_t get_event(void)
+{
+ int error;
+ apm_event_t event;
+
+ static int notified = 0;
+
+ error = apm_get_event(&event);
+ if (error == APM_SUCCESS)
+ return event;
+
+ if ((error != APM_NO_EVENTS) && (notified++ == 0))
+ apm_error("get_event", error);
+
+ return 0;
+}
+
+static void send_event(apm_event_t event, apm_event_t undo,
+ struct apm_bios_struct *sender)
+{
+ callback_list_t * call;
+ callback_list_t * fix;
+
+ for (call = callback_list; call != NULL; call = call->next) {
+ if (call->callback(event) && undo) {
+ for (fix = callback_list; fix != call; fix = fix->next)
+ fix->callback(undo);
+ if (apm_bios_info.version > 0x100)
+ apm_set_power_state(APM_STATE_REJECT);
+ return;
+ }
+ }
+
+ queue_event(event, sender);
+}
+
+static void check_events(void)
+{
+ apm_event_t event;
+
+ while ((event = get_event()) != 0) {
+#ifdef APM_DEBUG
+ if (event <= NR_APM_EVENT_NAME)
+ printk("APM BIOS received %s notify\n",
+ apm_event_name[event - 1]);
+ else
+ printk("APM BIOS received unknown event 0x%02x\n",
+ event);
+#endif
+ switch (event) {
+ case APM_SYS_STANDBY:
+ case APM_USER_STANDBY:
+#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
+ if (waiting_for_resume) {
+ return;
+ }
+ waiting_for_resume = 1;
+#endif
+ send_event(event, APM_STANDBY_RESUME, NULL);
+ if (standbys_pending <= 0)
+ standby();
+ break;
+
+ case APM_USER_SUSPEND:
+#ifdef CONFIG_APM_IGNORE_USER_SUSPEND
+ if (apm_bios_info.version > 0x100)
+ apm_set_power_state(APM_STATE_REJECT);
+ break;
+#endif
+ case APM_SYS_SUSPEND:
+#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
+ if (waiting_for_resume) {
+ return;
+ }
+ waiting_for_resume = 1;
+#endif
+ send_event(event, APM_NORMAL_RESUME, NULL);
+ if (suspends_pending <= 0)
+ suspend();
+ break;
+
+ case APM_NORMAL_RESUME:
+ case APM_CRITICAL_RESUME:
+ case APM_STANDBY_RESUME:
+#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
+ waiting_for_resume = 0;
+#endif
+ set_time();
+ send_event(event, 0, NULL);
+ break;
+
+ case APM_LOW_BATTERY:
+ case APM_POWER_STATUS_CHANGE:
+ send_event(event, 0, NULL);
+ break;
+
+ case APM_UPDATE_TIME:
+ set_time();
+ break;
+
+ case APM_CRITICAL_SUSPEND:
+ suspend();
+ break;
+ }
+ }
+}
+
+static void do_apm_timer(unsigned long unused)
+{
+ int err;
+
+ static int pending_count = 0;
+
+ if (((standbys_pending > 0) || (suspends_pending > 0))
+ && (apm_bios_info.version > 0x100)
+ && (pending_count-- <= 0)) {
+ pending_count = 4;
+
+ err = apm_set_power_state(APM_STATE_BUSY);
+ if (err)
+ apm_error("busy", err);
+ }
+
+ if (!(((standbys_pending > 0) || (suspends_pending > 0))
+ && (apm_bios_info.version == 0x100)))
+ check_events();
+
+ init_timer(&apm_timer);
+ apm_timer.expires = APM_CHECK_TIMEOUT + jiffies;
+ add_timer(&apm_timer);
+}
+
+/* Called from sys_idle, must make sure apm_enabled. */
+int apm_do_idle(void)
+{
+#ifdef CONFIG_APM_CPU_IDLE
+ unsigned short error;
+
+ if (!apm_enabled)
+ return 0;
+
+ APM_SET_CPU_IDLE(error);
+ if (error & 0xff)
+ return 0;
+
+ clock_slowed = (apm_bios_info.flags & APM_IDLE_SLOWS_CLOCK) != 0;
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+/* Called from sys_idle, must make sure apm_enabled. */
+void apm_do_busy(void)
+{
+#ifdef CONFIG_APM_CPU_IDLE
+ unsigned short error;
+
+ if (!apm_enabled)
+ return;
+
+#ifndef ALWAYS_CALL_BUSY
+ if (!clock_slowed)
+ return;
+#endif
+
+ APM_SET_CPU_BUSY(error);
+
+ clock_slowed = 0;
+#endif
+}
+
+static int check_apm_bios_struct(struct apm_bios_struct *as, const char *func)
+{
+ if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
+ printk("apm_bios: %s passed bad filp", func);
+ return 1;
+ }
+ return 0;
+}
+
+static int do_read(struct inode *inode, struct file *fp, char *buf, int count)
+{
+ struct apm_bios_struct * as;
+ int i;
+ apm_event_t event;
+ struct wait_queue wait = { current, NULL };
+
+ as = fp->private_data;
+ if (check_apm_bios_struct(as, "read"))
+ return -EIO;
+ if (count < sizeof(apm_event_t))
+ return -EINVAL;
+ if (queue_empty(as)) {
+ if (fp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ add_wait_queue(&process_list, &wait);
+repeat:
+ current->state = TASK_INTERRUPTIBLE;
+ if (queue_empty(as)
+ && !(current->signal & ~current->blocked)) {
+ schedule();
+ goto repeat;
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&process_list, &wait);
+ }
+ i = count;
+ while ((i >= sizeof(event)) && !queue_empty(as)) {
+ event = get_queued_event(as);
+ memcpy_tofs(buf, &event, sizeof(event));
+ switch (event) {
+ case APM_SYS_SUSPEND:
+ case APM_USER_SUSPEND:
+ as->suspends_read++;
+ break;
+
+ case APM_SYS_STANDBY:
+ case APM_USER_STANDBY:
+ as->standbys_read++;
+ break;
+ }
+ buf += sizeof(event);
+ i -= sizeof(event);
+ }
+ if (i < count)
+ return count - i;
+ if (current->signal & ~current->blocked)
+ return -ERESTARTSYS;
+ return 0;
+}
+
+static int do_select(struct inode *inode, struct file *fp, int sel_type,
+ select_table * wait)
+{
+ struct apm_bios_struct * as;
+
+ as = fp->private_data;
+ if (check_apm_bios_struct(as, "select"))
+ return 0;
+ if (sel_type != SEL_IN)
+ return 0;
+ if (!queue_empty(as))
+ return 1;
+ select_wait(&process_list, wait);
+ return 0;
+}
+
+static int do_ioctl(struct inode * inode, struct file *filp,
+ u_int cmd, u_long arg)
+{
+ struct apm_bios_struct * as;
+
+ as = filp->private_data;
+ if (check_apm_bios_struct(as, "ioctl"))
+ return -EIO;
+ if (!as->suser)
+ return -EPERM;
+ switch (cmd) {
+ case APM_IOC_STANDBY:
+ if (as->standbys_read > 0) {
+ as->standbys_read--;
+ as->standbys_pending--;
+ standbys_pending--;
+ }
+ else
+ send_event(APM_USER_STANDBY, APM_STANDBY_RESUME, as);
+ if (standbys_pending <= 0)
+ standby();
+ break;
+ case APM_IOC_SUSPEND:
+ if (as->suspends_read > 0) {
+ as->suspends_read--;
+ as->suspends_pending--;
+ suspends_pending--;
+ }
+ else
+ send_event(APM_USER_SUSPEND, APM_NORMAL_RESUME, as);
+ if (suspends_pending <= 0)
+ suspend();
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void do_release(struct inode * inode, struct file * filp)
+{
+ struct apm_bios_struct * as;
+
+ as = filp->private_data;
+ filp->private_data = NULL;
+ if (check_apm_bios_struct(as, "release"))
+ return;
+ if (as->standbys_pending > 0) {
+ standbys_pending -= as->standbys_pending;
+ if (standbys_pending <= 0)
+ standby();
+ }
+ if (as->suspends_pending > 0) {
+ suspends_pending -= as->suspends_pending;
+ if (suspends_pending <= 0)
+ suspend();
+ }
+ if (user_list == as)
+ user_list = as->next;
+ else {
+ struct apm_bios_struct * as1;
+
+ for (as1 = user_list;
+ (as1 != NULL) && (as1->next != as);
+ as1 = as1->next)
+ ;
+ if (as1 == NULL)
+ printk("apm_bios: filp not in user list");
+ else
+ as1->next = as->next;
+ }
+ kfree_s(as, sizeof(*as));
+}
+
+static int do_open(struct inode * inode, struct file * filp)
+{
+ struct apm_bios_struct * as;
+
+ as = (struct apm_bios_struct *)kmalloc(sizeof(*as), GFP_KERNEL);
+ if (as == NULL) {
+ printk("apm_bios: cannot allocate struct of size %d bytes",
+ sizeof(*as));
+ return -ENOMEM;
+ }
+ as->magic = APM_BIOS_MAGIC;
+ as->event_tail = as->event_head = 0;
+ as->suspends_pending = as->standbys_pending = 0;
+ as->suspends_read = as->standbys_read = 0;
+ as->suser = suser();
+ as->next = user_list;
+ user_list = as;
+ filp->private_data = as;
+ return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+int apm_get_info(char *buf, char **start, off_t fpos, int length, int dummy)
+{
+ char * p;
+ unsigned short bx;
+ unsigned short cx;
+ unsigned short dx;
+ unsigned short error;
+ unsigned short ac_line_status = 0xff;
+ unsigned short battery_status = 0xff;
+ unsigned short battery_flag = 0xff;
+ int percentage = -1;
+ int time_units = -1;
+ char *units = "?";
+
+ if (!apm_enabled)
+ return 0;
+ p = buf;
+
+ if (!(error = apm_get_power_status(&bx, &cx, &dx))) {
+ ac_line_status = (bx >> 8) & 0xff;
+ battery_status = bx & 0xff;
+ if ((cx & 0xff) != 0xff)
+ percentage = cx & 0xff;
+
+ if (apm_bios_info.version > 0x100) {
+ battery_flag = (cx >> 8) & 0xff;
+ if (dx != 0xffff) {
+ if ((dx & 0x8000) == 0x8000) {
+ units = "min";
+ time_units = dx & 0x7ffe;
+ } else {
+ units = "sec";
+ time_units = dx & 0x7fff;
+ }
+ }
+ }
+ }
+ /* Arguments, with symbols from linux/apm_bios.h. Information is
+ from the Get Power Status (0x0a) call unless otherwise noted.
+
+ 0) Linux driver version (this will change if format changes)
+ 1) APM BIOS Version. Usually 1.0 or 1.1.
+ 2) APM flags from APM Installation Check (0x00):
+ bit 0: APM_16_BIT_SUPPORT
+ bit 1: APM_32_BIT_SUPPORT
+ bit 2: APM_IDLE_SLOWS_CLOCK
+ bit 3: APM_BIOS_DISABLED
+ bit 4: APM_BIOS_DISENGAGED
+ 3) AC line status
+ 0x00: Off-line
+ 0x01: On-line
+ 0x02: On backup power (APM BIOS 1.1 only)
+ 0xff: Unknown
+ 4) Battery status
+ 0x00: High
+ 0x01: Low
+ 0x02: Critical
+ 0x03: Charging
+ 0xff: Unknown
+ 5) Battery flag
+ bit 0: High
+ bit 1: Low
+ bit 2: Critical
+ bit 3: Charging
+ bit 7: No system battery
+ 0xff: Unknown
+ 6) Remaining battery life (percentage of charge):
+ 0-100: valid
+ -1: Unknown
+ 7) Remaining battery life (time units):
+ Number of remaining minutes or seconds
+ -1: Unknown
+ 8) min = minutes; sec = seconds */
+
+ p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
+ driver_version,
+ (apm_bios_info.version >> 8) & 0xff,
+ apm_bios_info.version & 0xff,
+ apm_bios_info.flags,
+ ac_line_status,
+ battery_status,
+ battery_flag,
+ percentage,
+ time_units,
+ units);
+
+ return p - buf;
+}
+#endif
+
+static int apm_disabled = 0;
+
+void apm_setup(char *str, int *ints)
+{
+ if(strcmp(str,"off")==0)
+ apm_disabled=1;
+ if(strcmp(str,"on")==0)
+ apm_disabled=0;
+}
+
+void apm_bios_init(void)
+{
+ unsigned short bx;
+ unsigned short cx;
+ unsigned short dx;
+ unsigned short error;
+ char * power_stat;
+ char * bat_stat;
+
+ if (apm_disabled == 1)
+ {
+ printk("APM disabled.\n");
+ return;
+ }
+
+ if (apm_bios_info.version == 0) {
+ printk("APM BIOS not found.\n");
+ return;
+ }
+ printk("APM BIOS version %c.%c Flags 0x%02x (Driver version %s)\n",
+ ((apm_bios_info.version >> 8) & 0xff) + '0',
+ (apm_bios_info.version & 0xff) + '0',
+ apm_bios_info.flags,
+ driver_version);
+ if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) {
+ printk(" No 32 bit BIOS support\n");
+ return;
+ }
+
+ /*
+ * Fix for the Compaq Contura 3/25c which reports BIOS version 0.1
+ * but is reportedly a 1.0 BIOS.
+ */
+ if (apm_bios_info.version == 0x001)
+ apm_bios_info.version = 0x100;
+
+ printk(" Entry %x:%lx cseg16 %x dseg %x",
+ apm_bios_info.cseg, apm_bios_info.offset,
+ apm_bios_info.cseg_16, apm_bios_info.dseg);
+ if (apm_bios_info.version > 0x100)
+ printk(" cseg len %x, dseg len %x",
+ apm_bios_info.cseg_len, apm_bios_info.dseg_len);
+ printk("\n");
+
+ apm_bios_entry.offset = apm_bios_info.offset;
+ apm_bios_entry.segment = APM_CS;
+ set_base(gdt[APM_CS >> 3],
+ __PAGE_OFFSET + ((unsigned long)apm_bios_info.cseg << 4));
+ set_base(gdt[APM_CS_16 >> 3],
+ __PAGE_OFFSET + ((unsigned long)apm_bios_info.cseg_16 << 4));
+ set_base(gdt[APM_DS >> 3],
+ __PAGE_OFFSET + ((unsigned long)apm_bios_info.dseg << 4));
+ if (apm_bios_info.version == 0x100) {
+ set_limit(gdt[APM_CS >> 3], 64 * 1024);
+ set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
+ set_limit(gdt[APM_DS >> 3], 64 * 1024);
+ } else {
+#ifdef APM_RELAX_SEGMENTS
+ /* For ASUS motherboard, Award BIOS rev 110 (and others?) */
+ set_limit(gdt[APM_CS >> 3], 64 * 1024);
+ /* For some unknown machine. */
+ set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
+ /* For the DEC Hinote Ultra CT475 (and others?) */
+ set_limit(gdt[APM_DS >> 3], 64 * 1024);
+#else
+ set_limit(gdt[APM_CS >> 3], apm_bios_info.cseg_len);
+ set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
+ set_limit(gdt[APM_DS >> 3], apm_bios_info.dseg_len);
+#endif
+ apm_bios_info.version = 0x0101;
+ error = apm_driver_version(&apm_bios_info.version);
+ if (error != 0)
+ apm_bios_info.version = 0x100;
+ else {
+ apm_engage_power_management(0x0001);
+ printk( " Connection version %d.%d\n",
+ (apm_bios_info.version >> 8) & 0xff,
+ apm_bios_info.version & 0xff );
+ apm_bios_info.version = 0x0101;
+ }
+ }
+
+ error = apm_get_power_status(&bx, &cx, &dx);
+ if (error)
+ printk(" Power status not available\n");
+ else {
+ switch ((bx >> 8) & 0xff) {
+ case 0: power_stat = "off line"; break;
+ case 1: power_stat = "on line"; break;
+ case 2: power_stat = "on backup power"; break;
+ default: power_stat = "unknown"; break;
+ }
+ switch (bx & 0xff) {
+ case 0: bat_stat = "high"; break;
+ case 1: bat_stat = "low"; break;
+ case 2: bat_stat = "critical"; break;
+ case 3: bat_stat = "charging"; break;
+ default: bat_stat = "unknown"; break;
+ }
+ printk(" AC %s, battery status %s, battery life ",
+ power_stat, bat_stat);
+ if ((cx & 0xff) == 0xff)
+ printk("unknown\n");
+ else
+ printk("%d%%\n", cx & 0xff);
+ if (apm_bios_info.version > 0x100) {
+ printk(" battery flag 0x%02x, battery life ",
+ (cx >> 8) & 0xff);
+ if (dx == 0xffff)
+ printk("unknown\n");
+ else {
+ if ((dx & 0x8000))
+ printk("%d minutes\n", dx & 0x7ffe );
+ else
+ printk("%d seconds\n", dx & 0x7fff );
+ }
+ }
+ }
+
+#ifdef CONFIG_APM_DO_ENABLE
+ /*
+ * This call causes my NEC UltraLite Versa 33/C to hang if it is
+ * booted with PM disabled but not in the docking station.
+ * Unfortunate ...
+ */
+ error = apm_enable_power_management();
+ if (error)
+ apm_error("enable power management", error);
+ if (error == APM_DISABLED)
+ return;
+#endif
+
+ init_timer(&apm_timer);
+ apm_timer.function = do_apm_timer;
+ apm_timer.expires = APM_CHECK_TIMEOUT + jiffies;
+ add_timer(&apm_timer);
+
+ register_symtab(&apm_syms);
+
+#ifdef CONFIG_PROC_FS
+ proc_register_dynamic(&proc_root, &apm_proc_entry);
+#endif
+
+ misc_register(&apm_device);
+
+ apm_enabled = 1;
+}
#ifndef STANDARD_MEMORY_BIOS_CALL
#define ALT_MEM_K (*(unsigned long *) (PARAM+0x1e0))
#endif
-#ifdef CONFIG_APM
-#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+64))
-#endif
+#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40))
#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
#define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
int error;
unsigned long flags;
struct file * file = NULL;
+ unsigned long b[6];
error = verify_area(VERIFY_READ, buffer, 6*sizeof(long));
if (error)
return error;
- flags = get_user(buffer+3);
+ memcpy_fromfs(&b[0], buffer, 6*sizeof(long));
+ flags = b[3];
if (!(flags & MAP_ANONYMOUS)) {
- unsigned long fd = get_user(buffer+4);
+ unsigned long fd = b[4];
if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
return -EBADF;
}
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
- return do_mmap(file, get_user(buffer), get_user(buffer+1),
- get_user(buffer+2), flags, get_user(buffer+5));
+ down(¤t->mm->mmap_sem);
+ error = do_mmap(file, b[0], b[1], b[2], flags, b[5]);
+ up(¤t->mm->mmap_sem);
+ return error;
}
extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
)*60 + sec; /* finally seconds */
}
+/* not static: needed by APM */
unsigned long get_cmos_time(void)
{
unsigned int year, mon, day, hour, min, sec;
# CONFIG_MS_BUSMOUSE is not set
# CONFIG_ATIXL_BUSMOUSE is not set
# CONFIG_QIC02_TAPE is not set
-# CONFIG_APM is not set
# CONFIG_SERIAL is not set
#
WARNING:
--------
-This is still development code. It seems to work fine for me, but I haven't
-done any real hardcore testing against this driver. Also, things are likely
-to change, such as the major number used by the device driver as well as the
-names of the /dev entries.
+This code is distributed without warranty. Use at your own risk.
Installing:
-----------
#define MOD_DEC_USE_COUNT
#endif
-#define DRIVER_NAME "Compaq SMART2 Driver (v 0.9.8)"
+#define DRIVER_NAME "Compaq SMART2 Driver (v 1.0)"
#define MAJOR_NR COMPAQ_SMART2_MAJOR
#include <linux/blk.h>
#include "ida_ioctl.h"
#define READ_AHEAD 128
-#define NR_CMDS 64
+#define NR_CMDS 128 /* This can probably go as high as ~400 */
#define MAX_CTLR 8
#define CTLR_SHIFT 8
"SMART-2SL",
"SMART-3200",
"SMART-3100ES",
+ "SMART-221",
};
static struct hd_struct * ida;
static int pollcomplete(int ctlr);
static void getgeometry(int ctlr);
-static cmdlist_t * cmd_alloc(ctlr_info_t *h, int intr);
+static cmdlist_t * cmd_alloc(ctlr_info_t *h);
static void cmd_free(ctlr_info_t *h, cmdlist_t *c);
static int sendcmd(
*/
#ifdef CONFIG_BLK_CPQ_DA_PCI
# ifdef CONFIG_BLK_CPQ_DA_EISA
-# warning "SMART2: EISA+PCI"
# define smart2_read(h, offset) ( ((h)->vaddr) ? readl((h)->vaddr+(offset)) : inl((h)->ioaddr+(offset)) )
# define smart2_write(p, h, offset) ( ((h)->vaddr) ? writel((p), (h)->vaddr+(offset)) : outl((p), (h)->ioaddr+(offset)) )
# else
-# warning "SMART2: PCI"
# define smart2_read(h, offset) readl((h)->vaddr+(offset))
# define smart2_write(p, h, offset) writel((p), (h)->vaddr+(offset))
# endif
#else
# ifdef CONFIG_BLK_CPQ_DA_EISA
-# warning "SMART2: EISA"
# define smart2_read(h, offset) inl((h)->vaddr+(offset))
# define smart2_write(p, h, offset) outl((p), (h)->vaddr+(offset))
# else
/*
- * Place some files in /proc/array/* that contain some information about
- * each controller. There really isn't much useful in there now.
+ * Get us a file in /proc that says something about each controller. Right
+ * now, we add entries to /proc, but in the future we should probably get
+ * our own subdir in /proc (/proc/array/ida) and put our stuff in there.
*/
extern struct inode_operations proc_diskarray_inode_operations;
struct proc_dir_entry *proc_array = NULL;
goto doreq_done;
}
- if ((c = cmd_alloc(h, 1)) == NULL)
+ if ((c = cmd_alloc(h)) == NULL)
goto doreq_done;
blk_dev[MAJOR_NR+ctlr].current_request = creq->next;
c->ctlr = ctlr;
c->hdr.unit = MINOR(creq->rq_dev) >> NWD_SHIFT;
- c->hdr.prio = 0;
c->hdr.size = sizeof(rblk_t) >> 2;
c->size += sizeof(rblk_t);
- c->req.hdr.next = 0;
- c->req.hdr.rcode = 0;
- c->req.bp = 0;
c->req.hdr.sg_cnt = creq->nr_segments;
- c->req.hdr.reserved = 0;
c->req.hdr.blk = ida[(ctlr<<CTLR_SHIFT) + MINOR(creq->rq_dev)].start_sect + creq->sector;
c->req.hdr.blk_cnt = creq->nr_sectors;
c->bh = bh;
int error;
DBGINFO(printk("ida_ctlr_ioctl %d %x %p\n", ctlr, dsk, io));
- if ((c = cmd_alloc(h, 0)) == NULL)
+ if ((c = cmd_alloc(NULL)) == NULL)
return -ENOMEM;
c->ctlr = ctlr;
c->hdr.unit = (io->unit & UNITVALID) ? io->unit &0x7f : dsk;
- c->hdr.prio = 0;
c->hdr.size = sizeof(rblk_t) >> 2;
c->size += sizeof(rblk_t);
-
- c->req.hdr.next = 0;
- c->req.hdr.rcode = 0;
- c->req.bp = 0;
- c->req.hdr.reserved = 0;
-
- c->req.hdr.blk = 0;
- c->req.hdr.blk_cnt = 0;
c->req.hdr.cmd = io->cmd;
c->type = CMD_IOCTL_PEND;
break;
case IDA_WRITE:
case IDA_WRITE_MEDIA:
+ case DIAG_PASS_THRU:
error = verify_area(VERIFY_READ,
(void*)io->sg[0].addr, io->sg[0].size);
if (error) goto ioctl_err_exit;
switch(io->cmd) {
case PASSTHRU_A:
case IDA_READ:
+ case DIAG_PASS_THRU:
memcpy_tofs((void*)io->sg[0].addr, p, io->sg[0].size);
/* fall through and free p */
case IDA_WRITE:
io->rcode = c->req.hdr.rcode;
error = 0;
ioctl_err_exit:
- cmd_free(h, c);
+ cmd_free(NULL, c);
return error;
}
/*
- * Sooner or later we'll want to maintain our own cache of
- * commands. For now, just use kmalloc to get them
+ * Commands are pre-allocated in a large block. Here we use a simple bitmap
+ * scheme to suballocte them to the driver. Operations that are not time
+ * critical (and can wait for kmalloc and possibly sleep) can pass in NULL
+ * as the first argument to get a new command.
*/
-cmdlist_t * cmd_alloc(ctlr_info_t *h, int intr)
+cmdlist_t * cmd_alloc(ctlr_info_t *h)
{
cmdlist_t * c;
int i;
- do {
- i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS);
- if (i == NR_CMDS)
- return NULL;
- } while(set_bit(i%32, h->cmd_pool_bits+(i/32)) != 0);
+ if (h == NULL) {
+ c = (cmdlist_t*)kmalloc(sizeof(cmdlist_t), GFP_KERNEL);
+ } else {
+ do {
+ i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS);
+ if (i == NR_CMDS)
+ return NULL;
+ } while(set_bit(i%32, h->cmd_pool_bits+(i/32)) != 0);
+ c = h->cmd_pool + i;
+ h->nr_allocs++;
+ }
- c = h->cmd_pool + i;
memset(c, 0, sizeof(cmdlist_t));
c->busaddr = virt_to_bus(c);
- h->nr_allocs++;
return c;
}
void cmd_free(ctlr_info_t *h, cmdlist_t *c)
{
- int i = c - h->cmd_pool;
- clear_bit(i%32, h->cmd_pool_bits+(i/32));
- h->nr_frees++;
+ int i;
+
+ if (h == NULL) {
+ kfree(c);
+ } else {
+ i = c - h->cmd_pool;
+ clear_bit(i%32, h->cmd_pool_bits+(i/32));
+ h->nr_frees++;
+ }
}
/***********************************************************************
unsigned long i;
ctlr_info_t *info_p = hba[ctlr];
- c = cmd_alloc(info_p, 0);
+ c = cmd_alloc(info_p);
c->ctlr = ctlr;
c->hdr.unit = log_unit;
c->hdr.prio = 0;
case 0x40330E11: /* SMART-3100ES */
info_p->product = 5;
break;
+ case 0x40340E11: /* SMART-221 */
+ info_p->product = 6;
+ break;
default:
/*
* Well, its a SMART-2 or better, don't know which
int usage_count;
} drv_info_t;
+#ifdef __KERNEL__
typedef struct {
int ctlr;
char devname[8];
struct timer_list timer;
unsigned int misc_tflags;
} ctlr_info_t;
+#endif
#endif /* CPQARRAY_H */
comment 'Set IObase/IRQ/DMA for ftape in ./drivers/char/ftape/Makefile'
fi
-bool 'Advanced Power Management BIOS support' CONFIG_APM
-if [ "$CONFIG_APM" = "y" ]; then
- bool ' Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND
- bool ' Enable PM at boot time' CONFIG_APM_DO_ENABLE
- bool ' Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE
- bool ' Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK
- bool ' Power off on shutdown' CONFIG_APM_POWER_OFF
- bool ' Ignore multiple suspend' CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
-fi
if [ "$CONFIG_ALPHA_BOOK1" = "y" ]; then
bool 'Tadpole ANA H8 Support' CONFIG_H8
fi
endif
ifdef CONFIG_APM
-LX_OBJS += apm_bios.o
M = y
endif
+++ /dev/null
-/* -*- linux-c -*-
- * APM BIOS driver for Linux
- * Copyright 1994, 1995, 1996 Stephen Rothwell
- * (Stephen.Rothwell@canb.auug.org.au)
- *
- * 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, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * $Id: apm_bios.c,v 0.22 1995/03/09 14:12:02 sfr Exp $
- *
- * October 1995, Rik Faith (faith@cs.unc.edu):
- * Minor enhancements and updates (to the patch set) for 1.3.x
- * Documentation
- * January 1996, Rik Faith (faith@cs.unc.edu):
- * Make /proc/apm easy to format (bump driver version)
- * March 1996, Rik Faith (faith@cs.unc.edu):
- * Prohibit APM BIOS calls unless apm_enabled.
- * (Thanks to Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de>)
- * April 1996, Stephen Rothwell (Stephen.Rothwell@canb.auug.org.au)
- * Version 1.0 and 1.1
- * May 1996, Version 1.2
- *
- * History:
- * 0.6b: first version in official kernel, Linux 1.3.46
- * 0.7: changed /proc/apm format, Linux 1.3.58
- * 0.8: fixed gcc 2.7.[12] compilation problems, Linux 1.3.59
- * 0.9: only call bios if bios is present, Linux 1.3.72
- * 1.0: use fixed device number, consolidate /proc/apm into this file,
- * Linux 1.3.85
- * 1.1: support user-space standby and suspend, power off after system
- * halted, Linux 1.3.98
- * 1.2: When resetting RTC after resume, take care so that the time
- * is only incorrect by 30-60mS (vs. 1S previously) (Gabor J. Toth
- * <jtoth@princeton.edu>); improve interaction between
- * screen-blanking and gpm (Stephen Rothwell); Linux 1.99.4
- * 1.2a: Fix OOPs on power off with no APM BIOS
- * Jan Echternach <echter@informatik.uni-rostock.de>
- *
- * Reference:
- *
- * Intel Corporation, Microsoft Corporation. Advanced Power Management
- * (APM) BIOS Interface Specification, Revision 1.1, September 1993.
- * Intel Order Number 241704-001. Microsoft Part Number 781-110-X01.
- *
- * [This document is available free from Intel by calling 800.628.8686 (fax
- * 916.356.6100) or 800.548.4725; or via anonymous ftp from
- * ftp://ftp.intel.com/pub/IAL/software_specs/apmv11.doc. It is also
- * available from Microsoft by calling 206.882.8080.]
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-
-#include <asm/system.h>
-#include <asm/segment.h>
-
-#include <linux/types.h>
-#include <linux/stddef.h>
-#include <linux/timer.h>
-#include <linux/fcntl.h>
-#include <linux/malloc.h>
-#include <linux/linkage.h>
-#ifdef CONFIG_PROC_FS
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-#endif
-#include <linux/miscdevice.h>
-#include <linux/apm_bios.h>
-
-static struct symbol_table apm_syms = {
-#include <linux/symtab_begin.h>
- X(apm_register_callback),
- X(apm_unregister_callback),
-#include <linux/symtab_end.h>
-};
-
-extern unsigned long get_cmos_time(void);
-
-/*
- * The apm_bios device is one of the misc char devices.
- * This is its minor number.
- */
-#define APM_MINOR_DEV 134
-
-/* Configurable options:
- *
- * CONFIG_APM_IGNORE_USER_SUSPEND: define to ignore USER SUSPEND requests.
- * This is necessary on the NEC Versa M series, which generates these when
- * resuming from SYSTEM SUSPEND. However, enabling this on other laptops
- * will cause the laptop to generate a CRITICAL SUSPEND when an appropriate
- * USER SUSPEND is ignored -- this may prevent the APM driver from updating
- * the system time on a RESUME.
- *
- * CONFIG_APM_DO_ENABLE: enable APM features at boot time. From page 36 of
- * the specification: "When disabled, the APM BIOS does not automatically
- * power manage devices, enter the Standby State, enter the Suspend State,
- * or take power saving steps in response to CPU Idle calls." This driver
- * will make CPU Idle calls when Linux is idle (unless this feature is
- * turned off -- see below). This should always save battery power, but
- * more complicated APM features will be dependent on your BIOS
- * implementation. You may need to turn this option off if your computer
- * hangs at boot time when using APM support, or if it beeps continuously
- * instead of suspending. Turn this off if you have a NEC UltraLite Versa
- * 33/C or a Toshiba T400CDT. This is off by default since most machines
- * do fine without this feature.
- *
- * CONFIG_APM_CPU_IDLE: enable calls to APM CPU Idle/CPU Busy inside the
- * idle loop. On some machines, this can activate improved power savings,
- * such as a slowed CPU clock rate, when the machine is idle. These idle
- * call is made after the idle loop has run for some length of time (e.g.,
- * 333 mS). On some machines, this will cause a hang at boot time or
- * whenever the CPU becomes idle.
- *
- * CONFIG_APM_DISPLAY_BLANK: enable console blanking using the APM. Some
- * laptops can use this to turn of the LCD backlight when the VC screen
- * blanker blanks the screen. Note that this is only used by the VC screen
- * blanker, and probably won't turn off the backlight when using X11. Some
- * problems have been reported when using this option with gpm (if you'd
- * like to debug this, please do so).
- *
- * CONFIG_APM_IGNORE_MULTIPLE_SUSPEND: The IBM TP560 bios seems to insist
- * on returning multiple suspend/standby events whenever one occurs. We
- * really only need one at a time, so just ignore any beyond the first.
- * This is probably safe on most laptops.
- *
- * If you are debugging the APM support for your laptop, note that code for
- * all of these options is contained in this file, so you can #define or
- * #undef these on the next line to avoid recompiling the whole kernel.
- *
- */
-
-/* KNOWN PROBLEM MACHINES:
- *
- * U: TI 4000M TravelMate: BIOS is *NOT* APM compliant
- * [Confirmed by TI representative]
- * U: ACER 486DX4/75: uses dseg 0040, in violation of APM specification
- * [Confirmed by BIOS disassembly]
- * P: Toshiba 1950S: battery life information only gets updated after resume
- *
- * Legend: U = unusable with APM patches
- * P = partially usable with APM patches
- */
-
-/*
- * Define to have debug messages.
- */
-#undef APM_DEBUG
-
-/*
- * Define to always call the APM BIOS busy routine even if the clock was
- * not slowed by the idle routine.
- */
-#define ALWAYS_CALL_BUSY
-
-/*
- * Define to disable interrupts in APM BIOS calls (the CPU Idle BIOS call
- * should turn interrupts on before it does a 'hlt').
- */
-#define APM_NOINTS
-
-/*
- * Define to make the APM BIOS calls zero all data segment registers (do
- * that if an incorrect BIOS implementation will cause a kernel panic if it
- * tries to write to arbitrary memory).
- */
-#define APM_ZERO_SEGS
-
-/*
- * Define to make all set_limit calls use 64k limits. The APM 1.1 BIOS is
- * supposed to provide limit information that it recognizes. Many machines
- * do this correctly, but many others do not restrict themselves to their
- * claimed limit. When this happens, they will cause a segmentation
- * violation in the kernel at boot time. Most BIOS's, however, will
- * respect a 64k limit, so we use that. If you want to be pedantic and
- * hold your BIOS to its claims, then undefine this.
- */
-#define APM_RELAX_SEGMENTS
-
-/*
- * Need to poll the APM BIOS every second
- */
-#define APM_CHECK_TIMEOUT (HZ)
-
-/*
- * These are the actual BIOS calls in assembler. Depending on
- * APM_ZERO_SEGS and APM_NOINTS, we are being really paranoid here! Not
- * only are interrupts disabled, but all the segment registers (except SS)
- * are saved and zeroed this means that if the BIOS tries to reference any
- * data without explicitly loading the segment registers, the kernel will
- * fault immediately rather than have some unforeseen circumstances for the
- * rest of the kernel. And it will be very obvious! :-) Doing this
- * depends on CS referring to the same physical memory as DS so that DS can
- * be zeroed before the call. Unfortunately, we can't do anything about the
- * stack segment/pointer. Also, we tell the compiler that everything could
- * change.
- */
-#ifdef APM_NOINTS
-# define APM_DO_CLI "cli\n\t"
-#else
-# define APM_DO_CLI
-#endif
-#ifdef APM_ZERO_SEGS
-# define APM_DO_ZERO_SEGS \
- "pushl %%ds\n\t" \
- "pushl %%es\n\t" \
- "pushl %%fs\n\t" \
- "pushl %%gs\n\t" \
- "xorl %%edx, %%edx\n\t" \
- "mov %%dx, %%ds\n\t" \
- "mov %%dx, %%es\n\t" \
- "mov %%dx, %%fs\n\t" \
- "mov %%dx, %%gs\n\t"
-# define APM_DO_RESTORE_SEGS \
- "popl %%gs\n\t" \
- "popl %%fs\n\t" \
- "popl %%es\n\t" \
- "popl %%ds\n\t"
-#else
-# define APM_DO_ZERO_SEGS
-# define APM_DO_RESTORE_SEGS
-#endif
-
-#define APM_BIOS_CALL(error_reg) \
- __asm__ __volatile__( \
- APM_DO_ZERO_SEGS \
- "pushfl\n\t" \
- APM_DO_CLI \
- "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" \
- "setc %%" # error_reg "\n\t" \
- "popfl\n\t" \
- APM_DO_RESTORE_SEGS
-#define APM_BIOS_CALL_END \
- : "ax", "bx", "cx", "dx", "si", "di", "bp", "memory")
-
-#ifdef CONFIG_APM_CPU_IDLE
-#define APM_SET_CPU_IDLE(error) \
- APM_BIOS_CALL(al) \
- : "=a" (error) \
- : "a" (0x5305) \
- APM_BIOS_CALL_END
-#endif
-
-#define APM_SET_CPU_BUSY(error) \
- APM_BIOS_CALL(al) \
- : "=a" (error) \
- : "a" (0x5306) \
- APM_BIOS_CALL_END
-
-#define APM_SET_POWER_STATE(state, error) \
- APM_BIOS_CALL(al) \
- : "=a" (error) \
- : "a" (0x5307), "b" (0x0001), "c" (state) \
- APM_BIOS_CALL_END
-
-#ifdef CONFIG_APM_DISPLAY_BLANK
-#define APM_SET_DISPLAY_POWER_STATE(state, error) \
- APM_BIOS_CALL(al) \
- : "=a" (error) \
- : "a" (0x5307), "b" (0x01ff), "c" (state) \
- APM_BIOS_CALL_END
-#endif
-
-#ifdef CONFIG_APM_DO_ENABLE
-#define APM_ENABLE_POWER_MANAGEMENT(device, error) \
- APM_BIOS_CALL(al) \
- : "=a" (error) \
- : "a" (0x5308), "b" (device), "c" (1) \
- APM_BIOS_CALL_END
-#endif
-
-#define APM_GET_POWER_STATUS(bx, cx, dx, error) \
- APM_BIOS_CALL(al) \
- : "=a" (error), "=b" (bx), "=c" (cx), "=d" (dx) \
- : "a" (0x530a), "b" (1) \
- APM_BIOS_CALL_END
-
-#define APM_GET_EVENT(event, error) \
- APM_BIOS_CALL(al) \
- : "=a" (error), "=b" (event) \
- : "a" (0x530b) \
- APM_BIOS_CALL_END
-
-#define APM_DRIVER_VERSION(ver, ax, error) \
- APM_BIOS_CALL(bl) \
- : "=a" (ax), "=b" (error) \
- : "a" (0x530e), "b" (0), "c" (ver) \
- APM_BIOS_CALL_END
-
-#define APM_ENGAGE_POWER_MANAGEMENT(device, error) \
- APM_BIOS_CALL(al) \
- : "=a" (error) \
- : "a" (0x530f), "b" (device), "c" (1) \
- APM_BIOS_CALL_END
-
-/*
- * Forward declarations
- */
-static void suspend(void);
-static void standby(void);
-static void set_time(void);
-
-static void check_events(void);
-static void do_apm_timer(unsigned long);
-
-static int do_open(struct inode *, struct file *);
-static void do_release(struct inode *, struct file *);
-static int do_read(struct inode *, struct file *, char *, int);
-static int do_select(struct inode *, struct file *, int,
- select_table *);
-static int do_ioctl(struct inode *, struct file *, u_int, u_long);
-
-#ifdef CONFIG_PROC_FS
-static int apm_get_info(char *, char **, off_t, int, int);
-#endif
-
-extern int apm_register_callback(int (*)(apm_event_t));
-extern void apm_unregister_callback(int (*)(apm_event_t));
-
-/*
- * Local variables
- */
-static asmlinkage struct {
- unsigned long offset;
- unsigned short segment;
-} apm_bios_entry;
-static int apm_enabled = 0;
-#ifdef CONFIG_APM_CPU_IDLE
-static int clock_slowed = 0;
-#endif
-static int suspends_pending = 0;
-static int standbys_pending = 0;
-#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
-static int waiting_for_resume = 0;
-#endif
-
-static long clock_cmos_diff;
-static int got_clock_diff = 0;
-
-static struct wait_queue * process_list = NULL;
-static struct apm_bios_struct * user_list = NULL;
-
-static struct timer_list apm_timer;
-
-static char driver_version[] = "1.2";/* no spaces */
-
-#ifdef APM_DEBUG
-static char * apm_event_name[] = {
- "system standby",
- "system suspend",
- "normal resume",
- "critical resume",
- "low battery",
- "power status change",
- "update time",
- "critical suspend",
- "user standby",
- "user suspend",
- "system standby resume"
-};
-#define NR_APM_EVENT_NAME \
- (sizeof(apm_event_name) / sizeof(apm_event_name[0]))
-#endif
-
-static struct file_operations apm_bios_fops = {
- NULL, /* lseek */
- do_read,
- NULL, /* write */
- NULL, /* readdir */
- do_select,
- do_ioctl,
- NULL, /* mmap */
- do_open,
- do_release,
- NULL, /* fsync */
- NULL /* fasync */
-};
-
-static struct miscdevice apm_device = {
- APM_MINOR_DEV,
- "apm",
- &apm_bios_fops
-};
-
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry apm_proc_entry = {
- 0, 3, "apm", S_IFREG | S_IRUGO, 1, 0, 0, 0, 0, apm_get_info
-};
-#endif
-
-typedef struct callback_list_t {
- int (* callback)(apm_event_t);
- struct callback_list_t * next;
-} callback_list_t;
-
-static callback_list_t * callback_list = NULL;
-
-typedef struct lookup_t {
- int key;
- char * msg;
-} lookup_t;
-
-static const lookup_t error_table[] = {
-/* N/A { APM_SUCCESS, "Operation succeeded" }, */
- { APM_DISABLED, "Power management disabled" },
- { APM_CONNECTED, "Real mode interface already connected" },
- { APM_NOT_CONNECTED, "Interface not connected" },
- { APM_16_CONNECTED, "16 bit interface already connected" },
-/* N/A { APM_16_UNSUPPORTED, "16 bit interface not supported" }, */
- { APM_32_CONNECTED, "32 bit interface already connected" },
- { APM_32_UNSUPPORTED, "32 bit interface not supported" },
- { APM_BAD_DEVICE, "Unrecognized device ID" },
- { APM_BAD_PARAM, "Parameter out of range" },
- { APM_NOT_ENGAGED, "Interface not engaged" },
- { APM_BAD_STATE, "Unable to enter requested state" },
-/* N/A { APM_NO_EVENTS, "No events pending" }, */
- { APM_NOT_PRESENT, "No APM present" }
-};
-#define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t))
-
-static int apm_driver_version(u_short *val)
-{
- u_short error;
-
- APM_DRIVER_VERSION(*val, *val, error);
-
- if (error & 0xff)
- return (*val >> 8);
- return APM_SUCCESS;
-}
-
-static int apm_get_event(apm_event_t *event)
-{
- u_short error;
-
- APM_GET_EVENT(*event, error);
- if (error & 0xff)
- return (error >> 8);
- return APM_SUCCESS;
-}
-
-static int apm_set_power_state(u_short state)
-{
- u_short error;
-
- APM_SET_POWER_STATE(state, error);
- if (error & 0xff)
- return (error >> 8);
- return APM_SUCCESS;
-}
-
-#ifdef CONFIG_APM_POWER_OFF
-void apm_power_off(void)
-{
- if (apm_enabled)
- (void) apm_set_power_state(APM_STATE_OFF);
-}
-#endif
-
-#ifdef CONFIG_APM_DISPLAY_BLANK
-/* Called by apm_display_blank and apm_display_unblank when apm_enabled. */
-static int apm_set_display_power_state(u_short state)
-{
- u_short error;
-
- APM_SET_DISPLAY_POWER_STATE(state, error);
- if (error & 0xff)
- return (error >> 8);
- return APM_SUCCESS;
-}
-#endif
-
-#ifdef CONFIG_APM_DO_ENABLE
-/* Called by apm_setup if apm_enabled will be true. */
-static int apm_enable_power_management(void)
-{
- u_short error;
-
- APM_ENABLE_POWER_MANAGEMENT((apm_bios_info.version > 0x100)
- ? 0x0001 : 0xffff,
- error);
- if (error & 0xff)
- return (error >> 8);
- return APM_SUCCESS;
-}
-#endif
-
-static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
-{
- u_short error;
-
- APM_GET_POWER_STATUS(*status, *bat, *life, error);
- if (error & 0xff)
- return (error >> 8);
- return APM_SUCCESS;
-}
-
-static int apm_engage_power_management(u_short device)
-{
- u_short error;
-
- APM_ENGAGE_POWER_MANAGEMENT(device, error);
- if (error & 0xff)
- return (error >> 8);
- return APM_SUCCESS;
-}
-
-static void apm_error(char *str, int err)
-{
- int i;
-
- for (i = 0; i < ERROR_COUNT; i++)
- if (error_table[i].key == err) break;
- if (i < ERROR_COUNT)
- printk("apm_bios: %s: %s\n", str, error_table[i].msg);
- else
- printk("apm_bios: %s: unknown error code %#2.2x\n", str, err);
-}
-
-/* Called from console driver -- must make sure apm_enabled. */
-int apm_display_blank(void)
-{
-#ifdef CONFIG_APM_DISPLAY_BLANK
- int error;
-
- if (!apm_enabled)
- return 0;
- error = apm_set_display_power_state(APM_STATE_STANDBY);
- if (error == APM_SUCCESS)
- return 1;
- apm_error("set display standby", error);
-#endif
- return 0;
-}
-
-/* Called from console driver -- must make sure apm_enabled. */
-int apm_display_unblank(void)
-{
-#ifdef CONFIG_APM_DISPLAY_BLANK
- int error;
-
- if (!apm_enabled)
- return 0;
- error = apm_set_display_power_state(APM_STATE_READY);
- if (error == APM_SUCCESS)
- return 1;
- apm_error("set display ready", error);
-#endif
- return 0;
-}
-
-int apm_register_callback(int (*callback)(apm_event_t))
-{
- callback_list_t * new;
-
- new = kmalloc(sizeof(callback_list_t), GFP_KERNEL);
- if (new == NULL)
- return -ENOMEM;
- new->callback = callback;
- new->next = callback_list;
- callback_list = new;
- return 0;
-}
-
-void apm_unregister_callback(int (*callback)(apm_event_t))
-{
- callback_list_t ** ptr;
- callback_list_t * old;
-
- ptr = &callback_list;
- for (ptr = &callback_list; *ptr != NULL; ptr = &(*ptr)->next)
- if ((*ptr)->callback == callback)
- break;
- old = *ptr;
- *ptr = old->next;
- kfree_s(old, sizeof(callback_list_t));
-}
-
-static int queue_empty(struct apm_bios_struct * as)
-{
- return as->event_head == as->event_tail;
-}
-
-static apm_event_t get_queued_event(struct apm_bios_struct * as)
-{
- as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
- return as->events[as->event_tail];
-}
-
-static int queue_event(apm_event_t event, struct apm_bios_struct *sender)
-{
- struct apm_bios_struct * as;
-
- if (user_list == NULL)
- return 0;
- for (as = user_list; as != NULL; as = as->next) {
- if (as == sender)
- continue;
- as->event_head = (as->event_head + 1) % APM_MAX_EVENTS;
- if (as->event_head == as->event_tail) {
- static int notified;
-
- if (notified == 0) {
- printk( "apm_bios: an event queue overflowed\n" );
- notified = 1;
- }
- as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
- }
- as->events[as->event_head] = event;
- if (!as->suser)
- continue;
- switch (event) {
- case APM_SYS_SUSPEND:
- case APM_USER_SUSPEND:
- as->suspends_pending++;
- suspends_pending++;
- break;
-
- case APM_SYS_STANDBY:
- case APM_USER_STANDBY:
- as->standbys_pending++;
- standbys_pending++;
- break;
- }
- }
- wake_up_interruptible(&process_list);
- return 1;
-}
-
-static void set_time(void)
-{
- unsigned long flags;
-
- if (!got_clock_diff) /* Don't know time zone, can't set clock */
- return;
-
- save_flags(flags);
- cli();
- CURRENT_TIME = get_cmos_time() + clock_cmos_diff;
- restore_flags(flags);
-}
-
-static void suspend(void)
-{
- unsigned long flags;
- int err;
-
- /* Estimate time zone so that set_time can
- update the clock */
- save_flags(flags);
- clock_cmos_diff = -get_cmos_time();
- cli();
- clock_cmos_diff += CURRENT_TIME;
- got_clock_diff = 1;
- restore_flags(flags);
-
- err = apm_set_power_state(APM_STATE_SUSPEND);
- if (err)
- apm_error("suspend", err);
- set_time();
-}
-
-static void standby(void)
-{
- int err;
-
- err = apm_set_power_state(APM_STATE_STANDBY);
- if (err)
- apm_error("standby", err);
-}
-
-static apm_event_t get_event(void)
-{
- int error;
- apm_event_t event;
-
- static int notified = 0;
-
- error = apm_get_event(&event);
- if (error == APM_SUCCESS)
- return event;
-
- if ((error != APM_NO_EVENTS) && (notified++ == 0))
- apm_error("get_event", error);
-
- return 0;
-}
-
-static void send_event(apm_event_t event, apm_event_t undo,
- struct apm_bios_struct *sender)
-{
- callback_list_t * call;
- callback_list_t * fix;
-
- for (call = callback_list; call != NULL; call = call->next) {
- if (call->callback(event) && undo) {
- for (fix = callback_list; fix != call; fix = fix->next)
- fix->callback(undo);
- if (apm_bios_info.version > 0x100)
- apm_set_power_state(APM_STATE_REJECT);
- return;
- }
- }
-
- queue_event(event, sender);
-}
-
-static void check_events(void)
-{
- apm_event_t event;
-
- while ((event = get_event()) != 0) {
-#ifdef APM_DEBUG
- if (event <= NR_APM_EVENT_NAME)
- printk("APM BIOS received %s notify\n",
- apm_event_name[event - 1]);
- else
- printk("APM BIOS received unknown event 0x%02x\n",
- event);
-#endif
- switch (event) {
- case APM_SYS_STANDBY:
- case APM_USER_STANDBY:
-#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
- if (waiting_for_resume) {
- return;
- }
- waiting_for_resume = 1;
-#endif
- send_event(event, APM_STANDBY_RESUME, NULL);
- if (standbys_pending <= 0)
- standby();
- break;
-
- case APM_USER_SUSPEND:
-#ifdef CONFIG_APM_IGNORE_USER_SUSPEND
- if (apm_bios_info.version > 0x100)
- apm_set_power_state(APM_STATE_REJECT);
- break;
-#endif
- case APM_SYS_SUSPEND:
-#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
- if (waiting_for_resume) {
- return;
- }
- waiting_for_resume = 1;
-#endif
- send_event(event, APM_NORMAL_RESUME, NULL);
- if (suspends_pending <= 0)
- suspend();
- break;
-
- case APM_NORMAL_RESUME:
- case APM_CRITICAL_RESUME:
- case APM_STANDBY_RESUME:
-#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
- waiting_for_resume = 0;
-#endif
- set_time();
- send_event(event, 0, NULL);
- break;
-
- case APM_LOW_BATTERY:
- case APM_POWER_STATUS_CHANGE:
- send_event(event, 0, NULL);
- break;
-
- case APM_UPDATE_TIME:
- set_time();
- break;
-
- case APM_CRITICAL_SUSPEND:
- suspend();
- break;
- }
- }
-}
-
-static void do_apm_timer(unsigned long unused)
-{
- int err;
-
- static int pending_count = 0;
-
- if (((standbys_pending > 0) || (suspends_pending > 0))
- && (apm_bios_info.version > 0x100)
- && (pending_count-- <= 0)) {
- pending_count = 4;
-
- err = apm_set_power_state(APM_STATE_BUSY);
- if (err)
- apm_error("busy", err);
- }
-
- if (!(((standbys_pending > 0) || (suspends_pending > 0))
- && (apm_bios_info.version == 0x100)))
- check_events();
-
- init_timer(&apm_timer);
- apm_timer.expires = APM_CHECK_TIMEOUT + jiffies;
- add_timer(&apm_timer);
-}
-
-/* Called from sys_idle, must make sure apm_enabled. */
-int apm_do_idle(void)
-{
-#ifdef CONFIG_APM_CPU_IDLE
- unsigned short error;
-
- if (!apm_enabled)
- return 0;
-
- APM_SET_CPU_IDLE(error);
- if (error & 0xff)
- return 0;
-
- clock_slowed = (apm_bios_info.flags & APM_IDLE_SLOWS_CLOCK) != 0;
- return 1;
-#else
- return 0;
-#endif
-}
-
-/* Called from sys_idle, must make sure apm_enabled. */
-void apm_do_busy(void)
-{
-#ifdef CONFIG_APM_CPU_IDLE
- unsigned short error;
-
- if (!apm_enabled)
- return;
-
-#ifndef ALWAYS_CALL_BUSY
- if (!clock_slowed)
- return;
-#endif
-
- APM_SET_CPU_BUSY(error);
-
- clock_slowed = 0;
-#endif
-}
-
-static int check_apm_bios_struct(struct apm_bios_struct *as, const char *func)
-{
- if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
- printk("apm_bios: %s passed bad filp", func);
- return 1;
- }
- return 0;
-}
-
-static int do_read(struct inode *inode, struct file *fp, char *buf, int count)
-{
- struct apm_bios_struct * as;
- int i;
- apm_event_t event;
- struct wait_queue wait = { current, NULL };
-
- as = fp->private_data;
- if (check_apm_bios_struct(as, "read"))
- return -EIO;
- if (count < sizeof(apm_event_t))
- return -EINVAL;
- if (queue_empty(as)) {
- if (fp->f_flags & O_NONBLOCK)
- return -EAGAIN;
- add_wait_queue(&process_list, &wait);
-repeat:
- current->state = TASK_INTERRUPTIBLE;
- if (queue_empty(as)
- && !(current->signal & ~current->blocked)) {
- schedule();
- goto repeat;
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&process_list, &wait);
- }
- i = count;
- while ((i >= sizeof(event)) && !queue_empty(as)) {
- event = get_queued_event(as);
- memcpy_tofs(buf, &event, sizeof(event));
- switch (event) {
- case APM_SYS_SUSPEND:
- case APM_USER_SUSPEND:
- as->suspends_read++;
- break;
-
- case APM_SYS_STANDBY:
- case APM_USER_STANDBY:
- as->standbys_read++;
- break;
- }
- buf += sizeof(event);
- i -= sizeof(event);
- }
- if (i < count)
- return count - i;
- if (current->signal & ~current->blocked)
- return -ERESTARTSYS;
- return 0;
-}
-
-static int do_select(struct inode *inode, struct file *fp, int sel_type,
- select_table * wait)
-{
- struct apm_bios_struct * as;
-
- as = fp->private_data;
- if (check_apm_bios_struct(as, "select"))
- return 0;
- if (sel_type != SEL_IN)
- return 0;
- if (!queue_empty(as))
- return 1;
- select_wait(&process_list, wait);
- return 0;
-}
-
-static int do_ioctl(struct inode * inode, struct file *filp,
- u_int cmd, u_long arg)
-{
- struct apm_bios_struct * as;
-
- as = filp->private_data;
- if (check_apm_bios_struct(as, "ioctl"))
- return -EIO;
- if (!as->suser)
- return -EPERM;
- switch (cmd) {
- case APM_IOC_STANDBY:
- if (as->standbys_read > 0) {
- as->standbys_read--;
- as->standbys_pending--;
- standbys_pending--;
- }
- else
- send_event(APM_USER_STANDBY, APM_STANDBY_RESUME, as);
- if (standbys_pending <= 0)
- standby();
- break;
- case APM_IOC_SUSPEND:
- if (as->suspends_read > 0) {
- as->suspends_read--;
- as->suspends_pending--;
- suspends_pending--;
- }
- else
- send_event(APM_USER_SUSPEND, APM_NORMAL_RESUME, as);
- if (suspends_pending <= 0)
- suspend();
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static void do_release(struct inode * inode, struct file * filp)
-{
- struct apm_bios_struct * as;
-
- as = filp->private_data;
- filp->private_data = NULL;
- if (check_apm_bios_struct(as, "release"))
- return;
- if (as->standbys_pending > 0) {
- standbys_pending -= as->standbys_pending;
- if (standbys_pending <= 0)
- standby();
- }
- if (as->suspends_pending > 0) {
- suspends_pending -= as->suspends_pending;
- if (suspends_pending <= 0)
- suspend();
- }
- if (user_list == as)
- user_list = as->next;
- else {
- struct apm_bios_struct * as1;
-
- for (as1 = user_list;
- (as1 != NULL) && (as1->next != as);
- as1 = as1->next)
- ;
- if (as1 == NULL)
- printk("apm_bios: filp not in user list");
- else
- as1->next = as->next;
- }
- kfree_s(as, sizeof(*as));
-}
-
-static int do_open(struct inode * inode, struct file * filp)
-{
- struct apm_bios_struct * as;
-
- as = (struct apm_bios_struct *)kmalloc(sizeof(*as), GFP_KERNEL);
- if (as == NULL) {
- printk("apm_bios: cannot allocate struct of size %d bytes",
- sizeof(*as));
- return -ENOMEM;
- }
- as->magic = APM_BIOS_MAGIC;
- as->event_tail = as->event_head = 0;
- as->suspends_pending = as->standbys_pending = 0;
- as->suspends_read = as->standbys_read = 0;
- as->suser = suser();
- as->next = user_list;
- user_list = as;
- filp->private_data = as;
- return 0;
-}
-
-#ifdef CONFIG_PROC_FS
-int apm_get_info(char *buf, char **start, off_t fpos, int length, int dummy)
-{
- char * p;
- unsigned short bx;
- unsigned short cx;
- unsigned short dx;
- unsigned short error;
- unsigned short ac_line_status = 0xff;
- unsigned short battery_status = 0xff;
- unsigned short battery_flag = 0xff;
- int percentage = -1;
- int time_units = -1;
- char *units = "?";
-
- if (!apm_enabled)
- return 0;
- p = buf;
-
- if (!(error = apm_get_power_status(&bx, &cx, &dx))) {
- ac_line_status = (bx >> 8) & 0xff;
- battery_status = bx & 0xff;
- if ((cx & 0xff) != 0xff)
- percentage = cx & 0xff;
-
- if (apm_bios_info.version > 0x100) {
- battery_flag = (cx >> 8) & 0xff;
- if (dx != 0xffff) {
- if ((dx & 0x8000) == 0x8000) {
- units = "min";
- time_units = dx & 0x7ffe;
- } else {
- units = "sec";
- time_units = dx & 0x7fff;
- }
- }
- }
- }
- /* Arguments, with symbols from linux/apm_bios.h. Information is
- from the Get Power Status (0x0a) call unless otherwise noted.
-
- 0) Linux driver version (this will change if format changes)
- 1) APM BIOS Version. Usually 1.0 or 1.1.
- 2) APM flags from APM Installation Check (0x00):
- bit 0: APM_16_BIT_SUPPORT
- bit 1: APM_32_BIT_SUPPORT
- bit 2: APM_IDLE_SLOWS_CLOCK
- bit 3: APM_BIOS_DISABLED
- bit 4: APM_BIOS_DISENGAGED
- 3) AC line status
- 0x00: Off-line
- 0x01: On-line
- 0x02: On backup power (APM BIOS 1.1 only)
- 0xff: Unknown
- 4) Battery status
- 0x00: High
- 0x01: Low
- 0x02: Critical
- 0x03: Charging
- 0xff: Unknown
- 5) Battery flag
- bit 0: High
- bit 1: Low
- bit 2: Critical
- bit 3: Charging
- bit 7: No system battery
- 0xff: Unknown
- 6) Remaining battery life (percentage of charge):
- 0-100: valid
- -1: Unknown
- 7) Remaining battery life (time units):
- Number of remaining minutes or seconds
- -1: Unknown
- 8) min = minutes; sec = seconds */
-
- p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
- driver_version,
- (apm_bios_info.version >> 8) & 0xff,
- apm_bios_info.version & 0xff,
- apm_bios_info.flags,
- ac_line_status,
- battery_status,
- battery_flag,
- percentage,
- time_units,
- units);
-
- return p - buf;
-}
-#endif
-
-static int apm_disabled = 0;
-
-void apm_setup(char *str, int *ints)
-{
- if(strcmp(str,"off")==0)
- apm_disabled=1;
- if(strcmp(str,"on")==0)
- apm_disabled=0;
-}
-
-void apm_bios_init(void)
-{
- unsigned short bx;
- unsigned short cx;
- unsigned short dx;
- unsigned short error;
- char * power_stat;
- char * bat_stat;
-
- if (apm_disabled == 1)
- {
- printk("APM disabled.\n");
- return;
- }
-
- if (apm_bios_info.version == 0) {
- printk("APM BIOS not found.\n");
- return;
- }
- printk("APM BIOS version %c.%c Flags 0x%02x (Driver version %s)\n",
- ((apm_bios_info.version >> 8) & 0xff) + '0',
- (apm_bios_info.version & 0xff) + '0',
- apm_bios_info.flags,
- driver_version);
- if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) {
- printk(" No 32 bit BIOS support\n");
- return;
- }
-
- /*
- * Fix for the Compaq Contura 3/25c which reports BIOS version 0.1
- * but is reportedly a 1.0 BIOS.
- */
- if (apm_bios_info.version == 0x001)
- apm_bios_info.version = 0x100;
-
- printk(" Entry %x:%lx cseg16 %x dseg %x",
- apm_bios_info.cseg, apm_bios_info.offset,
- apm_bios_info.cseg_16, apm_bios_info.dseg);
- if (apm_bios_info.version > 0x100)
- printk(" cseg len %x, dseg len %x",
- apm_bios_info.cseg_len, apm_bios_info.dseg_len);
- printk("\n");
-
- apm_bios_entry.offset = apm_bios_info.offset;
- apm_bios_entry.segment = APM_CS;
- set_base(gdt[APM_CS >> 3],
- __PAGE_OFFSET + ((unsigned long)apm_bios_info.cseg << 4));
- set_base(gdt[APM_CS_16 >> 3],
- __PAGE_OFFSET + ((unsigned long)apm_bios_info.cseg_16 << 4));
- set_base(gdt[APM_DS >> 3],
- __PAGE_OFFSET + ((unsigned long)apm_bios_info.dseg << 4));
- if (apm_bios_info.version == 0x100) {
- set_limit(gdt[APM_CS >> 3], 64 * 1024);
- set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
- set_limit(gdt[APM_DS >> 3], 64 * 1024);
- } else {
-#ifdef APM_RELAX_SEGMENTS
- /* For ASUS motherboard, Award BIOS rev 110 (and others?) */
- set_limit(gdt[APM_CS >> 3], 64 * 1024);
- /* For some unknown machine. */
- set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
- /* For the DEC Hinote Ultra CT475 (and others?) */
- set_limit(gdt[APM_DS >> 3], 64 * 1024);
-#else
- set_limit(gdt[APM_CS >> 3], apm_bios_info.cseg_len);
- set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
- set_limit(gdt[APM_DS >> 3], apm_bios_info.dseg_len);
-#endif
- apm_bios_info.version = 0x0101;
- error = apm_driver_version(&apm_bios_info.version);
- if (error != 0)
- apm_bios_info.version = 0x100;
- else {
- apm_engage_power_management(0x0001);
- printk( " Connection version %d.%d\n",
- (apm_bios_info.version >> 8) & 0xff,
- apm_bios_info.version & 0xff );
- apm_bios_info.version = 0x0101;
- }
- }
-
- error = apm_get_power_status(&bx, &cx, &dx);
- if (error)
- printk(" Power status not available\n");
- else {
- switch ((bx >> 8) & 0xff) {
- case 0: power_stat = "off line"; break;
- case 1: power_stat = "on line"; break;
- case 2: power_stat = "on backup power"; break;
- default: power_stat = "unknown"; break;
- }
- switch (bx & 0xff) {
- case 0: bat_stat = "high"; break;
- case 1: bat_stat = "low"; break;
- case 2: bat_stat = "critical"; break;
- case 3: bat_stat = "charging"; break;
- default: bat_stat = "unknown"; break;
- }
- printk(" AC %s, battery status %s, battery life ",
- power_stat, bat_stat);
- if ((cx & 0xff) == 0xff)
- printk("unknown\n");
- else
- printk("%d%%\n", cx & 0xff);
- if (apm_bios_info.version > 0x100) {
- printk(" battery flag 0x%02x, battery life ",
- (cx >> 8) & 0xff);
- if (dx == 0xffff)
- printk("unknown\n");
- else {
- if ((dx & 0x8000))
- printk("%d minutes\n", dx & 0x7ffe );
- else
- printk("%d seconds\n", dx & 0x7fff );
- }
- }
- }
-
-#ifdef CONFIG_APM_DO_ENABLE
- /*
- * This call causes my NEC UltraLite Versa 33/C to hang if it is
- * booted with PM disabled but not in the docking station.
- * Unfortunate ...
- */
- error = apm_enable_power_management();
- if (error)
- apm_error("enable power management", error);
- if (error == APM_DISABLED)
- return;
-#endif
-
- init_timer(&apm_timer);
- apm_timer.function = do_apm_timer;
- apm_timer.expires = APM_CHECK_TIMEOUT + jiffies;
- add_timer(&apm_timer);
-
- register_symtab(&apm_syms);
-
-#ifdef CONFIG_PROC_FS
- proc_register_dynamic(&proc_root, &apm_proc_entry);
-#endif
-
- misc_register(&apm_device);
-
- apm_enabled = 1;
-}
{
int retval;
struct tty_driver *p;
- int found = 0;
+ int i, found = 0;
const char *othername = NULL;
+ struct termios *tp;
if (*driver->refcount)
return -EBUSY;
if (driver->next)
driver->next->prev = driver->prev;
+ for (i = 0; i < driver->num; i++) {
+ tp = driver->termios[i];
+ if (tp != NULL) {
+ kfree_s(tp, sizeof(struct termios));
+ driver->termios[i] = NULL;
+ }
+ tp = driver->termios_locked[i];
+ if (tp != NULL) {
+ kfree_s(tp, sizeof(struct termios));
+ driver->termios_locked[i] = NULL;
+ }
+ }
return 0;
}
if (slave_dev->hard_header == NULL
|| slave_dev->hard_header(skb,slave_dev,
ETH_P_IP,NULL,NULL,skb->len) >= 0) {
+ slave->bytes_queued += skb->len;
dev_queue_xmit (skb, slave_dev, 1);
eql->stats->tx_packets++;
- slave->bytes_queued += skb->len;
/* dev_kfree_skb(skb, FREE_WRITE); */
return 0;
}
#include <linux/bios32.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
int error;
struct iattr newattrs;
+
+ /* Not pretty: "inode->i_size" shouldn't really be "off_t". But it is. */
+ if ((off_t) length < 0)
+ return -EINVAL;
+
down(&inode->i_sem);
newattrs.ia_size = length;
newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
/*
* Include file for the interface to an APM BIOS
- * Copyright 1994, 1995 Stephen Rothwell (Stephen.Rothwell@pd.necisa.oz.au)
+ * Copyright 1994-1999 Stephen Rothwell (Stephen.Rothwell@canb.auug.org.au)
*
* 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
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
- *
- * $Id: apm_bios.h,v 0.9 1995/03/09 13:50:05 sfr Exp $
*/
typedef unsigned short apm_event_t;
extern struct apm_bios_info apm_bios_info;
extern void apm_bios_init(void);
+extern void apm_setup(char *, int *);
extern int apm_register_callback(int (*callback)(apm_event_t));
extern void apm_unregister_callback(int (*callback)(apm_event_t));
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#endif
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+#endif
#include <asm/bugs.h>
#ifdef CONFIG_BAYCOM
{ "baycom=", baycom_setup },
#endif
-#ifdef CONFIG_APM
- { "apm=", apm_setup },
-#endif
#ifdef CONFIG_BLK_CPQ_DA
#ifdef CONFIG_BLK_CPQ_DA_EISA
{ "smart2=", cpqarray_setup },
#endif
#ifdef CONFIG_PARIDE_PG
{ "pg.", pg_setup },
+#endif
+#ifdef CONFIG_APM
+ { "apm=", apm_setup },
#endif
{ 0, 0 }
} ;
+++ /dev/null
- Mylex DAC960/DAC1100 PCI RAID Controller Driver for Linux
-
- Version 2.0.0 for Linux 2.0.36
- Version 2.2.0 for Linux 2.2.3
-
- PRODUCTION RELEASE
-
- 23 March 1999
-
- Leonard N. Zubkoff
- Dandelion Digital
- lnz@dandelion.com
-
- Copyright 1998-1999 by Leonard N. Zubkoff <lnz@dandelion.com>
-
-
- INTRODUCTION
-
-Mylex, Inc. designs and manufactures a variety of high performance PCI RAID
-controllers. Mylex Corporation is located at 34551 Ardenwood Blvd., Fremont,
-California 94555, USA and can be reached at 510/796-6100 or on the World Wide
-Web at http://www.mylex.com. Mylex RAID Technical Support can be reached by
-electronic mail at support@mylex.com (for eXtremeRAID 1100 and older DAC960
-models) or techsup@mylex.com (for AcceleRAID models), by voice at 510/608-2400,
-or by FAX at 510/745-7715. Contact information for offices in Europe and Japan
-is available on the Web site.
-
-The latest information on Linux support for DAC960 PCI RAID Controllers, as
-well as the most recent release of this driver, will always be available from
-my Linux Home Page at URL "http://www.dandelion.com/Linux/". The Linux DAC960
-driver supports all current DAC960 PCI family controllers including the
-AcceleRAID models, as well as the eXtremeRAID 1100; see below for a complete
-list. For simplicity, in most places this documentation refers to DAC960
-generically rather than explicitly listing all the models.
-
-Bug reports should be sent via electronic mail to "lnz@dandelion.com". Please
-include with the bug report the complete configuration messages reported by the
-driver at startup, along with any subsequent system messages relevant to the
-controller's operation, and a detailed description of your system's hardware
-configuration.
-
-Please consult the DAC960 RAID controller documentation for detailed
-information regarding installation and configuration of the controllers. This
-document primarily provides information specific to the Linux DAC960 support.
-
-
- DRIVER FEATURES
-
-The DAC960 RAID controllers are supported solely as high performance RAID
-controllers, not as interfaces to arbitrary SCSI devices. The Linux DAC960
-driver operates at the block device level, the same level as the SCSI and IDE
-drivers. Unlike other RAID controllers currently supported on Linux, the
-DAC960 driver is not dependent on the SCSI subsystem, and hence avoids all the
-complexity and unnecessary code that would be associated with an implementation
-as a SCSI driver. The DAC960 driver is designed for as high a performance as
-possible with no compromises or extra code for compatibility with lower
-performance devices. The DAC960 driver includes extensive error logging and
-online configuration management capabilities. Except for initial configuration
-of the controller and adding new disk drives, most everything can be handled
-from Linux while the system is operational.
-
-The DAC960 driver is architected to support up to 8 controllers per system.
-Each DAC960 controller can support up to 15 disk drives per channel, for a
-maximum of 45 drives on a three channel controller. The drives installed on a
-controller are divided into one or more "Drive Groups", and then each Drive
-Group is subdivided further into 1 to 32 "Logical Drives". Each Logical Drive
-has a specific RAID Level and caching policy associated with it, and it appears
-to Linux as a single block device. Logical Drives are further subdivided into
-up to 7 partitions through the normal Linux and PC disk partitioning schemes.
-Logical Drives are also known as "System Drives", and Drive Groups are also
-called "Packs". Both terms are in use in the Mylex documentation; I have
-chosen to standardize on the more generic "Logical Drive" and "Drive Group".
-
-DAC960 RAID disk devices are named in the style of the Device File System
-(DEVFS). The device corresponding to Logical Drive D on Controller C is
-referred to as /dev/rd/cCdD, and the partitions are called /dev/rd/cCdDp1
-through /dev/rd/cCdDp7. For example, partition 3 of Logical Drive 5 on
-Controller 2 is referred to as /dev/rd/c2d5p3. Note that unlike with SCSI
-disks the device names will not change in the event of a disk drive failure.
-The DAC960 driver is assigned major numbers 48 - 55 with one major number per
-controller. The 8 bits of minor number are divided into 5 bits for the Logical
-Drive and 3 bits for the partition.
-
-
- SUPPORTED DAC960/DAC1100 PCI RAID CONTROLLERS
-
-The following list comprises the supported DAC960 and DAC1100 PCI RAID
-Controllers as of the date of this document. It is recommended that anyone
-purchasing a Mylex PCI RAID Controller not in the following table contact the
-author beforehand to verify that it is or will be supported.
-
-eXtremeRAID 1100 (DAC1164P)
- 3 Wide Ultra-2/LVD SCSI channels
- 233MHz StrongARM SA 110 Processor
- 64 Bit PCI (backward compatible with 32 Bit PCI slots)
- 16MB/32MB/64MB Parity SDRAM Memory with Battery Backup
-
-AcceleRAID 250 (DAC960PTL1)
- Uses onboard Symbios SCSI chips on certain motherboards
- Also includes one onboard Wide Ultra-2/LVD SCSI Channel
- 66MHz Intel i960RD RISC Processor
- 4MB/8MB/16MB/32MB/64MB/128MB ECC EDO Memory
-
-AcceleRAID 200 (DAC960PTL0)
- Uses onboard Symbios SCSI chips on certain motherboards
- Includes no onboard SCSI Channels
- 66MHz Intel i960RD RISC Processor
- 4MB/8MB/16MB/32MB/64MB/128MB ECC EDO Memory
-
-AcceleRAID 150 (DAC960PRL)
- Uses onboard Symbios SCSI chips on certain motherboards
- Also includes one onboard Wide Ultra-2/LVD SCSI Channel
- 33MHz Intel i960RP RISC Processor
- 4MB Parity EDO Memory
-
-DAC960PJ 1/2/3 Wide Ultra SCSI-3 Channels
- 66MHz Intel i960RD RISC Processor
- 4MB/8MB/16MB/32MB/64MB/128MB ECC EDO Memory
-
-DAC960PG 1/2/3 Wide Ultra SCSI-3 Channels
- 33MHz Intel i960RP RISC Processor
- 4MB/8MB ECC EDO Memory
-
-DAC960PU 1/2/3 Wide Ultra SCSI-3 Channels
- Intel i960CF RISC Processor
- 4MB/8MB EDRAM or 2MB/4MB/8MB/16MB/32MB DRAM Memory
-
-DAC960PD 1/2/3 Wide Fast SCSI-2 Channels
- Intel i960CF RISC Processor
- 4MB/8MB EDRAM or 2MB/4MB/8MB/16MB/32MB DRAM Memory
-
-DAC960PL 1/2/3 Wide Fast SCSI-2 Channels
- Intel i960 RISC Processor
- 2MB/4MB/8MB/16MB/32MB DRAM Memory
-
-For the eXtremeRAID 1100, firmware version 5.06-0-52 or above is required.
-
-For the AcceleRAID 250, 200, and 150, firmware version 4.06-0-57 or above is
-required.
-
-For the DAC960PJ and DAC960PG, firmware version 4.06-0-00 or above is required.
-
-For the DAC960PU, DAC960PD, and DAC960PL, firmware version 3.51-0-04 or above
-is required.
-
-Note that earlier revisions of the DAC960PU, DAC960PD, and DAC960PL controllers
-were delivered with version 2.xx firmware. Version 2.xx firmware is not
-supported by this driver and no support is envisioned. Contact Mylex RAID
-Technical Support to inquire about upgrading controllers with version 2.xx
-firmware to version 3.51-0-04. Upgrading to version 3.xx firmware requires
-installation of higher capacity Flash ROM chips, and not all DAC960PD and
-DAC960PL controllers can be upgraded.
-
-Please note that not all SCSI disk drives are suitable for use with DAC960
-controllers, and only particular firmware versions of any given model may
-actually function correctly. Similarly, not all motherboards have a BIOS that
-properly initializes the AcceleRAID 250, AcceleRAID 200, AcceleRAID 150,
-DAC960PJ, and DAC960PG because the Intel i960RD/RP is a multi-function device.
-If in doubt, contact Mylex RAID Technical Support (support@mylex.com) to verify
-compatibility. Mylex makes available a hard disk compatibility list by FTP at
-ftp://ftp.mylex.com/pub/dac960/diskcomp.html.
-
-
- DRIVER INSTALLATION
-
-This distribution was prepared for Linux kernel version 2.0.36 or 2.2.3.
-
-To install the DAC960 RAID driver, you may use the following commands,
-replacing "/usr/src" with wherever you keep your Linux kernel source tree:
-
- cd /usr/src
- tar -xvzf DAC960-2.0.0.tar.gz (or DAC960-2.2.0.tar.gz)
- mv README.DAC960 linux/Documentation
- mv DAC960.[ch] linux/drivers/block
- patch -p0 < DAC960.patch
- cd linux
- make config
- make depend
- make bzImage (or zImage)
-
-Then install "arch/i386/boot/bzImage" or "arch/i386/boot/zImage" as your
-standard kernel, run lilo if appropriate, and reboot.
-
-To create the necessary devices in /dev, the "make_rd" script included in
-"DAC960-Utilities.tar.gz" from http://www.dandelion.com/Linux/ may be used.
-LILO 21 and FDISK v2.9 include DAC960 support; also included in this archive
-are patches to LILO 20 and FDISK v2.8 that add DAC960 support, along with
-statically linked executables of LILO and FDISK. This modified version of LILO
-will allow booting from a DAC960 controller and/or mounting the root file
-system from a DAC960. Unfortunately, installing directly onto a DAC960 will be
-problematic until the various Linux distribution vendors update their
-installation utilities. VA Research Linux Systems (http://www.varesearch.com)
-has created an installation CD capable of installing its modified Red Hat 5.2
-environment directly onto DAC960 controllers, and copies of this CD are being
-made available to owners of supported Mylex RAID products by VA Research in
-cooperation with Mylex. Please see http://www.mylex.com/support/prsfrm.html to
-request an installation CD.
-
-
- INSTALLATION NOTES
-
-Before installing Linux or adding DAC960 logical drives to an existing Linux
-system, the controller must first be configured to provide one or more logical
-drives using the BIOS Configuration Utility or DACCF. Please note that since
-there are only at most 6 usable partitions on each logical drive, systems
-requiring more partitions should subdivide a drive group into multiple logical
-drives, each of which can have up to 6 partitions. Also, note that with large
-disk arrays it is advisable to enable the 8GB BIOS Geometry (255/63) rather
-than accepting the default 2GB BIOS Geometry (128/32); failing to so do will
-cause the logical drive geometry to have more than 65535 cylinders which will
-make it impossible for FDISK to be used properly. The 8GB BIOS Geometry can be
-enabled by configuring the DAC960 BIOS, which is accessible via Alt-M during
-the BIOS initialization sequence.
-
-For maximum performance and the most efficient E2FSCK performance, it is
-recommended that EXT2 file systems be built with a 4KB block size and 16 block
-stride to match the DAC960 controller's 64KB default stripe size. The command
-"mke2fs -b 4096 -R stride=16 <device>" is appropriate.
-
-
- DAC960 ANNOUNCEMENTS MAILING LIST
-
-The DAC960 Announcements Mailing List provides a forum for informing Linux
-users of new driver releases and other announcements regarding Linux support
-for DAC960 PCI RAID Controllers. To join the mailing list, send a message to
-"dac960-announce-request@dandelion.com" with the line "subscribe" in the
-message body.
-
-
- CONTROLLER CONFIGURATION AND STATUS MONITORING
-
-The DAC960 RAID controllers running firmware 4.06 or above include a Background
-Initialization facility so that system downtime is minimized both for initial
-installation and subsequent configuration of additional storage. The BIOS
-Configuration Utility (accessible via Alt-R during the BIOS initialization
-sequence) is used to quickly configure the controller, and then the logical
-drives that have been created are available for immediate use even while they
-are still being initialized by the controller. The primary need for online
-configuration and status monitoring is then to avoid system downtime when disk
-drives fail and must be replaced. Note that with a SAF-TE (SCSI Accessed
-Fault-Tolerant Enclosure) enclosure, the controller is able to rebuild failed
-drives automatically as soon as a drive replacement is made available.
-
-The primary interfaces for controller configuration and status monitoring are
-special files created in the /proc/rd/... hierarchy along with the normal
-system console logging mechanism. Whenever the system is operating, the DAC960
-driver queries each controller for status information every 10 seconds, and
-checks for additional conditions every 60 seconds. The initial status of each
-controller is always available for controller N in /proc/rd/cN/initial_status,
-and the current status as of the last status monitoring query is available in
-/proc/rd/cN/current_status. In addition, status changes are also logged by the
-driver to the system console and will appear in the log files maintained by
-syslog. The progress of asynchronous rebuild or consistency check operations
-is also available in /proc/rd/cN/current_status, and progress messages are
-logged to the system console at most every 60 seconds.
-
-To simplify the monitoring process for custom software, the special file
-/proc/rd/status returns "OK" when all DAC960 controllers in the system are
-operating normally and no failures have occurred, or "ALERT" if any logical
-drives are offline or critical or any non-standby physical drives are dead.
-
-Configuration commands for controller N are available via the special file
-/proc/rd/cN/user_command. A human readable command can be written to this
-special file to initiate a configuration operation, and the results of the
-operation can then be read back from the special file in addition to being
-logged to the system console. The shell command sequence
-
- echo "<configuration-command>" > /proc/rd/c0/user_command
- cat /proc/rd/c0/user_command
-
-is typically used to execute configuration commands. The configuration
-commands are:
-
- flush-cache
-
- The "flush-cache" command flushes the controller's cache. The system
- automatically flushes the cache at shutdown or if the driver module is
- unloaded, so this command is only needed to be certain a write back cache
- is flushed to disk before the system is powered off by a command to a UPS.
- Note that the flush-cache command also stops an asynchronous rebuild or
- consistency check, so it should not be used except when the system is being
- halted.
-
- kill <channel>:<target-id>
-
- The "kill" command marks the physical drive <channel>:<target-id> as DEAD.
- This command is provided primarily for testing, and should not be used
- during normal system operation.
-
- make-online <channel>:<target-id>
-
- The "make-online" command changes the physical drive <channel>:<target-id>
- from status DEAD to status ONLINE. In cases where multiple physical drives
- have been killed simultaneously, this command may be used to bring them
- back online, after which a consistency check is advisable.
-
- Warning: make-online should only be used on a dead physical drive that is
- an active part of a drive group, never on a standby drive.
-
- make-standby <channel>:<target-id>
-
- The "make-standby" command changes physical drive <channel>:<target-id>
- from status DEAD to status STANDBY. It should only be used in cases where
- a dead drive was replaced after an automatic rebuild was performed onto a
- standby drive. It cannot be used to add a standby drive to the controller
- configuration if one was not created initially; the BIOS Configuration
- Utility must be used for that currently.
-
- rebuild <channel>:<target-id>
-
- The "rebuild" command initiates an asynchronous rebuild onto physical drive
- <channel>:<target-id>. It should only be used when a dead drive has been
- replaced.
-
- check-consistency <logical-drive-number>
-
- The "check-consistency" command initiates an asynchronous consistency check
- of <logical-drive-number> with automatic restoration. It can be used
- whenever it is desired to verify the consistency of the redundancy
- information.
-
- cancel-rebuild
- cancel-consistency-check
-
- The "cancel-rebuild" and "cancel-consistency-check" commands cancel any
- rebuild or consistency check operations previously initiated.
-
-
- EXAMPLE I - DRIVE FAILURE WITHOUT A STANDBY DRIVE
-
-The following annotated logs demonstrate the controller configuration and and
-online status monitoring capabilities of the Linux DAC960 Driver. The test
-configuration comprises 6 1GB Quantum Atlas I disk drives on two channels of a
-DAC960PJ controller. The physical drives are configured into a single drive
-group without a standby drive, and the drive group has been configured into two
-logical drives, one RAID-5 and one RAID-6. First, here is the current status
-of the RAID configuration:
-
-gwynedd:/u/lnz# cat /proc/rd/c0/current_status
-***** DAC960 RAID Driver Version 2.0.0 of 23 March 1999 *****
-Copyright 1998-1999 by Leonard N. Zubkoff <lnz@dandelion.com>
-Configuring Mylex DAC960PJ PCI RAID Controller
- Firmware Version: 4.06-0-08, Channels: 3, Memory Size: 8MB
- PCI Bus: 0, Device: 19, Function: 1, I/O Address: Unassigned
- PCI Address: 0xFD4FC000 mapped at 0x8807000, IRQ Channel: 9
- Controller Queue Depth: 128, Maximum Blocks per Command: 128
- Driver Queue Depth: 127, Maximum Scatter/Gather Segments: 33
- Stripe Size: 64KB, Segment Size: 8KB, BIOS Geometry: 255/63
- Physical Devices:
- 0:1 - Disk: Online, 2201600 blocks
- 0:2 - Disk: Online, 2201600 blocks
- 0:3 - Disk: Online, 2201600 blocks
- 1:1 - Disk: Online, 2201600 blocks
- 1:2 - Disk: Online, 2201600 blocks
- 1:3 - Disk: Online, 2201600 blocks
- Logical Drives:
- /dev/rd/c0d0: RAID-5, Online, 5498880 blocks, Write Thru
- /dev/rd/c0d1: RAID-6, Online, 3305472 blocks, Write Thru
- No Rebuild or Consistency Check in Progress
-
-gwynedd:/u/lnz# cat /proc/rd/status
-OK
-
-The above messages indicate that everything is healthy, and /proc/rd/status
-returns "OK" indicating that there are no problems with any DAC960 controller
-in the system. For demonstration purposes, while I/O is active Physical Drive
-1:1 is now disconnected, simulating a drive failure. The failure is noted by
-the driver within 10 seconds of the controller's having detected it, and the
-driver logs the following console status messages indicating that Logical
-Drives 0 and 1 are now CRITICAL as a result of Physical Drive 1:1 being DEAD:
-
-DAC960#0: Logical Drive 0 (/dev/rd/c0d0) is now CRITICAL
-DAC960#0: Logical Drive 1 (/dev/rd/c0d1) is now CRITICAL
-DAC960#0: Physical Drive 1:2 Error Log: Sense Key = 6, ASC = 29, ASCQ = 02
-DAC960#0: Physical Drive 1:3 Error Log: Sense Key = 6, ASC = 29, ASCQ = 02
-DAC960#0: Physical Drive 1:1 killed because of timeout on SCSI command
-DAC960#0: Physical Drive 1:1 is now DEAD
-
-The Sense Keys logged here are just Check Condition / Unit Attention conditions
-arising from a SCSI bus reset that is forced by the controller during its error
-recovery procedures. Concurrently with the above, the driver status available
-from /proc/rd also reflects the drive failure. The status message in
-/proc/rd/status has changed from "OK" to "ALERT":
-
-gwynedd:/u/lnz# cat /proc/rd/status
-ALERT
-
-and /proc/rd/c0/current_status has been updated:
-
-gwynedd:/u/lnz# cat /proc/rd/c0/current_status
- ...
- Physical Devices:
- 0:1 - Disk: Online, 2201600 blocks
- 0:2 - Disk: Online, 2201600 blocks
- 0:3 - Disk: Online, 2201600 blocks
- 1:1 - Disk: Dead, 2201600 blocks
- 1:2 - Disk: Online, 2201600 blocks
- 1:3 - Disk: Online, 2201600 blocks
- Logical Drives:
- /dev/rd/c0d0: RAID-5, Critical, 5498880 blocks, Write Thru
- /dev/rd/c0d1: RAID-6, Critical, 3305472 blocks, Write Thru
- No Rebuild or Consistency Check in Progress
-
-Since there are no standby drives configured, the system can continue to access
-the logical drives in a performance degraded mode until the failed drive is
-replaced and a rebuild operation completed to restore the redundancy of the
-logical drives. Once Physical Drive 1:1 is replaced with a properly
-functioning drive, or if the physical drive was killed without having failed
-(e.g., due to electrical problems on the SCSI bus), the user can instruct the
-controller to initiate a rebuild operation onto the newly replaced drive:
-
-gwynedd:/u/lnz# echo "rebuild 1:1" > /proc/rd/c0/user_command
-gwynedd:/u/lnz# cat /proc/rd/c0/user_command
-Rebuild of Physical Drive 1:1 Initiated
-
-The echo command instructs the controller to initiate an asynchronous rebuild
-operation onto Physical Drive 1:1, and the status message that results from the
-operation is then available for reading from /proc/rd/c0/user_command, as well
-as being logged to the console by the driver.
-
-Within 10 seconds of this command the driver logs the initiation of the
-asynchronous rebuild operation:
-
-DAC960#0: Rebuild of Physical Drive 1:1 Initiated
-DAC960#0: Physical Drive 1:1 Error Log: Sense Key = 6, ASC = 29, ASCQ = 01
-DAC960#0: Physical Drive 1:1 is now WRITE-ONLY
-DAC960#0: Rebuild in Progress: Logical Drive 0 (/dev/rd/c0d0) 1% completed
-
-and /proc/rd/c0/current_status is updated:
-
-gwynedd:/u/lnz# cat /proc/rd/c0/current_status
- ...
- Physical Devices:
- 0:1 - Disk: Online, 2201600 blocks
- 0:2 - Disk: Online, 2201600 blocks
- 0:3 - Disk: Online, 2201600 blocks
- 1:1 - Disk: Write-Only, 2201600 blocks
- 1:2 - Disk: Online, 2201600 blocks
- 1:3 - Disk: Online, 2201600 blocks
- Logical Drives:
- /dev/rd/c0d0: RAID-5, Critical, 5498880 blocks, Write Thru
- /dev/rd/c0d1: RAID-6, Critical, 3305472 blocks, Write Thru
- Rebuild in Progress: Logical Drive 0 (/dev/rd/c0d0) 6% completed
-
-As the rebuild progresses, the current status in /proc/rd/c0/current_status is
-updated every 10 seconds:
-
-gwynedd:/u/lnz# cat /proc/rd/c0/current_status
- ...
- Physical Devices:
- 0:1 - Disk: Online, 2201600 blocks
- 0:2 - Disk: Online, 2201600 blocks
- 0:3 - Disk: Online, 2201600 blocks
- 1:1 - Disk: Write-Only, 2201600 blocks
- 1:2 - Disk: Online, 2201600 blocks
- 1:3 - Disk: Online, 2201600 blocks
- Logical Drives:
- /dev/rd/c0d0: RAID-5, Critical, 5498880 blocks, Write Thru
- /dev/rd/c0d1: RAID-6, Critical, 3305472 blocks, Write Thru
- Rebuild in Progress: Logical Drive 0 (/dev/rd/c0d0) 15% completed
-
-and every minute a progress message is logged to the console by the driver:
-
-DAC960#0: Rebuild in Progress: Logical Drive 0 (/dev/rd/c0d0) 32% completed
-DAC960#0: Rebuild in Progress: Logical Drive 0 (/dev/rd/c0d0) 63% completed
-DAC960#0: Rebuild in Progress: Logical Drive 0 (/dev/rd/c0d0) 94% completed
-DAC960#0: Rebuild in Progress: Logical Drive 1 (/dev/rd/c0d1) 94% completed
-
-Finally, the rebuild completes successfully. The driver logs the status of the
-logical and physical drives and the rebuild completion:
-
-DAC960#0: Logical Drive 0 (/dev/rd/c0d0) is now ONLINE
-DAC960#0: Logical Drive 1 (/dev/rd/c0d1) is now ONLINE
-DAC960#0: Physical Drive 1:1 is now ONLINE
-DAC960#0: Rebuild Completed Successfully
-
-/proc/rd/c0/current_status is updated:
-
-gwynedd:/u/lnz# cat /proc/rd/c0/current_status
- ...
- Physical Devices:
- 0:1 - Disk: Online, 2201600 blocks
- 0:2 - Disk: Online, 2201600 blocks
- 0:3 - Disk: Online, 2201600 blocks
- 1:1 - Disk: Online, 2201600 blocks
- 1:2 - Disk: Online, 2201600 blocks
- 1:3 - Disk: Online, 2201600 blocks
- Logical Drives:
- /dev/rd/c0d0: RAID-5, Online, 5498880 blocks, Write Thru
- /dev/rd/c0d1: RAID-6, Online, 3305472 blocks, Write Thru
- Rebuild Completed Successfully
-
-and /proc/rd/status indicates that everything is healthy once again:
-
-gwynedd:/u/lnz# cat /proc/rd/status
-OK
-
-
- EXAMPLE II - DRIVE FAILURE WITH A STANDBY DRIVE
-
-The following annotated logs demonstrate the controller configuration and and
-online status monitoring capabilities of the Linux DAC960 Driver. The test
-configuration comprises 6 1GB Quantum Atlas I disk drives on two channels of a
-DAC960PJ controller. The physical drives are configured into a single drive
-group with a standby drive, and the drive group has been configured into two
-logical drives, one RAID-5 and one RAID-6. First, here is the current status
-of the RAID configuration:
-
-gwynedd:/u/lnz# cat /proc/rd/c0/current_status
-***** DAC960 RAID Driver Version 2.0.0 of 23 March 1999 *****
-Copyright 1998-1999 by Leonard N. Zubkoff <lnz@dandelion.com>
-Configuring Mylex DAC960PJ PCI RAID Controller
- Firmware Version: 4.06-0-08, Channels: 3, Memory Size: 8MB
- PCI Bus: 0, Device: 19, Function: 1, I/O Address: Unassigned
- PCI Address: 0xFD4FC000 mapped at 0x8807000, IRQ Channel: 9
- Controller Queue Depth: 128, Maximum Blocks per Command: 128
- Driver Queue Depth: 127, Maximum Scatter/Gather Segments: 33
- Stripe Size: 64KB, Segment Size: 8KB, BIOS Geometry: 255/63
- Physical Devices:
- 0:1 - Disk: Online, 2201600 blocks
- 0:2 - Disk: Online, 2201600 blocks
- 0:3 - Disk: Online, 2201600 blocks
- 1:1 - Disk: Online, 2201600 blocks
- 1:2 - Disk: Online, 2201600 blocks
- 1:3 - Disk: Standby, 2201600 blocks
- Logical Drives:
- /dev/rd/c0d0: RAID-5, Online, 4399104 blocks, Write Thru
- /dev/rd/c0d1: RAID-6, Online, 2754560 blocks, Write Thru
- No Rebuild or Consistency Check in Progress
-
-gwynedd:/u/lnz# cat /proc/rd/status
-OK
-
-The above messages indicate that everything is healthy, and /proc/rd/status
-returns "OK" indicating that there are no problems with any DAC960 controller
-in the system. For demonstration purposes, while I/O is active Physical Drive
-1:2 is now disconnected, simulating a drive failure. The failure is noted by
-the driver within 10 seconds of the controller's having detected it, and the
-driver logs the following console status messages:
-
-DAC960#0: Logical Drive 0 (/dev/rd/c0d0) is now CRITICAL
-DAC960#0: Logical Drive 1 (/dev/rd/c0d1) is now CRITICAL
-DAC960#0: Physical Drive 1:1 Error Log: Sense Key = 6, ASC = 29, ASCQ = 02
-DAC960#0: Physical Drive 1:3 Error Log: Sense Key = 6, ASC = 29, ASCQ = 02
-DAC960#0: Physical Drive 1:2 killed because of timeout on SCSI command
-DAC960#0: Physical Drive 1:2 is now DEAD
-DAC960#0: Physical Drive 1:2 killed because it was removed
-
-Since a standby drive is configured, the controller automatically begins
-rebuilding onto the standby drive:
-
-DAC960#0: Physical Drive 1:3 is now WRITE-ONLY
-DAC960#0: Rebuild in Progress: Logical Drive 0 (/dev/rd/c0d0) 4% completed
-
-Concurrently with the above, the driver status available from /proc/rd also
-reflects the drive failure and automatic rebuild. The status message in
-/proc/rd/status has changed from "OK" to "ALERT":
-
-gwynedd:/u/lnz# cat /proc/rd/status
-ALERT
-
-and /proc/rd/c0/current_status has been updated:
-
-gwynedd:/u/lnz# cat /proc/rd/c0/current_status
- ...
- Physical Devices:
- 0:1 - Disk: Online, 2201600 blocks
- 0:2 - Disk: Online, 2201600 blocks
- 0:3 - Disk: Online, 2201600 blocks
- 1:1 - Disk: Online, 2201600 blocks
- 1:2 - Disk: Dead, 2201600 blocks
- 1:3 - Disk: Write-Only, 2201600 blocks
- Logical Drives:
- /dev/rd/c0d0: RAID-5, Critical, 4399104 blocks, Write Thru
- /dev/rd/c0d1: RAID-6, Critical, 2754560 blocks, Write Thru
- Rebuild in Progress: Logical Drive 0 (/dev/rd/c0d0) 4% completed
-
-As the rebuild progresses, the current status in /proc/rd/c0/current_status is
-updated every 10 seconds:
-
-gwynedd:/u/lnz# cat /proc/rd/c0/current_status
- ...
- Physical Devices:
- 0:1 - Disk: Online, 2201600 blocks
- 0:2 - Disk: Online, 2201600 blocks
- 0:3 - Disk: Online, 2201600 blocks
- 1:1 - Disk: Online, 2201600 blocks
- 1:2 - Disk: Dead, 2201600 blocks
- 1:3 - Disk: Write-Only, 2201600 blocks
- Logical Drives:
- /dev/rd/c0d0: RAID-5, Critical, 4399104 blocks, Write Thru
- /dev/rd/c0d1: RAID-6, Critical, 2754560 blocks, Write Thru
- Rebuild in Progress: Logical Drive 0 (/dev/rd/c0d0) 40% completed
-
-and every minute a progress message is logged on the console by the driver:
-
-DAC960#0: Rebuild in Progress: Logical Drive 0 (/dev/rd/c0d0) 40% completed
-DAC960#0: Rebuild in Progress: Logical Drive 0 (/dev/rd/c0d0) 76% completed
-DAC960#0: Rebuild in Progress: Logical Drive 1 (/dev/rd/c0d1) 66% completed
-DAC960#0: Rebuild in Progress: Logical Drive 1 (/dev/rd/c0d1) 84% completed
-
-Finally, the rebuild completes successfully. The driver logs the status of the
-logical and physical drives and the rebuild completion:
-
-DAC960#0: Logical Drive 0 (/dev/rd/c0d0) is now ONLINE
-DAC960#0: Logical Drive 1 (/dev/rd/c0d1) is now ONLINE
-DAC960#0: Physical Drive 1:3 is now ONLINE
-DAC960#0: Rebuild Completed Successfully
-
-/proc/rd/c0/current_status is updated:
-
-***** DAC960 RAID Driver Version 2.0.0 of 23 March 1999 *****
-Copyright 1998-1999 by Leonard N. Zubkoff <lnz@dandelion.com>
-Configuring Mylex DAC960PJ PCI RAID Controller
- Firmware Version: 4.06-0-08, Channels: 3, Memory Size: 8MB
- PCI Bus: 0, Device: 19, Function: 1, I/O Address: Unassigned
- PCI Address: 0xFD4FC000 mapped at 0x8807000, IRQ Channel: 9
- Controller Queue Depth: 128, Maximum Blocks per Command: 128
- Driver Queue Depth: 127, Maximum Scatter/Gather Segments: 33
- Stripe Size: 64KB, Segment Size: 8KB, BIOS Geometry: 255/63
- Physical Devices:
- 0:1 - Disk: Online, 2201600 blocks
- 0:2 - Disk: Online, 2201600 blocks
- 0:3 - Disk: Online, 2201600 blocks
- 1:1 - Disk: Online, 2201600 blocks
- 1:2 - Disk: Dead, 2201600 blocks
- 1:3 - Disk: Online, 2201600 blocks
- Logical Drives:
- /dev/rd/c0d0: RAID-5, Online, 4399104 blocks, Write Thru
- /dev/rd/c0d1: RAID-6, Online, 2754560 blocks, Write Thru
- Rebuild Completed Successfully
-
-and /proc/rd/status indicates that everything is healthy once again:
-
-gwynedd:/u/lnz# cat /proc/rd/status
-OK
-
-Note that the absence of a viable standby drive does not create an "ALERT"
-status. Once dead Physical Drive 1:2 has been replaced, the controller must be
-told that this has occurred and that the newly replaced drive should become the
-new standby drive:
-
-gwynedd:/u/lnz# echo "make-standby 1:2" > /proc/rd/c0/user_command
-gwynedd:/u/lnz# cat /proc/rd/c0/user_command
-Make Standby of Physical Drive 1:2 Succeeded
-
-The echo command instructs the controller to make Physical Drive 1:2 into a
-standby drive, and the status message that results from the operation is then
-available for reading from /proc/rd/c0/user_command, as well as being logged to
-the console by the driver. Within 60 seconds of this command the driver logs:
-
-DAC960#0: Physical Drive 1:2 Error Log: Sense Key = 6, ASC = 29, ASCQ = 01
-DAC960#0: Physical Drive 1:2 is now STANDBY
-DAC960#0: Make Standby of Physical Drive 1:2 Succeeded
-
-and /proc/rd/c0/current_status is updated:
-
-gwynedd:/u/lnz# cat /proc/rd/c0/current_status
- ...
- Physical Devices:
- 0:1 - Disk: Online, 2201600 blocks
- 0:2 - Disk: Online, 2201600 blocks
- 0:3 - Disk: Online, 2201600 blocks
- 1:1 - Disk: Online, 2201600 blocks
- 1:2 - Disk: Standby, 2201600 blocks
- 1:3 - Disk: Online, 2201600 blocks
- Logical Drives:
- /dev/rd/c0d0: RAID-5, Online, 4399104 blocks, Write Thru
- /dev/rd/c0d1: RAID-6, Online, 2754560 blocks, Write Thru
- Rebuild Completed Successfully
+++ /dev/null
-/*
-
- Linux Driver for Mylex DAC960 and DAC1100 PCI RAID Controllers
-
- Copyright 1998-1999 by Leonard N. Zubkoff <lnz@dandelion.com>
-
- This program is free software; you may redistribute and/or modify it under
- the terms of the GNU General Public License Version 2 as published by the
- Free Software Foundation.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for complete details.
-
- The author respectfully requests that any modifications to this software be
- sent directly to him for evaluation and testing.
-
-*/
-
-
-#define DAC960_DriverVersion "2.0.0"
-#define DAC960_DriverDate "23 March 1999"
-
-
-#include <linux/version.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/blk.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/ioport.h>
-#include <linux/locks.h>
-#include <linux/mm.h>
-#include <linux/malloc.h>
-#include <linux/proc_fs.h>
-#include <linux/timer.h>
-#include <linux/pci.h>
-#include <linux/bios32.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/segment.h>
-#include "DAC960.h"
-
-
-/*
- DAC960_ControllerCount is the number of DAC960 Controllers detected.
-*/
-
-static int
- DAC960_ControllerCount = 0;
-
-
-/*
- DAC960_ActiveControllerCount is the number of Active DAC960 Controllers
- detected.
-*/
-
-static int
- DAC960_ActiveControllerCount = 0;
-
-
-/*
- DAC960_Controllers is an array of pointers to the DAC960 Controller
- structures.
-*/
-
-static DAC960_Controller_T
- *DAC960_Controllers[DAC960_MaxControllers] = { NULL };
-
-
-/*
- DAC960_FileOperations is the File Operations structure for DAC960 Logical
- Disk Devices.
-*/
-
-static FileOperations_T
- DAC960_FileOperations =
- { lseek: NULL,
- read: block_read,
- write: block_write,
- readdir: NULL,
- select: NULL,
- ioctl: DAC960_Ioctl,
- mmap: NULL,
- open: DAC960_Open,
- release: DAC960_Release,
- fsync: block_fsync,
- fasync: NULL,
- check_media_change: NULL,
- revalidate: NULL };
-
-
-/*
- DAC960_ProcDirectoryEntry is the DAC960 /proc/rd directory entry.
-*/
-
-static PROC_DirectoryEntry_T
- DAC960_ProcDirectoryEntry;
-
-
-/*
- DAC960_AnnounceDriver announces the Driver Version and Date, Author's Name,
- Copyright Notice, and Electronic Mail Address.
-*/
-
-static void DAC960_AnnounceDriver(DAC960_Controller_T *Controller)
-{
- DAC960_Announce("***** DAC960 RAID Driver Version "
- DAC960_DriverVersion " of "
- DAC960_DriverDate " *****\n", Controller);
- DAC960_Announce("Copyright 1998-1999 by Leonard N. Zubkoff "
- "<lnz@dandelion.com>\n", Controller);
-}
-
-
-/*
- DAC960_Failure prints a standardized error message, and then returns false.
-*/
-
-static boolean DAC960_Failure(DAC960_Controller_T *Controller,
- char *ErrorMessage)
-{
- DAC960_Error("While configuring DAC960 PCI RAID Controller at\n",
- Controller);
- if (Controller->IO_Address == 0)
- DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A "
- "PCI Address 0x%X\n", Controller,
- Controller->Bus, Controller->Device,
- Controller->Function, Controller->PCI_Address);
- else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address "
- "0x%X PCI Address 0x%X\n", Controller,
- Controller->Bus, Controller->Device,
- Controller->Function, Controller->IO_Address,
- Controller->PCI_Address);
- DAC960_Error("%s FAILED - DETACHING\n", Controller, ErrorMessage);
- return false;
-}
-
-
-/*
- DAC960_ClearCommand clears critical fields of Command.
-*/
-
-static inline void DAC960_ClearCommand(DAC960_Command_T *Command)
-{
- DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
- CommandMailbox->Words[0] = 0;
- CommandMailbox->Words[1] = 0;
- CommandMailbox->Words[2] = 0;
- CommandMailbox->Words[3] = 0;
- Command->CommandStatus = 0;
-}
-
-
-/*
- DAC960_AllocateCommand allocates a Command structure from Controller's
- free list.
-*/
-
-static inline DAC960_Command_T *DAC960_AllocateCommand(DAC960_Controller_T
- *Controller)
-{
- DAC960_Command_T *Command = Controller->FreeCommands;
- if (Command == NULL) return NULL;
- Controller->FreeCommands = Command->Next;
- Command->Next = NULL;
- return Command;
-}
-
-
-/*
- DAC960_DeallocateCommand deallocates Command, returning it to Controller's
- free list.
-*/
-
-static inline void DAC960_DeallocateCommand(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- Command->Next = Controller->FreeCommands;
- Controller->FreeCommands = Command;
-}
-
-
-/*
- DAC960_QueueCommand queues Command.
-*/
-
-static void DAC960_QueueCommand(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- void *ControllerBaseAddress = Controller->BaseAddress;
- DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
- DAC960_CommandMailbox_T *NextCommandMailbox;
- CommandMailbox->Common.CommandIdentifier = Command - Controller->Commands;
- switch (Controller->ControllerType)
- {
- case DAC960_V5_Controller:
- NextCommandMailbox = Controller->NextCommandMailbox;
- DAC960_V5_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
- if (Controller->PreviousCommandMailbox1->Words[0] == 0 ||
- Controller->PreviousCommandMailbox2->Words[0] == 0)
- if (Controller->DualModeMemoryMailboxInterface)
- DAC960_V5_MemoryMailboxNewCommand(ControllerBaseAddress);
- else DAC960_V5_HardwareMailboxNewCommand(ControllerBaseAddress);
- Controller->PreviousCommandMailbox2 = Controller->PreviousCommandMailbox1;
- Controller->PreviousCommandMailbox1 = NextCommandMailbox;
- if (++NextCommandMailbox > Controller->LastCommandMailbox)
- NextCommandMailbox = Controller->FirstCommandMailbox;
- Controller->NextCommandMailbox = NextCommandMailbox;
- break;
- case DAC960_V4_Controller:
- NextCommandMailbox = Controller->NextCommandMailbox;
- DAC960_V4_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
- if (Controller->PreviousCommandMailbox1->Words[0] == 0 ||
- Controller->PreviousCommandMailbox2->Words[0] == 0)
- if (Controller->DualModeMemoryMailboxInterface)
- DAC960_V4_MemoryMailboxNewCommand(ControllerBaseAddress);
- else DAC960_V4_HardwareMailboxNewCommand(ControllerBaseAddress);
- Controller->PreviousCommandMailbox2 = Controller->PreviousCommandMailbox1;
- Controller->PreviousCommandMailbox1 = NextCommandMailbox;
- if (++NextCommandMailbox > Controller->LastCommandMailbox)
- NextCommandMailbox = Controller->FirstCommandMailbox;
- Controller->NextCommandMailbox = NextCommandMailbox;
- break;
- case DAC960_V3_Controller:
- while (DAC960_V3_MailboxFullP(ControllerBaseAddress))
- udelay(1);
- DAC960_V3_WriteCommandMailbox(ControllerBaseAddress, CommandMailbox);
- DAC960_V3_NewCommand(ControllerBaseAddress);
- break;
- }
-}
-
-
-/*
- DAC960_ExecuteCommand executes Command and waits for completion. It
- returns true on success and false on failure.
-*/
-
-static boolean DAC960_ExecuteCommand(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- Semaphore_T Semaphore = MUTEX_LOCKED;
- unsigned long ProcessorFlags;
- Command->Semaphore = &Semaphore;
- DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
- DAC960_QueueCommand(Command);
- DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
- down(&Semaphore);
- return Command->CommandStatus == DAC960_NormalCompletion;
-}
-
-
-/*
- DAC960_ExecuteType3 executes a DAC960 Type 3 Command and waits for
- completion. It returns true on success and false on failure.
-*/
-
-static boolean DAC960_ExecuteType3(DAC960_Controller_T *Controller,
- DAC960_CommandOpcode_T CommandOpcode,
- void *DataPointer)
-{
- DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
- DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
- boolean Result;
- DAC960_ClearCommand(Command);
- Command->CommandType = DAC960_ImmediateCommand;
- CommandMailbox->Type3.CommandOpcode = CommandOpcode;
- CommandMailbox->Type3.BusAddress = Virtual_to_Bus(DataPointer);
- Result = DAC960_ExecuteCommand(Command);
- DAC960_DeallocateCommand(Command);
- return Result;
-}
-
-
-/*
- DAC960_ExecuteType3D executes a DAC960 Type 3D Command and waits for
- completion. It returns true on success and false on failure.
-*/
-
-static boolean DAC960_ExecuteType3D(DAC960_Controller_T *Controller,
- DAC960_CommandOpcode_T CommandOpcode,
- unsigned char Channel,
- unsigned char TargetID,
- void *DataPointer)
-{
- DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
- DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
- boolean Result;
- DAC960_ClearCommand(Command);
- Command->CommandType = DAC960_ImmediateCommand;
- CommandMailbox->Type3D.CommandOpcode = CommandOpcode;
- CommandMailbox->Type3D.Channel = Channel;
- CommandMailbox->Type3D.TargetID = TargetID;
- CommandMailbox->Type3D.BusAddress = Virtual_to_Bus(DataPointer);
- Result = DAC960_ExecuteCommand(Command);
- DAC960_DeallocateCommand(Command);
- return Result;
-}
-
-
-/*
- DAC960_EnableMemoryMailboxInterface enables the Memory Mailbox Interface.
-*/
-
-static boolean DAC960_EnableMemoryMailboxInterface(DAC960_Controller_T
- *Controller)
-{
- void *ControllerBaseAddress = Controller->BaseAddress;
- DAC960_CommandMailbox_T *CommandMailboxesMemory;
- DAC960_StatusMailbox_T *StatusMailboxesMemory;
- DAC960_CommandMailbox_T CommandMailbox;
- DAC960_CommandStatus_T CommandStatus;
- void *SavedMemoryMailboxesAddress = NULL;
- short NextCommandMailboxIndex = 0;
- short NextStatusMailboxIndex = 0;
- long TimeoutCounter = 1000000;
- int i;
- if (Controller->ControllerType == DAC960_V5_Controller)
- DAC960_V5_RestoreMemoryMailboxInfo(Controller,
- &SavedMemoryMailboxesAddress,
- &NextCommandMailboxIndex,
- &NextStatusMailboxIndex);
- else DAC960_V4_RestoreMemoryMailboxInfo(Controller,
- &SavedMemoryMailboxesAddress,
- &NextCommandMailboxIndex,
- &NextStatusMailboxIndex);
- if (SavedMemoryMailboxesAddress == NULL)
- CommandMailboxesMemory =
- (DAC960_CommandMailbox_T *) __get_free_pages(GFP_KERNEL, 1, 0);
- else CommandMailboxesMemory = SavedMemoryMailboxesAddress;
- memset(CommandMailboxesMemory, 0, PAGE_SIZE << 1);
- Controller->FirstCommandMailbox = CommandMailboxesMemory;
- CommandMailboxesMemory += DAC960_CommandMailboxCount - 1;
- Controller->LastCommandMailbox = CommandMailboxesMemory;
- Controller->NextCommandMailbox =
- &Controller->FirstCommandMailbox[NextCommandMailboxIndex];
- if (--NextCommandMailboxIndex < 0)
- NextCommandMailboxIndex = DAC960_CommandMailboxCount - 1;
- Controller->PreviousCommandMailbox1 =
- &Controller->FirstCommandMailbox[NextCommandMailboxIndex];
- if (--NextCommandMailboxIndex < 0)
- NextCommandMailboxIndex = DAC960_CommandMailboxCount - 1;
- Controller->PreviousCommandMailbox2 =
- &Controller->FirstCommandMailbox[NextCommandMailboxIndex];
- StatusMailboxesMemory =
- (DAC960_StatusMailbox_T *) (CommandMailboxesMemory + 1);
- Controller->FirstStatusMailbox = StatusMailboxesMemory;
- StatusMailboxesMemory += DAC960_StatusMailboxCount - 1;
- Controller->LastStatusMailbox = StatusMailboxesMemory;
- Controller->NextStatusMailbox =
- &Controller->FirstStatusMailbox[NextStatusMailboxIndex];
- if (SavedMemoryMailboxesAddress != NULL) return true;
- /* Enable the Memory Mailbox Interface. */
- CommandMailbox.TypeX.CommandOpcode = 0x2B;
- CommandMailbox.TypeX.CommandIdentifier = 0;
- CommandMailbox.TypeX.CommandOpcode2 = 0x10;
- CommandMailbox.TypeX.CommandMailboxesBusAddress =
- Virtual_to_Bus(Controller->FirstCommandMailbox);
- CommandMailbox.TypeX.StatusMailboxesBusAddress =
- Virtual_to_Bus(Controller->FirstStatusMailbox);
- for (i = 0; i < 2; i++)
- switch (Controller->ControllerType)
- {
- case DAC960_V5_Controller:
- while (--TimeoutCounter >= 0)
- {
- if (DAC960_V5_HardwareMailboxEmptyP(ControllerBaseAddress))
- break;
- udelay(1);
- }
- if (TimeoutCounter < 0) return false;
- DAC960_V5_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox);
- DAC960_V5_HardwareMailboxNewCommand(ControllerBaseAddress);
- while (--TimeoutCounter >= 0)
- {
- if (DAC960_V5_HardwareMailboxStatusAvailableP(
- ControllerBaseAddress))
- break;
- udelay(1);
- }
- if (TimeoutCounter < 0) return false;
- CommandStatus = DAC960_V5_ReadStatusRegister(ControllerBaseAddress);
- DAC960_V5_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress);
- DAC960_V5_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress);
- if (CommandStatus == DAC960_NormalCompletion) return true;
- Controller->DualModeMemoryMailboxInterface = true;
- CommandMailbox.TypeX.CommandOpcode2 = 0x14;
- break;
- case DAC960_V4_Controller:
- while (--TimeoutCounter >= 0)
- {
- if (!DAC960_V4_HardwareMailboxFullP(ControllerBaseAddress))
- break;
- udelay(1);
- }
- if (TimeoutCounter < 0) return false;
- DAC960_V4_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox);
- DAC960_V4_HardwareMailboxNewCommand(ControllerBaseAddress);
- while (--TimeoutCounter >= 0)
- {
- if (DAC960_V4_HardwareMailboxStatusAvailableP(
- ControllerBaseAddress))
- break;
- udelay(1);
- }
- if (TimeoutCounter < 0) return false;
- CommandStatus = DAC960_V4_ReadStatusRegister(ControllerBaseAddress);
- DAC960_V4_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress);
- DAC960_V4_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress);
- if (CommandStatus == DAC960_NormalCompletion) return true;
- Controller->DualModeMemoryMailboxInterface = true;
- CommandMailbox.TypeX.CommandOpcode2 = 0x14;
- break;
- default:
- break;
- }
- return false;
-}
-
-
-/*
- DAC960_DetectControllers detects DAC960 PCI RAID Controllers by interrogating
- the PCI Configuration Space for Controller Type.
-*/
-
-static void DAC960_DetectControllers(DAC960_ControllerType_T ControllerType)
-{
- unsigned short VendorID = 0, DeviceID = 0, Index = 0;
- unsigned char Bus, DeviceFunction, IRQ_Channel;
- unsigned int BaseAddress0, BaseAddress1;
- unsigned int MemoryWindowSize = 0;
- switch (ControllerType)
- {
- case DAC960_V5_Controller:
- VendorID = PCI_VENDOR_ID_DEC;
- DeviceID = PCI_DEVICE_ID_DEC_21285;
- MemoryWindowSize = DAC960_V5_RegisterWindowSize;
- break;
- case DAC960_V4_Controller:
- VendorID = PCI_VENDOR_ID_MYLEX;
- DeviceID = PCI_DEVICE_ID_MYLEX_DAC960P_V4;
- MemoryWindowSize = DAC960_V4_RegisterWindowSize;
- break;
- case DAC960_V3_Controller:
- VendorID = PCI_VENDOR_ID_MYLEX;
- DeviceID = PCI_DEVICE_ID_MYLEX_DAC960P_V3;
- MemoryWindowSize = DAC960_V3_RegisterWindowSize;
- break;
- }
- while (pcibios_find_device(VendorID, DeviceID,
- Index++, &Bus, &DeviceFunction) == 0)
- {
- DAC960_Controller_T *Controller = (DAC960_Controller_T *)
- kmalloc(sizeof(DAC960_Controller_T), GFP_ATOMIC);
- DAC960_IO_Address_T IO_Address = 0;
- DAC960_PCI_Address_T PCI_Address = 0;
- unsigned char Device = DeviceFunction >> 3;
- unsigned char Function = DeviceFunction & 0x7;
- unsigned short SubsystemVendorID, SubsystemDeviceID;
- pcibios_read_config_dword(Bus, DeviceFunction,
- PCI_BASE_ADDRESS_0, &BaseAddress0);
- pcibios_read_config_dword(Bus, DeviceFunction,
- PCI_BASE_ADDRESS_1, &BaseAddress1);
- pcibios_read_config_word(Bus, DeviceFunction,
- PCI_SUBSYSTEM_VENDOR_ID, &SubsystemVendorID);
- pcibios_read_config_word(Bus, DeviceFunction,
- PCI_SUBSYSTEM_ID, &SubsystemDeviceID);
- pcibios_read_config_byte(Bus, DeviceFunction,
- PCI_INTERRUPT_LINE, &IRQ_Channel);
- switch (ControllerType)
- {
- case DAC960_V5_Controller:
- if (!(SubsystemVendorID == PCI_VENDOR_ID_MYLEX &&
- SubsystemDeviceID == PCI_DEVICE_ID_MYLEX_DAC960P_V5))
- goto Ignore;
- PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK;
- break;
- case DAC960_V4_Controller:
- PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK;
- break;
- case DAC960_V3_Controller:
- IO_Address = BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
- PCI_Address = BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK;
- break;
- }
- if (DAC960_ControllerCount == DAC960_MaxControllers)
- {
- DAC960_Error("More than %d DAC960 Controllers detected - "
- "ignoring from Controller at\n",
- NULL, DAC960_MaxControllers);
- goto Ignore;
- }
- if (Controller == NULL)
- {
- DAC960_Error("Unable to allocate Controller structure for "
- "Controller at\n", NULL);
- goto Ignore;
- }
- memset(Controller, 0, sizeof(DAC960_Controller_T));
- Controller->ControllerNumber = DAC960_ControllerCount;
- DAC960_Controllers[DAC960_ControllerCount++] = Controller;
- DAC960_AnnounceDriver(Controller);
- Controller->ControllerType = ControllerType;
- Controller->IO_Address = IO_Address;
- Controller->PCI_Address = PCI_Address;
- Controller->Bus = Bus;
- Controller->Device = Device;
- Controller->Function = Function;
- sprintf(Controller->ControllerName, "c%d", Controller->ControllerNumber);
- /*
- Acquire shared access to the IRQ Channel.
- */
- if (IRQ_Channel == 0 || IRQ_Channel >= NR_IRQS)
- {
- DAC960_Error("IRQ Channel %d illegal for Controller at\n",
- Controller, IRQ_Channel);
- goto Failure;
- }
- strcpy(Controller->FullModelName, "DAC960");
- if (request_irq(IRQ_Channel, DAC960_InterruptHandler,
- SA_INTERRUPT | SA_SHIRQ, Controller->FullModelName,
- Controller) < 0)
- {
- DAC960_Error("Unable to acquire IRQ Channel %d for Controller at\n",
- Controller, IRQ_Channel);
- goto Failure;
- }
- Controller->IRQ_Channel = IRQ_Channel;
- /*
- Map the Controller Register Window.
- */
- if (MemoryWindowSize < PAGE_SIZE)
- MemoryWindowSize = PAGE_SIZE;
- Controller->MemoryMappedAddress =
- ioremap_nocache(PCI_Address & PAGE_MASK, MemoryWindowSize);
- Controller->BaseAddress =
- Controller->MemoryMappedAddress + (PCI_Address & ~PAGE_MASK);
- if (Controller->MemoryMappedAddress == NULL)
- {
- DAC960_Error("Unable to map Controller Register Window for "
- "Controller at\n", Controller);
- goto Failure;
- }
- switch (ControllerType)
- {
- case DAC960_V5_Controller:
- DAC960_V5_DisableInterrupts(Controller->BaseAddress);
- if (!DAC960_EnableMemoryMailboxInterface(Controller))
- {
- DAC960_Error("Unable to Enable Memory Mailbox Interface "
- "for Controller at\n", Controller);
- goto Failure;
- }
- DAC960_V5_EnableInterrupts(Controller->BaseAddress);
- break;
- case DAC960_V4_Controller:
- DAC960_V4_DisableInterrupts(Controller->BaseAddress);
- if (!DAC960_EnableMemoryMailboxInterface(Controller))
- {
- DAC960_Error("Unable to Enable Memory Mailbox Interface "
- "for Controller at\n", Controller);
- goto Failure;
- }
- DAC960_V4_EnableInterrupts(Controller->BaseAddress);
- break;
- case DAC960_V3_Controller:
- request_region(Controller->IO_Address, 0x80,
- Controller->FullModelName);
- DAC960_V3_EnableInterrupts(Controller->BaseAddress);
- break;
- }
- DAC960_ActiveControllerCount++;
- Controller->Commands[0].Controller = Controller;
- Controller->Commands[0].Next = NULL;
- Controller->FreeCommands = &Controller->Commands[0];
- continue;
- Failure:
- if (IO_Address == 0)
- DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A "
- "PCI Address 0x%X\n", Controller,
- Bus, Device, Function, PCI_Address);
- else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address "
- "0x%X PCI Address 0x%X\n", Controller,
- Bus, Device, Function, IO_Address, PCI_Address);
- if (Controller == NULL) break;
- if (Controller->IRQ_Channel > 0)
- free_irq(IRQ_Channel, Controller);
- if (Controller->MemoryMappedAddress != NULL)
- iounmap(Controller->MemoryMappedAddress);
- DAC960_Controllers[Controller->ControllerNumber] = NULL;
- Ignore:
- kfree(Controller);
- }
-}
-
-
-/*
- DAC960_ReadControllerConfiguration reads the Configuration Information
- from Controller and initializes the Controller structure.
-*/
-
-static boolean DAC960_ReadControllerConfiguration(DAC960_Controller_T
- *Controller)
-{
- DAC960_Enquiry2_T Enquiry2;
- DAC960_Config2_T Config2;
- int LogicalDriveNumber, Channel, TargetID;
- if (!DAC960_ExecuteType3(Controller, DAC960_Enquiry,
- &Controller->Enquiry[0]))
- return DAC960_Failure(Controller, "ENQUIRY");
- if (!DAC960_ExecuteType3(Controller, DAC960_Enquiry2, &Enquiry2))
- return DAC960_Failure(Controller, "ENQUIRY2");
- if (!DAC960_ExecuteType3(Controller, DAC960_ReadConfig2, &Config2))
- return DAC960_Failure(Controller, "READ CONFIG2");
- if (!DAC960_ExecuteType3(Controller, DAC960_GetLogicalDriveInformation,
- &Controller->LogicalDriveInformation[0]))
- return DAC960_Failure(Controller, "GET LOGICAL DRIVE INFORMATION");
- for (Channel = 0; Channel < Enquiry2.ActualChannels; Channel++)
- for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++)
- if (!DAC960_ExecuteType3D(Controller, DAC960_GetDeviceState,
- Channel, TargetID,
- &Controller->DeviceState[0][Channel][TargetID]))
- return DAC960_Failure(Controller, "GET DEVICE STATE");
- /*
- Initialize the Controller Model Name and Full Model Name fields.
- */
- switch (Enquiry2.HardwareID.SubModel)
- {
- case DAC960_P_PD_PU:
- if (Enquiry2.SCSICapability.BusSpeed == DAC960_Ultra)
- strcpy(Controller->ModelName, "DAC960PU");
- else strcpy(Controller->ModelName, "DAC960PD");
- break;
- case DAC960_PL:
- strcpy(Controller->ModelName, "DAC960PL");
- break;
- case DAC960_PG:
- strcpy(Controller->ModelName, "DAC960PG");
- break;
- case DAC960_PJ:
- strcpy(Controller->ModelName, "DAC960PJ");
- break;
- case DAC960_PR:
- strcpy(Controller->ModelName, "DAC960PR");
- break;
- case DAC960_PT:
- strcpy(Controller->ModelName, "DAC960PT");
- break;
- case DAC960_PTL0:
- strcpy(Controller->ModelName, "DAC960PTL0");
- break;
- case DAC960_PRL:
- strcpy(Controller->ModelName, "DAC960PRL");
- break;
- case DAC960_PTL1:
- strcpy(Controller->ModelName, "DAC960PTL1");
- break;
- case DAC1164_P:
- strcpy(Controller->ModelName, "DAC1164P");
- break;
- default:
- return DAC960_Failure(Controller, "MODEL VERIFICATION");
- }
- strcpy(Controller->FullModelName, "Mylex ");
- strcat(Controller->FullModelName, Controller->ModelName);
- /*
- Initialize the Controller Firmware Version field and verify that it
- is a supported firmware version. The supported firmware versions are:
-
- DAC1164P 5.06 and above
- DAC960PTL/PJ/PG 4.06 and above
- DAC960PU/PD/PL 3.51 and above
- */
- sprintf(Controller->FirmwareVersion, "%d.%02d-%c-%02d",
- Enquiry2.FirmwareID.MajorVersion, Enquiry2.FirmwareID.MinorVersion,
- Enquiry2.FirmwareID.FirmwareType, Enquiry2.FirmwareID.TurnID);
- if (!((Controller->FirmwareVersion[0] == '5' &&
- strcmp(Controller->FirmwareVersion, "5.06") >= 0) ||
- (Controller->FirmwareVersion[0] == '4' &&
- strcmp(Controller->FirmwareVersion, "4.06") >= 0) ||
- (Controller->FirmwareVersion[0] == '3' &&
- strcmp(Controller->FirmwareVersion, "3.51") >= 0)))
- {
- DAC960_Failure(Controller, "FIRMWARE VERSION VERIFICATION");
- DAC960_Error("Firmware Version = '%s'\n", Controller,
- Controller->FirmwareVersion);
- return false;
- }
- /*
- Initialize the Controller Channels, Memory Size, and SAF-TE Fault
- Management Enabled fields.
- */
- Controller->Channels = Enquiry2.ActualChannels;
- Controller->MemorySize = Enquiry2.MemorySize >> 20;
- Controller->SAFTE_FaultManagementEnabled =
- Enquiry2.FaultManagementType == DAC960_SAFTE;
- /*
- Initialize the Controller Queue Depth, Driver Queue Depth, Logical Drive
- Count, Maximum Blocks per Command, and Maximum Scatter/Gather Segments.
- The Driver Queue Depth must be at most one less than the Controller Queue
- Depth to allow for an automatic drive rebuild operation.
- */
- Controller->ControllerQueueDepth = Controller->Enquiry[0].MaxCommands;
- Controller->DriverQueueDepth = Controller->ControllerQueueDepth - 1;
- Controller->LogicalDriveCount = Controller->Enquiry[0].NumberOfLogicalDrives;
- Controller->MaxBlocksPerCommand = Enquiry2.MaxBlocksPerCommand;
- Controller->MaxScatterGatherSegments = Enquiry2.MaxScatterGatherEntries;
- /*
- Initialize the Stripe Size, Segment Size, and Geometry Translation.
- */
- Controller->StripeSize = Config2.BlocksPerStripe * Config2.BlockFactor
- >> (10 - DAC960_BlockSizeBits);
- Controller->SegmentSize = Config2.BlocksPerCacheLine * Config2.BlockFactor
- >> (10 - DAC960_BlockSizeBits);
- switch (Config2.DriveGeometry)
- {
- case DAC960_Geometry_128_32:
- Controller->GeometryTranslationHeads = 128;
- Controller->GeometryTranslationSectors = 32;
- break;
- case DAC960_Geometry_255_63:
- Controller->GeometryTranslationHeads = 255;
- Controller->GeometryTranslationSectors = 63;
- break;
- default:
- return DAC960_Failure(Controller, "CONFIG2 DRIVE GEOMETRY");
- }
- /*
- Initialize the Logical Drive Initial State.
- */
- for (LogicalDriveNumber = 0;
- LogicalDriveNumber < Controller->LogicalDriveCount;
- LogicalDriveNumber++)
- Controller->LogicalDriveInitialState[LogicalDriveNumber] =
- Controller->LogicalDriveInformation[0]
- [LogicalDriveNumber].LogicalDriveState;
- return true;
-}
-
-
-/*
- DAC960_ReportControllerConfiguration reports the configuration of
- Controller.
-*/
-
-static boolean DAC960_ReportControllerConfiguration(DAC960_Controller_T
- *Controller)
-{
- int LogicalDriveNumber, Channel, TargetID;
- DAC960_Info("Configuring Mylex %s PCI RAID Controller\n",
- Controller, Controller->ModelName);
- DAC960_Info(" Firmware Version: %s, Channels: %d, Memory Size: %dMB\n",
- Controller, Controller->FirmwareVersion,
- Controller->Channels, Controller->MemorySize);
- DAC960_Info(" PCI Bus: %d, Device: %d, Function: %d, I/O Address: ",
- Controller, Controller->Bus,
- Controller->Device, Controller->Function);
- if (Controller->IO_Address == 0)
- DAC960_Info("Unassigned\n", Controller);
- else DAC960_Info("0x%X\n", Controller, Controller->IO_Address);
- DAC960_Info(" PCI Address: 0x%X mapped at 0x%lX, IRQ Channel: %d\n",
- Controller, Controller->PCI_Address,
- (unsigned long) Controller->BaseAddress,
- Controller->IRQ_Channel);
- DAC960_Info(" Controller Queue Depth: %d, "
- "Maximum Blocks per Command: %d\n",
- Controller, Controller->ControllerQueueDepth,
- Controller->MaxBlocksPerCommand);
- DAC960_Info(" Driver Queue Depth: %d, "
- "Maximum Scatter/Gather Segments: %d\n",
- Controller, Controller->DriverQueueDepth,
- Controller->MaxScatterGatherSegments);
- DAC960_Info(" Stripe Size: %dKB, Segment Size: %dKB, "
- "BIOS Geometry: %d/%d\n", Controller,
- Controller->StripeSize,
- Controller->SegmentSize,
- Controller->GeometryTranslationHeads,
- Controller->GeometryTranslationSectors);
- if (Controller->SAFTE_FaultManagementEnabled)
- DAC960_Info(" SAF-TE Fault Management Enabled\n", Controller);
- DAC960_Info(" Physical Devices:\n", Controller);
- for (Channel = 0; Channel < Controller->Channels; Channel++)
- for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++)
- {
- DAC960_DeviceState_T *DeviceState =
- &Controller->DeviceState[Controller->DeviceStateIndex]
- [Channel][TargetID];
- if (!DeviceState->Present) continue;
- switch (DeviceState->DeviceType)
- {
- case DAC960_OtherType:
- DAC960_Info(" %d:%d - Other\n", Controller, Channel, TargetID);
- break;
- case DAC960_DiskType:
- DAC960_Info(" %d:%d - Disk: %s, %d blocks\n", Controller,
- Channel, TargetID,
- (DeviceState->DeviceState == DAC960_Device_Dead
- ? "Dead"
- : DeviceState->DeviceState == DAC960_Device_WriteOnly
- ? "Write-Only"
- : DeviceState->DeviceState == DAC960_Device_Online
- ? "Online" : "Standby"),
- DeviceState->DiskSize);
- break;
- case DAC960_SequentialType:
- DAC960_Info(" %d:%d - Sequential\n", Controller,
- Channel, TargetID);
- break;
- case DAC960_CDROM_or_WORM_Type:
- DAC960_Info(" %d:%d - CD-ROM or WORM\n", Controller,
- Channel, TargetID);
- break;
- }
-
- }
- DAC960_Info(" Logical Drives:\n", Controller);
- for (LogicalDriveNumber = 0;
- LogicalDriveNumber < Controller->LogicalDriveCount;
- LogicalDriveNumber++)
- {
- DAC960_LogicalDriveInformation_T *LogicalDriveInformation =
- &Controller->LogicalDriveInformation
- [Controller->LogicalDriveInformationIndex][LogicalDriveNumber];
- DAC960_Info(" /dev/rd/c%dd%d: RAID-%d, %s, %d blocks, %s\n",
- Controller, Controller->ControllerNumber, LogicalDriveNumber,
- LogicalDriveInformation->RAIDLevel,
- (LogicalDriveInformation->LogicalDriveState ==
- DAC960_LogicalDrive_Online
- ? "Online"
- : LogicalDriveInformation->LogicalDriveState ==
- DAC960_LogicalDrive_Critical
- ? "Critical" : "Offline"),
- LogicalDriveInformation->LogicalDriveSize,
- (LogicalDriveInformation->WriteBack
- ? "Write Back" : "Write Thru"));
- }
- return true;
-}
-
-
-/*
- DAC960_RegisterBlockDevice registers the Block Device structures
- associated with Controller.
-*/
-
-static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
-{
- static void (*RequestFunctions[DAC960_MaxControllers])(void) =
- { DAC960_RequestFunction0, DAC960_RequestFunction1,
- DAC960_RequestFunction2, DAC960_RequestFunction3,
- DAC960_RequestFunction4, DAC960_RequestFunction5,
- DAC960_RequestFunction6, DAC960_RequestFunction7 };
- int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
- GenericDiskInfo_T *GenericDiskInfo;
- int MinorNumber;
- /*
- Register the Block Device Major Number for this DAC960 Controller.
- */
- if (register_blkdev(MajorNumber, "rd", &DAC960_FileOperations) < 0)
- {
- DAC960_Error("UNABLE TO ACQUIRE MAJOR NUMBER %d - DETACHING\n",
- Controller, MajorNumber);
- return false;
- }
- /*
- Initialize the I/O Request Function.
- */
- blk_dev[MajorNumber].request_fn =
- RequestFunctions[Controller->ControllerNumber];
- /*
- Initialize the Disk Partitions array, Partition Sizes array, Block Sizes
- array, Max Sectors per Request array, and Max Segments per Request array.
- */
- for (MinorNumber = 0; MinorNumber < DAC960_MinorCount; MinorNumber++)
- {
- Controller->BlockSizes[MinorNumber] = BLOCK_SIZE;
- Controller->MaxSectorsPerRequest[MinorNumber] =
- Controller->MaxBlocksPerCommand;
- Controller->MaxSegmentsPerRequest[MinorNumber] =
- Controller->MaxScatterGatherSegments;
- }
- Controller->GenericDiskInfo.part = Controller->DiskPartitions;
- Controller->GenericDiskInfo.sizes = Controller->PartitionSizes;
- blksize_size[MajorNumber] = Controller->BlockSizes;
- max_sectors[MajorNumber] = Controller->MaxSectorsPerRequest;
- max_segments[MajorNumber] = Controller->MaxSegmentsPerRequest;
- /*
- Initialize Read Ahead to 128 sectors.
- */
- read_ahead[MajorNumber] = 128;
- /*
- Complete initialization of the Generic Disk Information structure.
- */
- Controller->GenericDiskInfo.major = MajorNumber;
- Controller->GenericDiskInfo.major_name = "rd";
- Controller->GenericDiskInfo.minor_shift = DAC960_MaxPartitionsBits;
- Controller->GenericDiskInfo.max_p = DAC960_MaxPartitions;
- Controller->GenericDiskInfo.max_nr = DAC960_MaxLogicalDrives;
- Controller->GenericDiskInfo.init = DAC960_InitializeGenericDiskInfo;
- Controller->GenericDiskInfo.nr_real = Controller->LogicalDriveCount;
- Controller->GenericDiskInfo.real_devices = Controller;
- Controller->GenericDiskInfo.next = NULL;
- /*
- Install the Generic Disk Information structure at the end of the list.
- */
- if ((GenericDiskInfo = gendisk_head) != NULL)
- {
- while (GenericDiskInfo->next != NULL)
- GenericDiskInfo = GenericDiskInfo->next;
- GenericDiskInfo->next = &Controller->GenericDiskInfo;
- }
- else gendisk_head = &Controller->GenericDiskInfo;
- /*
- Indicate the Block Device Registration completed successfully,
- */
- return true;
-}
-
-
-/*
- DAC960_UnregisterBlockDevice unregisters the Block Device structures
- associated with Controller.
-*/
-
-static void DAC960_UnregisterBlockDevice(DAC960_Controller_T *Controller)
-{
- int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
- /*
- Unregister the Block Device Major Number for this DAC960 Controller.
- */
- unregister_blkdev(MajorNumber, "rd");
- /*
- Remove the I/O Request Function.
- */
- blk_dev[MajorNumber].request_fn = NULL;
- /*
- Remove the Disk Partitions array, Partition Sizes array, Block Sizes
- array, Max Sectors per Request array, and Max Segments per Request array.
- */
- Controller->GenericDiskInfo.part = NULL;
- Controller->GenericDiskInfo.sizes = NULL;
- blk_size[MajorNumber] = NULL;
- blksize_size[MajorNumber] = NULL;
- max_sectors[MajorNumber] = NULL;
- max_segments[MajorNumber] = NULL;
- /*
- Remove the Generic Disk Information structure from the list.
- */
- if (gendisk_head != &Controller->GenericDiskInfo)
- {
- GenericDiskInfo_T *GenericDiskInfo = gendisk_head;
- while (GenericDiskInfo != NULL &&
- GenericDiskInfo->next != &Controller->GenericDiskInfo)
- GenericDiskInfo = GenericDiskInfo->next;
- if (GenericDiskInfo != NULL)
- GenericDiskInfo->next = GenericDiskInfo->next->next;
- }
- else gendisk_head = Controller->GenericDiskInfo.next;
-}
-
-
-/*
- DAC960_InitializeController initializes Controller.
-*/
-
-static void DAC960_InitializeController(DAC960_Controller_T *Controller)
-{
- if (DAC960_ReadControllerConfiguration(Controller) &&
- DAC960_ReportControllerConfiguration(Controller) &&
- DAC960_RegisterBlockDevice(Controller))
- {
- /*
- Initialize the Command structures.
- */
- DAC960_Command_T *Commands = Controller->Commands;
- int CommandIdentifier;
- Controller->FreeCommands = NULL;
- for (CommandIdentifier = 0;
- CommandIdentifier < Controller->DriverQueueDepth;
- CommandIdentifier++)
- {
- Commands[CommandIdentifier].Controller = Controller;
- Commands[CommandIdentifier].Next = Controller->FreeCommands;
- Controller->FreeCommands = &Commands[CommandIdentifier];
- }
- /*
- Initialize the Monitoring Timer.
- */
- init_timer(&Controller->MonitoringTimer);
- Controller->MonitoringTimer.expires =
- jiffies + DAC960_MonitoringTimerInterval;
- Controller->MonitoringTimer.data = (unsigned long) Controller;
- Controller->MonitoringTimer.function = DAC960_MonitoringTimerFunction;
- add_timer(&Controller->MonitoringTimer);
- Controller->ControllerInitialized = true;
- }
- else DAC960_FinalizeController(Controller);
-}
-
-
-/*
- DAC960_FinalizeController finalizes Controller.
-*/
-
-static void DAC960_FinalizeController(DAC960_Controller_T *Controller)
-{
- if (Controller->ControllerInitialized)
- {
- del_timer(&Controller->MonitoringTimer);
- DAC960_Notice("Flushing Cache...", Controller);
- DAC960_ExecuteType3(Controller, DAC960_Flush, NULL);
- DAC960_Notice("done\n", Controller);
- switch (Controller->ControllerType)
- {
- case DAC960_V5_Controller:
- if (!Controller->DualModeMemoryMailboxInterface)
- DAC960_V5_SaveMemoryMailboxInfo(Controller);
- break;
- case DAC960_V4_Controller:
- if (!Controller->DualModeMemoryMailboxInterface)
- DAC960_V4_SaveMemoryMailboxInfo(Controller);
- break;
- case DAC960_V3_Controller:
- break;
- }
- }
- free_irq(Controller->IRQ_Channel, Controller);
- iounmap(Controller->MemoryMappedAddress);
- if (Controller->IO_Address > 0)
- release_region(Controller->IO_Address, 0x80);
- DAC960_UnregisterBlockDevice(Controller);
- DAC960_Controllers[Controller->ControllerNumber] = NULL;
- kfree(Controller);
-}
-
-
-/*
- DAC960_Initialize initializes the DAC960 Driver.
-*/
-
-void DAC960_Initialize(void)
-{
- int ControllerNumber;
- DAC960_DetectControllers(DAC960_V5_Controller);
- DAC960_DetectControllers(DAC960_V4_Controller);
- DAC960_DetectControllers(DAC960_V3_Controller);
- if (DAC960_ActiveControllerCount == 0) return;
- for (ControllerNumber = 0;
- ControllerNumber < DAC960_ControllerCount;
- ControllerNumber++)
- if (DAC960_Controllers[ControllerNumber] != NULL)
- DAC960_InitializeController(DAC960_Controllers[ControllerNumber]);
- DAC960_CreateProcEntries();
-}
-
-
-/*
- DAC960_Finalize finalizes the DAC960 Driver.
-*/
-
-void DAC960_Finalize(void)
-{
- int ControllerNumber;
- if (DAC960_ActiveControllerCount == 0) return;
- for (ControllerNumber = 0;
- ControllerNumber < DAC960_ControllerCount;
- ControllerNumber++)
- if (DAC960_Controllers[ControllerNumber] != NULL)
- DAC960_FinalizeController(DAC960_Controllers[ControllerNumber]);
- DAC960_DestroyProcEntries();
-}
-
-
-/*
- DAC960_ProcessRequest attempts to remove one I/O Request from Controller's
- I/O Request Queue and queues it to the Controller. WaitForCommand is true if
- this function should wait for a Command to become available if necessary.
- This function returns true if an I/O Request was queued and false otherwise.
-*/
-
-static boolean DAC960_ProcessRequest(DAC960_Controller_T *Controller,
- boolean WaitForCommand)
-{
- IO_Request_T **RequestQueuePointer =
- &blk_dev[DAC960_MAJOR + Controller->ControllerNumber].current_request;
- IO_Request_T *Request;
- DAC960_Command_T *Command;
- char *RequestBuffer;
- while (true)
- {
- Request = *RequestQueuePointer;
- if (Request == NULL || Request->rq_status == RQ_INACTIVE) return false;
- Command = DAC960_AllocateCommand(Controller);
- if (Command != NULL) break;
- if (!WaitForCommand) return false;
- sleep_on(&Controller->CommandWaitQueue);
- }
- DAC960_ClearCommand(Command);
- if (Request->cmd == READ)
- Command->CommandType = DAC960_ReadCommand;
- else Command->CommandType = DAC960_WriteCommand;
- Command->Semaphore = Request->sem;
- Command->LogicalDriveNumber = DAC960_LogicalDriveNumber(Request->rq_dev);
- Command->BlockNumber =
- Request->sector
- + Controller->GenericDiskInfo.part[MINOR(Request->rq_dev)].start_sect;
- Command->BlockCount = Request->nr_sectors;
- Command->SegmentCount = Request->nr_segments;
- Command->BufferHeader = Request->bh;
- RequestBuffer = Request->buffer;
- Request->rq_status = RQ_INACTIVE;
- *RequestQueuePointer = Request->next;
- wake_up(&wait_for_request);
- if (Command->SegmentCount == 1)
- {
- DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
- if (Command->CommandType == DAC960_ReadCommand)
- CommandMailbox->Type5.CommandOpcode = DAC960_Read;
- else CommandMailbox->Type5.CommandOpcode = DAC960_Write;
- CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
- CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber;
- CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
- CommandMailbox->Type5.BusAddress = Virtual_to_Bus(RequestBuffer);
- }
- else
- {
- DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
- DAC960_ScatterGatherSegment_T
- *ScatterGatherList = Command->ScatterGatherList;
- BufferHeader_T *BufferHeader = Command->BufferHeader;
- char *LastDataEndPointer = NULL;
- int SegmentNumber = 0;
- if (Command->CommandType == DAC960_ReadCommand)
- CommandMailbox->Type5.CommandOpcode = DAC960_ReadWithOldScatterGather;
- else
- CommandMailbox->Type5.CommandOpcode = DAC960_WriteWithOldScatterGather;
- CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
- CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber;
- CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
- CommandMailbox->Type5.BusAddress = Virtual_to_Bus(ScatterGatherList);
- CommandMailbox->Type5.ScatterGatherCount = Command->SegmentCount;
- while (BufferHeader != NULL)
- {
- if (BufferHeader->b_data == LastDataEndPointer)
- {
- ScatterGatherList[SegmentNumber-1].SegmentByteCount +=
- BufferHeader->b_size;
- LastDataEndPointer += BufferHeader->b_size;
- }
- else
- {
- ScatterGatherList[SegmentNumber].SegmentDataPointer =
- Virtual_to_Bus(BufferHeader->b_data);
- ScatterGatherList[SegmentNumber].SegmentByteCount =
- BufferHeader->b_size;
- LastDataEndPointer = BufferHeader->b_data + BufferHeader->b_size;
- if (SegmentNumber++ > Controller->MaxScatterGatherSegments)
- panic("DAC960: Scatter/Gather Segment Overflow\n");
- }
- BufferHeader = BufferHeader->b_reqnext;
- }
- if (SegmentNumber != Command->SegmentCount)
- panic("DAC960: SegmentNumber != SegmentCount\n");
- }
- DAC960_QueueCommand(Command);
- return true;
-}
-
-
-/*
- DAC960_ProcessRequests attempts to remove as many I/O Requests as possible
- from Controller's I/O Request Queue and queue them to the Controller.
-*/
-
-static inline void DAC960_ProcessRequests(DAC960_Controller_T *Controller)
-{
- int Counter = 0;
- while (DAC960_ProcessRequest(Controller, Counter++ == 0)) ;
-}
-
-
-/*
- DAC960_RequestFunction0 is the I/O Request Function for DAC960 Controller 0.
-*/
-
-static void DAC960_RequestFunction0(void)
-{
- DAC960_Controller_T *Controller = DAC960_Controllers[0];
- ProcessorFlags_T ProcessorFlags;
- /*
- Acquire exclusive access to Controller.
- */
- DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
- /*
- Process I/O Requests for Controller.
- */
- DAC960_ProcessRequests(Controller);
- /*
- Release exclusive access to Controller.
- */
- DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
-}
-
-
-/*
- DAC960_RequestFunction1 is the I/O Request Function for DAC960 Controller 1.
-*/
-
-static void DAC960_RequestFunction1(void)
-{
- DAC960_Controller_T *Controller = DAC960_Controllers[1];
- ProcessorFlags_T ProcessorFlags;
- /*
- Acquire exclusive access to Controller.
- */
- DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
- /*
- Process I/O Requests for Controller.
- */
- DAC960_ProcessRequests(Controller);
- /*
- Release exclusive access to Controller.
- */
- DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
-}
-
-
-/*
- DAC960_RequestFunction2 is the I/O Request Function for DAC960 Controller 2.
-*/
-
-static void DAC960_RequestFunction2(void)
-{
- DAC960_Controller_T *Controller = DAC960_Controllers[2];
- ProcessorFlags_T ProcessorFlags;
- /*
- Acquire exclusive access to Controller.
- */
- DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
- /*
- Process I/O Requests for Controller.
- */
- DAC960_ProcessRequests(Controller);
- /*
- Release exclusive access to Controller.
- */
- DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
-}
-
-
-/*
- DAC960_RequestFunction3 is the I/O Request Function for DAC960 Controller 3.
-*/
-
-static void DAC960_RequestFunction3(void)
-{
- DAC960_Controller_T *Controller = DAC960_Controllers[3];
- ProcessorFlags_T ProcessorFlags;
- /*
- Acquire exclusive access to Controller.
- */
- DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
- /*
- Process I/O Requests for Controller.
- */
- DAC960_ProcessRequests(Controller);
- /*
- Release exclusive access to Controller.
- */
- DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
-}
-
-
-/*
- DAC960_RequestFunction4 is the I/O Request Function for DAC960 Controller 4.
-*/
-
-static void DAC960_RequestFunction4(void)
-{
- DAC960_Controller_T *Controller = DAC960_Controllers[4];
- ProcessorFlags_T ProcessorFlags;
- /*
- Acquire exclusive access to Controller.
- */
- DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
- /*
- Process I/O Requests for Controller.
- */
- DAC960_ProcessRequests(Controller);
- /*
- Release exclusive access to Controller.
- */
- DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
-}
-
-
-/*
- DAC960_RequestFunction5 is the I/O Request Function for DAC960 Controller 5.
-*/
-
-static void DAC960_RequestFunction5(void)
-{
- DAC960_Controller_T *Controller = DAC960_Controllers[5];
- ProcessorFlags_T ProcessorFlags;
- /*
- Acquire exclusive access to Controller.
- */
- DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
- /*
- Process I/O Requests for Controller.
- */
- DAC960_ProcessRequests(Controller);
- /*
- Release exclusive access to Controller.
- */
- DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
-}
-
-
-/*
- DAC960_RequestFunction6 is the I/O Request Function for DAC960 Controller 6.
-*/
-
-static void DAC960_RequestFunction6(void)
-{
- DAC960_Controller_T *Controller = DAC960_Controllers[6];
- ProcessorFlags_T ProcessorFlags;
- /*
- Acquire exclusive access to Controller.
- */
- DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
- /*
- Process I/O Requests for Controller.
- */
- DAC960_ProcessRequests(Controller);
- /*
- Release exclusive access to Controller.
- */
- DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
-}
-
-
-/*
- DAC960_RequestFunction7 is the I/O Request Function for DAC960 Controller 7.
-*/
-
-static void DAC960_RequestFunction7(void)
-{
- DAC960_Controller_T *Controller = DAC960_Controllers[7];
- ProcessorFlags_T ProcessorFlags;
- /*
- Acquire exclusive access to Controller.
- */
- DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
- /*
- Process I/O Requests for Controller.
- */
- DAC960_ProcessRequests(Controller);
- /*
- Release exclusive access to Controller.
- */
- DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
-}
-
-
-/*
- DAC960_ReadWriteError prints an appropriate error message for Command when
- an error occurs on a Read or Write operation.
-*/
-
-static void DAC960_ReadWriteError(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- char *CommandName = "UNKNOWN";
- switch (Command->CommandType)
- {
- case DAC960_ReadCommand:
- case DAC960_ReadRetryCommand:
- CommandName = "READ";
- break;
- case DAC960_WriteCommand:
- case DAC960_WriteRetryCommand:
- CommandName = "WRITE";
- break;
- case DAC960_MonitoringCommand:
- case DAC960_ImmediateCommand:
- break;
- }
- switch (Command->CommandStatus)
- {
- case DAC960_IrrecoverableDataError:
- DAC960_Error("Irrecoverable Data Error on %s:\n",
- Controller, CommandName);
- break;
- case DAC960_LogicalDriveNonexistentOrOffline:
- DAC960_Error("Logical Drive Nonexistent or Offline on %s:\n",
- Controller, CommandName);
- break;
- case DAC960_AccessBeyondEndOfLogicalDrive:
- DAC960_Error("Attempt to Access Beyond End of Logical Drive "
- "on %s:\n", Controller, CommandName);
- break;
- case DAC960_BadDataEncountered:
- DAC960_Error("Bad Data Encountered on %s:\n", Controller, CommandName);
- break;
- default:
- DAC960_Error("Unexpected Error Status %04X on %s:\n",
- Controller, Command->CommandStatus, CommandName);
- break;
- }
- DAC960_Error(" /dev/rd/c%dd%d: absolute blocks %d..%d\n",
- Controller, Controller->ControllerNumber,
- Command->LogicalDriveNumber, Command->BlockNumber,
- Command->BlockNumber + Command->BlockCount - 1);
- if (DAC960_PartitionNumber(Command->BufferHeader->b_rdev) > 0)
- DAC960_Error(" /dev/rd/c%dd%dp%d: relative blocks %d..%d\n",
- Controller, Controller->ControllerNumber,
- Command->LogicalDriveNumber,
- DAC960_PartitionNumber(Command->BufferHeader->b_rdev),
- Command->BufferHeader->b_rsector,
- Command->BufferHeader->b_rsector + Command->BlockCount - 1);
-}
-
-
-/*
- DAC960_ProcessCompletedBuffer performs completion processing for an
- individual Buffer.
-*/
-
-static inline void DAC960_ProcessCompletedBuffer(BufferHeader_T *BufferHeader,
- boolean SuccessfulIO)
-{
- mark_buffer_uptodate(BufferHeader, SuccessfulIO);
- unlock_buffer(BufferHeader);
-}
-
-
-/*
- DAC960_ProcessCompletedCommand performs completion processing for Command.
-*/
-
-static void DAC960_ProcessCompletedCommand(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- DAC960_CommandType_T CommandType = Command->CommandType;
- DAC960_CommandStatus_T CommandStatus = Command->CommandStatus;
- BufferHeader_T *BufferHeader = Command->BufferHeader;
- if (CommandType == DAC960_ReadCommand ||
- CommandType == DAC960_WriteCommand)
- {
- if (CommandStatus == DAC960_NormalCompletion)
- {
- /*
- Perform completion processing for all buffers in this I/O Request.
- */
- while (BufferHeader != NULL)
- {
- BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext;
- BufferHeader->b_reqnext = NULL;
- DAC960_ProcessCompletedBuffer(BufferHeader, true);
- BufferHeader = NextBufferHeader;
- }
- /*
- Wake up requestor for swap file paging requests.
- */
- if (Command->Semaphore != NULL)
- {
- up(Command->Semaphore);
- Command->Semaphore = NULL;
- }
- add_blkdev_randomness(DAC960_MAJOR + Controller->ControllerNumber);
- }
- else if ((CommandStatus == DAC960_IrrecoverableDataError ||
- CommandStatus == DAC960_BadDataEncountered) &&
- BufferHeader != NULL &&
- BufferHeader->b_reqnext != NULL)
- {
- DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
- if (CommandType == DAC960_ReadCommand)
- {
- Command->CommandType = DAC960_ReadRetryCommand;
- CommandMailbox->Type5.CommandOpcode = DAC960_Read;
- }
- else
- {
- Command->CommandType = DAC960_WriteRetryCommand;
- CommandMailbox->Type5.CommandOpcode = DAC960_Write;
- }
- Command->BlockCount = BufferHeader->b_size >> DAC960_BlockSizeBits;
- CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
- CommandMailbox->Type5.BusAddress =
- Virtual_to_Bus(BufferHeader->b_data);
- DAC960_QueueCommand(Command);
- return;
- }
- else
- {
- if (CommandStatus != DAC960_LogicalDriveNonexistentOrOffline)
- DAC960_ReadWriteError(Command);
- /*
- Perform completion processing for all buffers in this I/O Request.
- */
- while (BufferHeader != NULL)
- {
- BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext;
- BufferHeader->b_reqnext = NULL;
- DAC960_ProcessCompletedBuffer(BufferHeader, false);
- BufferHeader = NextBufferHeader;
- }
- /*
- Wake up requestor for swap file paging requests.
- */
- if (Command->Semaphore != NULL)
- {
- up(Command->Semaphore);
- Command->Semaphore = NULL;
- }
- }
- }
- else if (CommandType == DAC960_ReadRetryCommand ||
- CommandType == DAC960_WriteRetryCommand)
- {
- BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext;
- BufferHeader->b_reqnext = NULL;
- /*
- Perform completion processing for this single buffer.
- */
- if (CommandStatus == DAC960_NormalCompletion)
- DAC960_ProcessCompletedBuffer(BufferHeader, true);
- else
- {
- if (CommandStatus != DAC960_LogicalDriveNonexistentOrOffline)
- DAC960_ReadWriteError(Command);
- DAC960_ProcessCompletedBuffer(BufferHeader, false);
- }
- if (NextBufferHeader != NULL)
- {
- DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
- Command->BlockNumber +=
- BufferHeader->b_size >> DAC960_BlockSizeBits;
- Command->BlockCount =
- NextBufferHeader->b_size >> DAC960_BlockSizeBits;
- Command->BufferHeader = NextBufferHeader;
- CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
- CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
- CommandMailbox->Type5.BusAddress =
- Virtual_to_Bus(NextBufferHeader->b_data);
- DAC960_QueueCommand(Command);
- return;
- }
- }
- else if (CommandType == DAC960_MonitoringCommand)
- {
- DAC960_CommandOpcode_T CommandOpcode =
- Command->CommandMailbox.Common.CommandOpcode;
- unsigned int OldCriticalLogicalDriveCount = 0;
- unsigned int NewCriticalLogicalDriveCount = 0;
- if (CommandOpcode == DAC960_Enquiry)
- {
- DAC960_Enquiry_T *OldEnquiry =
- &Controller->Enquiry[Controller->EnquiryIndex];
- DAC960_Enquiry_T *NewEnquiry =
- &Controller->Enquiry[Controller->EnquiryIndex ^= 1];
- OldCriticalLogicalDriveCount = OldEnquiry->CriticalLogicalDriveCount;
- NewCriticalLogicalDriveCount = NewEnquiry->CriticalLogicalDriveCount;
- if (NewEnquiry->StatusFlags.DeferredWriteError !=
- OldEnquiry->StatusFlags.DeferredWriteError)
- DAC960_Critical("Deferred Write Error Flag is now %s\n", Controller,
- (NewEnquiry->StatusFlags.DeferredWriteError
- ? "TRUE" : "FALSE"));
- if ((NewCriticalLogicalDriveCount > 0 ||
- NewCriticalLogicalDriveCount != OldCriticalLogicalDriveCount) ||
- (NewEnquiry->OfflineLogicalDriveCount > 0 ||
- NewEnquiry->OfflineLogicalDriveCount !=
- OldEnquiry->OfflineLogicalDriveCount) ||
- (NewEnquiry->DeadDriveCount > 0 ||
- NewEnquiry->DeadDriveCount !=
- OldEnquiry->DeadDriveCount) ||
- (NewEnquiry->EventLogSequenceNumber !=
- OldEnquiry->EventLogSequenceNumber) ||
- Controller->MonitoringTimerCount == 0 ||
- (jiffies - Controller->SecondaryMonitoringTime
- >= DAC960_SecondaryMonitoringInterval))
- {
- Controller->NeedLogicalDriveInformation = true;
- Controller->NewEventLogSequenceNumber =
- NewEnquiry->EventLogSequenceNumber;
- Controller->NeedErrorTableInformation = true;
- Controller->NeedDeviceStateInformation = true;
- Controller->DeviceStateChannel = 0;
- Controller->DeviceStateTargetID = 0;
- Controller->SecondaryMonitoringTime = jiffies;
- }
- if (NewEnquiry->RebuildFlag == DAC960_StandbyRebuildInProgress ||
- NewEnquiry->RebuildFlag == DAC960_BackgroundRebuildInProgress ||
- OldEnquiry->RebuildFlag == DAC960_StandbyRebuildInProgress ||
- OldEnquiry->RebuildFlag == DAC960_BackgroundRebuildInProgress)
- Controller->NeedRebuildProgress = true;
- if (OldEnquiry->RebuildFlag == DAC960_BackgroundCheckInProgress)
- switch (NewEnquiry->RebuildFlag)
- {
- case DAC960_NoStandbyRebuildOrCheckInProgress:
- DAC960_Progress("Consistency Check Completed Successfully\n",
- Controller);
- break;
- case DAC960_StandbyRebuildInProgress:
- case DAC960_BackgroundRebuildInProgress:
- break;
- case DAC960_BackgroundCheckInProgress:
- Controller->NeedConsistencyCheckProgress = true;
- break;
- case DAC960_StandbyRebuildCompletedWithError:
- DAC960_Progress("Consistency Check Completed with Error\n",
- Controller);
- break;
- case DAC960_BackgroundRebuildOrCheckFailed_DriveFailed:
- DAC960_Progress("Consistency Check Failed - "
- "Physical Drive Failed\n", Controller);
- break;
- case DAC960_BackgroundRebuildOrCheckFailed_LogicalDriveFailed:
- DAC960_Progress("Consistency Check Failed - "
- "Logical Drive Failed\n", Controller);
- break;
- case DAC960_BackgroundRebuildOrCheckFailed_OtherCauses:
- DAC960_Progress("Consistency Check Failed - Other Causes\n",
- Controller);
- break;
- case DAC960_BackgroundRebuildOrCheckSuccessfullyTerminated:
- DAC960_Progress("Consistency Check Successfully Terminated\n",
- Controller);
- break;
- }
- else if (NewEnquiry->RebuildFlag == DAC960_BackgroundCheckInProgress)
- Controller->NeedConsistencyCheckProgress = true;
- }
- else if (CommandOpcode == DAC960_GetLogicalDriveInformation)
- {
- int LogicalDriveNumber;
- for (LogicalDriveNumber = 0;
- LogicalDriveNumber < Controller->LogicalDriveCount;
- LogicalDriveNumber++)
- {
- DAC960_LogicalDriveInformation_T *OldLogicalDriveInformation =
- &Controller->LogicalDriveInformation
- [Controller->LogicalDriveInformationIndex]
- [LogicalDriveNumber];
- DAC960_LogicalDriveInformation_T *NewLogicalDriveInformation =
- &Controller->LogicalDriveInformation
- [Controller->LogicalDriveInformationIndex ^ 1]
- [LogicalDriveNumber];
- if (NewLogicalDriveInformation->LogicalDriveState !=
- OldLogicalDriveInformation->LogicalDriveState)
- DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
- "is now %s\n", Controller,
- LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber,
- (NewLogicalDriveInformation->LogicalDriveState
- == DAC960_LogicalDrive_Online
- ? "ONLINE"
- : NewLogicalDriveInformation->LogicalDriveState
- == DAC960_LogicalDrive_Critical
- ? "CRITICAL" : "OFFLINE"));
- if (NewLogicalDriveInformation->WriteBack !=
- OldLogicalDriveInformation->WriteBack)
- DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
- "is now %s\n", Controller,
- LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber,
- (NewLogicalDriveInformation->WriteBack
- ? "WRITE BACK" : "WRITE THRU"));
- }
- Controller->LogicalDriveInformationIndex ^= 1;
- }
- else if (CommandOpcode == DAC960_PerformEventLogOperation)
- {
- DAC960_EventLogEntry_T *EventLogEntry = &Controller->EventLogEntry;
- if (EventLogEntry->SequenceNumber ==
- Controller->OldEventLogSequenceNumber)
- {
- unsigned char SenseKey = EventLogEntry->SenseKey;
- unsigned char AdditionalSenseCode =
- EventLogEntry->AdditionalSenseCode;
- unsigned char AdditionalSenseCodeQualifier =
- EventLogEntry->AdditionalSenseCodeQualifier;
- if (SenseKey == 9 &&
- AdditionalSenseCode == 0x80 &&
- AdditionalSenseCodeQualifier < DAC960_EventMessagesCount)
- DAC960_Critical("Physical Drive %d:%d %s\n", Controller,
- EventLogEntry->Channel,
- EventLogEntry->TargetID,
- DAC960_EventMessages[
- AdditionalSenseCodeQualifier]);
- else if (!((SenseKey == 2 &&
- AdditionalSenseCode == 0x04 &&
- (AdditionalSenseCodeQualifier == 0x01 ||
- AdditionalSenseCodeQualifier == 0x02)) ||
- (SenseKey == 6 && AdditionalSenseCode == 0x29 &&
- Controller->MonitoringTimerCount == 0)))
- DAC960_Critical("Physical Drive %d:%d Error Log: "
- "Sense Key = %d, ASC = %02X, ASCQ = %02X\n",
- Controller,
- EventLogEntry->Channel,
- EventLogEntry->TargetID,
- SenseKey,
- AdditionalSenseCode,
- AdditionalSenseCodeQualifier);
- }
- Controller->OldEventLogSequenceNumber++;
- }
- else if (CommandOpcode == DAC960_GetErrorTable)
- {
- DAC960_ErrorTable_T *OldErrorTable =
- &Controller->ErrorTable[Controller->ErrorTableIndex];
- DAC960_ErrorTable_T *NewErrorTable =
- &Controller->ErrorTable[Controller->ErrorTableIndex ^= 1];
- int Channel, TargetID;
- for (Channel = 0; Channel < Controller->Channels; Channel++)
- for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++)
- {
- DAC960_ErrorTableEntry_T *NewErrorEntry =
- &NewErrorTable->ErrorTableEntries[Channel][TargetID];
- DAC960_ErrorTableEntry_T *OldErrorEntry =
- &OldErrorTable->ErrorTableEntries[Channel][TargetID];
- if ((NewErrorEntry->ParityErrorCount !=
- OldErrorEntry->ParityErrorCount) ||
- (NewErrorEntry->SoftErrorCount !=
- OldErrorEntry->SoftErrorCount) ||
- (NewErrorEntry->HardErrorCount !=
- OldErrorEntry->HardErrorCount) ||
- (NewErrorEntry->MiscErrorCount !=
- OldErrorEntry->MiscErrorCount))
- DAC960_Critical("Physical Drive %d:%d Errors: "
- "Parity = %d, Soft = %d, "
- "Hard = %d, Misc = %d\n",
- Controller, Channel, TargetID,
- NewErrorEntry->ParityErrorCount,
- NewErrorEntry->SoftErrorCount,
- NewErrorEntry->HardErrorCount,
- NewErrorEntry->MiscErrorCount);
- }
- }
- else if (CommandOpcode == DAC960_GetDeviceState)
- {
- DAC960_DeviceState_T *OldDeviceState =
- &Controller->DeviceState[Controller->DeviceStateIndex]
- [Controller->DeviceStateChannel]
- [Controller->DeviceStateTargetID];
- DAC960_DeviceState_T *NewDeviceState =
- &Controller->DeviceState[Controller->DeviceStateIndex ^ 1]
- [Controller->DeviceStateChannel]
- [Controller->DeviceStateTargetID];
- if (NewDeviceState->DeviceState != OldDeviceState->DeviceState)
- DAC960_Critical("Physical Drive %d:%d is now %s\n", Controller,
- Controller->DeviceStateChannel,
- Controller->DeviceStateTargetID,
- (NewDeviceState->DeviceState == DAC960_Device_Dead
- ? "DEAD"
- : NewDeviceState->DeviceState
- == DAC960_Device_WriteOnly
- ? "WRITE-ONLY"
- : NewDeviceState->DeviceState
- == DAC960_Device_Online
- ? "ONLINE" : "STANDBY"));
- if (++Controller->DeviceStateTargetID == DAC960_MaxTargets)
- {
- Controller->DeviceStateChannel++;
- Controller->DeviceStateTargetID = 0;
- }
- }
- else if (CommandOpcode == DAC960_GetRebuildProgress)
- {
- unsigned int LogicalDriveNumber =
- Controller->RebuildProgress.LogicalDriveNumber;
- unsigned int LogicalDriveSize =
- Controller->RebuildProgress.LogicalDriveSize;
- unsigned int BlocksCompleted =
- LogicalDriveSize - Controller->RebuildProgress.RemainingBlocks;
- switch (CommandStatus)
- {
- case DAC960_NormalCompletion:
- Controller->EphemeralProgressMessage = true;
- DAC960_Progress("Rebuild in Progress: "
- "Logical Drive %d (/dev/rd/c%dd%d) "
- "%d%% completed\n",
- Controller, LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber,
- (100 * (BlocksCompleted >> 7))
- / (LogicalDriveSize >> 7));
- Controller->EphemeralProgressMessage = false;
- break;
- case DAC960_RebuildFailed_LogicalDriveFailure:
- DAC960_Progress("Rebuild Failed due to "
- "Logical Drive Failure\n", Controller);
- break;
- case DAC960_RebuildFailed_BadBlocksOnOther:
- DAC960_Progress("Rebuild Failed due to "
- "Bad Blocks on Other Drives\n", Controller);
- break;
- case DAC960_RebuildFailed_NewDriveFailed:
- DAC960_Progress("Rebuild Failed due to "
- "Failure of Drive Being Rebuilt\n", Controller);
- break;
- case DAC960_RebuildSuccessful:
- case DAC960_NoRebuildOrCheckInProgress:
- DAC960_Progress("Rebuild Completed Successfully\n", Controller);
- break;
- }
- }
- else if (CommandOpcode == DAC960_RebuildStat)
- {
- unsigned int LogicalDriveNumber =
- Controller->RebuildProgress.LogicalDriveNumber;
- unsigned int LogicalDriveSize =
- Controller->RebuildProgress.LogicalDriveSize;
- unsigned int BlocksCompleted =
- LogicalDriveSize - Controller->RebuildProgress.RemainingBlocks;
- if (CommandStatus == DAC960_NormalCompletion)
- {
- Controller->EphemeralProgressMessage = true;
- DAC960_Progress("Consistency Check in Progress: "
- "Logical Drive %d (/dev/rd/c%dd%d) "
- "%d%% completed\n",
- Controller, LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber,
- (100 * (BlocksCompleted >> 7))
- / (LogicalDriveSize >> 7));
- Controller->EphemeralProgressMessage = false;
- }
- }
- if (Controller->NeedLogicalDriveInformation &&
- NewCriticalLogicalDriveCount >= OldCriticalLogicalDriveCount)
- {
- Controller->NeedLogicalDriveInformation = false;
- Command->CommandMailbox.Type3.CommandOpcode =
- DAC960_GetLogicalDriveInformation;
- Command->CommandMailbox.Type3.BusAddress =
- Virtual_to_Bus(
- &Controller->LogicalDriveInformation
- [Controller->LogicalDriveInformationIndex ^ 1]);
- DAC960_QueueCommand(Command);
- return;
- }
- if (Controller->NewEventLogSequenceNumber
- - Controller->OldEventLogSequenceNumber > 0)
- {
- Command->CommandMailbox.Type3E.CommandOpcode =
- DAC960_PerformEventLogOperation;
- Command->CommandMailbox.Type3E.OperationType =
- DAC960_GetEventLogEntry;
- Command->CommandMailbox.Type3E.OperationQualifier = 1;
- Command->CommandMailbox.Type3E.SequenceNumber =
- Controller->OldEventLogSequenceNumber;
- Command->CommandMailbox.Type3E.BusAddress =
- Virtual_to_Bus(&Controller->EventLogEntry);
- DAC960_QueueCommand(Command);
- return;
- }
- if (Controller->NeedErrorTableInformation)
- {
- Controller->NeedErrorTableInformation = false;
- Command->CommandMailbox.Type3.CommandOpcode = DAC960_GetErrorTable;
- Command->CommandMailbox.Type3.BusAddress =
- Virtual_to_Bus(
- &Controller->ErrorTable[Controller->ErrorTableIndex ^ 1]);
- DAC960_QueueCommand(Command);
- return;
- }
- if (Controller->NeedDeviceStateInformation)
- {
- while (Controller->DeviceStateChannel < Controller->Channels)
- {
- DAC960_DeviceState_T *OldDeviceState =
- &Controller->DeviceState[Controller->DeviceStateIndex]
- [Controller->DeviceStateChannel]
- [Controller->DeviceStateTargetID];
- if (OldDeviceState->Present &&
- OldDeviceState->DeviceType == DAC960_DiskType)
- {
- Command->CommandMailbox.Type3D.CommandOpcode =
- DAC960_GetDeviceState;
- Command->CommandMailbox.Type3D.Channel =
- Controller->DeviceStateChannel;
- Command->CommandMailbox.Type3D.TargetID =
- Controller->DeviceStateTargetID;
- Command->CommandMailbox.Type3D.BusAddress =
- Virtual_to_Bus(&Controller->DeviceState
- [Controller->DeviceStateIndex ^ 1]
- [Controller->DeviceStateChannel]
- [Controller->DeviceStateTargetID]);
- DAC960_QueueCommand(Command);
- return;
- }
- if (++Controller->DeviceStateTargetID == DAC960_MaxTargets)
- {
- Controller->DeviceStateChannel++;
- Controller->DeviceStateTargetID = 0;
- }
- }
- Controller->NeedDeviceStateInformation = false;
- Controller->DeviceStateIndex ^= 1;
- }
- if (Controller->NeedRebuildProgress)
- {
- Controller->NeedRebuildProgress = false;
- Command->CommandMailbox.Type3.CommandOpcode =
- DAC960_GetRebuildProgress;
- Command->CommandMailbox.Type3.BusAddress =
- Virtual_to_Bus(&Controller->RebuildProgress);
- DAC960_QueueCommand(Command);
- return;
- }
- if (Controller->NeedConsistencyCheckProgress)
- {
- Controller->NeedConsistencyCheckProgress = false;
- Command->CommandMailbox.Type3.CommandOpcode = DAC960_RebuildStat;
- Command->CommandMailbox.Type3.BusAddress =
- Virtual_to_Bus(&Controller->RebuildProgress);
- DAC960_QueueCommand(Command);
- return;
- }
- if (Controller->NeedLogicalDriveInformation &&
- NewCriticalLogicalDriveCount < OldCriticalLogicalDriveCount)
- {
- Controller->NeedLogicalDriveInformation = false;
- Command->CommandMailbox.Type3.CommandOpcode =
- DAC960_GetLogicalDriveInformation;
- Command->CommandMailbox.Type3.BusAddress =
- Virtual_to_Bus(
- &Controller->LogicalDriveInformation
- [Controller->LogicalDriveInformationIndex ^ 1]);
- DAC960_QueueCommand(Command);
- return;
- }
- Controller->MonitoringTimerCount++;
- Controller->MonitoringTimer.expires =
- jiffies + DAC960_MonitoringTimerInterval;
- add_timer(&Controller->MonitoringTimer);
- }
- else if (CommandType == DAC960_ImmediateCommand)
- {
- up(Command->Semaphore);
- Command->Semaphore = NULL;
- return;
- }
- else panic("DAC960: Unknown Command Type %d\n", CommandType);
- /*
- Queue a Status Monitoring Command to the Controller using the just
- completed Command if one was deferred previously due to lack of a
- free Command when the Monitoring Timer Function was called.
- */
- if (Controller->MonitoringCommandDeferred)
- {
- Controller->MonitoringCommandDeferred = false;
- DAC960_QueueMonitoringCommand(Command);
- return;
- }
- /*
- Execute a User Command using the just completed Command if one was
- deferred previously due to lack of a free Command.
- */
- if (Controller->UserCommandDeferred)
- {
- Controller->UserCommandDeferred = false;
- Controller->UserCommand = Command;
- up(Controller->UserCommandSemaphore);
- return;
- }
- /*
- Deallocate the Command, and wake up any processes waiting on a free Command.
- */
- DAC960_DeallocateCommand(Command);
- wake_up(&Controller->CommandWaitQueue);
-}
-
-
-/*
- DAC960_InterruptHandler handles hardware interrupts from DAC960 Controllers.
-*/
-
-static void DAC960_InterruptHandler(int IRQ_Channel,
- void *DeviceIdentifier,
- Registers_T *InterruptRegisters)
-{
- DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
- void *ControllerBaseAddress = Controller->BaseAddress;
- DAC960_StatusMailbox_T *NextStatusMailbox;
- ProcessorFlags_T ProcessorFlags;
- /*
- Acquire exclusive access to Controller.
- */
- DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags);
- /*
- Process Hardware Interrupts for Controller.
- */
- switch (Controller->ControllerType)
- {
- case DAC960_V5_Controller:
- DAC960_V5_AcknowledgeInterrupt(ControllerBaseAddress);
- NextStatusMailbox = Controller->NextStatusMailbox;
- while (NextStatusMailbox->Fields.Valid)
- {
- DAC960_CommandIdentifier_T CommandIdentifier =
- NextStatusMailbox->Fields.CommandIdentifier;
- DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier];
- Command->CommandStatus = NextStatusMailbox->Fields.CommandStatus;
- NextStatusMailbox->Word = 0;
- if (++NextStatusMailbox > Controller->LastStatusMailbox)
- NextStatusMailbox = Controller->FirstStatusMailbox;
- DAC960_ProcessCompletedCommand(Command);
- }
- Controller->NextStatusMailbox = NextStatusMailbox;
- break;
- case DAC960_V4_Controller:
- DAC960_V4_AcknowledgeInterrupt(ControllerBaseAddress);
- NextStatusMailbox = Controller->NextStatusMailbox;
- while (NextStatusMailbox->Fields.Valid)
- {
- DAC960_CommandIdentifier_T CommandIdentifier =
- NextStatusMailbox->Fields.CommandIdentifier;
- DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier];
- Command->CommandStatus = NextStatusMailbox->Fields.CommandStatus;
- NextStatusMailbox->Word = 0;
- if (++NextStatusMailbox > Controller->LastStatusMailbox)
- NextStatusMailbox = Controller->FirstStatusMailbox;
- DAC960_ProcessCompletedCommand(Command);
- }
- Controller->NextStatusMailbox = NextStatusMailbox;
- break;
- case DAC960_V3_Controller:
- while (DAC960_V3_StatusAvailableP(ControllerBaseAddress))
- {
- DAC960_CommandIdentifier_T CommandIdentifier =
- DAC960_V3_ReadStatusCommandIdentifier(ControllerBaseAddress);
- DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier];
- Command->CommandStatus =
- DAC960_V3_ReadStatusRegister(ControllerBaseAddress);
- DAC960_V3_AcknowledgeInterrupt(ControllerBaseAddress);
- DAC960_V3_AcknowledgeStatus(ControllerBaseAddress);
- DAC960_ProcessCompletedCommand(Command);
- }
- break;
- }
- /*
- Attempt to remove additional I/O Requests from the Controller's
- I/O Request Queue and queue them to the Controller.
- */
- while (DAC960_ProcessRequest(Controller, false)) ;
- /*
- Release exclusive access to Controller.
- */
- DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags);
-}
-
-
-/*
- DAC960_QueueMonitoringCommand queues a Monitoring Command to Controller.
-*/
-
-static void DAC960_QueueMonitoringCommand(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
- DAC960_ClearCommand(Command);
- Command->CommandType = DAC960_MonitoringCommand;
- CommandMailbox->Type3.CommandOpcode = DAC960_Enquiry;
- CommandMailbox->Type3.BusAddress =
- Virtual_to_Bus(&Controller->Enquiry[Controller->EnquiryIndex ^ 1]);
- DAC960_QueueCommand(Command);
-}
-
-
-/*
- DAC960_MonitoringTimerFunction is the timer function for monitoring
- the status of DAC960 Controllers.
-*/
-
-static void DAC960_MonitoringTimerFunction(unsigned long TimerData)
-{
- DAC960_Controller_T *Controller = (DAC960_Controller_T *) TimerData;
- DAC960_Command_T *Command;
- ProcessorFlags_T ProcessorFlags;
- /*
- Acquire exclusive access to Controller.
- */
- DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
- /*
- Queue a Status Monitoring Command to Controller.
- */
- Command = DAC960_AllocateCommand(Controller);
- if (Command != NULL)
- DAC960_QueueMonitoringCommand(Command);
- else Controller->MonitoringCommandDeferred = true;
- /*
- Release exclusive access to Controller.
- */
- DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
-}
-
-
-/*
- DAC960_Open is the Device Open Function for the DAC960 Driver.
-*/
-
-static int DAC960_Open(Inode_T *Inode, File_T *File)
-{
- int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev);
- int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev);
- DAC960_Controller_T *Controller;
- if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1)
- return -ENXIO;
- Controller = DAC960_Controllers[ControllerNumber];
- if (Controller == NULL ||
- LogicalDriveNumber > Controller->LogicalDriveCount - 1)
- return -ENXIO;
- if (Controller->LogicalDriveInformation
- [Controller->LogicalDriveInformationIndex]
- [LogicalDriveNumber].LogicalDriveState
- == DAC960_LogicalDrive_Offline)
- return -ENXIO;
- if (Controller->LogicalDriveInitialState[LogicalDriveNumber]
- == DAC960_LogicalDrive_Offline)
- {
- Controller->LogicalDriveInitialState[LogicalDriveNumber] =
- DAC960_LogicalDrive_Online;
- DAC960_InitializeGenericDiskInfo(&Controller->GenericDiskInfo);
- resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber);
- }
- if (Controller->GenericDiskInfo.sizes[MINOR(Inode->i_rdev)] == 0)
- return -ENXIO;
- /*
- Increment Controller and Logical Drive Usage Counts.
- */
- Controller->ControllerUsageCount++;
- Controller->LogicalDriveUsageCount[LogicalDriveNumber]++;
- return 0;
-}
-
-
-/*
- DAC960_Release is the Device Release Function for the DAC960 Driver.
-*/
-
-static void DAC960_Release(Inode_T *Inode, File_T *File)
-{
- int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev);
- int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev);
- DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
- /*
- Force any buffered data to be written.
- */
- fsync_dev(Inode->i_rdev);
- /*
- Decrement the Logical Drive and Controller Usage Counts.
- */
- Controller->LogicalDriveUsageCount[LogicalDriveNumber]--;
- Controller->ControllerUsageCount--;
-}
-
-
-/*
- DAC960_Ioctl is the Device Ioctl Function for the DAC960 Driver.
-*/
-
-static int DAC960_Ioctl(Inode_T *Inode, File_T *File,
- unsigned int Request, unsigned long Argument)
-{
- int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev);
- int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev);
- int PartitionNumber, ErrorCode;
- unsigned short Cylinders;
- DiskGeometry_T *Geometry;
- DAC960_Controller_T *Controller;
- if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1)
- return -ENXIO;
- Controller = DAC960_Controllers[ControllerNumber];
- if (Controller == NULL ||
- LogicalDriveNumber > Controller->LogicalDriveCount - 1)
- return -ENXIO;
- switch (Request)
- {
- case HDIO_GETGEO:
- /* Get BIOS Disk Geometry. */
- Geometry = (DiskGeometry_T *) Argument;
- if (Geometry == NULL) return -EINVAL;
- ErrorCode = verify_area(VERIFY_WRITE, Geometry, sizeof(DiskGeometry_T));
- if (ErrorCode != 0) return ErrorCode;
- Cylinders =
- Controller->LogicalDriveInformation
- [Controller->LogicalDriveInformationIndex]
- [LogicalDriveNumber].LogicalDriveSize
- / (Controller->GeometryTranslationHeads *
- Controller->GeometryTranslationSectors);
- put_user(Controller->GeometryTranslationHeads, &Geometry->heads);
- put_user(Controller->GeometryTranslationSectors, &Geometry->sectors);
- put_user(Cylinders, &Geometry->cylinders);
- put_user(Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)]
- .start_sect, &Geometry->start);
- return 0;
- case BLKGETSIZE:
- /* Get Device Size. */
- if ((long *) Argument == NULL) return -EINVAL;
- ErrorCode = verify_area(VERIFY_WRITE, (long *) Argument, sizeof(long));
- if (ErrorCode != 0) return ErrorCode;
- put_user(Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)].nr_sects,
- (long *) Argument);
- return 0;
- case BLKRAGET:
- /* Get Read-Ahead. */
- if ((int *) Argument == NULL) return -EINVAL;
- ErrorCode = verify_area(VERIFY_WRITE, (int *) Argument, sizeof(int));
- if (ErrorCode != 0) return ErrorCode;
- put_user(read_ahead[MAJOR(Inode->i_rdev)], (int *) Argument);
- return 0;
- case BLKRASET:
- /* Set Read-Ahead. */
- if (!suser()) return -EACCES;
- if (Argument > 256) return -EINVAL;
- read_ahead[MAJOR(Inode->i_rdev)] = Argument;
- return 0;
- case BLKFLSBUF:
- /* Flush Buffers. */
- if (!suser()) return -EACCES;
- fsync_dev(Inode->i_rdev);
- invalidate_buffers(Inode->i_rdev);
- return 0;
- case BLKRRPART:
- /* Re-Read Partition Table. */
- if (!suser()) return -EACCES;
- if (Controller->LogicalDriveUsageCount[LogicalDriveNumber] > 1)
- return -EBUSY;
- for (PartitionNumber = 0;
- PartitionNumber < DAC960_MaxPartitions;
- PartitionNumber++)
- {
- KernelDevice_T Device = DAC960_KernelDevice(ControllerNumber,
- LogicalDriveNumber,
- PartitionNumber);
- int MinorNumber = DAC960_MinorNumber(LogicalDriveNumber,
- PartitionNumber);
- if (Controller->GenericDiskInfo.part[MinorNumber].nr_sects == 0)
- continue;
- /*
- Flush all changes and invalidate buffered state.
- */
- sync_dev(Device);
- invalidate_inodes(Device);
- invalidate_buffers(Device);
- /*
- Clear existing partition sizes.
- */
- if (PartitionNumber > 0)
- {
- Controller->GenericDiskInfo.part[MinorNumber].start_sect = 0;
- Controller->GenericDiskInfo.part[MinorNumber].nr_sects = 0;
- }
- /*
- Reset the Block Size so that the partition table can be read.
- */
- set_blocksize(Device, BLOCK_SIZE);
- }
- resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber);
- return 0;
- }
- return -EINVAL;
-}
-
-
-/*
- DAC960_GenericDiskInit is the Generic Disk Information Initialization
- Function for the DAC960 Driver.
-*/
-
-static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *GenericDiskInfo)
-{
- DAC960_Controller_T *Controller =
- (DAC960_Controller_T *) GenericDiskInfo->real_devices;
- DAC960_LogicalDriveInformation_T *LogicalDriveInformation =
- Controller->LogicalDriveInformation
- [Controller->LogicalDriveInformationIndex];
- int LogicalDriveNumber;
- for (LogicalDriveNumber = 0;
- LogicalDriveNumber < Controller->LogicalDriveCount;
- LogicalDriveNumber++)
- GenericDiskInfo->part[DAC960_MinorNumber(LogicalDriveNumber, 0)].nr_sects =
- LogicalDriveInformation[LogicalDriveNumber].LogicalDriveSize;
-}
-
-
-/*
- DAC960_Message prints Driver Messages.
-*/
-
-static void DAC960_Message(DAC960_MessageLevel_T MessageLevel,
- char *Format,
- DAC960_Controller_T *Controller,
- ...)
-{
- static char Buffer[DAC960_LineBufferSize];
- static boolean BeginningOfLine = true;
- va_list Arguments;
- int Length = 0;
- va_start(Arguments, Controller);
- Length = vsprintf(Buffer, Format, Arguments);
- va_end(Arguments);
- if (Controller == NULL)
- printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
- DAC960_ControllerCount, Buffer);
- else if (MessageLevel == DAC960_AnnounceLevel ||
- MessageLevel == DAC960_InfoLevel)
- {
- if (!Controller->ControllerInitialized)
- {
- strcpy(&Controller->InitialStatusBuffer[
- Controller->InitialStatusLength], Buffer);
- Controller->InitialStatusLength += Length;
- if (MessageLevel == DAC960_AnnounceLevel)
- {
- static int AnnouncementLines = 0;
- if (++AnnouncementLines <= 2)
- printk("%sDAC960: %s", DAC960_MessageLevelMap[MessageLevel],
- Buffer);
- }
- else
- {
- if (BeginningOfLine)
- {
- if (Buffer[0] != '\n' || Length > 1)
- printk("%sDAC960#%d: %s",
- DAC960_MessageLevelMap[MessageLevel],
- Controller->ControllerNumber, Buffer);
- }
- else printk("%s", Buffer);
- }
- }
- else
- {
- strcpy(&Controller->CurrentStatusBuffer[
- Controller->CurrentStatusLength], Buffer);
- Controller->CurrentStatusLength += Length;
- }
- }
- else if (MessageLevel == DAC960_ProgressLevel)
- {
- strcpy(Controller->RebuildProgressBuffer, Buffer);
- Controller->RebuildProgressLength = Length;
- if (Controller->EphemeralProgressMessage)
- {
- if (jiffies - Controller->LastProgressReportTime
- >= DAC960_ProgressReportingInterval)
- {
- printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
- Controller->ControllerNumber, Buffer);
- Controller->LastProgressReportTime = jiffies;
- }
- }
- else printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
- Controller->ControllerNumber, Buffer);
- }
- else if (MessageLevel == DAC960_UserCriticalLevel)
- {
- strcpy(&Controller->UserStatusBuffer[Controller->UserStatusLength],
- Buffer);
- Controller->UserStatusLength += Length;
- if (Buffer[0] != '\n' || Length > 1)
- printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
- Controller->ControllerNumber, Buffer);
- }
- else
- {
- if (BeginningOfLine)
- printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
- Controller->ControllerNumber, Buffer);
- else printk("%s", Buffer);
- }
- BeginningOfLine = (Buffer[Length-1] == '\n');
-}
-
-
-/*
- DAC960_AllocateUserCommand allocates a Command structure for a User Command.
- If a User Command is already active, NULL is returned.
-*/
-
-static DAC960_Command_T *DAC960_AllocateUserCommand(DAC960_Controller_T
- *Controller)
-{
- Semaphore_T Semaphore = MUTEX_LOCKED;
- DAC960_Command_T *Command = NULL;
- ProcessorFlags_T ProcessorFlags;
- /*
- Acquire exclusive access to Controller.
- */
- DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
- /*
- Acquire exclusive access to the User Command facility.
- */
- if (Controller->UserCommandActive) goto Done;
- Controller->UserCommandActive = true;
- /*
- Allocate a Command. If none is available, set the User Command Deferred
- flag to tell the Interrupt Handler to save the next Command completed.
- */
- Command = DAC960_AllocateCommand(Controller);
- if (Command == NULL)
- {
- Controller->UserCommandDeferred = true;
- Controller->UserCommandSemaphore = &Semaphore;
- DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
- down(&Semaphore);
- DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
- Command = Controller->UserCommand;
- Controller->UserCommand = NULL;
- }
- /*
- Initialize the Command.
- */
- DAC960_ClearCommand(Command);
- Command->CommandType = DAC960_ImmediateCommand;
- /*
- Release exclusive access to Controller.
- */
- Done:
- DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
- return Command;
-}
-
-
-/*
- DAC960_DeallocateUserCommand deallocates a User Command.
-*/
-
-static void DAC960_DeallocateUserCommand(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- ProcessorFlags_T ProcessorFlags;
- /*
- Acquire exclusive access to Controller.
- */
- DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
- /*
- Deallocate the Command.
- */
- DAC960_DeallocateCommand(Command);
- /*
- Release exclusive access to the User Command facility.
- */
- Controller->UserCommandActive = false;
- /*
- Release exclusive access to Controller.
- */
- DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
-}
-
-
-/*
- DAC960_ParsePhysicalDrive parses spaces followed by a Physical Drive
- Channel:TargetID specification from a User Command string. It updates
- Channel and TargetID and returns true on success and returns false otherwise.
-*/
-
-static boolean DAC960_ParsePhysicalDrive(DAC960_Controller_T *Controller,
- char *UserCommandString,
- unsigned char *Channel,
- unsigned char *TargetID)
-{
- char *NewUserCommandString = UserCommandString;
- unsigned long XChannel, XTargetID;
- while (*UserCommandString == ' ') UserCommandString++;
- if (UserCommandString == NewUserCommandString)
- return false;
- XChannel = simple_strtoul(UserCommandString, &NewUserCommandString, 10);
- if (NewUserCommandString == UserCommandString ||
- *NewUserCommandString != ':' ||
- XChannel >= Controller->Channels)
- return false;
- UserCommandString = ++NewUserCommandString;
- XTargetID = simple_strtoul(UserCommandString, &NewUserCommandString, 10);
- if (NewUserCommandString == UserCommandString ||
- *NewUserCommandString != '\0' ||
- XTargetID >= DAC960_MaxTargets)
- return false;
- *Channel = XChannel;
- *TargetID = XTargetID;
- return true;
-}
-
-
-/*
- DAC960_ParseLogicalDrive parses spaces followed by a Logical Drive Number
- specification from a User Command string. It updates LogicalDriveNumber and
- returns true on success and returns false otherwise.
-*/
-
-static boolean DAC960_ParseLogicalDrive(DAC960_Controller_T *Controller,
- char *UserCommandString,
- unsigned char *LogicalDriveNumber)
-{
- char *NewUserCommandString = UserCommandString;
- unsigned long XLogicalDriveNumber;
- while (*UserCommandString == ' ') UserCommandString++;
- if (UserCommandString == NewUserCommandString)
- return false;
- XLogicalDriveNumber =
- simple_strtoul(UserCommandString, &NewUserCommandString, 10);
- if (NewUserCommandString == UserCommandString ||
- *NewUserCommandString != '\0' ||
- XLogicalDriveNumber >= Controller->LogicalDriveCount)
- return false;
- *LogicalDriveNumber = XLogicalDriveNumber;
- return true;
-}
-
-
-/*
- DAC960_SetDeviceState sets the Device State for a Physical Drive.
-*/
-
-static void DAC960_SetDeviceState(DAC960_Controller_T *Controller,
- DAC960_Command_T *Command,
- unsigned char Channel,
- unsigned char TargetID,
- DAC960_PhysicalDeviceState_T DeviceState,
- const char *DeviceStateString)
-{
- DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
- CommandMailbox->Type3D.CommandOpcode = DAC960_StartDevice;
- CommandMailbox->Type3D.Channel = Channel;
- CommandMailbox->Type3D.TargetID = TargetID;
- CommandMailbox->Type3D.DeviceState = DeviceState;
- CommandMailbox->Type3D.Modifier = 0;
- DAC960_ExecuteCommand(Command);
- switch (Command->CommandStatus)
- {
- case DAC960_NormalCompletion:
- DAC960_UserCritical("%s of Physical Drive %d:%d Succeeded\n", Controller,
- DeviceStateString, Channel, TargetID);
- break;
- case DAC960_UnableToStartDevice:
- DAC960_UserCritical("%s of Physical Drive %d:%d Failed - "
- "Unable to Start Device\n", Controller,
- DeviceStateString, Channel, TargetID);
- break;
- case DAC960_NoDeviceAtAddress:
- DAC960_UserCritical("%s of Physical Drive %d:%d Failed - "
- "No Device at Address\n", Controller,
- DeviceStateString, Channel, TargetID);
- break;
- case DAC960_InvalidChannelOrTargetOrModifier:
- DAC960_UserCritical("%s of Physical Drive %d:%d Failed - "
- "Invalid Channel or Target or Modifier\n",
- Controller, DeviceStateString, Channel, TargetID);
- break;
- case DAC960_ChannelBusy:
- DAC960_UserCritical("%s of Physical Drive %d:%d Failed - "
- "Channel Busy\n", Controller,
- DeviceStateString, Channel, TargetID);
- break;
- default:
- DAC960_UserCritical("%s of Physical Drive %d:%d Failed - "
- "Unexpected Status %04X\n", Controller,
- DeviceStateString, Channel, TargetID,
- Command->CommandStatus);
- break;
- }
-}
-
-
-/*
- DAC960_ExecuteUserCommand executes a User Command.
-*/
-
-static boolean DAC960_ExecuteUserCommand(DAC960_Controller_T *Controller,
- char *UserCommand)
-{
- DAC960_Command_T *Command;
- DAC960_CommandMailbox_T *CommandMailbox;
- unsigned char Channel, TargetID, LogicalDriveNumber;
- Command = DAC960_AllocateUserCommand(Controller);
- if (Command == NULL) return false;
- CommandMailbox = &Command->CommandMailbox;
- Controller->UserStatusLength = 0;
- if (strcmp(UserCommand, "flush-cache") == 0)
- {
- CommandMailbox->Type3.CommandOpcode = DAC960_Flush;
- DAC960_ExecuteCommand(Command);
- DAC960_UserCritical("Cache Flush Completed\n", Controller);
- }
- else if (strncmp(UserCommand, "kill", 4) == 0 &&
- DAC960_ParsePhysicalDrive(Controller, &UserCommand[4],
- &Channel, &TargetID))
- {
- DAC960_DeviceState_T *DeviceState =
- &Controller->DeviceState[Controller->DeviceStateIndex]
- [Channel][TargetID];
- if (DeviceState->Present &&
- DeviceState->DeviceType == DAC960_DiskType &&
- DeviceState->DeviceState != DAC960_Device_Dead)
- DAC960_SetDeviceState(Controller, Command, Channel, TargetID,
- DAC960_Device_Dead, "Kill");
- else DAC960_UserCritical("Kill of Physical Drive %d:%d Illegal\n",
- Controller, Channel, TargetID);
- }
- else if (strncmp(UserCommand, "make-online", 11) == 0 &&
- DAC960_ParsePhysicalDrive(Controller, &UserCommand[11],
- &Channel, &TargetID))
- {
- DAC960_DeviceState_T *DeviceState =
- &Controller->DeviceState[Controller->DeviceStateIndex]
- [Channel][TargetID];
- if (DeviceState->Present &&
- DeviceState->DeviceType == DAC960_DiskType &&
- DeviceState->DeviceState == DAC960_Device_Dead)
- DAC960_SetDeviceState(Controller, Command, Channel, TargetID,
- DAC960_Device_Online, "Make Online");
- else DAC960_UserCritical("Make Online of Physical Drive %d:%d Illegal\n",
- Controller, Channel, TargetID);
-
- }
- else if (strncmp(UserCommand, "make-standby", 12) == 0 &&
- DAC960_ParsePhysicalDrive(Controller, &UserCommand[12],
- &Channel, &TargetID))
- {
- DAC960_DeviceState_T *DeviceState =
- &Controller->DeviceState[Controller->DeviceStateIndex]
- [Channel][TargetID];
- if (DeviceState->Present &&
- DeviceState->DeviceType == DAC960_DiskType &&
- DeviceState->DeviceState == DAC960_Device_Dead)
- DAC960_SetDeviceState(Controller, Command, Channel, TargetID,
- DAC960_Device_Standby, "Make Standby");
- else DAC960_UserCritical("Make Standby of Physical Drive %d:%d Illegal\n",
- Controller, Channel, TargetID);
- }
- else if (strncmp(UserCommand, "rebuild", 7) == 0 &&
- DAC960_ParsePhysicalDrive(Controller, &UserCommand[7],
- &Channel, &TargetID))
- {
- CommandMailbox->Type3D.CommandOpcode = DAC960_RebuildAsync;
- CommandMailbox->Type3D.Channel = Channel;
- CommandMailbox->Type3D.TargetID = TargetID;
- DAC960_ExecuteCommand(Command);
- switch (Command->CommandStatus)
- {
- case DAC960_NormalCompletion:
- DAC960_UserCritical("Rebuild of Physical Drive %d:%d Initiated\n",
- Controller, Channel, TargetID);
- break;
- case DAC960_AttemptToRebuildOnlineDrive:
- DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - "
- "Attempt to Rebuild Online or "
- "Unresponsive Drive\n",
- Controller, Channel, TargetID);
- break;
- case DAC960_NewDiskFailedDuringRebuild:
- DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - "
- "New Disk Failed During Rebuild\n",
- Controller, Channel, TargetID);
- break;
- case DAC960_InvalidDeviceAddress:
- DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - "
- "Invalid Device Address\n",
- Controller, Channel, TargetID);
- break;
- case DAC960_RebuildOrCheckAlreadyInProgress:
- DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - "
- "Rebuild or Consistency Check Already "
- "in Progress\n", Controller, Channel, TargetID);
- break;
- default:
- DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - "
- "Unexpected Status %04X\n", Controller,
- Channel, TargetID, Command->CommandStatus);
- break;
- }
- }
- else if (strncmp(UserCommand, "check-consistency", 17) == 0 &&
- DAC960_ParseLogicalDrive(Controller, &UserCommand[17],
- &LogicalDriveNumber))
- {
- CommandMailbox->Type3C.CommandOpcode = DAC960_CheckConsistencyAsync;
- CommandMailbox->Type3C.LogicalDriveNumber = LogicalDriveNumber;
- CommandMailbox->Type3C.AutoRestore = true;
- DAC960_ExecuteCommand(Command);
- switch (Command->CommandStatus)
- {
- case DAC960_NormalCompletion:
- DAC960_UserCritical("Consistency Check of Logical Drive %d "
- "(/dev/rd/c%dd%d) Initiated\n",
- Controller, LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber);
- break;
- case DAC960_DependentDiskIsDead:
- DAC960_UserCritical("Consistency Check of Logical Drive %d "
- "(/dev/rd/c%dd%d) Failed - "
- "Dependent Physical Drive is DEAD\n",
- Controller, LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber);
- break;
- case DAC960_InvalidOrNonredundantLogicalDrive:
- DAC960_UserCritical("Consistency Check of Logical Drive %d "
- "(/dev/rd/c%dd%d) Failed - "
- "Invalid or Nonredundant Logical Drive\n",
- Controller, LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber);
- break;
- case DAC960_RebuildOrCheckAlreadyInProgress:
- DAC960_UserCritical("Consistency Check of Logical Drive %d "
- "(/dev/rd/c%dd%d) Failed - Rebuild or "
- "Consistency Check Already in Progress\n",
- Controller, LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber);
- break;
- default:
- DAC960_UserCritical("Consistency Check of Logical Drive %d "
- "(/dev/rd/c%dd%d) Failed - "
- "Unexpected Status %04X\n",
- Controller, LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber, Command->CommandStatus);
- break;
- }
- }
- else if (strcmp(UserCommand, "cancel-rebuild") == 0 ||
- strcmp(UserCommand, "cancel-consistency-check") == 0)
- {
- unsigned char OldRebuildRateConstant;
- CommandMailbox->Type3R.CommandOpcode = DAC960_RebuildControl;
- CommandMailbox->Type3R.RebuildRateConstant = 0xFF;
- CommandMailbox->Type3R.BusAddress =
- Virtual_to_Bus(&OldRebuildRateConstant);
- DAC960_ExecuteCommand(Command);
- switch (Command->CommandStatus)
- {
- case DAC960_NormalCompletion:
- DAC960_UserCritical("Rebuild or Consistency Check Cancelled\n",
- Controller);
- break;
- default:
- DAC960_UserCritical("Cancellation of Rebuild or "
- "Consistency Check Failed - "
- "Unexpected Status %04X\n",
- Controller, Command->CommandStatus);
- break;
- }
- }
- else DAC960_UserCritical("Illegal User Command: '%s'\n",
- Controller, UserCommand);
- DAC960_DeallocateUserCommand(Command);
- return true;
-}
-
-
-/*
- DAC960_ProcReadStatus implements reading /proc/rd/status.
-*/
-
-static int DAC960_ProcReadStatus(Inode_T *Inode, File_T *File,
- char *Buffer, int Count)
-{
- char *StatusMessage = "OK\n";
- int StatusMessageOffset, BytesAvailable;
- int ControllerNumber;
- for (ControllerNumber = 0;
- ControllerNumber < DAC960_ControllerCount;
- ControllerNumber++)
- {
- DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
- DAC960_Enquiry_T *Enquiry;
- if (Controller == NULL) continue;
- Enquiry = &Controller->Enquiry[Controller->EnquiryIndex];
- if (Enquiry->CriticalLogicalDriveCount > 0 ||
- Enquiry->OfflineLogicalDriveCount > 0 ||
- Enquiry->DeadDriveCount > 0)
- {
- StatusMessage = "ALERT\n";
- break;
- }
- }
- StatusMessageOffset = File->f_pos;
- BytesAvailable = strlen(StatusMessage) - StatusMessageOffset;
- if (Count > BytesAvailable) Count = BytesAvailable;
- if (Count <= 0) return 0;
- memcpy_tofs(Buffer, &StatusMessage[StatusMessageOffset], Count);
- File->f_pos += Count;
- return Count;
-}
-
-
-/*
- DAC960_ProcReadInitialStatus implements reading /proc/rd/cN/initial_status.
-*/
-
-static int DAC960_ProcReadInitialStatus(Inode_T *Inode, File_T *File,
- char *Buffer, int Count)
-{
- DAC960_Controller_T *Controller = NULL;
- int InitialStatusOffset, BytesAvailable;
- int ControllerNumber;
- for (ControllerNumber = 0;
- ControllerNumber < DAC960_ControllerCount;
- ControllerNumber++)
- {
- Controller = DAC960_Controllers[ControllerNumber];
- if (Controller == NULL) continue;
- if (Controller->InitialStatusProcEntry.low_ino == Inode->i_ino) break;
- }
- InitialStatusOffset = File->f_pos;
- BytesAvailable = Controller->InitialStatusLength - InitialStatusOffset;
- if (Count > BytesAvailable) Count = BytesAvailable;
- if (Count <= 0) return 0;
- memcpy_tofs(Buffer,
- &Controller->InitialStatusBuffer[InitialStatusOffset], Count);
- File->f_pos += Count;
- return Count;
-}
-
-
-/*
- DAC960_ProcReadCurrentStatus implements reading /proc/rd/cN/current_status.
-*/
-
-static int DAC960_ProcReadCurrentStatus(Inode_T *Inode, File_T *File,
- char *Buffer, int Count)
-{
- DAC960_Controller_T *Controller = NULL;
- int CurrentStatusOffset, BytesAvailable;
- int ControllerNumber;
- for (ControllerNumber = 0;
- ControllerNumber < DAC960_ControllerCount;
- ControllerNumber++)
- {
- Controller = DAC960_Controllers[ControllerNumber];
- if (Controller == NULL) continue;
- if (Controller->CurrentStatusProcEntry.low_ino == Inode->i_ino) break;
- }
- Controller->CurrentStatusLength = 0;
- DAC960_AnnounceDriver(Controller);
- DAC960_ReportControllerConfiguration(Controller);
- Controller->CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' ';
- Controller->CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' ';
- if (Controller->RebuildProgressLength > 0)
- {
- strcpy(&Controller->CurrentStatusBuffer[Controller->CurrentStatusLength],
- Controller->RebuildProgressBuffer);
- Controller->CurrentStatusLength += Controller->RebuildProgressLength;
- }
- else
- {
- char *StatusMessage = "No Rebuild or Consistency Check in Progress\n";
- strcpy(&Controller->CurrentStatusBuffer[Controller->CurrentStatusLength],
- StatusMessage);
- Controller->CurrentStatusLength += strlen(StatusMessage);
- }
- CurrentStatusOffset = File->f_pos;
- BytesAvailable = Controller->CurrentStatusLength - CurrentStatusOffset;
- if (Count > BytesAvailable) Count = BytesAvailable;
- if (Count <= 0) return 0;
- memcpy_tofs(Buffer,
- &Controller->CurrentStatusBuffer[CurrentStatusOffset], Count);
- File->f_pos += Count;
- return Count;
-}
-
-
-/*
- DAC960_ProcReadUserCommand implements reading /proc/rd/cN/user_command.
-*/
-
-static int DAC960_ProcReadUserCommand(Inode_T *Inode, File_T *File,
- char *Buffer, int Count)
-{
- DAC960_Controller_T *Controller = NULL;
- int UserStatusOffset, BytesAvailable;
- int ControllerNumber;
- for (ControllerNumber = 0;
- ControllerNumber < DAC960_ControllerCount;
- ControllerNumber++)
- {
- Controller = DAC960_Controllers[ControllerNumber];
- if (Controller == NULL) continue;
- if (Controller->UserCommandProcEntry.low_ino == Inode->i_ino) break;
- }
- UserStatusOffset = File->f_pos;
- BytesAvailable = Controller->UserStatusLength - UserStatusOffset;
- if (Count > BytesAvailable) Count = BytesAvailable;
- if (Count <= 0) return 0;
- memcpy_tofs(Buffer, &Controller->UserStatusBuffer[UserStatusOffset], Count);
- File->f_pos += Count;
- return Count;
-}
-
-
-/*
- DAC960_ProcWriteUserCommand implements writing /proc/rd/cN/user_command.
-*/
-
-static int DAC960_ProcWriteUserCommand(Inode_T *Inode, File_T *File,
- const char *Buffer, int Count)
-{
- DAC960_Controller_T *Controller = NULL;
- char CommandBuffer[80];
- int ControllerNumber, Length;
- if (Count > sizeof(CommandBuffer)-1) return -EINVAL;
- memcpy_fromfs(CommandBuffer, Buffer, Count);
- CommandBuffer[Count] = '\0';
- Length = strlen(CommandBuffer);
- if (CommandBuffer[Length-1] == '\n')
- CommandBuffer[--Length] = '\0';
- for (ControllerNumber = 0;
- ControllerNumber < DAC960_ControllerCount;
- ControllerNumber++)
- {
- Controller = DAC960_Controllers[ControllerNumber];
- if (Controller == NULL) continue;
- if (Controller->UserCommandProcEntry.low_ino == Inode->i_ino) break;
- }
- return (DAC960_ExecuteUserCommand(Controller, CommandBuffer)
- ? Count : -EBUSY);
-}
-
-
-/*
- DAC960_CreateProcEntries creates the /proc/rd/... entries for the DAC960
- Driver.
-*/
-
-static void DAC960_CreateProcEntries(void)
-{
- static PROC_DirectoryEntry_T StatusProcEntry;
- static FileOperations_T
- StatusFileOperations = { read: DAC960_ProcReadStatus };
- static InodeOperations_T
- StatusInodeOperations = { &StatusFileOperations };
- static FileOperations_T
- InitialStatusFileOperations = { read: DAC960_ProcReadInitialStatus };
- static InodeOperations_T
- InitialStatusInodeOperations = { &InitialStatusFileOperations };
- static FileOperations_T
- CurrentStatusFileOperations = { read: DAC960_ProcReadCurrentStatus };
- static InodeOperations_T
- CurrentStatusInodeOperations = { &CurrentStatusFileOperations };
- static FileOperations_T
- UserCommandFileOperations = { read: DAC960_ProcReadUserCommand,
- write: DAC960_ProcWriteUserCommand };
- static InodeOperations_T
- UserCommandInodeOperations = { &UserCommandFileOperations };
- int ControllerNumber;
- DAC960_ProcDirectoryEntry.name = "rd";
- DAC960_ProcDirectoryEntry.namelen = strlen(DAC960_ProcDirectoryEntry.name);
- DAC960_ProcDirectoryEntry.mode = S_IFDIR | S_IRUGO | S_IXUGO;
- DAC960_ProcDirectoryEntry.ops = &proc_dir_inode_operations;
- proc_register_dynamic(&proc_root, &DAC960_ProcDirectoryEntry);
- StatusProcEntry.name = "status";
- StatusProcEntry.namelen = strlen(StatusProcEntry.name);
- StatusProcEntry.mode = S_IFREG | S_IRUGO;
- StatusProcEntry.ops = &StatusInodeOperations;
- proc_register_dynamic(&DAC960_ProcDirectoryEntry, &StatusProcEntry);
- for (ControllerNumber = 0;
- ControllerNumber < DAC960_ControllerCount;
- ControllerNumber++)
- {
- DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
- PROC_DirectoryEntry_T *ControllerProcEntry, *InitialStatusProcEntry;
- PROC_DirectoryEntry_T *CurrentStatusProcEntry, *UserCommandProcEntry;
- if (Controller == NULL) continue;
- ControllerProcEntry = &Controller->ControllerProcEntry;
- ControllerProcEntry->name = Controller->ControllerName;
- ControllerProcEntry->namelen = strlen(ControllerProcEntry->name);
- ControllerProcEntry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
- ControllerProcEntry->ops = &proc_dir_inode_operations;
- proc_register_dynamic(&DAC960_ProcDirectoryEntry, ControllerProcEntry);
- InitialStatusProcEntry = &Controller->InitialStatusProcEntry;
- InitialStatusProcEntry->name = "initial_status";
- InitialStatusProcEntry->namelen = strlen(InitialStatusProcEntry->name);
- InitialStatusProcEntry->mode = S_IFREG | S_IRUGO;
- InitialStatusProcEntry->ops = &InitialStatusInodeOperations;
- proc_register_dynamic(ControllerProcEntry, InitialStatusProcEntry);
- CurrentStatusProcEntry = &Controller->CurrentStatusProcEntry;
- CurrentStatusProcEntry->name = "current_status";
- CurrentStatusProcEntry->namelen = strlen(CurrentStatusProcEntry->name);
- CurrentStatusProcEntry->mode = S_IFREG | S_IRUGO;
- CurrentStatusProcEntry->ops = &CurrentStatusInodeOperations;
- proc_register_dynamic(ControllerProcEntry, CurrentStatusProcEntry);
- UserCommandProcEntry = &Controller->UserCommandProcEntry;
- UserCommandProcEntry->name = "user_command";
- UserCommandProcEntry->namelen = strlen(UserCommandProcEntry->name);
- UserCommandProcEntry->mode = S_IFREG | S_IWUSR | S_IRUSR;
- UserCommandProcEntry->ops = &UserCommandInodeOperations;
- proc_register_dynamic(ControllerProcEntry, UserCommandProcEntry);
- }
-}
-
-
-/*
- DAC960_DestroyProcEntries destroys the /proc/rd/... entries for the DAC960
- Driver.
-*/
-
-static void DAC960_DestroyProcEntries(void)
-{
- proc_unregister(&proc_root, DAC960_ProcDirectoryEntry.low_ino);
-}
+++ /dev/null
-/*
-
- Linux Driver for Mylex DAC960 and DAC1100 PCI RAID Controllers
-
- Copyright 1998-1999 by Leonard N. Zubkoff <lnz@dandelion.com>
-
- This program is free software; you may redistribute and/or modify it under
- the terms of the GNU General Public License Version 2 as published by the
- Free Software Foundation.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for complete details.
-
- The author respectfully requests that any modifications to this software be
- sent directly to him for evaluation and testing.
-
-*/
-
-
-/*
- DAC960_DriverVersion protects the private portion of this file.
-*/
-
-#ifdef DAC960_DriverVersion
-
-
-/*
- Define the maximum number of DAC960 Controllers supported by this driver.
-*/
-
-#define DAC960_MaxControllers 8
-
-
-/*
- Define the maximum number of Controller Channels supported by this driver.
-*/
-
-#define DAC960_MaxChannels 3
-
-
-/*
- Define the maximum number of Targets per Channel supported by this driver.
-*/
-
-#define DAC960_MaxTargets 16
-
-
-/*
- Define the maximum number of Logical Drives supported by any DAC960 model.
-*/
-
-#define DAC960_MaxLogicalDrives 32
-
-
-/*
- Define the maximum number of Partitions allowed for each Logical Drive.
-*/
-
-#define DAC960_MaxPartitions 8
-#define DAC960_MaxPartitionsBits 3
-
-
-/*
- Define the maximum Driver Queue Depth and Controller Queue Depth supported
- by any DAC960 model.
-*/
-
-#define DAC960_MaxDriverQueueDepth 127
-#define DAC960_MaxControllerQueueDepth 128
-
-
-/*
- Define the maximum number of Scatter/Gather Segments supported by any
- DAC960 model.
-*/
-
-#define DAC960_MaxScatterGatherSegments 33
-
-
-/*
- Define the DAC960 Controller Monitoring Timer Interval.
-*/
-
-#define DAC960_MonitoringTimerInterval (10 * HZ)
-
-
-/*
- Define the DAC960 Controller Secondary Monitoring Interval.
-*/
-
-#define DAC960_SecondaryMonitoringInterval (60 * HZ)
-
-
-/*
- Define the DAC960 Controller Progress Reporting Interval.
-*/
-
-#define DAC960_ProgressReportingInterval (60 * HZ)
-
-
-/*
- Define the number of Command Mailboxes and Status Mailboxes used by the
- Memory Mailbox Interface.
-*/
-
-#define DAC960_CommandMailboxCount 256
-#define DAC960_StatusMailboxCount 1024
-
-
-/*
- Define macros to extract the Controller Number, Logical Drive Number, and
- Partition Number from a Kernel Device, and to construct a Major Number, Minor
- Number, and Kernel Device from the Controller Number, Logical Drive Number,
- and Partition Number. There is one Major Number assigned to each Controller.
- The associated Minor Number is divided into the Logical Drive Number and
- Partition Number.
-*/
-
-#define DAC960_ControllerNumber(Device) \
- (MAJOR(Device) - DAC960_MAJOR)
-
-#define DAC960_LogicalDriveNumber(Device) \
- (MINOR(Device) >> DAC960_MaxPartitionsBits)
-
-#define DAC960_PartitionNumber(Device) \
- (MINOR(Device) & (DAC960_MaxPartitions - 1))
-
-#define DAC960_MajorNumber(ControllerNumber) \
- (DAC960_MAJOR + (ControllerNumber))
-
-#define DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber) \
- (((LogicalDriveNumber) << DAC960_MaxPartitionsBits) | (PartitionNumber))
-
-#define DAC960_MinorCount (DAC960_MaxLogicalDrives \
- * DAC960_MaxPartitions)
-
-#define DAC960_KernelDevice(ControllerNumber, \
- LogicalDriveNumber, \
- PartitionNumber) \
- MKDEV(DAC960_MajorNumber(ControllerNumber), \
- DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber))
-
-
-/*
- Define the DAC960 Controller fixed Block Size and Block Size Bits.
-*/
-
-#define DAC960_BlockSize 512
-#define DAC960_BlockSizeBits 9
-
-
-/*
- Define the Controller Line, Status Buffer, Rebuild Progress, and
- User Message Sizes.
-*/
-
-#define DAC960_LineBufferSize 100
-#define DAC960_StatusBufferSize 5000
-#define DAC960_RebuildProgressSize 200
-#define DAC960_UserMessageSize 200
-
-
-/*
- Define the Driver Message Levels.
-*/
-
-typedef enum DAC960_MessageLevel
-{
- DAC960_AnnounceLevel = 0,
- DAC960_InfoLevel = 1,
- DAC960_NoticeLevel = 2,
- DAC960_WarningLevel = 3,
- DAC960_ErrorLevel = 4,
- DAC960_ProgressLevel = 5,
- DAC960_CriticalLevel = 6,
- DAC960_UserCriticalLevel = 7
-}
-DAC960_MessageLevel_T;
-
-static char
- *DAC960_MessageLevelMap[] =
- { KERN_NOTICE, KERN_NOTICE, KERN_NOTICE, KERN_WARNING,
- KERN_ERR, KERN_CRIT, KERN_CRIT, KERN_CRIT };
-
-
-/*
- Define Driver Message macros.
-*/
-
-#define DAC960_Announce(Format, Arguments...) \
- DAC960_Message(DAC960_AnnounceLevel, Format, ##Arguments)
-
-#define DAC960_Info(Format, Arguments...) \
- DAC960_Message(DAC960_InfoLevel, Format, ##Arguments)
-
-#define DAC960_Notice(Format, Arguments...) \
- DAC960_Message(DAC960_NoticeLevel, Format, ##Arguments)
-
-#define DAC960_Warning(Format, Arguments...) \
- DAC960_Message(DAC960_WarningLevel, Format, ##Arguments)
-
-#define DAC960_Error(Format, Arguments...) \
- DAC960_Message(DAC960_ErrorLevel, Format, ##Arguments)
-
-#define DAC960_Progress(Format, Arguments...) \
- DAC960_Message(DAC960_ProgressLevel, Format, ##Arguments)
-
-#define DAC960_Critical(Format, Arguments...) \
- DAC960_Message(DAC960_CriticalLevel, Format, ##Arguments)
-
-#define DAC960_UserCritical(Format, Arguments...) \
- DAC960_Message(DAC960_UserCriticalLevel, Format, ##Arguments)
-
-
-/*
- Define the types of DAC960 Controllers that are supported.
-*/
-
-typedef enum
-{
- DAC960_V5_Controller = 1, /* DAC1164P */
- DAC960_V4_Controller = 2, /* DAC960PTL/PJ/PG */
- DAC960_V3_Controller = 3 /* DAC960PU/PD/PL */
-}
-DAC960_ControllerType_T;
-
-
-/*
- Define a Boolean data type.
-*/
-
-typedef enum { false, true } __attribute__ ((packed)) boolean;
-
-
-/*
- Define a 32 bit I/O Address data type.
-*/
-
-typedef unsigned int DAC960_IO_Address_T;
-
-
-/*
- Define a 32 bit PCI Bus Address data type.
-*/
-
-typedef unsigned int DAC960_PCI_Address_T;
-
-
-/*
- Define a 32 bit Bus Address data type.
-*/
-
-typedef unsigned int DAC960_BusAddress_T;
-
-
-/*
- Define a 32 bit Byte Count data type.
-*/
-
-typedef unsigned int DAC960_ByteCount_T;
-
-
-/*
- Define types for some of the structures that interface with the rest
- of the Linux Kernel and I/O Subsystem.
-*/
-
-typedef struct buffer_head BufferHeader_T;
-typedef struct file File_T;
-typedef struct file_operations FileOperations_T;
-typedef struct gendisk GenericDiskInfo_T;
-typedef struct hd_geometry DiskGeometry_T;
-typedef struct hd_struct DiskPartition_T;
-typedef struct inode Inode_T;
-typedef struct inode_operations InodeOperations_T;
-typedef kdev_t KernelDevice_T;
-typedef struct proc_dir_entry PROC_DirectoryEntry_T;
-typedef unsigned long ProcessorFlags_T;
-typedef struct pt_regs Registers_T;
-typedef struct request IO_Request_T;
-typedef struct semaphore Semaphore_T;
-typedef struct timer_list Timer_T;
-typedef struct wait_queue WaitQueue_T;
-
-
-/*
- Define the DAC960 V5 Controller Interface Register Offsets.
-*/
-
-#define DAC960_V5_RegisterWindowSize 0x80
-
-typedef enum
-{
- DAC960_V5_InboundDoorBellRegisterOffset = 0x60,
- DAC960_V5_OutboundDoorBellRegisterOffset = 0x61,
- DAC960_V5_InterruptMaskRegisterOffset = 0x34,
- DAC960_V5_CommandOpcodeRegisterOffset = 0x50,
- DAC960_V5_CommandIdentifierRegisterOffset = 0x51,
- DAC960_V5_MailboxRegister2Offset = 0x52,
- DAC960_V5_MailboxRegister3Offset = 0x53,
- DAC960_V5_MailboxRegister4Offset = 0x54,
- DAC960_V5_MailboxRegister5Offset = 0x55,
- DAC960_V5_MailboxRegister6Offset = 0x56,
- DAC960_V5_MailboxRegister7Offset = 0x57,
- DAC960_V5_MailboxRegister8Offset = 0x58,
- DAC960_V5_MailboxRegister9Offset = 0x59,
- DAC960_V5_MailboxRegister10Offset = 0x5A,
- DAC960_V5_MailboxRegister11Offset = 0x5B,
- DAC960_V5_MailboxRegister12Offset = 0x5C,
- DAC960_V5_StatusCommandIdentifierRegOffset = 0x5D,
- DAC960_V5_StatusRegisterOffset = 0x5E
-}
-DAC960_V5_RegisterOffsets_T;
-
-
-/*
- Define the structure of the DAC960 V5 Inbound Door Bell Register.
-*/
-
-typedef union DAC960_V5_InboundDoorBellRegister
-{
- unsigned char All;
- struct {
- boolean HardwareMailboxNewCommand:1; /* Bit 0 */
- boolean AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */
- boolean GenerateInterrupt:1; /* Bit 2 */
- boolean ControllerReset:1; /* Bit 3 */
- boolean MemoryMailboxNewCommand:1; /* Bit 4 */
- unsigned char :3; /* Bits 5-7 */
- } Write;
- struct {
- boolean HardwareMailboxEmpty:1; /* Bit 0 */
- unsigned char :7; /* Bits 1-7 */
- } Read;
-}
-DAC960_V5_InboundDoorBellRegister_T;
-
-
-/*
- Define the structure of the DAC960 V5 Outbound Door Bell Register.
-*/
-
-typedef union DAC960_V5_OutboundDoorBellRegister
-{
- unsigned char All;
- struct {
- boolean AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */
- boolean AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */
- unsigned char :6; /* Bits 2-7 */
- } Write;
- struct {
- boolean HardwareMailboxStatusAvailable:1; /* Bit 0 */
- boolean MemoryMailboxStatusAvailable:1; /* Bit 1 */
- unsigned char :6; /* Bits 2-7 */
- } Read;
-}
-DAC960_V5_OutboundDoorBellRegister_T;
-
-
-/*
- Define the structure of the DAC960 V5 Interrupt Mask Register.
-*/
-
-typedef union DAC960_V5_InterruptMaskRegister
-{
- unsigned char All;
- struct {
- unsigned char :2; /* Bits 0-1 */
- boolean DisableInterrupts:1; /* Bit 2 */
- unsigned char :5; /* Bits 3-7 */
- } Bits;
-}
-DAC960_V5_InterruptMaskRegister_T;
-
-
-/*
- Define the DAC960 V4 Controller Interface Register Offsets.
-*/
-
-#define DAC960_V4_RegisterWindowSize 0x2000
-
-typedef enum
-{
- DAC960_V4_InboundDoorBellRegisterOffset = 0x0020,
- DAC960_V4_OutboundDoorBellRegisterOffset = 0x002C,
- DAC960_V4_InterruptMaskRegisterOffset = 0x0034,
- DAC960_V4_CommandOpcodeRegisterOffset = 0x1000,
- DAC960_V4_CommandIdentifierRegisterOffset = 0x1001,
- DAC960_V4_MailboxRegister2Offset = 0x1002,
- DAC960_V4_MailboxRegister3Offset = 0x1003,
- DAC960_V4_MailboxRegister4Offset = 0x1004,
- DAC960_V4_MailboxRegister5Offset = 0x1005,
- DAC960_V4_MailboxRegister6Offset = 0x1006,
- DAC960_V4_MailboxRegister7Offset = 0x1007,
- DAC960_V4_MailboxRegister8Offset = 0x1008,
- DAC960_V4_MailboxRegister9Offset = 0x1009,
- DAC960_V4_MailboxRegister10Offset = 0x100A,
- DAC960_V4_MailboxRegister11Offset = 0x100B,
- DAC960_V4_MailboxRegister12Offset = 0x100C,
- DAC960_V4_StatusCommandIdentifierRegOffset = 0x1018,
- DAC960_V4_StatusRegisterOffset = 0x101A
-}
-DAC960_V4_RegisterOffsets_T;
-
-
-/*
- Define the structure of the DAC960 V4 Inbound Door Bell Register.
-*/
-
-typedef union DAC960_V4_InboundDoorBellRegister
-{
- unsigned int All;
- struct {
- boolean HardwareMailboxNewCommand:1; /* Bit 0 */
- boolean AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */
- boolean GenerateInterrupt:1; /* Bit 2 */
- boolean ControllerReset:1; /* Bit 3 */
- boolean MemoryMailboxNewCommand:1; /* Bit 4 */
- unsigned int :27; /* Bits 5-31 */
- } Write;
- struct {
- boolean HardwareMailboxFull:1; /* Bit 0 */
- unsigned int :31; /* Bits 1-31 */
- } Read;
-}
-DAC960_V4_InboundDoorBellRegister_T;
-
-
-/*
- Define the structure of the DAC960 V4 Outbound Door Bell Register.
-*/
-
-typedef union DAC960_V4_OutboundDoorBellRegister
-{
- unsigned int All;
- struct {
- boolean AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */
- boolean AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */
- unsigned int :30; /* Bits 2-31 */
- } Write;
- struct {
- boolean HardwareMailboxStatusAvailable:1; /* Bit 0 */
- boolean MemoryMailboxStatusAvailable:1; /* Bit 1 */
- unsigned int :30; /* Bits 2-31 */
- } Read;
-}
-DAC960_V4_OutboundDoorBellRegister_T;
-
-
-/*
- Define the structure of the DAC960 V4 Interrupt Mask Register.
-*/
-
-typedef union DAC960_V4_InterruptMaskRegister
-{
- unsigned int All;
- struct {
- unsigned int MessageUnitInterruptMask1:2; /* Bits 0-1 */
- boolean DisableInterrupts:1; /* Bit 2 */
- unsigned int MessageUnitInterruptMask2:5; /* Bits 3-7 */
- unsigned int Reserved0:24; /* Bits 8-31 */
- } Bits;
-}
-DAC960_V4_InterruptMaskRegister_T;
-
-
-/*
- Define the DAC960 V3 Controller Interface Register Offsets.
-*/
-
-#define DAC960_V3_RegisterWindowSize 0x80
-
-typedef enum
-{
- DAC960_V3_CommandOpcodeRegisterOffset = 0x00,
- DAC960_V3_CommandIdentifierRegisterOffset = 0x01,
- DAC960_V3_MailboxRegister2Offset = 0x02,
- DAC960_V3_MailboxRegister3Offset = 0x03,
- DAC960_V3_MailboxRegister4Offset = 0x04,
- DAC960_V3_MailboxRegister5Offset = 0x05,
- DAC960_V3_MailboxRegister6Offset = 0x06,
- DAC960_V3_MailboxRegister7Offset = 0x07,
- DAC960_V3_MailboxRegister8Offset = 0x08,
- DAC960_V3_MailboxRegister9Offset = 0x09,
- DAC960_V3_MailboxRegister10Offset = 0x0A,
- DAC960_V3_MailboxRegister11Offset = 0x0B,
- DAC960_V3_MailboxRegister12Offset = 0x0C,
- DAC960_V3_StatusCommandIdentifierRegOffset = 0x0D,
- DAC960_V3_StatusRegisterOffset = 0x0E,
- DAC960_V3_InboundDoorBellRegisterOffset = 0x40,
- DAC960_V3_OutboundDoorBellRegisterOffset = 0x41,
- DAC960_V3_InterruptEnableRegisterOffset = 0x43
-}
-DAC960_V3_RegisterOffsets_T;
-
-
-/*
- Define the structure of the DAC960 V3 Inbound Door Bell Register.
-*/
-
-typedef union DAC960_V3_InboundDoorBellRegister
-{
- unsigned char All;
- struct {
- boolean NewCommand:1; /* Bit 0 */
- boolean AcknowledgeStatus:1; /* Bit 1 */
- boolean GenerateInterrupt:1; /* Bit 2 */
- boolean ControllerReset:1; /* Bit 3 */
- unsigned char :4; /* Bits 4-7 */
- } Write;
- struct {
- boolean MailboxFull:1; /* Bit 0 */
- unsigned char :7; /* Bits 1-7 */
- } Read;
-}
-DAC960_V3_InboundDoorBellRegister_T;
-
-
-/*
- Define the structure of the DAC960 V3 Outbound Door Bell Register.
-*/
-
-typedef union DAC960_V3_OutboundDoorBellRegister
-{
- unsigned char All;
- struct {
- boolean AcknowledgeInterrupt:1; /* Bit 0 */
- unsigned char :7; /* Bits 1-7 */
- } Write;
- struct {
- boolean StatusAvailable:1; /* Bit 0 */
- unsigned char :7; /* Bits 1-7 */
- } Read;
-}
-DAC960_V3_OutboundDoorBellRegister_T;
-
-
-/*
- Define the structure of the DAC960 V3 Interrupt Enable Register.
-*/
-
-typedef union DAC960_V3_InterruptEnableRegister
-{
- unsigned char All;
- struct {
- boolean EnableInterrupts:1; /* Bit 0 */
- unsigned char :7; /* Bits 1-7 */
- } Bits;
-}
-DAC960_V3_InterruptEnableRegister_T;
-
-
-/*
- Define the DAC960 Command Identifier type.
-*/
-
-typedef unsigned char DAC960_CommandIdentifier_T;
-
-
-/*
- Define the DAC960 Command Opcodes.
-*/
-
-typedef enum
-{
- /* I/O Commands */
- DAC960_ReadExtended = 0x33,
- DAC960_WriteExtended = 0x34,
- DAC960_ReadAheadExtended = 0x35,
- DAC960_ReadExtendedWithScatterGather = 0xB3,
- DAC960_WriteExtendedWithScatterGather = 0xB4,
- DAC960_Read = 0x36,
- DAC960_ReadWithOldScatterGather = 0xB6,
- DAC960_Write = 0x37,
- DAC960_WriteWithOldScatterGather = 0xB7,
- DAC960_DCDB = 0x04,
- DAC960_DCDBWithScatterGather = 0x84,
- DAC960_Flush = 0x0A,
- /* Controller Status Related Commands */
- DAC960_Enquiry = 0x53,
- DAC960_Enquiry2 = 0x1C,
- DAC960_GetLogicalDriveElement = 0x55,
- DAC960_GetLogicalDriveInformation = 0x19,
- DAC960_IOPortRead = 0x39,
- DAC960_IOPortWrite = 0x3A,
- DAC960_GetSDStats = 0x3E,
- DAC960_GetPDStats = 0x3F,
- DAC960_PerformEventLogOperation = 0x72,
- /* Device Related Commands */
- DAC960_StartDevice = 0x10,
- DAC960_GetDeviceState = 0x50,
- DAC960_StopChannel = 0x13,
- DAC960_StartChannel = 0x12,
- DAC960_ResetChannel = 0x1A,
- /* Commands Associated with Data Consistency and Errors */
- DAC960_Rebuild = 0x09,
- DAC960_RebuildAsync = 0x16,
- DAC960_CheckConsistency = 0x0F,
- DAC960_CheckConsistencyAsync = 0x1E,
- DAC960_RebuildStat = 0x0C,
- DAC960_GetRebuildProgress = 0x27,
- DAC960_RebuildControl = 0x1F,
- DAC960_ReadBadBlockTable = 0x0B,
- DAC960_ReadBadDataTable = 0x25,
- DAC960_ClearBadDataTable = 0x26,
- DAC960_GetErrorTable = 0x17,
- DAC960_AddCapacityAsync = 0x2A,
- /* Configuration Related Commands */
- DAC960_ReadConfig2 = 0x3D,
- DAC960_WriteConfig2 = 0x3C,
- DAC960_ReadConfigurationOnDisk = 0x4A,
- DAC960_WriteConfigurationOnDisk = 0x4B,
- DAC960_ReadConfiguration = 0x4E,
- DAC960_ReadBackupConfiguration = 0x4D,
- DAC960_WriteConfiguration = 0x4F,
- DAC960_AddConfiguration = 0x4C,
- DAC960_ReadConfigurationLabel = 0x48,
- DAC960_WriteConfigurationLabel = 0x49,
- /* Firmware Upgrade Related Commands */
- DAC960_LoadImage = 0x20,
- DAC960_StoreImage = 0x21,
- DAC960_ProgramImage = 0x22,
- /* Diagnostic Commands */
- DAC960_SetDiagnosticMode = 0x31,
- DAC960_RunDiagnostic = 0x32,
- /* Subsystem Service Commands */
- DAC960_GetSubsystemData = 0x70,
- DAC960_SetSubsystemParameters = 0x71
-}
-__attribute__ ((packed))
-DAC960_CommandOpcode_T;
-
-
-/*
- Define the DAC960 Command Status Codes.
-*/
-
-#define DAC960_NormalCompletion 0x0000 /* Common */
-#define DAC960_CheckConditionReceived 0x0002 /* Common */
-#define DAC960_NoDeviceAtAddress 0x0102 /* Common */
-#define DAC960_InvalidDeviceAddress 0x0105 /* Common */
-#define DAC960_InvalidParameter 0x0105 /* Common */
-#define DAC960_IrrecoverableDataError 0x0001 /* I/O */
-#define DAC960_LogicalDriveNonexistentOrOffline 0x0002 /* I/O */
-#define DAC960_AccessBeyondEndOfLogicalDrive 0x0105 /* I/O */
-#define DAC960_BadDataEncountered 0x010C /* I/O */
-#define DAC960_DeviceBusy 0x0008 /* DCDB */
-#define DAC960_DeviceNonresponsive 0x000E /* DCDB */
-#define DAC960_CommandTerminatedAbnormally 0x000F /* DCDB */
-#define DAC960_UnableToStartDevice 0x0002 /* Device */
-#define DAC960_InvalidChannelOrTargetOrModifier 0x0105 /* Device */
-#define DAC960_ChannelBusy 0x0106 /* Device */
-#define DAC960_ChannelNotStopped 0x0002 /* Device */
-#define DAC960_AttemptToRebuildOnlineDrive 0x0002 /* Consistency */
-#define DAC960_RebuildBadBlocksEncountered 0x0003 /* Consistency */
-#define DAC960_NewDiskFailedDuringRebuild 0x0004 /* Consistency */
-#define DAC960_RebuildOrCheckAlreadyInProgress 0x0106 /* Consistency */
-#define DAC960_DependentDiskIsDead 0x0002 /* Consistency */
-#define DAC960_InconsistentBlocksFound 0x0003 /* Consistency */
-#define DAC960_InvalidOrNonredundantLogicalDrive 0x0105 /* Consistency */
-#define DAC960_NoRebuildOrCheckInProgress 0x0105 /* Consistency */
-#define DAC960_RebuildInProgress_DataValid 0x0000 /* Consistency */
-#define DAC960_RebuildFailed_LogicalDriveFailure 0x0002 /* Consistency */
-#define DAC960_RebuildFailed_BadBlocksOnOther 0x0003 /* Consistency */
-#define DAC960_RebuildFailed_NewDriveFailed 0x0004 /* Consistency */
-#define DAC960_RebuildSuccessful 0x0100 /* Consistency */
-#define DAC960_AddCapacityInProgress 0x0004 /* Consistency */
-#define DAC960_AddCapacityFailedOrSuspended 0x00F4 /* Consistency */
-#define DAC960_Config2ChecksumError 0x0002 /* Configuration */
-#define DAC960_ConfigurationSuspended 0x0106 /* Configuration */
-#define DAC960_FailedToConfigureNVRAM 0x0105 /* Configuration */
-#define DAC960_ConfigurationNotSavedStateChange 0x0106 /* Configuration */
-#define DAC960_SubsystemNotInstalled 0x0001 /* Subsystem */
-#define DAC960_SubsystemFailed 0x0002 /* Subsystem */
-#define DAC960_SubsystemBusy 0x0106 /* Subsystem */
-
-typedef unsigned short DAC960_CommandStatus_T;
-
-
-/*
- Define the Enquiry reply structure.
-*/
-
-typedef struct DAC960_Enquiry
-{
- unsigned char NumberOfLogicalDrives; /* Byte 0 */
- unsigned int :24; /* Bytes 1-3 */
- unsigned int LogicalDriveSizes[32]; /* Bytes 4-131 */
- unsigned short FlashAge; /* Bytes 132-133 */
- struct {
- boolean DeferredWriteError:1; /* Byte 134 Bit 0 */
- boolean BatteryLow:1; /* Byte 134 Bit 1 */
- unsigned char :6; /* Byte 134 Bits 2-7 */
- } StatusFlags;
- unsigned char :8; /* Byte 135 */
- unsigned char MinorFirmwareVersion; /* Byte 136 */
- unsigned char MajorFirmwareVersion; /* Byte 137 */
- enum {
- DAC960_NoStandbyRebuildOrCheckInProgress = 0x00,
- DAC960_StandbyRebuildInProgress = 0x01,
- DAC960_BackgroundRebuildInProgress = 0x02,
- DAC960_BackgroundCheckInProgress = 0x03,
- DAC960_StandbyRebuildCompletedWithError = 0xFF,
- DAC960_BackgroundRebuildOrCheckFailed_DriveFailed = 0xF0,
- DAC960_BackgroundRebuildOrCheckFailed_LogicalDriveFailed = 0xF1,
- DAC960_BackgroundRebuildOrCheckFailed_OtherCauses = 0xF2,
- DAC960_BackgroundRebuildOrCheckSuccessfullyTerminated = 0xF3
- } __attribute__ ((packed)) RebuildFlag; /* Byte 138 */
- unsigned char MaxCommands; /* Byte 139 */
- unsigned char OfflineLogicalDriveCount; /* Byte 140 */
- unsigned char :8; /* Byte 141 */
- unsigned short EventLogSequenceNumber; /* Bytes 142-143 */
- unsigned char CriticalLogicalDriveCount; /* Byte 144 */
- unsigned int :24; /* Bytes 145-147 */
- unsigned char DeadDriveCount; /* Byte 148 */
- unsigned char :8; /* Byte 149 */
- unsigned char RebuildCount; /* Byte 150 */
- struct {
- unsigned char :3; /* Byte 151 Bits 0-2 */
- boolean BatteryBackupUnitPresent:1; /* Byte 151 Bit 3 */
- unsigned char :3; /* Byte 151 Bits 4-6 */
- unsigned char :1; /* Byte 151 Bit 7 */
- } MiscFlags;
- struct {
- unsigned char TargetID;
- unsigned char Channel;
- } DeadDrives[21]; /* Bytes 152-194 */
- unsigned char Reserved[62]; /* Bytes 195-255 */
-}
-__attribute__ ((packed))
-DAC960_Enquiry_T;
-
-
-/*
- Define the Enquiry2 reply structure.
-*/
-
-typedef struct DAC960_Enquiry2
-{
- struct {
- enum {
- DAC960_P_PD_PU = 0x01,
- DAC960_PL = 0x02,
- DAC960_PG = 0x10,
- DAC960_PJ = 0x11,
- DAC960_PR = 0x12,
- DAC960_PT = 0x13,
- DAC960_PTL0 = 0x14,
- DAC960_PRL = 0x15,
- DAC960_PTL1 = 0x16,
- DAC1164_P = 0x20
- } __attribute__ ((packed)) SubModel; /* Byte 0 */
- unsigned char ActualChannels; /* Byte 1 */
- enum {
- DAC960_FiveChannelBoard = 0x01,
- DAC960_ThreeChannelBoard = 0x02,
- DAC960_TwoChannelBoard = 0x03,
- DAC960_ThreeChannelASIC_DAC = 0x04
- } __attribute__ ((packed)) Model; /* Byte 2 */
- enum {
- DAC960_EISA_Controller = 0x01,
- DAC960_MicroChannel_Controller = 0x02,
- DAC960_PCI_Controller = 0x03,
- DAC960_SCSItoSCSI_Controller = 0x08
- } __attribute__ ((packed)) ProductFamily; /* Byte 3 */
- } HardwareID; /* Bytes 0-3 */
- /* MajorVersion.MinorVersion-FirmwareType-TurnID */
- struct {
- unsigned char MajorVersion; /* Byte 4 */
- unsigned char MinorVersion; /* Byte 5 */
- unsigned char TurnID; /* Byte 6 */
- char FirmwareType; /* Byte 7 */
- } FirmwareID; /* Bytes 4-7 */
- unsigned char :8; /* Byte 8 */
- unsigned int :24; /* Bytes 9-11 */
- unsigned char ConfiguredChannels; /* Byte 12 */
- unsigned char ActualChannels; /* Byte 13 */
- unsigned char MaxTargets; /* Byte 14 */
- unsigned char MaxTags; /* Byte 15 */
- unsigned char MaxLogicalDrives; /* Byte 16 */
- unsigned char MaxArms; /* Byte 17 */
- unsigned char MaxSpans; /* Byte 18 */
- unsigned char :8; /* Byte 19 */
- unsigned int :32; /* Bytes 20-23 */
- unsigned int MemorySize; /* Bytes 24-27 */
- unsigned int CacheSize; /* Bytes 28-31 */
- unsigned int FlashMemorySize; /* Bytes 32-35 */
- unsigned int NonVolatileMemorySize; /* Bytes 36-39 */
- struct {
- enum {
- DAC960_DRAM = 0x00,
- DAC960_EDO = 0x01,
- DAC960_SDRAM = 0x02
- } __attribute__ ((packed)) RamType:3; /* Byte 40 Bits 0-2 */
- enum {
- DAC960_None = 0x00,
- DAC960_Parity = 0x01,
- DAC960_ECC = 0x02
- } __attribute__ ((packed)) ErrorCorrection:3; /* Byte 40 Bits 3-5 */
- boolean FastPageMode:1; /* Byte 40 Bit 6 */
- boolean LowPowerMemory:1; /* Byte 40 Bit 7 */
- unsigned char :8; /* Bytes 41 */
- } MemoryType;
- unsigned short ClockSpeed; /* Bytes 42-43 */
- unsigned short MemorySpeed; /* Bytes 44-45 */
- unsigned short HardwareSpeed; /* Bytes 46-47 */
- unsigned int :32; /* Bytes 48-51 */
- unsigned int :32; /* Bytes 52-55 */
- unsigned char :8; /* Byte 56 */
- unsigned char :8; /* Byte 57 */
- unsigned short :16; /* Bytes 58-59 */
- unsigned short MaxCommands; /* Bytes 60-61 */
- unsigned short MaxScatterGatherEntries; /* Bytes 62-63 */
- unsigned short MaxDriveCommands; /* Bytes 64-65 */
- unsigned short MaxIODescriptors; /* Bytes 66-67 */
- unsigned short MaxCombinedSectors; /* Bytes 68-69 */
- unsigned char Latency; /* Byte 70 */
- unsigned char :8; /* Byte 71 */
- unsigned char SCSITimeout; /* Byte 72 */
- unsigned char :8; /* Byte 73 */
- unsigned short MinFreeLines; /* Bytes 74-75 */
- unsigned int :32; /* Bytes 76-79 */
- unsigned int :32; /* Bytes 80-83 */
- unsigned char RebuildRateConstant; /* Byte 84 */
- unsigned char :8; /* Byte 85 */
- unsigned char :8; /* Byte 86 */
- unsigned char :8; /* Byte 87 */
- unsigned int :32; /* Bytes 88-91 */
- unsigned int :32; /* Bytes 92-95 */
- unsigned short PhysicalDriveBlockSize; /* Bytes 96-97 */
- unsigned short LogicalDriveBlockSize; /* Bytes 98-99 */
- unsigned short MaxBlocksPerCommand; /* Bytes 100-101 */
- unsigned short BlockFactor; /* Bytes 102-103 */
- unsigned short CacheLineSize; /* Bytes 104-105 */
- struct {
- enum {
- DAC960_Narrow_8bit = 0x00,
- DAC960_Wide_16bit = 0x01,
- DAC960_Wide_32bit = 0x02
- } __attribute__ ((packed)) BusWidth:2; /* Byte 106 Bits 0-1 */
- enum {
- DAC960_Fast = 0x00,
- DAC960_Ultra = 0x01,
- DAC960_Ultra2 = 0x02
- } __attribute__ ((packed)) BusSpeed:2; /* Byte 106 Bits 2-3 */
- boolean Differential:1; /* Byte 106 Bit 4 */
- unsigned char :3; /* Byte 106 Bits 5-7 */
- } SCSICapability;
- unsigned char :8; /* Byte 107 */
- unsigned int :32; /* Bytes 108-111 */
- unsigned short FirmwareBuildNumber; /* Bytes 112-113 */
- enum {
- DAC960_AEMI = 0x01,
- DAC960_OEM1 = 0x02,
- DAC960_OEM2 = 0x04,
- DAC960_OEM3 = 0x08,
- DAC960_Conner = 0x10,
- DAC960_SAFTE = 0x20
- } __attribute__ ((packed)) FaultManagementType; /* Byte 114 */
- unsigned char :8; /* Byte 115 */
- struct {
- boolean Clustering:1; /* Byte 116 Bit 0 */
- boolean MylexOnlineRAIDExpansion:1; /* Byte 116 Bit 1 */
- unsigned int :30; /* Bytes 116-119 */
- } FirmwareFeatures;
- unsigned int :32; /* Bytes 120-123 */
- unsigned int :32; /* Bytes 124-127 */
-}
-DAC960_Enquiry2_T;
-
-
-/*
- Define the Logical Drive State type.
-*/
-
-typedef enum
-{
- DAC960_LogicalDrive_Online = 0x03,
- DAC960_LogicalDrive_Critical = 0x04,
- DAC960_LogicalDrive_Offline = 0xFF
-}
-__attribute__ ((packed))
-DAC960_LogicalDriveState_T;
-
-
-/*
- Define the Get Logical Drive Information reply structure.
-*/
-
-typedef struct DAC960_LogicalDriveInformation
-{
- unsigned int LogicalDriveSize; /* Bytes 0-3 */
- DAC960_LogicalDriveState_T LogicalDriveState; /* Byte 4 */
- unsigned char RAIDLevel:7; /* Byte 5 Bits 0-6 */
- boolean WriteBack:1; /* Byte 5 Bit 7 */
- unsigned int :16; /* Bytes 6-7 */
-}
-DAC960_LogicalDriveInformation_T;
-
-
-/*
- Define the Perform Event Log Operation Types.
-*/
-
-typedef enum
-{
- DAC960_GetEventLogEntry = 0x00
-}
-__attribute__ ((packed))
-DAC960_PerformEventLogOpType_T;
-
-
-/*
- Define the Get Event Log Entry reply structure.
-*/
-
-typedef struct DAC960_EventLogEntry
-{
- unsigned char MessageType; /* Byte 0 */
- unsigned char MessageLength; /* Byte 1 */
- unsigned char TargetID:5; /* Byte 2 Bits 0-4 */
- unsigned char Channel:3; /* Byte 2 Bits 5-7 */
- unsigned char LogicalUnit:6; /* Byte 3 Bits 0-5 */
- unsigned char :2; /* Byte 3 Bits 6-7 */
- unsigned short SequenceNumber; /* Bytes 4-5 */
- unsigned char ErrorCode:7; /* Byte 6 Bits 0-6 */
- boolean Valid:1; /* Byte 6 Bit 7 */
- unsigned char SegmentNumber; /* Byte 7 */
- unsigned char SenseKey:4; /* Byte 8 Bits 0-3 */
- unsigned char :1; /* Byte 8 Bit 4 */
- boolean ILI:1; /* Byte 8 Bit 5 */
- boolean EOM:1; /* Byte 8 Bit 6 */
- boolean Filemark:1; /* Byte 8 Bit 7 */
- unsigned char Information[4]; /* Bytes 9-12 */
- unsigned char AdditionalSenseLength; /* Byte 13 */
- unsigned char CommandSpecificInformation[4]; /* Bytes 14-17 */
- unsigned char AdditionalSenseCode; /* Byte 18 */
- unsigned char AdditionalSenseCodeQualifier; /* Byte 19 */
- unsigned char Dummy[12]; /* Bytes 20-31 */
-}
-DAC960_EventLogEntry_T;
-
-#define DAC960_EventMessagesCount 13
-
-static char
- *DAC960_EventMessages[DAC960_EventMessagesCount] =
- { "killed because write recovery failed",
- "killed because of SCSI bus reset failure",
- "killed because of double check condition",
- "killed because it was removed",
- "killed because of gross error on SCSI chip",
- "killed because of bad tag returned from drive",
- "killed because of timeout on SCSI command",
- "killed because of reset SCSI command issued from system",
- "killed because busy or parity error count exceeded limit",
- "killed because of 'kill drive' command from system",
- "killed because of selection timeout",
- "killed due to SCSI phase sequence error",
- "killed due to unknown status" };
-
-
-/*
- Define the Physical Device State type.
-*/
-
-typedef enum
-{
- DAC960_Device_Dead = 0x00,
- DAC960_Device_WriteOnly = 0x02,
- DAC960_Device_Online = 0x03,
- DAC960_Device_Standby = 0x10
-}
-__attribute__ ((packed))
-DAC960_PhysicalDeviceState_T;
-
-
-/*
- Define the Get Device State reply structure.
-*/
-
-typedef struct DAC960_DeviceState
-{
- boolean Present:1; /* Byte 0 Bit 0 */
- unsigned char :7; /* Byte 0 Bits 1-7 */
- enum {
- DAC960_OtherType = 0x00,
- DAC960_DiskType = 0x01,
- DAC960_SequentialType = 0x02,
- DAC960_CDROM_or_WORM_Type = 0x03
- } __attribute__ ((packed)) DeviceType:2; /* Byte 1 Bits 0-1 */
- boolean :1; /* Byte 1 Bit 2 */
- boolean Fast20:1; /* Byte 1 Bit 3 */
- boolean Sync:1; /* Byte 1 Bit 4 */
- boolean Fast:1; /* Byte 1 Bit 5 */
- boolean Wide:1; /* Byte 1 Bit 6 */
- boolean TaggedQueuingSupported:1; /* Byte 1 Bit 7 */
- DAC960_PhysicalDeviceState_T DeviceState; /* Byte 2 */
- unsigned char :8; /* Byte 3 */
- unsigned char SynchronousMultiplier; /* Byte 4 */
- unsigned char SynchronousOffset:5; /* Byte 5 Bits 0-4 */
- unsigned char :3; /* Byte 5 Bits 5-7 */
- unsigned long DiskSize __attribute__ ((packed)); /* Bytes 6-9 */
-}
-DAC960_DeviceState_T;
-
-
-/*
- Define the Get Rebuild Progress reply structure.
-*/
-
-typedef struct DAC960_RebuildProgress
-{
- unsigned int LogicalDriveNumber; /* Bytes 0-3 */
- unsigned int LogicalDriveSize; /* Bytes 4-7 */
- unsigned int RemainingBlocks; /* Bytes 8-11 */
-}
-DAC960_RebuildProgress_T;
-
-
-/*
- Define the Error Table Entry and Get Error Table reply structure.
-*/
-
-typedef struct DAC960_ErrorTableEntry
-{
- unsigned char ParityErrorCount; /* Byte 0 */
- unsigned char SoftErrorCount; /* Byte 1 */
- unsigned char HardErrorCount; /* Byte 2 */
- unsigned char MiscErrorCount; /* Byte 3 */
-}
-DAC960_ErrorTableEntry_T;
-
-
-/*
- Define the Get Error Table reply structure.
-*/
-
-typedef struct DAC960_ErrorTable
-{
- DAC960_ErrorTableEntry_T
- ErrorTableEntries[DAC960_MaxChannels][DAC960_MaxTargets];
-}
-DAC960_ErrorTable_T;
-
-
-/*
- Define the Config2 reply structure.
-*/
-
-typedef struct DAC960_Config2
-{
- unsigned char :1; /* Byte 0 Bit 0 */
- boolean ActiveNegationEnabled:1; /* Byte 0 Bit 1 */
- unsigned char :5; /* Byte 0 Bits 2-6 */
- boolean NoRescanIfResetReceivedDuringScan:1; /* Byte 0 Bit 7 */
- boolean StorageWorksSupportEnabled:1; /* Byte 1 Bit 0 */
- boolean HewlettPackardSupportEnabled:1; /* Byte 1 Bit 1 */
- boolean NoDisconnectOnFirstCommand:1; /* Byte 1 Bit 2 */
- unsigned char :2; /* Byte 1 Bits 3-4 */
- boolean AEMI_ARM:1; /* Byte 1 Bit 5 */
- boolean AEMI_OFM:1; /* Byte 1 Bit 6 */
- unsigned char :1; /* Byte 1 Bit 7 */
- enum {
- DAC960_OEMID_Mylex = 0x00,
- DAC960_OEMID_IBM = 0x08,
- DAC960_OEMID_HP = 0x0A,
- DAC960_OEMID_DEC = 0x0C,
- DAC960_OEMID_Siemens = 0x10,
- DAC960_OEMID_Intel = 0x12
- } __attribute__ ((packed)) OEMID; /* Byte 2 */
- unsigned char OEMModelNumber; /* Byte 3 */
- unsigned char PhysicalSector; /* Byte 4 */
- unsigned char LogicalSector; /* Byte 5 */
- unsigned char BlockFactor; /* Byte 6 */
- boolean ReadAheadEnabled:1; /* Byte 7 Bit 0 */
- boolean LowBIOSDelay:1; /* Byte 7 Bit 1 */
- unsigned char :2; /* Byte 7 Bits 2-3 */
- boolean ReassignRestrictedToOneSector:1; /* Byte 7 Bit 4 */
- unsigned char :1; /* Byte 7 Bit 5 */
- boolean ForceUnitAccessDuringWriteRecovery:1; /* Byte 7 Bit 6 */
- boolean EnableLeftSymmetricRAID5Algorithm:1; /* Byte 7 Bit 7 */
- unsigned char DefaultRebuildRate; /* Byte 8 */
- unsigned char :8; /* Byte 9 */
- unsigned char BlocksPerCacheLine; /* Byte 10 */
- unsigned char BlocksPerStripe; /* Byte 11 */
- struct {
- enum {
- DAC960_Async = 0x00,
- DAC960_Sync_8MHz = 0x01,
- DAC960_Sync_5MHz = 0x02,
- DAC960_Sync_10or20MHz = 0x03 /* Bits 0-1 */
- } __attribute__ ((packed)) Speed:2;
- boolean Force8Bit:1; /* Bit 2 */
- boolean DisableFast20:1; /* Bit 3 */
- unsigned char :3; /* Bits 4-6 */
- boolean EnableTaggedQueuing:1; /* Bit 7 */
- } __attribute__ ((packed)) ChannelParameters[6]; /* Bytes 12-17 */
- unsigned char SCSIInitiatorID; /* Byte 18 */
- unsigned char :8; /* Byte 19 */
- enum {
- DAC960_StartupMode_ControllerSpinUp = 0x00,
- DAC960_StartupMode_PowerOnSpinUp = 0x01
- } __attribute__ ((packed)) StartupMode; /* Byte 20 */
- unsigned char SimultaneousDeviceSpinUpCount; /* Byte 21 */
- unsigned char SecondsDelayBetweenSpinUps; /* Byte 22 */
- unsigned char Reserved1[29]; /* Bytes 23-51 */
- boolean BIOSDisabled:1; /* Byte 52 Bit 0 */
- boolean CDROMBootEnabled:1; /* Byte 52 Bit 1 */
- unsigned char :3; /* Byte 52 Bits 2-4 */
- enum {
- DAC960_Geometry_128_32 = 0x00,
- DAC960_Geometry_255_63 = 0x01,
- DAC960_Geometry_Reserved1 = 0x02,
- DAC960_Geometry_Reserved2 = 0x03
- } __attribute__ ((packed)) DriveGeometry:2; /* Byte 52 Bits 5-6 */
- unsigned char :1; /* Byte 52 Bit 7 */
- unsigned char Reserved2[9]; /* Bytes 53-61 */
- unsigned short Checksum; /* Bytes 62-63 */
-}
-DAC960_Config2_T;
-
-
-/*
- Define the Scatter/Gather List Type 1 32 Bit Address 32 Bit Byte Count
- structure.
-*/
-
-typedef struct DAC960_ScatterGatherSegment
-{
- DAC960_BusAddress_T SegmentDataPointer; /* Bytes 0-3 */
- DAC960_ByteCount_T SegmentByteCount; /* Bytes 4-7 */
-}
-DAC960_ScatterGatherSegment_T;
-
-
-/*
- Define the 13 Byte DAC960 Command Mailbox structure. Bytes 13-15 are
- not used. The Command Mailbox structure is padded to 16 bytes for
- efficient access.
-*/
-
-typedef union DAC960_CommandMailbox
-{
- unsigned int Words[4]; /* Words 0-3 */
- unsigned char Bytes[16]; /* Bytes 0-15 */
- struct {
- DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */
- DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
- unsigned char Dummy[14]; /* Bytes 2-15 */
- } __attribute__ ((packed)) Common;
- struct {
- DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */
- DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
- unsigned char Dummy1[6]; /* Bytes 2-7 */
- DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */
- unsigned char Dummy2[4]; /* Bytes 12-15 */
- } __attribute__ ((packed)) Type3;
- struct {
- DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */
- DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
- unsigned char Dummy1[5]; /* Bytes 2-6 */
- unsigned char LogicalDriveNumber:6; /* Byte 7 Bits 0-6 */
- boolean AutoRestore:1; /* Byte 7 Bit 7 */
- unsigned char Dummy2[8]; /* Bytes 8-15 */
- } __attribute__ ((packed)) Type3C;
- struct {
- DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */
- DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
- unsigned char Channel; /* Byte 2 */
- unsigned char TargetID; /* Byte 3 */
- DAC960_PhysicalDeviceState_T DeviceState:5; /* Byte 4 Bits 0-4 */
- unsigned char Modifier:3; /* Byte 4 Bits 5-7 */
- unsigned char Dummy1[3]; /* Bytes 5-7 */
- DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */
- unsigned char Dummy2[4]; /* Bytes 12-15 */
- } __attribute__ ((packed)) Type3D;
- struct {
- DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */
- DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
- DAC960_PerformEventLogOpType_T OperationType; /* Byte 2 */
- unsigned char OperationQualifier; /* Byte 3 */
- unsigned short SequenceNumber; /* Bytes 4-5 */
- unsigned char Dummy1[2]; /* Bytes 6-7 */
- DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */
- unsigned char Dummy2[4]; /* Bytes 12-15 */
- } __attribute__ ((packed)) Type3E;
- struct {
- DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */
- DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
- unsigned char Dummy1[2]; /* Bytes 2-3 */
- unsigned char RebuildRateConstant; /* Byte 4 */
- unsigned char Dummy2[3]; /* Bytes 5-7 */
- DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */
- unsigned char Dummy3[4]; /* Bytes 12-15 */
- } __attribute__ ((packed)) Type3R;
- struct {
- DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */
- DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
- struct {
- unsigned short TransferLength:11; /* Bytes 2-3 */
- unsigned char LogicalDriveNumber:5; /* Byte 3 Bits 3-7 */
- } __attribute__ ((packed)) LD;
- unsigned int LogicalBlockAddress; /* Bytes 4-7 */
- DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */
- unsigned char ScatterGatherCount:6; /* Byte 12 Bits 0-5 */
- enum {
- DAC960_ScatterGather_32BitAddress_32BitByteCount = 0x0,
- DAC960_ScatterGather_32BitAddress_16BitByteCount = 0x1,
- DAC960_ScatterGather_32BitByteCount_32BitAddress = 0x2,
- DAC960_ScatterGather_16BitByteCount_32BitAddress = 0x3
- } __attribute__ ((packed)) ScatterGatherType:2; /* Byte 12 Bits 6-7 */
- unsigned char Dummy[3]; /* Bytes 13-15 */
- } __attribute__ ((packed)) Type5;
- struct {
- DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */
- DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
- unsigned char CommandOpcode2; /* Byte 2 */
- unsigned char :8; /* Byte 3 */
- DAC960_BusAddress_T CommandMailboxesBusAddress; /* Bytes 4-7 */
- DAC960_BusAddress_T StatusMailboxesBusAddress; /* Bytes 8-11 */
- unsigned char Dummy[4]; /* Bytes 12-15 */
- } __attribute__ ((packed)) TypeX;
-}
-DAC960_CommandMailbox_T;
-
-
-/*
- Define the DAC960 Controller Status Mailbox structure.
-*/
-
-typedef union DAC960_StatusMailbox
-{
- unsigned int Word; /* Bytes 0-3 */
- struct {
- DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 0 */
- unsigned char :7; /* Byte 1 Bits 0-6 */
- boolean Valid:1; /* Byte 1 Bit 7 */
- DAC960_CommandStatus_T CommandStatus; /* Bytes 2-3 */
- } Fields;
-}
-DAC960_StatusMailbox_T;
-
-
-/*
- Define the DAC960 Driver Command Types.
-*/
-
-typedef enum
-{
- DAC960_ReadCommand = 1,
- DAC960_WriteCommand = 2,
- DAC960_ReadRetryCommand = 3,
- DAC960_WriteRetryCommand = 4,
- DAC960_MonitoringCommand = 5,
- DAC960_ImmediateCommand = 6
-}
-DAC960_CommandType_T;
-
-
-/*
- Define the DAC960 Driver Command structure.
-*/
-
-typedef struct DAC960_Command
-{
- DAC960_CommandType_T CommandType;
- DAC960_CommandMailbox_T CommandMailbox;
- DAC960_CommandStatus_T CommandStatus;
- struct DAC960_Controller *Controller;
- struct DAC960_Command *Next;
- Semaphore_T *Semaphore;
- unsigned int LogicalDriveNumber;
- unsigned int BlockNumber;
- unsigned int BlockCount;
- unsigned int SegmentCount;
- BufferHeader_T *BufferHeader;
- DAC960_ScatterGatherSegment_T
- ScatterGatherList[DAC960_MaxScatterGatherSegments];
-}
-DAC960_Command_T;
-
-
-/*
- Define the DAC960 Driver Controller structure.
-*/
-
-typedef struct DAC960_Controller
-{
- void *BaseAddress;
- void *MemoryMappedAddress;
- DAC960_ControllerType_T ControllerType;
- DAC960_IO_Address_T IO_Address;
- DAC960_PCI_Address_T PCI_Address;
- unsigned char ControllerNumber;
- unsigned char ControllerName[4];
- unsigned char ModelName[12];
- unsigned char FullModelName[18];
- unsigned char FirmwareVersion[14];
- unsigned char Bus;
- unsigned char Device;
- unsigned char Function;
- unsigned char IRQ_Channel;
- unsigned char Channels;
- unsigned char MemorySize;
- unsigned char LogicalDriveCount;
- unsigned char GeometryTranslationHeads;
- unsigned char GeometryTranslationSectors;
- unsigned short ControllerQueueDepth;
- unsigned short DriverQueueDepth;
- unsigned short MaxBlocksPerCommand;
- unsigned short MaxScatterGatherSegments;
- unsigned short StripeSize;
- unsigned short SegmentSize;
- unsigned short NewEventLogSequenceNumber;
- unsigned short OldEventLogSequenceNumber;
- unsigned short InitialStatusLength;
- unsigned short CurrentStatusLength;
- unsigned short UserStatusLength;
- unsigned short RebuildProgressLength;
- unsigned int ControllerUsageCount;
- unsigned int EnquiryIndex;
- unsigned int LogicalDriveInformationIndex;
- unsigned int ErrorTableIndex;
- unsigned int DeviceStateIndex;
- unsigned int DeviceStateChannel;
- unsigned int DeviceStateTargetID;
- unsigned long MonitoringTimerCount;
- unsigned long SecondaryMonitoringTime;
- unsigned long LastProgressReportTime;
- boolean DualModeMemoryMailboxInterface;
- boolean SAFTE_FaultManagementEnabled;
- boolean ControllerInitialized;
- boolean UserCommandActive;
- boolean UserCommandDeferred;
- boolean MonitoringCommandDeferred;
- boolean NeedLogicalDriveInformation;
- boolean NeedErrorTableInformation;
- boolean NeedDeviceStateInformation;
- boolean NeedRebuildProgress;
- boolean NeedConsistencyCheckProgress;
- boolean EphemeralProgressMessage;
- Timer_T MonitoringTimer;
- Semaphore_T *UserCommandSemaphore;
- GenericDiskInfo_T GenericDiskInfo;
- DAC960_Command_T *FreeCommands;
- DAC960_Command_T *UserCommand;
- DAC960_CommandMailbox_T *FirstCommandMailbox;
- DAC960_CommandMailbox_T *LastCommandMailbox;
- DAC960_CommandMailbox_T *NextCommandMailbox;
- DAC960_CommandMailbox_T *PreviousCommandMailbox1;
- DAC960_CommandMailbox_T *PreviousCommandMailbox2;
- DAC960_StatusMailbox_T *FirstStatusMailbox;
- DAC960_StatusMailbox_T *LastStatusMailbox;
- DAC960_StatusMailbox_T *NextStatusMailbox;
- PROC_DirectoryEntry_T ControllerProcEntry;
- PROC_DirectoryEntry_T InitialStatusProcEntry;
- PROC_DirectoryEntry_T CurrentStatusProcEntry;
- PROC_DirectoryEntry_T UserCommandProcEntry;
- WaitQueue_T *CommandWaitQueue;
- DAC960_Enquiry_T Enquiry[2];
- DAC960_ErrorTable_T ErrorTable[2];
- DAC960_EventLogEntry_T EventLogEntry;
- DAC960_RebuildProgress_T RebuildProgress;
- DAC960_LogicalDriveInformation_T
- LogicalDriveInformation[2][DAC960_MaxLogicalDrives];
- DAC960_LogicalDriveState_T LogicalDriveInitialState[DAC960_MaxLogicalDrives];
- DAC960_DeviceState_T DeviceState[2][DAC960_MaxChannels][DAC960_MaxTargets];
- DAC960_Command_T Commands[DAC960_MaxDriverQueueDepth];
- DiskPartition_T DiskPartitions[DAC960_MinorCount];
- int LogicalDriveUsageCount[DAC960_MaxLogicalDrives];
- int PartitionSizes[DAC960_MinorCount];
- int BlockSizes[DAC960_MinorCount];
- int MaxSectorsPerRequest[DAC960_MinorCount];
- int MaxSegmentsPerRequest[DAC960_MinorCount];
- char InitialStatusBuffer[DAC960_StatusBufferSize];
- char CurrentStatusBuffer[DAC960_StatusBufferSize];
- char UserStatusBuffer[DAC960_UserMessageSize];
- char RebuildProgressBuffer[DAC960_RebuildProgressSize];
-}
-DAC960_Controller_T;
-
-
-/*
- DAC960_AcquireControllerLock acquires exclusive access to Controller.
-*/
-
-static inline
-void DAC960_AcquireControllerLock(DAC960_Controller_T *Controller,
- ProcessorFlags_T *ProcessorFlags)
-{
- save_flags(*ProcessorFlags);
- cli();
-}
-
-
-/*
- DAC960_ReleaseControllerLock releases exclusive access to Controller.
-*/
-
-static inline
-void DAC960_ReleaseControllerLock(DAC960_Controller_T *Controller,
- ProcessorFlags_T *ProcessorFlags)
-{
- restore_flags(*ProcessorFlags);
-}
-
-
-/*
- DAC960_AcquireControllerLockRF acquires exclusive access to Controller,
- but is only called from the request function when interrupts are disabled.
-*/
-
-static inline
-void DAC960_AcquireControllerLockRF(DAC960_Controller_T *Controller,
- ProcessorFlags_T *ProcessorFlags)
-{
-}
-
-
-/*
- DAC960_ReleaseControllerLockRF releases exclusive access to Controller,
- but is only called from the request function when interrupts are disabled.
-*/
-
-static inline
-void DAC960_ReleaseControllerLockRF(DAC960_Controller_T *Controller,
- ProcessorFlags_T *ProcessorFlags)
-{
-}
-
-
-/*
- DAC960_AcquireControllerLockIH acquires exclusive access to Controller,
- but is only called from the interrupt handler when interrupts are disabled.
-*/
-
-static inline
-void DAC960_AcquireControllerLockIH(DAC960_Controller_T *Controller,
- ProcessorFlags_T *ProcessorFlags)
-{
-}
-
-
-/*
- DAC960_ReleaseControllerLockIH releases exclusive access to Controller,
- but is only called from the interrupt handler when interrupts are disabled.
-*/
-
-static inline
-void DAC960_ReleaseControllerLockIH(DAC960_Controller_T *Controller,
- ProcessorFlags_T *ProcessorFlags)
-{
-}
-
-
-/*
- Define inline functions to provide an abstraction for reading and writing the
- DAC960 V5 Controller Interface Registers.
-*/
-
-static inline
-void DAC960_V5_HardwareMailboxNewCommand(void *ControllerBaseAddress)
-{
- DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_V5_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress)
-{
- DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_V5_GenerateInterrupt(void *ControllerBaseAddress)
-{
- DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.GenerateInterrupt = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_V5_ControllerReset(void *ControllerBaseAddress)
-{
- DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.ControllerReset = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_V5_MemoryMailboxNewCommand(void *ControllerBaseAddress)
-{
- DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset);
-}
-
-static inline
-boolean DAC960_V5_HardwareMailboxEmptyP(void *ControllerBaseAddress)
-{
- DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All =
- readb(ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset);
- return InboundDoorBellRegister.Read.HardwareMailboxEmpty;
-}
-
-static inline
-void DAC960_V5_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress)
-{
- DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
- writeb(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_V5_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress)
-{
- DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
- writeb(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_V5_AcknowledgeInterrupt(void *ControllerBaseAddress)
-{
- DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
- OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
- writeb(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset);
-}
-
-static inline
-boolean DAC960_V5_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress)
-{
- DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All =
- readb(ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset);
- return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable;
-}
-
-static inline
-boolean DAC960_V5_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress)
-{
- DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All =
- readb(ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset);
- return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable;
-}
-
-static inline
-void DAC960_V5_EnableInterrupts(void *ControllerBaseAddress)
-{
- DAC960_V5_InterruptMaskRegister_T InterruptMaskRegister;
- InterruptMaskRegister.All = 0;
- InterruptMaskRegister.Bits.DisableInterrupts = false;
- writeb(InterruptMaskRegister.All,
- ControllerBaseAddress + DAC960_V5_InterruptMaskRegisterOffset);
-}
-
-static inline
-void DAC960_V5_DisableInterrupts(void *ControllerBaseAddress)
-{
- DAC960_V5_InterruptMaskRegister_T InterruptMaskRegister;
- InterruptMaskRegister.All = 0;
- InterruptMaskRegister.Bits.DisableInterrupts = true;
- writeb(InterruptMaskRegister.All,
- ControllerBaseAddress + DAC960_V5_InterruptMaskRegisterOffset);
-}
-
-static inline
-boolean DAC960_V5_InterruptsEnabledP(void *ControllerBaseAddress)
-{
- DAC960_V5_InterruptMaskRegister_T InterruptMaskRegister;
- InterruptMaskRegister.All =
- readb(ControllerBaseAddress + DAC960_V5_InterruptMaskRegisterOffset);
- return !InterruptMaskRegister.Bits.DisableInterrupts;
-}
-
-static inline
-void DAC960_V5_WriteCommandMailbox(DAC960_CommandMailbox_T *NextCommandMailbox,
- DAC960_CommandMailbox_T *CommandMailbox)
-{
- NextCommandMailbox->Words[1] = CommandMailbox->Words[1];
- NextCommandMailbox->Words[2] = CommandMailbox->Words[2];
- NextCommandMailbox->Words[3] = CommandMailbox->Words[3];
- NextCommandMailbox->Words[0] = CommandMailbox->Words[0];
-}
-
-static inline
-void DAC960_V5_WriteHardwareMailbox(void *ControllerBaseAddress,
- DAC960_CommandMailbox_T *CommandMailbox)
-{
- writel(CommandMailbox->Words[0],
- ControllerBaseAddress + DAC960_V5_CommandOpcodeRegisterOffset);
- writel(CommandMailbox->Words[1],
- ControllerBaseAddress + DAC960_V5_MailboxRegister4Offset);
- writel(CommandMailbox->Words[2],
- ControllerBaseAddress + DAC960_V5_MailboxRegister8Offset);
- writeb(CommandMailbox->Bytes[12],
- ControllerBaseAddress + DAC960_V5_MailboxRegister12Offset);
-}
-
-static inline DAC960_CommandIdentifier_T
-DAC960_V5_ReadStatusCommandIdentifier(void *ControllerBaseAddress)
-{
- return readb(ControllerBaseAddress
- + DAC960_V5_StatusCommandIdentifierRegOffset);
-}
-
-static inline DAC960_CommandStatus_T
-DAC960_V5_ReadStatusRegister(void *ControllerBaseAddress)
-{
- return readw(ControllerBaseAddress + DAC960_V5_StatusRegisterOffset);
-}
-
-static inline
-void DAC960_V5_SaveMemoryMailboxInfo(DAC960_Controller_T *Controller)
-{
- void *ControllerBaseAddress = Controller->BaseAddress;
- writel(0x743C485E,
- ControllerBaseAddress + DAC960_V5_CommandOpcodeRegisterOffset);
- writel((unsigned long) Controller->FirstCommandMailbox,
- ControllerBaseAddress + DAC960_V5_MailboxRegister4Offset);
- writew(Controller->NextCommandMailbox - Controller->FirstCommandMailbox,
- ControllerBaseAddress + DAC960_V5_MailboxRegister8Offset);
- writew(Controller->NextStatusMailbox - Controller->FirstStatusMailbox,
- ControllerBaseAddress + DAC960_V5_MailboxRegister10Offset);
-}
-
-static inline
-void DAC960_V5_RestoreMemoryMailboxInfo(DAC960_Controller_T *Controller,
- void **MemoryMailboxAddress,
- short *NextCommandMailboxIndex,
- short *NextStatusMailboxIndex)
-{
- void *ControllerBaseAddress = Controller->BaseAddress;
- if (readl(ControllerBaseAddress
- + DAC960_V5_CommandOpcodeRegisterOffset) != 0x743C485E)
- return;
- *MemoryMailboxAddress =
- (void *) readl(ControllerBaseAddress + DAC960_V5_MailboxRegister4Offset);
- *NextCommandMailboxIndex =
- readw(ControllerBaseAddress + DAC960_V5_MailboxRegister8Offset);
- *NextStatusMailboxIndex =
- readw(ControllerBaseAddress + DAC960_V5_MailboxRegister10Offset);
-}
-
-
-/*
- Define inline functions to provide an abstraction for reading and writing the
- DAC960 V4 Controller Interface Registers.
-*/
-
-static inline
-void DAC960_V4_HardwareMailboxNewCommand(void *ControllerBaseAddress)
-{
- DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true;
- writel(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_V4_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress)
-{
- DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true;
- writel(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_V4_GenerateInterrupt(void *ControllerBaseAddress)
-{
- DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.GenerateInterrupt = true;
- writel(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_V4_ControllerReset(void *ControllerBaseAddress)
-{
- DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.ControllerReset = true;
- writel(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_V4_MemoryMailboxNewCommand(void *ControllerBaseAddress)
-{
- DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true;
- writel(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
-}
-
-static inline
-boolean DAC960_V4_HardwareMailboxFullP(void *ControllerBaseAddress)
-{
- DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All =
- readl(ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
- return InboundDoorBellRegister.Read.HardwareMailboxFull;
-}
-
-static inline
-void DAC960_V4_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress)
-{
- DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
- writel(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_V4_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress)
-{
- DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
- writel(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_V4_AcknowledgeInterrupt(void *ControllerBaseAddress)
-{
- DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
- OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
- writel(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset);
-}
-
-static inline
-boolean DAC960_V4_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress)
-{
- DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All =
- readl(ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset);
- return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable;
-}
-
-static inline
-boolean DAC960_V4_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress)
-{
- DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All =
- readl(ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset);
- return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable;
-}
-
-static inline
-void DAC960_V4_EnableInterrupts(void *ControllerBaseAddress)
-{
- DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister;
- InterruptMaskRegister.All = 0;
- InterruptMaskRegister.Bits.MessageUnitInterruptMask1 = 0x3;
- InterruptMaskRegister.Bits.DisableInterrupts = false;
- InterruptMaskRegister.Bits.MessageUnitInterruptMask2 = 0x1F;
- writel(InterruptMaskRegister.All,
- ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset);
-}
-
-static inline
-void DAC960_V4_DisableInterrupts(void *ControllerBaseAddress)
-{
- DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister;
- InterruptMaskRegister.All = 0;
- InterruptMaskRegister.Bits.MessageUnitInterruptMask1 = 0x3;
- InterruptMaskRegister.Bits.DisableInterrupts = true;
- InterruptMaskRegister.Bits.MessageUnitInterruptMask2 = 0x1F;
- writel(InterruptMaskRegister.All,
- ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset);
-}
-
-static inline
-boolean DAC960_V4_InterruptsEnabledP(void *ControllerBaseAddress)
-{
- DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister;
- InterruptMaskRegister.All =
- readl(ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset);
- return !InterruptMaskRegister.Bits.DisableInterrupts;
-}
-
-static inline
-void DAC960_V4_WriteCommandMailbox(DAC960_CommandMailbox_T *NextCommandMailbox,
- DAC960_CommandMailbox_T *CommandMailbox)
-{
- NextCommandMailbox->Words[1] = CommandMailbox->Words[1];
- NextCommandMailbox->Words[2] = CommandMailbox->Words[2];
- NextCommandMailbox->Words[3] = CommandMailbox->Words[3];
- NextCommandMailbox->Words[0] = CommandMailbox->Words[0];
-}
-
-static inline
-void DAC960_V4_WriteHardwareMailbox(void *ControllerBaseAddress,
- DAC960_CommandMailbox_T *CommandMailbox)
-{
- writel(CommandMailbox->Words[0],
- ControllerBaseAddress + DAC960_V4_CommandOpcodeRegisterOffset);
- writel(CommandMailbox->Words[1],
- ControllerBaseAddress + DAC960_V4_MailboxRegister4Offset);
- writel(CommandMailbox->Words[2],
- ControllerBaseAddress + DAC960_V4_MailboxRegister8Offset);
- writeb(CommandMailbox->Bytes[12],
- ControllerBaseAddress + DAC960_V4_MailboxRegister12Offset);
-}
-
-static inline DAC960_CommandIdentifier_T
-DAC960_V4_ReadStatusCommandIdentifier(void *ControllerBaseAddress)
-{
- return readb(ControllerBaseAddress
- + DAC960_V4_StatusCommandIdentifierRegOffset);
-}
-
-static inline DAC960_CommandStatus_T
-DAC960_V4_ReadStatusRegister(void *ControllerBaseAddress)
-{
- return readw(ControllerBaseAddress + DAC960_V4_StatusRegisterOffset);
-}
-
-static inline
-void DAC960_V4_SaveMemoryMailboxInfo(DAC960_Controller_T *Controller)
-{
- void *ControllerBaseAddress = Controller->BaseAddress;
- writel(0xAABBFFFF,
- ControllerBaseAddress + DAC960_V4_CommandOpcodeRegisterOffset);
- writel((unsigned long) Controller->FirstCommandMailbox,
- ControllerBaseAddress + DAC960_V4_MailboxRegister4Offset);
- writew(Controller->NextCommandMailbox - Controller->FirstCommandMailbox,
- ControllerBaseAddress + DAC960_V4_MailboxRegister8Offset);
- writew(Controller->NextStatusMailbox - Controller->FirstStatusMailbox,
- ControllerBaseAddress + DAC960_V4_MailboxRegister10Offset);
-}
-
-static inline
-void DAC960_V4_RestoreMemoryMailboxInfo(DAC960_Controller_T *Controller,
- void **MemoryMailboxAddress,
- short *NextCommandMailboxIndex,
- short *NextStatusMailboxIndex)
-{
- void *ControllerBaseAddress = Controller->BaseAddress;
- if (readl(ControllerBaseAddress
- + DAC960_V4_CommandOpcodeRegisterOffset) != 0xAABBFFFF)
- return;
- *MemoryMailboxAddress =
- (void *) readl(ControllerBaseAddress + DAC960_V4_MailboxRegister4Offset);
- *NextCommandMailboxIndex =
- readw(ControllerBaseAddress + DAC960_V4_MailboxRegister8Offset);
- *NextStatusMailboxIndex =
- readw(ControllerBaseAddress + DAC960_V4_MailboxRegister10Offset);
-}
-
-
-/*
- Define inline functions to provide an abstraction for reading and writing the
- DAC960 V3 Controller Interface Registers.
-*/
-
-static inline
-void DAC960_V3_NewCommand(void *ControllerBaseAddress)
-{
- DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.NewCommand = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_V3_AcknowledgeStatus(void *ControllerBaseAddress)
-{
- DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.AcknowledgeStatus = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_V3_GenerateInterrupt(void *ControllerBaseAddress)
-{
- DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.GenerateInterrupt = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_V3_ControllerReset(void *ControllerBaseAddress)
-{
- DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.ControllerReset = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
-}
-
-static inline
-boolean DAC960_V3_MailboxFullP(void *ControllerBaseAddress)
-{
- DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All =
- readb(ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
- return InboundDoorBellRegister.Read.MailboxFull;
-}
-
-static inline
-void DAC960_V3_AcknowledgeInterrupt(void *ControllerBaseAddress)
-{
- DAC960_V3_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeInterrupt = true;
- writeb(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_V3_OutboundDoorBellRegisterOffset);
-}
-
-static inline
-boolean DAC960_V3_StatusAvailableP(void *ControllerBaseAddress)
-{
- DAC960_V3_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All =
- readb(ControllerBaseAddress + DAC960_V3_OutboundDoorBellRegisterOffset);
- return OutboundDoorBellRegister.Read.StatusAvailable;
-}
-
-static inline
-void DAC960_V3_EnableInterrupts(void *ControllerBaseAddress)
-{
- DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister;
- InterruptEnableRegister.All = 0;
- InterruptEnableRegister.Bits.EnableInterrupts = true;
- writeb(InterruptEnableRegister.All,
- ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset);
-}
-
-static inline
-void DAC960_V3_DisableInterrupts(void *ControllerBaseAddress)
-{
- DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister;
- InterruptEnableRegister.All = 0;
- InterruptEnableRegister.Bits.EnableInterrupts = false;
- writeb(InterruptEnableRegister.All,
- ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset);
-}
-
-static inline
-boolean DAC960_V3_InterruptsEnabledP(void *ControllerBaseAddress)
-{
- DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister;
- InterruptEnableRegister.All =
- readb(ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset);
- return InterruptEnableRegister.Bits.EnableInterrupts;
-}
-
-static inline
-void DAC960_V3_WriteCommandMailbox(void *ControllerBaseAddress,
- DAC960_CommandMailbox_T *CommandMailbox)
-{
- writel(CommandMailbox->Words[0],
- ControllerBaseAddress + DAC960_V3_CommandOpcodeRegisterOffset);
- writel(CommandMailbox->Words[1],
- ControllerBaseAddress + DAC960_V3_MailboxRegister4Offset);
- writel(CommandMailbox->Words[2],
- ControllerBaseAddress + DAC960_V3_MailboxRegister8Offset);
- writeb(CommandMailbox->Bytes[12],
- ControllerBaseAddress + DAC960_V3_MailboxRegister12Offset);
-}
-
-static inline DAC960_CommandIdentifier_T
-DAC960_V3_ReadStatusCommandIdentifier(void *ControllerBaseAddress)
-{
- return readb(ControllerBaseAddress
- + DAC960_V3_StatusCommandIdentifierRegOffset);
-}
-
-static inline DAC960_CommandStatus_T
-DAC960_V3_ReadStatusRegister(void *ControllerBaseAddress)
-{
- return readw(ControllerBaseAddress + DAC960_V3_StatusRegisterOffset);
-}
-
-
-/*
- Virtual_to_Bus and Bus_to_Virtual map between Kernel Virtual Addresses
- and PCI Bus Addresses.
-*/
-
-static inline DAC960_BusAddress_T Virtual_to_Bus(void *VirtualAddress)
-{
- return (DAC960_BusAddress_T) virt_to_bus(VirtualAddress);
-}
-
-static inline void *Bus_to_Virtual(DAC960_BusAddress_T BusAddress)
-{
- return (void *) bus_to_virt(BusAddress);
-}
-
-
-/*
- Define compatibility macros between Linux 2.0 and Linux 2.1.
-*/
-
-#if LINUX_VERSION_CODE < 0x20100
-
-#define MODULE_PARM(Variable, Type)
-#define ioremap_nocache(Offset, Size) vremap(Offset, Size)
-#define iounmap(Address) vfree(Address)
-
-#endif
-
-
-/*
- Define prototypes for the forward referenced DAC960 Driver Internal Functions.
-*/
-
-static void DAC960_FinalizeController(DAC960_Controller_T *);
-static void DAC960_RequestFunction0(void);
-static void DAC960_RequestFunction1(void);
-static void DAC960_RequestFunction2(void);
-static void DAC960_RequestFunction3(void);
-static void DAC960_RequestFunction4(void);
-static void DAC960_RequestFunction5(void);
-static void DAC960_RequestFunction6(void);
-static void DAC960_RequestFunction7(void);
-static void DAC960_InterruptHandler(int, void *, Registers_T *);
-static void DAC960_QueueMonitoringCommand(DAC960_Command_T *);
-static void DAC960_MonitoringTimerFunction(unsigned long);
-static int DAC960_Open(Inode_T *, File_T *);
-static void DAC960_Release(Inode_T *, File_T *);
-static int DAC960_Ioctl(Inode_T *, File_T *, unsigned int, unsigned long);
-static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *);
-static void DAC960_Message(DAC960_MessageLevel_T, char *,
- DAC960_Controller_T *, ...);
-static void DAC960_CreateProcEntries(void);
-static void DAC960_DestroyProcEntries(void);
-
-
-#endif /* DAC960_DriverVersion */
unsigned long newbrk, oldbrk;
struct mm_struct *mm = current->mm;
+ down(&mm->mmap_sem);
+
if (brk < mm->end_code)
- return mm->brk;
+ goto out;
newbrk = PAGE_ALIGN(brk);
oldbrk = PAGE_ALIGN(mm->brk);
if (oldbrk == newbrk)
- return mm->brk = brk;
+ goto set_brk;
/*
* Always allow shrinking brk
*/
if (brk <= mm->brk) {
- mm->brk = brk;
do_munmap(newbrk, oldbrk-newbrk);
- return brk;
+ goto set_brk;
}
/*
* Check against rlimit and stack..
if (rlim >= RLIM_INFINITY)
rlim = ~0;
if (brk - mm->end_code > rlim)
- return mm->brk;
+ goto out;
/*
* Check against existing mmap mappings.
*/
if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE))
- return mm->brk;
+ goto out;
/*
* Check if we have enough memory..
*/
if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT))
- return mm->brk;
+ goto out;
/*
* Ok, looks good - let it rip.
if(do_mmap(NULL, oldbrk, newbrk-oldbrk,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE, 0) != oldbrk)
- return mm->brk;
- return mm->brk = brk;
+ goto out;
+set_brk:
+ mm->brk = brk;
+out:
+ up(&mm->mmap_sem);
+ return mm->brk;
}
/*
asmlinkage int sys_munmap(unsigned long addr, size_t len)
{
- return do_munmap(addr, len);
+ int ret;
+
+ down(¤t->mm->mmap_sem);
+ ret = do_munmap(addr, len);
+ up(¤t->mm->mmap_sem);
+ return ret;
}
/*
int do_munmap(unsigned long addr, size_t len)
{
struct vm_area_struct *mpnt, *prev, *next, **npp, *free;
-
+
if ((addr & ~PAGE_MASK) || addr > MAX_USER_ADDR || len > MAX_USER_ADDR-addr)
return -EINVAL;
} while (free);
/* we could zap the page tables here too.. */
-
return 0;
}
{
struct vm_area_struct *prev, *mpnt, *next;
- down(&mm->mmap_sem);
mpnt = find_vma(mm, start_addr);
if (!mpnt)
- goto no_vma;
+ return;
avl_neighbours(mpnt, mm->mmap_avl, &prev, &next);
/* we have prev->vm_next == mpnt && mpnt->vm_next = next */
kfree_s(mpnt, sizeof(*mpnt));
mpnt = prev;
}
-no_vma:
- up(&mm->mmap_sem);
}
if(active_map&(1<<unit))
return -EBUSY;
active_map|=(1<<unit);
+ open_map&=~(1<<unit);
netlink_handler[unit]=function;
return 0;
}
{
active_map&=~(1<<unit);
netlink_handler[unit]=netlink_err;
+ open_map&=~(1<<unit);
}
int netlink_post(int unit, struct sk_buff *skb)
X(ip_id_count),
X(ip_send_check),
X(ip_forward),
+ X(ip_queue_xmit),
+ X(ip_fragment),
X(sysctl_ip_forward),
#if defined(CONFIG_ULTRA) || defined(CONFIG_WD80x3) || \