say M here and read Documentation/modules.txt. This is recommended.
The module will be called myri_sbus.o.
+D-Link 2000-based Gigabit Ethernet support
+CONFIG_DL2K
+ This driver supports D-Link 2000-based gigabit ethernet cards, which
+ includes
+ D-Link DGE-550T Gigabit Ethernet Adapter.
+ D-Link DL2000-based Gigabit Ethernet Adapter.
+
+ If you want to compile this driver as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want),
+ say M here and read Documentation/modules.txt. This is recommended.
+ The module will be called dl2k.o.
+
AMD LANCE and PCnet (AT1500 and NE2100) support
CONFIG_LANCE
If you have a network (Ethernet) card of this type, say Y and read
BOOKS := wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \
kernel-api.sgml parportbook.sgml kernel-hacking.sgml \
kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \
- deviceiobook.sgml procfs-guide.sgml
+ deviceiobook.sgml procfs-guide.sgml tulip-user.sgml
PS := $(patsubst %.sgml, %.ps, $(BOOKS))
PDF := $(patsubst %.sgml, %.pdf, $(BOOKS))
$(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/sound/via82cxxx_audio.c \
<via-audio.tmpl >via-audio.sgml
+tulip-user.sgml: tulip-user.tmpl
+ $(TOPDIR)/scripts/docgen <$< >$@
+
sis900.sgml: sis900.tmpl $(TOPDIR)/drivers/net/sis900.c
$(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/net/sis900.c \
<sis900.tmpl >sis900.sgml
</authorgroup>
<copyright>
- <year>2000</year>
+ <year>1999-2001</year>
<holder>Jeff Garzik</holder>
</copyright>
<title>Known Bugs And Assumptions</title>
<para>
<variablelist>
- <varlistentry><term>MMAP support</term>
- <listitem>
- <para>
- MMAP support is currently missing. Make sure to
- test with Quake.
- </para>
- </listitem></varlistentry>
-
- <varlistentry><term>AC97 codec timeout during init</term>
- <listitem>
- <para>
- A warning message "via82cxxx: timeout while reading AC97
- codec" is printed during driver initialization. This
- message can safely be ignored.
- </para>
- </listitem></varlistentry>
-
<varlistentry><term>Low volume</term>
<listitem>
<para>
<para>
AC97 mixer interface fixes and debugging by Ron Cemer <email>roncemer@gte.net</email>.
</para>
+ <para>
+ Rui Sousa <email>rui.sousa@conexant.com</email>, for bugfixing
+ MMAP support, and several other notable fixes that resulted from
+ his hard work and testing.
+ </para>
+ <para>
+ Adrian Cox <email>adrian@humboldt.co.uk</email>, for bugfixing
+ MMAP support, and several other notable fixes that resulted from
+ his hard work and testing.
+ </para>
</chapter>
<chapter id="notes">
and device ids are not examined.
</para>
<para>
- GNU indent formatting options: -kr -i8 -pcs
+ GNU indent formatting options:
+ <programlisting>
+-kr -i8 -ts8 -br -ce -bap -sob -l80 -pcs -cs -ss -bs -di1 -nbc -lp -psl
+ </programlisting>
</para>
<para>
Via has graciously donated e-mail support and source code to help further
<chapter id="changelog">
<title>Driver ChangeLog</title>
+<sect1 id="version1115"><title>
+Version 1.1.15
+</title>
+ <itemizedlist spacing=compact>
+ <listitem>
+ <para>
+ Support for variable fragment size and variable fragment number (Rui
+ Sousa)
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Fixes for the SPEED, STEREO, CHANNELS, FMT ioctls when in read &
+ write mode (Rui Sousa)
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Mmaped sound is now fully functional. (Rui Sousa)
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Make sure to enable PCI device before reading any of its PCI
+ config information. (fixes potential hotplug problems)
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Clean up code a bit and add more internal function documentation.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ AC97 codec access fixes (Adrian Cox)
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Big endian fixes (Adrian Cox)
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ MIDI support (Adrian Cox)
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Detect and report locked-rate AC97 codecs. If your hardware only
+ supports 48Khz (locked rate), then your recording/playback software
+ must upsample or downsample accordingly. The hardware cannot do it.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Use new pci_request_regions and pci_disable_device functions in
+ kernel 2.4.6.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+</sect1>
+
<sect1 id="version1114"><title>
Version 1.1.14
</title>
Change History
--------------
+Version 0.9.18 - July 6, 2001
+
+* Fix race leading to crashes on some machines.
+* Minimize race leading to low performance.
+* Correct interrupt acknowledgement to cover all three
+ relevant Rx events.
+* Add ethtool driver info support.
+* Collect additional driver-internal statistics.
+* Add descriptions for module parameters.
+* Support new SIOCxMIIxxx ioctls added in kernel 2.4.6.
+* Multicast filter big endian fix.
+* Support new PCI PM API added in kernel 2.4.6.
+
+
Version 0.9.17 - May 7, 2001
* Fix chipset wakeup bug which prevent media connection for 8139B
--- /dev/null
+
+ D-Link DL2000-based Gigabit Ethernet Adapter Installation
+ for Linux
+ July 5, 2001
+
+Contents
+========
+ - Compatibility List
+ - Quick Install
+ - Compiling the Driver
+ - Installing the Driver
+ - Option parameter
+ - Configuration Script Sample
+ - Troubleshooting
+
+
+Compatiblity List
+=================
+Adapter Support:
+
+D-Link DGE-550T Gigabit Ethernet Adapter.
+D-Link DL2000-based Gigabit Ethernet Adapter.
+
+
+The driver support Linux kernal 2.4.x later. We had tested it
+on the environments below.
+
+ . Red Hat v6.2 (update to kernel 2.4.4)
+ . Red Hat v7.0 (update to kernel 2.4.4)
+ . Red Hat v7.1 (kernel 2.4.2-2)
+
+
+Quick Install
+=============
+Install linux driver as following command:
+
+1. make all
+2. insmod dl2x.o
+3. ifconfig eth0 up 10.xxx.xxx.xxx netmask 255.0.0.0
+ ^^^^^^^^^^^^^^^\ ^^^^^^^^\
+ IP NETMASK
+Now eth0 bring up, you can test it by "ping" or get more information by
+"ifconfig". If test ok, then continue next step.
+
+4. cp dl2x.o /lib/modules/`uname -r`/kernel/drivers/net
+5. Add the following lines to /etc/modules.conf:
+ alias eth0 dl2x
+6. Run "netconfig" or "netconf" to create configuration script ifcfg-eth0
+ located at /etc/sysconfig/network-scripts or create it manually.
+ [see - Configuration Script Sample]
+7. Driver will automatically load and configure at next boot time.
+
+Compiling the Driver
+====================
+ In Linux, NIC drivers are most commonly configured as loadable modules.
+The approach of building a monolithic kernel has become obsolete. The driver
+can be compiled as part of a monolithic kernel, but is strongly discouraged.
+The remainder of this section assumes the driver is built as a loadable module.
+In the Linux environment, it is a good idea to rebuild the driver from the
+source instead of relying on a precompiled version. This approach provides
+better reliability since a precompiled driver might depend on libraries or
+kernel features that are not present in a given Linux installation.
+
+The 3 files necessary to build Linux device driver are dl2x.c, dl2x.h and
+Makefile. To compile, the Linux installation must include the gcc compiler,
+the kernel source, and the kernel headers. The Linux driver supports Linux
+Kernels 2.4.x. Copy the files to a directory and enter the following command
+to compile and link the driver:
+
+CD-ROM drive
+------------
+
+[root@XXX /] mkdir cdrom
+[root@XXX /] mount -r -t iso9660 -o conv=auto /dev/cdrom /cdrom
+[root@XXX /] cd root
+[root@XXX /root] mkdir dl2x
+[root@XXX /root] cd dl2x
+[root@XXX dl2x] cp /cdrom/linux/dl2x.tgz /root/dl2x
+[root@XXX dl2x] tar xfvz dl2x.tgz
+[root@XXX dl2x] make all
+
+Floppy disc drive
+-----------------
+
+[root@XXX /] cd root
+[root@XXX /root] mkdir dl2x
+[root@XXX /root] cd dl2x
+[root@XXX dl2x] mcopy a:/linux/dl2x.tgz /root/dl2x
+[root@XXX dl2x] tar xfvz dl2x.tgz
+[root@XXX dl2x] make all
+
+Installing the Driver
+=====================
+
+ Manual Installation
+ -------------------
+ Once the driver has been compiled, it must be loaded, enabled, and bound
+ to a protocol stack in order to establish network connectivity. To load a
+ module enter the command:
+
+ insmod dl2x.o
+
+
+ or
+
+ insmod dl2x.o <optional parameter> ; add parameter
+
+ ===============================================================
+ example: insmod dl2x.o media=100mbps_hd
+ or insmod dl2x.o media=3
+ or insmod dl2x.o media=3 2 ; for 2 cards
+ ===============================================================
+
+ Please reference the list of the command line parameters supported by
+ the Linux device driver below.
+
+ The insmod command only loads the driver and gives it a name of the form
+ eth0, eth1, etc. To bring the NIC into an operational state,
+ it is necessary to issue the following command:
+
+ ifconfig eth0 up
+
+ Finally, to bind the driver to the active protocol (e.g., TCP/IP with
+ Linux), enter the following command:
+
+ ifup eth0
+
+ Note that this is meaningful only if the system can find a configuration
+ script that contains the necessary network information. A sample will be
+ given in the next paragraph.
+
+ The commands to unload a driver are as follows:
+
+ ifdown eth0
+ ifconfig eth0 down
+ rmmod dl2x.o
+
+ The following are the commands to list the currently loaded modules and
+ to see the current network configuration.
+
+ lsmod
+ ifconfig
+
+
+ Automated Installation
+ ----------------------
+ This section describes how to install the driver such that it is
+ automatically loaded and configured at boot time. The following description
+ is based on a Red Hat 6.0/7.0 distribution, but it can easily be ported to
+ other distributions as well.
+
+ Red Hat v6.x/v7.x
+ -----------------
+ 1. Copy dl2x.o to the network modules directory, typically
+ /lib/modules/2.x.x-xx/net or /lib/modules/2.x.x/kernel/drivers/net.
+ 2. Locate the boot module configuration file, most commonly modules.conf
+ or conf.modules in the /etc directory. Add the following lines:
+
+ alias ethx dl2x
+ options dl2x <optional parameters>
+
+ where ethx will be eth0 if the NIC is the only ethernet adapter, eth1 if
+ one other ethernet adapter is installed, etc. Refer to the table in the
+ previous section for the list of optional parameters.
+ 3. Locate the network configuration scripts, normally the
+ /etc/sysconfig/network-scripts directory, and create a configuration
+ script named ifcfg-ethx that contains network information.
+ 4. Note that for most Linux distributions, Red Hat included, a configuration
+ utility with a graphical user interface is provided to perform steps 2
+ and 3 above.
+
+
+Parameter Description
+=====================
+You can install this driver without any addtional parameter. However, if you
+are going to have extensive functions then it is necessary to set extra
+parameter. Below is a list of the command line parameters supported by the
+Linux device
+driver.
+
+mtu=packet_size - Specifies the maximum packet size. default
+ is 1500.
+
+media=xxxxxxxxx - Specifies the media type the NIC operates at.
+ autosense Autosensing active media.
+ 10mbps_hd 10Mbps half duplex.
+ 10mbps_fd 10Mbps full duplex.
+ 100mbps_hd 100Mbps half duplex.
+ 100mbps_fd 100Mbps full duplex.
+ 1000mbps_fd 1000Mbps full duplex.
+ 1000mbps_hd 1000Mbps half duplex.
+ 0 Autosensing active media.
+ 1 10Mbps half duplex.
+ 2 10Mbps full duplex.
+ 3 100Mbps half duplex.
+ 4 100Mbps full duplex.
+ 5 1000Mbps full duplex.
+ 6 1000Mbps half duplex.
+ By default, the NIC operates at autosense.
+
+vlan=x - Specifies the VLAN ID. If vlan=0, the
+ Virtual Local Area Network (VLAN) function is
+ disable.
+
+jumbo=x - Specifies the jumbo frame support. If jumbo=1,
+ the NIC accept jumbo frames. By default, this
+ function is disabled.
+
+Configuration Script Sample
+===========================
+Here is a sample of a simple configuration script:
+
+DEVICE=eth0
+USERCTL=no
+ONBOOT=yes
+POOTPROTO=none
+BROADCAST=207.200.5.255
+NETWORK=207.200.5.0
+NETMASK=255.255.255.0
+IPADDR=207.200.5.2
+
+
+Troubleshooting
+===============
+Q: Couldn't compiler the driver ?
+A1: Copy all necessary files on same current directory. Make sure all files
+ are Unix file format (no LF). You can use some convertible program conver
+ it from DOS to UNIX. (Like dos2unix, UltraEdit-32 ...).
+
+A2: The default include directory configured in Makefile is
+ /usr/src/linux/include. If kernel source was not installed, you could
+ not compile driver. Try to install kernel source, and make sure kernel
+ source in /usr/src/linux. If there is a copy of header files in
+ /usr/include, you can try to change the variable "INCLUDEDIR" in Makefile from
+ /usr/src/linux/include to /usr/include.
+
L: linux-net@vger.kernel.org
S: Maintained
+ACENIC DRIVER
+P: Jes Sorensen
+M: jes@trained-monkey.org
+L: linux-acenic@sunsite.dk
+S: Maintained
+
ACI MIXER DRIVER
P: Robert Siemer
M: Robert.Siemer@gmx.de
HIPPI
P: Jes Sorensen
-M: jes@linuxcare.com
-L: linux-hippi@sunsite.auc.dk
+M: jes@trained-monkey.org
+L: linux-hippi@sunsite.dk
S: Maintained
HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
M68K
P: Jes Sorensen
-M: jes@linuxcare.com
+M: jes@trained-monkey.org
W: http://www.clark.net/pub/lawrencc/linux/index.html
L: linux-m68k@lists.linux-m68k.org
S: Maintained
#
# CONFIG_ACENIC is not set
# CONFIG_ACENIC_OMIT_TIGON_I is not set
+# CONFIG_DL2K is not set
# CONFIG_MYRI_SBUS is not set
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
if (VMPI.vm86dbg_active && VMPI.vm86dbg_TFpendig) \
pushw(ssp,sp,popw(ssp,sp) | TF_MASK);
#define VM86_FAULT_RETURN \
- if (VMPI.force_return_for_pic && (VEFLAGS & IF_MASK)) \
+ if (VMPI.force_return_for_pic && (VEFLAGS & (IF_MASK | VIF_MASK))) \
return_to_32bit(regs, VM86_PICRETURN); \
return;
unsigned int rtas_size;
unsigned int old_rtas;
-/* Set for a newworld machine */
+/* Set for a newworld or CHRP machine */
int use_of_interrupt_tree;
+struct device_node *dflt_interrupt_controller;
+int num_interrupt_controllers;
+
int pmac_newworld;
static struct device_node *allnodes;
*prev_propp = PTRUNRELOC(pp);
prev_propp = &pp->next;
}
- *prev_propp = 0;
+ if (np->node != NULL) {
+ /* Add a "linux,phandle" property" */
+ pp = (struct property *) mem_start;
+ *prev_propp = PTRUNRELOC(pp);
+ prev_propp = &pp->next;
+ namep = (char *) (pp + 1);
+ pp->name = PTRUNRELOC(namep);
+ strcpy(namep, RELOC("linux,phandle"));
+ mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1);
+ pp->value = (unsigned char *) PTRUNRELOC(&np->node);
+ pp->length = sizeof(np->node);
+ }
+ *prev_propp = NULL;
/* get the node's full name */
l = (int) call_prom(RELOC("package-to-path"), 3, 1, node,
finish_device_tree(void)
{
unsigned long mem = (unsigned long) klimit;
+ struct device_node *np;
- /* All newworld machines now use the interrupt tree */
- struct device_node *np = allnodes;
-
- while(np && (_machine == _MACH_Pmac)) {
+ /* All newworld pmac machines and CHRPs now use the interrupt tree */
+ for (np = allnodes; np != NULL; np = np->allnext) {
if (get_property(np, "interrupt-parent", 0)) {
- pmac_newworld = 1;
+ use_of_interrupt_tree = 1;
break;
}
- np = np->allnext;
}
- if ((_machine == _MACH_chrp) || (boot_infos == 0 && pmac_newworld))
- use_of_interrupt_tree = 1;
+ if (_machine == _MACH_Pmac && use_of_interrupt_tree)
+ pmac_newworld = 1;
+
+#ifdef CONFIG_BOOTX_TEXT
+ if (boot_infos && pmac_newworld) {
+ prom_print("WARNING ! BootX/miBoot booting is not supported on this machine\n");
+ prom_print(" You should use an Open Firmware bootloader\n");
+ }
+#endif /* CONFIG_BOOTX_TEXT */
+
+ if (use_of_interrupt_tree) {
+ /*
+ * We want to find out here how many interrupt-controller
+ * nodes there are, and if we are booted from BootX,
+ * we need a pointer to the first (and hopefully only)
+ * such node. But we can't use find_devices here since
+ * np->name has not been set yet. -- paulus
+ */
+ int n = 0;
+ char *name;
+
+ for (np = allnodes; np != NULL; np = np->allnext) {
+ if ((name = get_property(np, "name", NULL)) == NULL
+ || strcmp(name, "interrupt-controller") != 0)
+ continue;
+ if (n == 0)
+ dflt_interrupt_controller = np;
+ ++n;
+ }
+ num_interrupt_controllers = n;
+ }
mem = finish_node(allnodes, mem, NULL, 1, 1);
dev_tree_size = mem - (unsigned long) allnodes;
if (ifunc != NULL) {
mem_start = ifunc(np, mem_start, naddrc, nsizec);
}
- if (use_of_interrupt_tree) {
+ if (use_of_interrupt_tree)
mem_start = finish_node_interrupts(np, mem_start);
- }
/* Look for #address-cells and #size-cells properties. */
ip = (int *) get_property(np, "#address-cells", 0);
return mem_start;
}
-/* This routine walks the interrupt tree for a given device node and gather
- * all necessary informations according to the draft interrupt mapping
- * for CHRP. The current version was only tested on Apple "Core99" machines
- * and may not handle cascaded controllers correctly.
+/*
+ * Find the interrupt parent of a node.
*/
-__init
-static unsigned long
-finish_node_interrupts(struct device_node *np, unsigned long mem_start)
+static struct device_node *intr_parent(struct device_node *p)
{
- /* Finish this node */
- unsigned int *isizep, *asizep, *interrupts, *map, *map_mask, *reg;
- phandle *parent;
- struct device_node *node, *parent_node;
- int l, isize, ipsize, asize, map_size, regpsize;
-
- /* Currently, we don't look at all nodes with no "interrupts" property */
- interrupts = (unsigned int *)get_property(np, "interrupts", &l);
- if (interrupts == NULL)
- return mem_start;
- ipsize = l>>2;
+ phandle *parp;
+
+ parp = (phandle *) get_property(p, "interrupt-parent", NULL);
+ if (parp == NULL)
+ return p->parent;
+ p = find_phandle(*parp);
+ if (p != NULL)
+ return p;
+ /*
+ * On a powermac booted with BootX, we don't get to know the
+ * phandles for any nodes, so find_phandle will return NULL.
+ * Fortunately these machines only have one interrupt controller
+ * so there isn't in fact any ambiguity. -- paulus
+ */
+ if (num_interrupt_controllers == 1)
+ p = dflt_interrupt_controller;
+ return p;
+}
- reg = (unsigned int *)get_property(np, "reg", &l);
- regpsize = l>>2;
+/*
+ * Find out the size of each entry of the interrupts property
+ * for a node.
+ */
+static int
+prom_n_intr_cells(struct device_node *np)
+{
+ struct device_node *p;
+ unsigned int *icp;
+
+ for (p = np; (p = intr_parent(p)) != NULL; ) {
+ icp = (unsigned int *)
+ get_property(p, "#interrupt-cells", NULL);
+ if (icp != NULL)
+ return *icp;
+ if (get_property(p, "interrupt-controller", NULL) != NULL
+ || get_property(p, "interrupt-map", NULL) != NULL) {
+ printk("oops, node %s doesn't have #interrupt-cells\n",
+ p->full_name);
+ return 1;
+ }
+ }
+ printk("prom_n_intr_cells failed for %s\n", np->full_name);
+ return 1;
+}
- /* We assume default interrupt cell size is 1 (bugus ?) */
- isize = 1;
- node = np;
-
- do {
- /* We adjust the cell size if the current parent contains an #interrupt-cells
- * property */
- isizep = (unsigned int *)get_property(node, "#interrupt-cells", &l);
- if (isizep)
- isize = *isizep;
-
- /* We don't do interrupt cascade (ISA) for now, we stop on the first
- * controller found
- */
- if (get_property(node, "interrupt-controller", &l)) {
- int i,j;
- int cvt_irq;
-
- /* XXX on chrp, offset interrupt numbers for the
- 8259 by 0, those for the openpic by 16 */
- cvt_irq = _machine == _MACH_chrp
- && get_property(node, "interrupt-parent", NULL) == 0;
- np->intrs = (struct interrupt_info *) mem_start;
- np->n_intrs = ipsize / isize;
- mem_start += np->n_intrs * sizeof(struct interrupt_info);
- for (i = 0; i < np->n_intrs; ++i) {
- np->intrs[i].line = *interrupts++;
- if (cvt_irq)
- np->intrs[i].line = openpic_to_irq(np->intrs[i].line);
- np->intrs[i].sense = 1;
- if (isize > 1)
- np->intrs[i].sense = *interrupts++;
- for (j=2; j<isize; j++)
- interrupts++;
+/*
+ * Map an interrupt from a device up to the platform interrupt
+ * descriptor.
+ */
+static int
+map_interrupt(unsigned int **irq, struct device_node **ictrler,
+ struct device_node *np, unsigned int *ints, int nintrc)
+{
+ struct device_node *p, *ipar;
+ unsigned int *imap, *imask, *ip;
+ int i, imaplen, match;
+ int newintrc, newaddrc;
+ unsigned int *reg;
+ int naddrc;
+
+ reg = (unsigned int *) get_property(np, "reg", NULL);
+ naddrc = prom_n_addr_cells(np);
+ p = intr_parent(np);
+ while (p != NULL) {
+ if (get_property(p, "interrupt-controller", NULL) != NULL)
+ /* this node is an interrupt controller, stop here */
+ break;
+ imap = (unsigned int *)
+ get_property(p, "interrupt-map", &imaplen);
+ if (imap == NULL) {
+ p = intr_parent(p);
+ continue;
+ }
+ imask = (unsigned int *)
+ get_property(p, "interrupt-map-mask", NULL);
+ if (imask == NULL) {
+ printk("oops, %s has interrupt-map but no mask\n",
+ p->full_name);
+ return 0;
}
+ imaplen /= sizeof(unsigned int);
+ match = 0;
+ ipar = NULL;
+ while (imaplen > 0 && !match) {
+ /* check the child-interrupt field */
+ match = 1;
+ for (i = 0; i < naddrc && match; ++i)
+ match = ((reg[i] ^ imap[i]) & imask[i]) == 0;
+ for (; i < naddrc + nintrc && match; ++i)
+ match = ((ints[i-naddrc] ^ imap[i]) & imask[i]) == 0;
+ imap += naddrc + nintrc;
+ imaplen -= naddrc + nintrc;
+ /* grab the interrupt parent */
+ ipar = find_phandle((phandle) *imap++);
+ --imaplen;
+ if (ipar == NULL && num_interrupt_controllers == 1)
+ /* cope with BootX not giving us phandles */
+ ipar = dflt_interrupt_controller;
+ if (ipar == NULL) {
+ printk("oops, no int parent %x in map of %s\n",
+ imap[-1], p->full_name);
+ return 0;
+ }
+ /* find the parent's # addr and intr cells */
+ ip = (unsigned int *)
+ get_property(ipar, "#interrupt-cells", NULL);
+ if (ip == NULL) {
+ printk("oops, no #interrupt-cells on %s\n",
+ ipar->full_name);
+ return 0;
+ }
+ newintrc = *ip;
+ ip = (unsigned int *)
+ get_property(ipar, "#address-cells", NULL);
+ newaddrc = (ip == NULL)? 0: *ip;
+ imap += newaddrc + newintrc;
+ imaplen -= newaddrc + newintrc;
+ }
+ if (imaplen < 0) {
+ printk("oops, error decoding int-map on %s, len=%d\n",
+ p->full_name, imaplen);
+ return 0;
+ }
+ if (!match) {
+ printk("oops, no match in %s int-map for %s\n",
+ p->full_name, np->full_name);
+ return 0;
+ }
+ p = ipar;
+ naddrc = newaddrc;
+ nintrc = newintrc;
+ ints = imap - nintrc;
+ reg = ints - naddrc;
+ }
+ if (p == NULL)
+ printk("hmmm, int tree for %s doesn't have ctrler\n",
+ np->full_name);
+ *irq = ints;
+ *ictrler = p;
+ return nintrc;
+}
+
+/*
+ * New version of finish_node_interrupts.
+ */
+static unsigned long
+finish_node_interrupts(struct device_node *np, unsigned long mem_start)
+{
+ unsigned int *ints;
+ int intlen, intrcells;
+ int i, j, n, offset;
+ unsigned int *irq;
+ struct device_node *ic;
+
+ ints = (unsigned int *) get_property(np, "interrupts", &intlen);
+ if (ints == NULL)
return mem_start;
- }
- /* We lookup for an interrupt-map. This code can only handle one interrupt
- * per device in the map. We also don't handle #address-cells in the parent
- * I skip the pci node itself here, may not be necessary but I don't like it's
- * reg property.
- */
- if (np != node)
- map = (unsigned int *)get_property(node, "interrupt-map", &l);
- else
- map = NULL;
- if (map && l) {
- int i, found, temp_isize;
- map_size = l>>2;
- map_mask = (unsigned int *)get_property(node, "interrupt-map-mask", &l);
- asizep = (unsigned int *)get_property(node, "#address-cells", &l);
- if (asizep && l == sizeof(unsigned int))
- asize = *asizep;
- else
- asize = 0;
- found = 0;
- while(map_size>0 && !found) {
- found = 1;
- for (i=0; i<asize; i++) {
- unsigned int mask = map_mask ? map_mask[i] : 0xffffffff;
- if (!reg || (i>=regpsize) || ((mask & *map) != (mask & reg[i])))
- found = 0;
- map++;
- map_size--;
- }
- for (i=0; i<isize; i++) {
- unsigned int mask = map_mask ? map_mask[i+asize] : 0xffffffff;
- if ((mask & *map) != (mask & interrupts[i]))
- found = 0;
- map++;
- map_size--;
- }
- parent = *((phandle *)(map));
- map+=1; map_size-=1;
- parent_node = find_phandle(parent);
- temp_isize = isize;
- if (parent_node) {
- isizep = (unsigned int *)get_property(parent_node, "#interrupt-cells", &l);
- if (isizep)
- temp_isize = *isizep;
- }
- if (!found) {
- map += temp_isize;
- map_size-=temp_isize;
- }
- }
- if (found) {
- node = parent_node;
- reg = NULL;
- regpsize = 0;
- interrupts = (unsigned int *)map;
- ipsize = temp_isize*1;
- continue;
- }
- }
- /* We look for an explicit interrupt-parent.
- */
- parent = (phandle *)get_property(node, "interrupt-parent", &l);
- if (parent && (l == sizeof(phandle)) &&
- (parent_node = find_phandle(*parent))) {
- node = parent_node;
- continue;
- }
- /* Default, get real parent */
- node = node->parent;
- } while(node);
+ intrcells = prom_n_intr_cells(np);
+ intlen /= intrcells * sizeof(unsigned int);
+ np->n_intrs = intlen;
+ np->intrs = (struct interrupt_info *) mem_start;
+ mem_start += intlen * sizeof(struct interrupt_info);
+
+ for (i = 0; i < intlen; ++i) {
+ np->intrs[i].line = 0;
+ np->intrs[i].sense = 1;
+ n = map_interrupt(&irq, &ic, np, ints, intrcells);
+ if (n <= 0)
+ continue;
+ offset = 0;
+ /*
+ * On a CHRP we have an 8259 which is subordinate to
+ * the openpic in the interrupt tree, but we want the
+ * openpic's interrupt numbers offsetted, not the 8259's.
+ * So we apply the offset if the controller is at the
+ * root of the interrupt tree, i.e. has no interrupt-parent.
+ * This doesn't cope with the general case of multiple
+ * cascaded interrupt controllers, but then neither will
+ * irq.c at the moment either. -- paulus
+ */
+ if (num_interrupt_controllers > 1 && ic != NULL
+ && get_property(ic, "interrupt-parent", NULL) == NULL)
+ offset = 16;
+ np->intrs[i].line = irq[0] + offset;
+ if (n > 1)
+ np->intrs[i].sense = irq[1];
+ if (n > 2) {
+ printk("hmmm, got %d intr cells for %s:", n,
+ np->full_name);
+ for (j = 0; j < n; ++j)
+ printk(" %d", irq[j]);
+ printk("\n");
+ }
+ ints += intrcells;
+ }
return mem_start;
}
-
/*
* When BootX makes a copy of the device tree from the MacOS
* Name Registry, it is in the format we use but all of the pointers
ip = (int *) get_property(np, "#address-cells", 0);
if (ip != NULL)
return *ip;
- } while(np->parent);
+ } while (np->parent);
/* No #address-cells property for the root node, default to 1 */
return 1;
}
ip = (int *) get_property(np, "#size-cells", 0);
if (ip != NULL)
return *ip;
- } while(np->parent);
+ } while (np->parent);
/* No #size-cells property for the root node, default to 1 */
return 1;
}
{
struct address_range *adr;
struct pci_reg_property *pci_addrs;
- int i, l, *ip, ml;
- struct pci_intr_map *imp;
+ int i, l, *ip;
pci_addrs = (struct pci_reg_property *)
get_property(np, "assigned-addresses", &l);
if (use_of_interrupt_tree)
return mem_start;
- /*
- * If the pci host bridge has an interrupt-map property,
- * look for our node in it.
- */
- if (np->parent != 0 && pci_addrs != 0
- && (imp = (struct pci_intr_map *)
- get_property(np->parent, "interrupt-map", &ml)) != 0
- && (ip = (int *) get_property(np, "interrupts", &l)) != 0) {
- unsigned int devfn = pci_addrs[0].addr.a_hi & 0xff00;
- unsigned int cell_size;
- struct device_node* np2;
- /* This is hackish, but is only used for BootX booting */
- cell_size = sizeof(struct pci_intr_map);
- np2 = np->parent;
- while(np2) {
- if (device_is_compatible(np2, "uni-north")) {
- cell_size += 4;
- break;
- }
- np2 = np2->parent;
- }
- np->n_intrs = 0;
- np->intrs = (struct interrupt_info *) mem_start;
- for (i = 0; (ml -= cell_size) >= 0; ++i) {
- if (imp->addr.a_hi == devfn) {
- np->intrs[np->n_intrs].line = imp->intr;
- np->intrs[np->n_intrs].sense = 1; /* FIXME */
- ++np->n_intrs;
- }
- imp = (struct pci_intr_map *)(((unsigned int)imp)
- + cell_size);
- }
- if (np->n_intrs == 0)
- np->intrs = 0;
- mem_start += np->n_intrs * sizeof(struct interrupt_info);
- return mem_start;
- }
-
ip = (int *) get_property(np, "AAPL,interrupts", &l);
if (ip == 0 && np->parent)
ip = (int *) get_property(np->parent, "AAPL,interrupts", &l);
ip = (int *) get_property(np, "AAPL,interrupts", &l);
if (ip != 0) {
np->intrs = (struct interrupt_info *) mem_start;
- if (_machine == _MACH_Pmac) {
- /* for the iMac */
- np->n_intrs = l / sizeof(int);
- /* Hack for BootX on Core99 */
- if (keylargo)
- np->n_intrs = np->n_intrs/2;
- for (i = 0; i < np->n_intrs; ++i) {
- np->intrs[i].line = *ip++;
- if (keylargo)
- np->intrs[i].sense = *ip++;
- else
- np->intrs[i].sense = 1;
- }
- } else {
- /* CHRP machines */
- np->n_intrs = l / (2 * sizeof(int));
- for (i = 0; i < np->n_intrs; ++i) {
- np->intrs[i].line = openpic_to_irq(*ip++);
- np->intrs[i].sense = *ip++;
- }
+ np->n_intrs = l / sizeof(int);
+ for (i = 0; i < np->n_intrs; ++i) {
+ np->intrs[i].line = *ip++;
+ np->intrs[i].sense = 1;
}
mem_start += np->n_intrs * sizeof(struct interrupt_info);
}
{
struct property *pp;
- for (pp = np->properties; pp != 0; pp = pp->next) {
+ for (pp = np->properties; pp != 0; pp = pp->next)
if (pp->name != NULL && strcmp(pp->name, name) == 0) {
if (lenp != 0)
*lenp = pp->length;
return pp->value;
}
- }
return 0;
}
{
mark_buffer_uptodate(bh, uptodate);
unlock_buffer(bh);
+ atomic_dec(&bh->b_count);
}
/**
continue;
/* We have the buffer lock */
+ atomic_inc(&bh->b_count);
bh->b_end_io = end_buffer_io_sync;
switch(rw) {
static char ps2esdi_valid[MAX_HD];
static int ps2esdi_sizes[MAX_HD << 6];
static int ps2esdi_blocksizes[MAX_HD << 6];
+static int ps2esdi_maxsect[MAX_HD << 6];
static int ps2esdi_drives;
static struct hd_struct ps2esdi[MAX_HD << 6];
static u_short io_base;
*
*/
-static char *serial_version = "5.05b";
-static char *serial_revdate = "2001-05-03";
+static char *serial_version = "5.05c";
+static char *serial_revdate = "2001-07-08";
/*
* Serial driver configuration section. Here are the various options:
struct serial_state *state,
unsigned long flags)
{
- unsigned char scratch, scratch2, scratch3;
+ unsigned char scratch, scratch2, scratch3, scratch4;
/*
* First we check to see if it's an Oxford Semiconductor UART.
* XR16C854.
*
*/
+
+ /* Save the DLL and DLM */
+
serial_outp(info, UART_LCR, UART_LCR_DLAB);
+ scratch3 = serial_inp(info, UART_DLL);
+ scratch4 = serial_inp(info, UART_DLM);
+
serial_outp(info, UART_DLL, 0);
serial_outp(info, UART_DLM, 0);
- state->revision = serial_inp(info, UART_DLL);
+ scratch2 = serial_inp(info, UART_DLL);
scratch = serial_inp(info, UART_DLM);
serial_outp(info, UART_LCR, 0);
+
if (scratch == 0x10 || scratch == 0x14) {
+ if (scratch == 0x10)
+ state->revision = scratch2;
state->type = PORT_16850;
return;
}
+ /* Restore the DLL and DLM */
+
+ serial_outp(info, UART_LCR, UART_LCR_DLAB);
+ serial_outp(info, UART_DLL, scratch3);
+ serial_outp(info, UART_DLM, scratch4);
+ serial_outp(info, UART_LCR, 0);
/*
* We distinguish between the '654 and the '650 by counting
* how many bytes are in the FIFO. I'm using this for now,
* seems to be mainly needed on card using the PLX which also use I/O
* mapped memory.
*/
-static int
-#ifndef MODULE
-__devinit
-#endif
+static int __devinit
pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
u8 data, *p, irq_config;
#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc)
#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8)
-static int
-#ifndef MODULE
-__devinit
-#endif
+static int __devinit
pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
u16 data, *p;
#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc)
#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc)
-static int
-#ifndef MODULE
-__devinit
-#endif
+static int __devinit
pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
u8 data;
}
/* Added for EKF Intel i960 serial boards */
-static int
-#ifndef MODULE
-__devinit
-#endif
+static int __devinit
pci_inteli960ni_fn(struct pci_dev *dev,
struct pci_board *board,
int enable)
{ 0, 0 }
};
-static int
-#ifndef MODULE
-__devinit
-#endif
+static int __devinit
pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
int i, j;
return 0;
}
-static int
-#ifndef MODULE
-__devinit
-#endif
+static int __devinit
pci_xircom_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
__set_current_state(TASK_UNINTERRUPTIBLE);
-/* $Id: eicon.h,v 1.23.6.3 2001/05/17 21:15:33 kai Exp $
+/* $Id: eicon.h,v 1.23.6.4 2001/06/09 15:14:16 kai Exp $
*
* ISDN low-level module for Eicon active ISDN-Cards.
*
* 26 AVM A1 PCMCIA (Fritz) p0=irq p1=iobase
* 27 AVM PnP/PCI p0=irq p1=iobase (PCI no parameter)
* 28 Sedlbauer Speed Fax+ p0=irq p1=iobase (from isapnp setup)
- * 29 Siemens I-Surf p0=irq p1=iobase p2=memory (from isapnp setup)
- * 30 ACER P10 p0=irq p1=iobase (from isapnp setup)
+ * 29 Siemens I-Surf p0=irq p1=iobase p2=memory (from isapnp setup)
+ * 30 ACER P10 p0=irq p1=iobase (from isapnp setup)
* 31 HST Saphir p0=irq p1=iobase
* 32 Telekom A4T none
* 33 Scitel Quadro p0=subcontroller (4*S0, subctrl 1...4)
*
*/
-const char *CardType[] =
-{"No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3", "Creatix/Teles PnP",
- "AVM A1", "Elsa ML", "Elsa Quickstep", "Teles PCMCIA", "ITK ix1-micro Rev.2",
- "Elsa PCMCIA", "Eicon.Diehl Diva", "ISDNLink", "TeleInt", "Teles 16.3c",
- "Sedlbauer Speed Card", "USR Sportster", "ith mic Linux", "Elsa PCI",
- "Compaq ISA", "NETjet-S", "Teles PCI", "Sedlbauer Speed Star (PCMCIA)",
- "AMD 7930", "NICCY", "S0Box", "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI",
- "Sedlbauer Speed Fax +", "Siemens I-Surf", "Acer P10", "HST Saphir",
- "Telekom A4T", "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692",
- "HFC 2BDS0 SX", "NETspider-U", "HFC-2BDS0-SP PCMCIA",
+const char *CardType[] = {
+ "No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3",
+ "Creatix/Teles PnP", "AVM A1", "Elsa ML", "Elsa Quickstep",
+ "Teles PCMCIA", "ITK ix1-micro Rev.2", "Elsa PCMCIA",
+ "Eicon.Diehl Diva", "ISDNLink", "TeleInt", "Teles 16.3c",
+ "Sedlbauer Speed Card", "USR Sportster", "ith mic Linux",
+ "Elsa PCI", "Compaq ISA", "NETjet-S", "Teles PCI",
+ "Sedlbauer Speed Star (PCMCIA)", "AMD 7930", "NICCY", "S0Box",
+ "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI", "Sedlbauer Speed Fax +",
+ "Siemens I-Surf", "Acer P10", "HST Saphir", "Telekom A4T",
+ "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692",
+ "HFC 2BDS0 SX", "NETspider-U", "HFC-2BDS0-SP PCMCIA",
};
void HiSax_closecard(int cardnr);
#ifdef CONFIG_HISAX_ELSA
#define DEFAULT_CARD ISDN_CTYPE_ELSA
#define DEFAULT_CFG {0,0,0,0}
-int elsa_init_pcmcia(void*, int, int*, int);
+int elsa_init_pcmcia(void *, int, int *, int);
EXPORT_SYMBOL(elsa_init_pcmcia);
-#endif /* CONFIG_HISAX_ELSA */
+#endif
#ifdef CONFIG_HISAX_AVM_A1
#undef DEFAULT_CARD
#undef DEFAULT_CFG
#define DEFAULT_CARD ISDN_CTYPE_A1_PCMCIA
#define DEFAULT_CFG {11,0x170,0,0}
-int avm_a1_init_pcmcia(void*, int, int*, int);
+int avm_a1_init_pcmcia(void *, int, int *, int);
EXPORT_SYMBOL(avm_a1_init_pcmcia);
-#endif /* CONFIG_HISAX_AVM_A1_PCMCIA */
+#endif
#ifdef CONFIG_HISAX_FRITZPCI
#undef DEFAULT_CARD
#undef DEFAULT_CFG
#define DEFAULT_CARD ISDN_CTYPE_SEDLBAUER
#define DEFAULT_CFG {11,0x270,0,0}
-int sedl_init_pcmcia(void*, int, int*, int);
+int sedl_init_pcmcia(void *, int, int *, int);
EXPORT_SYMBOL(sedl_init_pcmcia);
-#endif /* CONFIG_HISAX_SEDLBAUER */
+#endif
#ifdef CONFIG_HISAX_SPORTSTER
#undef DEFAULT_CARD
#undef DEFAULT_CFG
#define DEFAULT_CARD ISDN_CTYPE_HFC_SX
#define DEFAULT_CFG {5,0x2E0,0,0}
-int hfc_init_pcmcia(void*, int, int*, int);
+int hfc_init_pcmcia(void *, int, int *, int);
EXPORT_SYMBOL(hfc_init_pcmcia);
#endif
#define DEFAULT_CFG {5,0x250,0,0}
#endif
-#ifdef CONFIG_HISAX_BKM_A4T
+#ifdef CONFIG_HISAX_BKM_A4T
#undef DEFAULT_CARD
#undef DEFAULT_CFG
#define DEFAULT_CARD ISDN_CTYPE_BKM_A4T
#define EMPTY_CARD {0, DEFAULT_PROTO, {0, 0, 0, 0}, NULL}
-struct IsdnCard cards[] =
-{
+struct IsdnCard cards[] = {
FIRST_CARD,
EMPTY_CARD,
EMPTY_CARD,
#ifdef IO0_IO1
MODULE_PARM(io0, "1-8i");
MODULE_PARM(io1, "1-8i");
-#endif /* IO0_IO1 */
+#endif
#endif /* MODULE */
int nrcards;
extern char *lli_revision;
extern char *tei_revision;
-char *
-HiSax_getrev(const char *revision)
+char *HiSax_getrev(const char *revision)
{
char *rev;
char *p;
return rev;
}
-void __init
-HiSaxVersion(void)
+void __init HiSaxVersion(void)
{
char tmp[64];
strcpy(tmp, l3_revision);
printk(KERN_INFO "HiSax: Layer3 Revision %s\n", HiSax_getrev(tmp));
strcpy(tmp, lli_revision);
- printk(KERN_INFO "HiSax: LinkLayer Revision %s\n", HiSax_getrev(tmp));
+ printk(KERN_INFO "HiSax: LinkLayer Revision %s\n",
+ HiSax_getrev(tmp));
certification_check(1);
}
-void
-HiSax_mod_dec_use_count(void)
+void HiSax_mod_dec_use_count(void)
{
MOD_DEC_USE_COUNT;
}
-void
-HiSax_mod_inc_use_count(void)
+void HiSax_mod_inc_use_count(void)
{
MOD_INC_USE_COUNT;
}
#ifndef MODULE
#define MAX_ARG (HISAX_MAX_CARDS*5)
-static int __init
-HiSax_setup(char *line)
+static int __init HiSax_setup(char *line)
{
int i, j, argc;
int ints[MAX_ARG + 1];
str = get_options(line, MAX_ARG, ints);
argc = ints[0];
- printk(KERN_DEBUG"HiSax_setup: argc(%d) str(%s)\n", argc, str);
+ printk(KERN_DEBUG "HiSax_setup: argc(%d) str(%s)\n", argc, str);
i = 0;
j = 1;
while (argc && (i < HISAX_MAX_CARDS)) {
strcpy(HiSaxID, "HiSax");
HiSax_id = HiSaxID;
}
- return(1);
+ return 1;
}
__setup("hisax=", HiSax_setup);
#endif
#if CARD_DIEHLDIVA
-extern int setup_diva(struct IsdnCard *card);
+extern int setup_diva(struct IsdnCard *card);
#endif
#if CARD_ASUSCOM
/*
* Find card with given driverId
*/
-static inline struct IsdnCardState
-*hisax_findcard(int driverid)
+static inline struct IsdnCardState *hisax_findcard(int driverid)
{
int i;
for (i = 0; i < nrcards; i++)
if (cards[i].cs)
if (cards[i].cs->myid == driverid)
- return (cards[i].cs);
- return (NULL);
+ return cards[i].cs;
+ return NULL;
}
/*
* Find card with given card number
*/
-struct IsdnCardState
-*hisax_get_card(int cardnr)
+struct IsdnCardState *hisax_get_card(int cardnr)
{
- if ((cardnr <= nrcards) && (cardnr>0))
- if (cards[cardnr-1].cs)
- return (cards[cardnr-1].cs);
- return (NULL);
+ if ((cardnr <= nrcards) && (cardnr > 0))
+ if (cards[cardnr - 1].cs)
+ return cards[cardnr - 1].cs;
+ return NULL;
}
-int
-HiSax_readstatus(u_char * buf, int len, int user, int id, int channel)
+int HiSax_readstatus(u_char * buf, int len, int user, int id, int channel)
{
- int count,cnt;
+ int count, cnt;
u_char *p = buf;
struct IsdnCardState *cs = hisax_findcard(id);
if (cs) {
if (len > HISAX_STATUS_BUFSIZE) {
- printk(KERN_WARNING "HiSax: status overflow readstat %d/%d\n",
- len, HISAX_STATUS_BUFSIZE);
+ printk(KERN_WARNING
+ "HiSax: status overflow readstat %d/%d\n",
+ len, HISAX_STATUS_BUFSIZE);
}
- count = cs->status_end - cs->status_read +1;
+ count = cs->status_end - cs->status_read + 1;
if (count >= len)
count = len;
if (user)
return len;
} else {
printk(KERN_ERR
- "HiSax: if_readstatus called with invalid driverId!\n");
+ "HiSax: if_readstatus called with invalid driverId!\n");
return -ENODEV;
}
}
-inline int
-jiftime(char *s, long mark)
+static inline int jiftime(char *s, long mark)
{
s += 8;
*s-- = mark % 10 + '0';
mark /= 10;
*s-- = mark % 10 + '0';
- return(8);
+ return 8;
}
static u_char tmpbuf[HISAX_STATUS_BUFSIZE];
-void
-VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args)
+void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt,
+ va_list args)
{
-/* if head == NULL the fmt contains the full info */
+ /* if head == NULL the fmt contains the full info */
long flags;
int count, i;
len = strlen(fmt);
}
if (!cs) {
- printk(KERN_WARNING "HiSax: No CardStatus for message %s", p);
+ printk(KERN_WARNING "HiSax: No CardStatus for message %s",
+ p);
restore_flags(flags);
return;
}
if (len > HISAX_STATUS_BUFSIZE) {
printk(KERN_WARNING "HiSax: status overflow %d/%d\n",
- len, HISAX_STATUS_BUFSIZE);
+ len, HISAX_STATUS_BUFSIZE);
restore_flags(flags);
return;
}
count = len;
- i = cs->status_end - cs->status_write +1;
+ i = cs->status_end - cs->status_write + 1;
if (i >= len)
i = len;
len -= i;
cs->status_write += len;
}
#ifdef KERNELSTACK_DEBUG
- i = (ulong)&len - current->kernel_stack_page;
+ i = (ulong) & len - current->kernel_stack_page;
sprintf(tmpbuf, "kstack %s %lx use %ld\n", current->comm,
current->kernel_stack_page, i);
len = strlen(tmpbuf);
}
}
-void
-HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...)
+void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...)
{
va_list args;
va_end(args);
}
-int
-ll_run(struct IsdnCardState *cs, int addfeatures)
+int ll_run(struct IsdnCardState *cs, int addfeatures)
{
long flags;
isdn_ctrl ic;
return 0;
}
-void
-ll_stop(struct IsdnCardState *cs)
+void ll_stop(struct IsdnCardState *cs)
{
isdn_ctrl ic;
ic.command = ISDN_STAT_STOP;
ic.driver = cs->myid;
cs->iif.statcallb(&ic);
-// CallcFreeChan(cs);
+ // CallcFreeChan(cs);
}
-static void
-ll_unload(struct IsdnCardState *cs)
+static void ll_unload(struct IsdnCardState *cs)
{
isdn_ctrl ic;
kfree(cs->dlog);
}
-static void
-closecard(int cardnr)
+static void closecard(int cardnr)
{
struct IsdnCardState *csta = cards[cardnr].cs;
ll_unload(csta);
}
-static int __devinit
-init_card(struct IsdnCardState *cs)
+static int __devinit init_card(struct IsdnCardState *cs)
{
int irq_cnt, cnt = 3;
long flags;
if (!cs->irq)
- return(cs->cardmsg(cs, CARD_INIT, NULL));
+ return cs->cardmsg(cs, CARD_INIT, NULL);
save_flags(flags);
cli();
irq_cnt = kstat_irqs(cs->irq);
- printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], cs->irq,
- irq_cnt);
+ printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ],
+ cs->irq, irq_cnt);
if (request_irq(cs->irq, cs->irq_func, cs->irq_flags, "HiSax", cs)) {
printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
- cs->irq);
+ cs->irq);
restore_flags(flags);
- return(1);
+ return 1;
}
while (cnt) {
cs->cardmsg(cs, CARD_INIT, NULL);
sti();
set_current_state(TASK_UNINTERRUPTIBLE);
/* Timeout 10ms */
- schedule_timeout((10*HZ)/1000);
+ schedule_timeout((10 * HZ) / 1000);
restore_flags(flags);
- printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ],
- cs->irq, kstat_irqs(cs->irq));
+ printk(KERN_INFO "%s: IRQ %d count %d\n",
+ CardType[cs->typ], cs->irq, kstat_irqs(cs->irq));
if (kstat_irqs(cs->irq) == irq_cnt) {
printk(KERN_WARNING
"%s: IRQ(%d) getting no interrupts during init %d\n",
CardType[cs->typ], cs->irq, 4 - cnt);
if (cnt == 1) {
free_irq(cs->irq, cs);
- return (2);
+ return 2;
} else {
cs->cardmsg(cs, CARD_RESET, NULL);
cnt--;
}
} else {
cs->cardmsg(cs, CARD_TEST, NULL);
- return(0);
+ return 0;
}
}
restore_flags(flags);
- return(3);
+ return 3;
}
-static int __devinit
-checkcard(int cardnr, char *id, int *busy_flag)
+static int __devinit checkcard(int cardnr, char *id, int *busy_flag)
{
long flags;
int ret = 0;
}
memset(cs, 0, sizeof(struct IsdnCardState));
card->cs = cs;
- cs->chanlimit = 2; /* maximum B-channel number */
- cs->logecho = 0; /* No echo logging */
+ cs->chanlimit = 2; /* maximum B-channel number */
+ cs->logecho = 0; /* No echo logging */
cs->cardnr = cardnr;
cs->debug = L1_DEB_WARN;
cs->HW_Flags = 0;
if (card->typ <= 0 || card->typ > ISDN_CTYPE_COUNT) {
printk(KERN_WARNING
- "HiSax: Card Type %d out of range\n",
- card->typ);
+ "HiSax: Card Type %d out of range\n", card->typ);
goto outf_cs;
}
if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) {
printk(KERN_WARNING
- "HiSax: No memory for dlog(card %d)\n",
- cardnr + 1);
+ "HiSax: No memory for dlog(card %d)\n", cardnr + 1);
goto outf_cs;
}
if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) {
ISDN_FEATURE_P_NI1 |
#endif
0;
-
+
cs->iif.command = HiSax_command;
cs->iif.writecmd = NULL;
cs->iif.writebuf_skb = HiSax_writebuf_skb;
break;
#endif
#if CARD_HFC_PCI
- case ISDN_CTYPE_HFC_PCI:
+ case ISDN_CTYPE_HFC_PCI:
ret = setup_hfcpci(card);
break;
#endif
#if CARD_HFC_SX
- case ISDN_CTYPE_HFC_SX:
+ case ISDN_CTYPE_HFC_SX:
ret = setup_hfcsx(card);
break;
#endif
ret = setup_testemu(card);
break;
#endif
-#if CARD_BKM_A4T
+#if CARD_BKM_A4T
case ISDN_CTYPE_BKM_A4T:
ret = setup_bkm_a4t(card);
break;
goto outf_cs;
}
if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) {
- printk(KERN_WARNING
- "HiSax: No memory for isac rcvbuf\n");
+ printk(KERN_WARNING "HiSax: No memory for isac rcvbuf\n");
ll_unload(cs);
goto outf_cs;
}
return ret;
}
-void __devinit
-HiSax_shiftcards(int idx)
+void __devinit HiSax_shiftcards(int idx)
{
int i;
memcpy(&cards[i], &cards[i + 1], sizeof(cards[i]));
}
-int __devinit
-HiSax_inithardware(int *busy_flag)
+int __devinit HiSax_inithardware(int *busy_flag)
{
int foundcards = 0;
int i = 0;
foundcards++;
i++;
} else {
- printk(KERN_WARNING "HiSax: Card %s not installed !\n",
+ printk(KERN_WARNING
+ "HiSax: Card %s not installed !\n",
CardType[cards[i].typ]);
HiSax_shiftcards(i);
nrcards--;
return foundcards;
}
-void
-HiSax_closecard(int cardnr)
+void HiSax_closecard(int cardnr)
{
- int i,last=nrcards - 1;
+ int i, last = nrcards - 1;
- if (cardnr>last)
+ if (cardnr > last)
return;
if (cards[cardnr].cs) {
ll_stop(cards[cardnr].cs);
release_tei(cards[cardnr].cs);
-
CallcFreeChan(cards[cardnr].cs);
-
+
closecard(cardnr);
if (cards[cardnr].cs->irq)
free_irq(cards[cardnr].cs->irq, cards[cardnr].cs);
cards[cardnr].cs = NULL;
}
i = cardnr;
- while (i!=last) {
- cards[i] = cards[i+1];
+ while (i <= last) {
+ cards[i] = cards[i + 1];
i++;
}
nrcards--;
}
-void
-HiSax_reportcard(int cardnr, int sel)
+void HiSax_reportcard(int cardnr, int sel)
{
struct IsdnCardState *cs = cards[cardnr].cs;
printk(KERN_DEBUG "HiSax: Type %s\n", CardType[cs->typ]);
printk(KERN_DEBUG "HiSax: debuglevel %x\n", cs->debug);
printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%lX\n",
- (ulong) & HiSax_reportcard);
+ (ulong) & HiSax_reportcard);
printk(KERN_DEBUG "HiSax: cs 0x%lX\n", (ulong) cs);
printk(KERN_DEBUG "HiSax: HW_Flags %lx bc0 flg %lx bc1 flg %lx\n",
- cs->HW_Flags, cs->bcs[0].Flag, cs->bcs[1].Flag);
+ cs->HW_Flags, cs->bcs[0].Flag, cs->bcs[1].Flag);
printk(KERN_DEBUG "HiSax: bcs 0 mode %d ch%d\n",
- cs->bcs[0].mode, cs->bcs[0].channel);
+ cs->bcs[0].mode, cs->bcs[0].channel);
printk(KERN_DEBUG "HiSax: bcs 1 mode %d ch%d\n",
- cs->bcs[1].mode, cs->bcs[1].channel);
+ cs->bcs[1].mode, cs->bcs[1].channel);
#ifdef ERROR_STATISTIC
printk(KERN_DEBUG "HiSax: dc errors(rx,crc,tx) %d,%d,%d\n",
- cs->err_rx, cs->err_crc, cs->err_tx);
- printk(KERN_DEBUG "HiSax: bc0 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n",
- cs->bcs[0].err_inv, cs->bcs[0].err_rdo, cs->bcs[0].err_crc, cs->bcs[0].err_tx);
- printk(KERN_DEBUG "HiSax: bc1 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n",
- cs->bcs[1].err_inv, cs->bcs[1].err_rdo, cs->bcs[1].err_crc, cs->bcs[1].err_tx);
+ cs->err_rx, cs->err_crc, cs->err_tx);
+ printk(KERN_DEBUG
+ "HiSax: bc0 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n",
+ cs->bcs[0].err_inv, cs->bcs[0].err_rdo, cs->bcs[0].err_crc,
+ cs->bcs[0].err_tx);
+ printk(KERN_DEBUG
+ "HiSax: bc1 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n",
+ cs->bcs[1].err_inv, cs->bcs[1].err_rdo, cs->bcs[1].err_crc,
+ cs->bcs[1].err_tx);
if (sel == 99) {
cs->err_rx = 0;
cs->err_crc = 0;
static int __init HiSax_init(void)
{
int i, retval;
-#ifdef MODULE
+#ifdef MODULE
int j;
int nzproto = 0;
#endif
#ifdef MODULE
if (!type[0]) {
- /* We 'll register drivers later, but init basic functions*/
+ /* We 'll register drivers later, but init basic functions */
return 0;
}
#ifdef CONFIG_HISAX_ELSA
nzproto++;
}
switch (type[i]) {
- case ISDN_CTYPE_16_0:
- cards[j].para[0] = irq[i];
- cards[j].para[1] = mem[i];
- cards[j].para[2] = io[i];
- break;
+ case ISDN_CTYPE_16_0:
+ cards[j].para[0] = irq[i];
+ cards[j].para[1] = mem[i];
+ cards[j].para[2] = io[i];
+ break;
- case ISDN_CTYPE_8_0:
- cards[j].para[0] = irq[i];
- cards[j].para[1] = mem[i];
- break;
+ case ISDN_CTYPE_8_0:
+ cards[j].para[0] = irq[i];
+ cards[j].para[1] = mem[i];
+ break;
#ifdef IO0_IO1
- case ISDN_CTYPE_PNP:
- case ISDN_CTYPE_NICCY:
- cards[j].para[0] = irq[i];
- cards[j].para[1] = io0[i];
- cards[j].para[2] = io1[i];
- break;
- case ISDN_CTYPE_COMPAQ_ISA:
- cards[j].para[0] = irq[i];
- cards[j].para[1] = io0[i];
- cards[j].para[2] = io1[i];
- cards[j].para[3] = io[i];
- break;
-#endif
- case ISDN_CTYPE_ELSA:
- case ISDN_CTYPE_HFC_PCI:
- cards[j].para[0] = io[i];
- break;
- case ISDN_CTYPE_16_3:
- case ISDN_CTYPE_TELESPCMCIA:
- case ISDN_CTYPE_A1:
- case ISDN_CTYPE_A1_PCMCIA:
- case ISDN_CTYPE_ELSA_PNP:
- case ISDN_CTYPE_ELSA_PCMCIA:
- case ISDN_CTYPE_IX1MICROR2:
- case ISDN_CTYPE_DIEHLDIVA:
- case ISDN_CTYPE_ASUSCOM:
- case ISDN_CTYPE_TELEINT:
- case ISDN_CTYPE_SEDLBAUER:
- case ISDN_CTYPE_SEDLBAUER_PCMCIA:
- case ISDN_CTYPE_SEDLBAUER_FAX:
- case ISDN_CTYPE_SPORTSTER:
- case ISDN_CTYPE_MIC:
- case ISDN_CTYPE_TELES3C:
- case ISDN_CTYPE_ACERP10:
- case ISDN_CTYPE_S0BOX:
- case ISDN_CTYPE_FRITZPCI:
- case ISDN_CTYPE_HSTSAPHIR:
- case ISDN_CTYPE_GAZEL:
- case ISDN_CTYPE_HFC_SX:
- case ISDN_CTYPE_HFC_SP_PCMCIA:
- cards[j].para[0] = irq[i];
- cards[j].para[1] = io[i];
- break;
- case ISDN_CTYPE_ISURF:
+ case ISDN_CTYPE_PNP:
+ case ISDN_CTYPE_NICCY:
+ cards[j].para[0] = irq[i];
+ cards[j].para[1] = io0[i];
+ cards[j].para[2] = io1[i];
+ break;
+ case ISDN_CTYPE_COMPAQ_ISA:
+ cards[j].para[0] = irq[i];
+ cards[j].para[1] = io0[i];
+ cards[j].para[2] = io1[i];
+ cards[j].para[3] = io[i];
+ break;
+#endif
+ case ISDN_CTYPE_ELSA:
+ case ISDN_CTYPE_HFC_PCI:
+ cards[j].para[0] = io[i];
+ break;
+ case ISDN_CTYPE_16_3:
+ case ISDN_CTYPE_TELESPCMCIA:
+ case ISDN_CTYPE_A1:
+ case ISDN_CTYPE_A1_PCMCIA:
+ case ISDN_CTYPE_ELSA_PNP:
+ case ISDN_CTYPE_ELSA_PCMCIA:
+ case ISDN_CTYPE_IX1MICROR2:
+ case ISDN_CTYPE_DIEHLDIVA:
+ case ISDN_CTYPE_ASUSCOM:
+ case ISDN_CTYPE_TELEINT:
+ case ISDN_CTYPE_SEDLBAUER:
+ case ISDN_CTYPE_SEDLBAUER_PCMCIA:
+ case ISDN_CTYPE_SEDLBAUER_FAX:
+ case ISDN_CTYPE_SPORTSTER:
+ case ISDN_CTYPE_MIC:
+ case ISDN_CTYPE_TELES3C:
+ case ISDN_CTYPE_ACERP10:
+ case ISDN_CTYPE_S0BOX:
+ case ISDN_CTYPE_FRITZPCI:
+ case ISDN_CTYPE_HSTSAPHIR:
+ case ISDN_CTYPE_GAZEL:
+ case ISDN_CTYPE_HFC_SX:
+ case ISDN_CTYPE_HFC_SP_PCMCIA:
+ cards[j].para[0] = irq[i];
+ cards[j].para[1] = io[i];
+ break;
+ case ISDN_CTYPE_ISURF:
+ cards[j].para[0] = irq[i];
+ cards[j].para[1] = io[i];
+ cards[j].para[2] = mem[i];
+ break;
+ case ISDN_CTYPE_ELSA_PCI:
+ case ISDN_CTYPE_NETJET_S:
+ case ISDN_CTYPE_AMD7930:
+ case ISDN_CTYPE_TELESPCI:
+ case ISDN_CTYPE_W6692:
+ case ISDN_CTYPE_NETJET_U:
+ break;
+ case ISDN_CTYPE_BKM_A4T:
+ break;
+ case ISDN_CTYPE_SCT_QUADRO:
+ if (irq[i]) {
cards[j].para[0] = irq[i];
- cards[j].para[1] = io[i];
- cards[j].para[2] = mem[i];
- break;
- case ISDN_CTYPE_ELSA_PCI:
- case ISDN_CTYPE_NETJET_S:
- case ISDN_CTYPE_AMD7930:
- case ISDN_CTYPE_TELESPCI:
- case ISDN_CTYPE_W6692:
- case ISDN_CTYPE_NETJET_U:
- break;
- case ISDN_CTYPE_BKM_A4T:
- break;
- case ISDN_CTYPE_SCT_QUADRO:
- if (irq[i]) {
- cards[j].para[0] = irq[i];
- } else {
- /* QUADRO is a 4 BRI card */
- cards[j++].para[0] = 1;
- cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
- cards[j].protocol = protocol[i];
- cards[j++].para[0] = 2;
- cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
- cards[j].protocol = protocol[i];
- cards[j++].para[0] = 3;
- cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
- cards[j].protocol = protocol[i];
- cards[j].para[0] = 4;
- }
- break;
+ } else {
+ /* QUADRO is a 4 BRI card */
+ cards[j++].para[0] = 1;
+ cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+ cards[j].protocol = protocol[i];
+ cards[j++].para[0] = 2;
+ cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+ cards[j].protocol = protocol[i];
+ cards[j++].para[0] = 3;
+ cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+ cards[j].protocol = protocol[i];
+ cards[j].para[0] = 4;
+ }
+ break;
}
j++;
}
if (!nzproto) {
- printk(KERN_WARNING "HiSax: Warning - no protocol specified\n");
- printk(KERN_WARNING "HiSax: using protocol %s\n", DEFAULT_PROTO_NAME);
+ printk(KERN_WARNING
+ "HiSax: Warning - no protocol specified\n");
+ printk(KERN_WARNING "HiSax: using protocol %s\n",
+ DEFAULT_PROTO_NAME);
}
#endif
if (!HiSax_id)
retval = -EIO;
goto out_isdnl1;
}
-
+
return 0;
out_isdnl1:
static void __exit HiSax_exit(void)
{
- int cardnr = nrcards -1;
+ int cardnr = nrcards - 1;
long flags;
save_flags(flags);
cli();
- while(cardnr>=0)
+ while (cardnr >= 0)
HiSax_closecard(cardnr--);
Isdnl1Free();
TeiFree();
nrcards = 0;
/* Initialize all structs, even though we only accept
two pcmcia cards
- */
+ */
for (i = 0; i < HISAX_MAX_CARDS; i++) {
cards[i].para[0] = irq[i];
cards[i].para[1] = io[i];
}
}
cards[0].para[0] = pcm_irq;
- cards[0].para[1] = (int)pcm_iob;
+ cards[0].para[1] = (int) pcm_iob;
cards[0].protocol = prot;
cards[0].typ = ISDN_CTYPE_ELSA_PCMCIA;
HiSax_inithardware(busy_flag);
printk(KERN_NOTICE "HiSax: module installed\n");
#endif
- return (0);
+ return 0;
}
#endif
nrcards = 0;
/* Initialize all structs, even though we only accept
two pcmcia cards
- */
+ */
for (i = 0; i < HISAX_MAX_CARDS; i++) {
cards[i].para[0] = irq[i];
cards[i].para[1] = io[i];
}
}
cards[0].para[0] = pcm_irq;
- cards[0].para[1] = (int)pcm_iob;
+ cards[0].para[1] = (int) pcm_iob;
cards[0].protocol = prot;
cards[0].typ = ISDN_CTYPE_HFC_SP_PCMCIA;
nzproto = 1;
HiSax_inithardware(busy_flag);
printk(KERN_NOTICE "HiSax: module installed\n");
#endif
- return (0);
+ return 0;
}
#endif
nrcards = 0;
/* Initialize all structs, even though we only accept
two pcmcia cards
- */
+ */
for (i = 0; i < HISAX_MAX_CARDS; i++) {
cards[i].para[0] = irq[i];
cards[i].para[1] = io[i];
}
}
cards[0].para[0] = pcm_irq;
- cards[0].para[1] = (int)pcm_iob;
+ cards[0].para[1] = (int) pcm_iob;
cards[0].protocol = prot;
cards[0].typ = ISDN_CTYPE_SEDLBAUER_PCMCIA;
nzproto = 1;
HiSax_inithardware(busy_flag);
printk(KERN_NOTICE "HiSax: module installed\n");
#endif
- return (0);
+ return 0;
}
#endif
nrcards = 0;
/* Initialize all structs, even though we only accept
two pcmcia cards
- */
+ */
for (i = 0; i < HISAX_MAX_CARDS; i++) {
cards[i].para[0] = irq[i];
cards[i].para[1] = io[i];
}
}
cards[0].para[0] = pcm_irq;
- cards[0].para[1] = (int)pcm_iob;
+ cards[0].para[1] = (int) pcm_iob;
cards[0].protocol = prot;
cards[0].typ = ISDN_CTYPE_A1_PCMCIA;
nzproto = 1;
HiSax_inithardware(busy_flag);
printk(KERN_NOTICE "HiSax: module installed\n");
#endif
- return (0);
+ return 0;
}
#endif
-int __devinit hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *card)
+int __devinit hisax_init_pcmcia(void *pcm_iob, int *busy_flag,
+ struct IsdnCard *card)
{
u_char ids[16];
int ret = -1;
else
sprintf(ids, "HiSax");
if (!checkcard(nrcards, ids, busy_flag)) {
- return(-1);
+ return -1;
}
ret = nrcards;
nrcards++;
- return (ret);
+ return ret;
}
#include <linux/pci.h>
+++ /dev/null
-6f9433a8b696076562562d090e3c420f isac.c
-13c3eed869f5139f44c563e3a8fea1f5 isdnl1.c
-addcff863b0ff1e366c0f2ae9fa6e81e isdnl2.c
-7076deb94a363945c21ea27aca4a720a isdnl3.c
-51c603829b6cc4f8421f744ad657ceff tei.c
-669050ab5079f02887ed0239d86e5474 callc.c
-e592db58630c1f1029cc064110108156 cert.c
-fadeb3b85bb23bc1ac48470c0848d6fa l3dss1.c
-cf7dec9fac6283716904d26b99188476 l3_1tr6.c
-65d9e5471bc129624f858ebcf0743525 elsa.c
-b4cf8a4dceed9ea6dcba65a85b4eecc7 diva.c
-99e67bea8f6945fa0d4e0aded5bf0fa0 sedlbauer.c
-/* $Id: isdn_tty.c,v 1.94.6.2 2001/06/09 15:14:15 kai Exp $
+/* $Id: isdn_tty.c,v 1.94.6.3 2001/07/03 14:48:25 kai Exp $
* Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
*
static int si2bit[8] =
{4, 1, 4, 4, 4, 4, 4, 4};
-char *isdn_tty_revision = "$Revision: 1.94.6.2 $";
+char *isdn_tty_revision = "$Revision: 1.94.6.3 $";
/* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
status = info->lsr;
restore_flags(flags);
result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
- put_user(result, (uint *) value);
- return 0;
+ return put_user(result, (uint *) value);
}
| ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
| ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
| ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
- put_user(result, (uint *) value);
- return 0;
+ return put_user(result, (uint *) value);
}
static int
uint arg;
int pre_dtr;
- get_user(arg, (uint *) value);
+ if (get_user(arg, (uint *) value))
+ return -EFAULT;
switch (cmd) {
case TIOCMBIS:
#ifdef ISDN_DEBUG_MODEM_IOCTL
uint cmd, ulong arg)
{
modem_info *info = (modem_info *) tty->driver_data;
- int error;
int retval;
if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_ioctl"))
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "ttyI%d ioctl TIOCGSOFTCAR\n", info->line);
#endif
- error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
- if (error)
- return error;
- put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
- return 0;
+ return put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
case TIOCSSOFTCAR:
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line);
#endif
- error = verify_area(VERIFY_READ, (void *) arg, sizeof(long));
- if (error)
- return error;
- get_user(arg, (ulong *) arg);
+ if (get_user(arg, (ulong *) arg))
+ return -EFAULT;
tty->termios->c_cflag =
((tty->termios->c_cflag & ~CLOCAL) |
(arg ? CLOCAL : 0));
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line);
#endif
- error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
- if (error)
- return error;
return isdn_tty_get_modem_info(info, (uint *) arg);
case TIOCMBIS:
case TIOCMBIC:
case TIOCMSET:
- error = verify_area(VERIFY_READ, (void *) arg, sizeof(uint));
- if (error)
- return error;
return isdn_tty_set_modem_info(info, cmd, (uint *) arg);
case TIOCSERGETLSR: /* Get line status register */
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line);
#endif
- error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
- if (error)
- return error;
- else
- return isdn_tty_get_lsr_info(info, (uint *) arg);
+ return isdn_tty_get_lsr_info(info, (uint *) arg);
default:
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line);
--- /dev/null
+mainmenu_option next_comment
+comment 'Fusion MPT device support'
+
+dep_tristate "Fusion MPT (base + ScsiHost) drivers" CONFIG_FUSION $CONFIG_SCSI $CONFIG_BLK_DEV_SD
+
+if [ "$CONFIG_FUSION" = "y" -o "$CONFIG_FUSION" = "m" ]; then
+
+ if [ "$CONFIG_BLK_DEV_SD" = "y" -a "$CONFIG_FUSION" = "y" ]; then
+ define_bool CONFIG_FUSION_BOOT y
+ comment "(ability to boot linux kernel from Fusion device is ENABLED!)"
+ else
+ define_bool CONFIG_FUSION_BOOT n
+ comment "(ability to boot linux kernel from Fusion device is DISABLED!)"
+ fi
+
+ if [ "$CONFIG_MODULES" = "y" ]; then
+ # How can we force these options to module or nothing?
+ dep_tristate " Enhanced SCSI error reporting" CONFIG_FUSION_ISENSE $CONFIG_FUSION m
+ dep_tristate " Fusion MPT misc device (ioctl) driver" CONFIG_FUSION_CTL $CONFIG_FUSION m
+ fi
+
+ dep_tristate " Fusion MPT LAN driver" CONFIG_FUSION_LAN $CONFIG_FUSION $CONFIG_NET
+ if [ "$CONFIG_FUSION_LAN" != "n" ]; then
+ define_bool CONFIG_NET_FC y
+ fi
+
+else
+
+ define_bool CONFIG_FUSION_BOOT n
+ # These <should> be define_tristate, but we leave them define_bool
+ # for backward compatibility with pre-linux-2.2.15 kernels.
+ # (Bugzilla:fibrebugs, #384)
+ define_bool CONFIG_FUSION_ISENSE n
+ define_bool CONFIG_FUSION_CTL n
+ define_bool CONFIG_FUSION_LAN n
+
+fi
+
+endmenu
--- /dev/null
+#
+# Makefile for the LSI Logic Fusion MPT (Message Passing Technology) drivers.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now inherited from the
+# parent makefile.
+#
+# Note 3! If you want to turn on various debug defines for an extended period of
+# time but don't want them lingering around in the Makefile when you pass it on
+# to someone else, use the MPT_CFLAGS env variable (thanks Steve). -nromer
+
+#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-{ LSI_LOGIC
+
+# Architecture-specific...
+# # intel
+#EXTRA_CFLAGS += -g
+# # sparc64
+#EXTRA_CFLAGS += -gstabs+
+
+EXTRA_CFLAGS += -I. ${MPT_CFLAGS}
+
+# Fusion MPT drivers; recognized debug defines...
+# MPT general:
+#EXTRA_CFLAGS += -DDEBUG
+#EXTRA_CFLAGS += -DMPT_DEBUG
+#EXTRA_CFLAGS += -DMPT_DEBUG_MSG_FRAME
+#EXTRA_CFLAGS += -DMPT_DEBUG_SPINLOCK
+# driver/module specifics...
+# For mptbase:
+#CFLAGS_mptbase.o += -DMPT_DEBUG_HANDSHAKE
+#CFLAGS_mptbase.o += -DMPT_DEBUG_IRQ
+# For {mptscsih, mptctl}:
+#CFLAGS_mptscsih.o += -DMPT_SCSI_USE_NEW_EH
+#CFLAGS_mptscsih.o += -DMPT_SCSI_CACHE_AUTOSENSE
+#CFLAGS_mptscsih.o += -DMPT_DEBUG_SG
+#CFLAGS_mptctl.o += -DMPT_DEBUG_SG
+# For mptlan:
+#CFLAGS_mptlan.o += -DMPT_LAN_IO_DEBUG
+# For isense:
+
+# EXP...
+##mptscsih-objs := scsihost.o scsiherr.o
+
+#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC
+
+O_TARGET := fusion.o
+
+export-objs := mptbase.o mptscsih.o mptlan.o mptctl.o isense.o
+
+# ? what's list-multi for?
+#list-multi := fusion.o mptscsih.o
+
+obj-$(CONFIG_FUSION) += mptbase.o mptscsih.o
+obj-$(CONFIG_FUSION_ISENSE) += isense.o
+obj-$(CONFIG_FUSION_CTL) += mptctl.o
+obj-$(CONFIG_FUSION_LAN) += mptlan.o
+
+O_OBJS := $(filter-out $(export-objs), $(obj-y))
+OX_OBJS := $(filter $(export-objs), $(obj-y))
+M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
+
+include $(TOPDIR)/Rules.make
+
+
+# EXP...
+## Fusion MPT extra's...
+##mptscsih.o: $(mptscsih-objs)
+## $(LD) -r -o $@ $(mptscsih-objs)
--- /dev/null
+#ifndef SCSI_ASCQ_TBL_C_INCLUDED
+#define SCSI_ASCQ_TBL_C_INCLUDED
+
+/* AuToMaGiCaLlY generated from: "t10.org/asc-num.txt"
+ *******************************************************************************
+ * File: ASC-NUM.TXT
+ *
+ * SCSI ASC/ASCQ Assignments
+ * Numeric Sorted Listing
+ * as of 5/18/00
+ *
+ * D - DIRECT ACCESS DEVICE (SBC-2) device column key
+ * .T - SEQUENTIAL ACCESS DEVICE (SSC) -------------------
+ * . L - PRINTER DEVICE (SSC) blank = reserved
+ * . P - PROCESSOR DEVICE (SPC) not blank = allowed
+ * . .W - WRITE ONCE READ MULTIPLE DEVICE (SBC-2)
+ * . . R - CD DEVICE (MMC)
+ * . . S - SCANNER DEVICE (SCSI-2)
+ * . . .O - OPTICAL MEMORY DEVICE (SBC-2)
+ * . . . M - MEDIA CHANGER DEVICE (SMC)
+ * . . . C - COMMUNICATION DEVICE (SCSI-2)
+ * . . . .A - STORAGE ARRAY DEVICE (SCC)
+ * . . . . E - ENCLOSURE SERVICES DEVICE (SES)
+ * . . . . B - SIMPLIFIED DIRECT-ACCESS DEVICE (RBC)
+ * . . . . .K - OPTICAL CARD READER/WRITER DEVICE (OCRW)
+ * ASC/ASCQ DTLPWRSOMCAEBK Description
+ * ------- -------------- ----------------------------------------------------
+ */
+
+static char SenseDevTypes001[] = "DTLPWRSOMCAEBK";
+static char SenseDevTypes002[] = ".T............";
+static char SenseDevTypes003[] = ".T....S.......";
+static char SenseDevTypes004[] = ".TL...S.......";
+static char SenseDevTypes005[] = ".....R........";
+static char SenseDevTypes006[] = "DTL.WRSOM.AEBK";
+static char SenseDevTypes007[] = "D...W..O....BK";
+static char SenseDevTypes008[] = "D...WR.OM...BK";
+static char SenseDevTypes009[] = "DTL.W.SO....BK";
+static char SenseDevTypes010[] = "DTL..R.O....B.";
+static char SenseDevTypes011[] = "DT..W..OMCA.BK";
+static char SenseDevTypes012[] = "..............";
+static char SenseDevTypes013[] = "DTL.WRSOMCAEBK";
+static char SenseDevTypes014[] = "DTL.WRSOM...BK";
+static char SenseDevTypes015[] = "DT...R.OM...BK";
+static char SenseDevTypes016[] = "DTLPWRSO.C...K";
+static char SenseDevTypes017[] = "DT..WR.O....B.";
+static char SenseDevTypes018[] = "....WR.O.....K";
+static char SenseDevTypes019[] = "....WR.O......";
+static char SenseDevTypes020[] = ".T...RS.......";
+static char SenseDevTypes021[] = ".............K";
+static char SenseDevTypes022[] = "DT..W..O....B.";
+static char SenseDevTypes023[] = "DT..WRSO....BK";
+static char SenseDevTypes024[] = "DT..W.SO....BK";
+static char SenseDevTypes025[] = "....WR.O....B.";
+static char SenseDevTypes026[] = "....W..O....B.";
+static char SenseDevTypes027[] = "DT.....O....BK";
+static char SenseDevTypes028[] = "DTL.WRSO....BK";
+static char SenseDevTypes029[] = "DT..WR.O....BK";
+static char SenseDevTypes030[] = "DT..W..O....BK";
+static char SenseDevTypes031[] = "D...WR.O....BK";
+static char SenseDevTypes032[] = "D......O.....K";
+static char SenseDevTypes033[] = "D......O....BK";
+static char SenseDevTypes034[] = "DT..WR.OM...BK";
+static char SenseDevTypes035[] = "D.............";
+static char SenseDevTypes036[] = "DTLPWRSOMCAE.K";
+static char SenseDevTypes037[] = "DTLPWRSOMCA.BK";
+static char SenseDevTypes038[] = ".T...R........";
+static char SenseDevTypes039[] = "DT..WR.OM...B.";
+static char SenseDevTypes040[] = "DTL.WRSOMCAE.K";
+static char SenseDevTypes041[] = "DTLPWRSOMCAE..";
+static char SenseDevTypes042[] = "......S.......";
+static char SenseDevTypes043[] = "............B.";
+static char SenseDevTypes044[] = "DTLPWRSO.CA..K";
+static char SenseDevTypes045[] = "DT...R.......K";
+static char SenseDevTypes046[] = "D.L..R.O....B.";
+static char SenseDevTypes047[] = "..L...........";
+static char SenseDevTypes048[] = ".TL...........";
+static char SenseDevTypes049[] = "DTLPWRSOMC..BK";
+static char SenseDevTypes050[] = "DT..WR.OMCAEBK";
+static char SenseDevTypes051[] = "DT..WR.OMCAEB.";
+static char SenseDevTypes052[] = ".T...R.O......";
+static char SenseDevTypes053[] = "...P..........";
+static char SenseDevTypes054[] = "DTLPWRSOM.AE.K";
+static char SenseDevTypes055[] = "DTLPWRSOM.AE..";
+static char SenseDevTypes056[] = ".......O......";
+static char SenseDevTypes057[] = "DTLPWRSOM...BK";
+static char SenseDevTypes058[] = "DT..WR.O..A.BK";
+static char SenseDevTypes059[] = "DTLPWRSOM....K";
+static char SenseDevTypes060[] = "D......O......";
+static char SenseDevTypes061[] = ".....R......B.";
+static char SenseDevTypes062[] = "D...........B.";
+static char SenseDevTypes063[] = "............BK";
+static char SenseDevTypes064[] = "..........A...";
+
+static ASCQ_Table_t ASCQ_Table[] = {
+ {
+ 0x00, 0x00,
+ SenseDevTypes001,
+ "NO ADDITIONAL SENSE INFORMATION"
+ },
+ {
+ 0x00, 0x01,
+ SenseDevTypes002,
+ "FILEMARK DETECTED"
+ },
+ {
+ 0x00, 0x02,
+ SenseDevTypes003,
+ "END-OF-PARTITION/MEDIUM DETECTED"
+ },
+ {
+ 0x00, 0x03,
+ SenseDevTypes002,
+ "SETMARK DETECTED"
+ },
+ {
+ 0x00, 0x04,
+ SenseDevTypes003,
+ "BEGINNING-OF-PARTITION/MEDIUM DETECTED"
+ },
+ {
+ 0x00, 0x05,
+ SenseDevTypes004,
+ "END-OF-DATA DETECTED"
+ },
+ {
+ 0x00, 0x06,
+ SenseDevTypes001,
+ "I/O PROCESS TERMINATED"
+ },
+ {
+ 0x00, 0x11,
+ SenseDevTypes005,
+ "AUDIO PLAY OPERATION IN PROGRESS"
+ },
+ {
+ 0x00, 0x12,
+ SenseDevTypes005,
+ "AUDIO PLAY OPERATION PAUSED"
+ },
+ {
+ 0x00, 0x13,
+ SenseDevTypes005,
+ "AUDIO PLAY OPERATION SUCCESSFULLY COMPLETED"
+ },
+ {
+ 0x00, 0x14,
+ SenseDevTypes005,
+ "AUDIO PLAY OPERATION STOPPED DUE TO ERROR"
+ },
+ {
+ 0x00, 0x15,
+ SenseDevTypes005,
+ "NO CURRENT AUDIO STATUS TO RETURN"
+ },
+ {
+ 0x00, 0x16,
+ SenseDevTypes001,
+ "OPERATION IN PROGRESS"
+ },
+ {
+ 0x00, 0x17,
+ SenseDevTypes006,
+ "CLEANING REQUESTED"
+ },
+ {
+ 0x01, 0x00,
+ SenseDevTypes007,
+ "NO INDEX/SECTOR SIGNAL"
+ },
+ {
+ 0x02, 0x00,
+ SenseDevTypes008,
+ "NO SEEK COMPLETE"
+ },
+ {
+ 0x03, 0x00,
+ SenseDevTypes009,
+ "PERIPHERAL DEVICE WRITE FAULT"
+ },
+ {
+ 0x03, 0x01,
+ SenseDevTypes002,
+ "NO WRITE CURRENT"
+ },
+ {
+ 0x03, 0x02,
+ SenseDevTypes002,
+ "EXCESSIVE WRITE ERRORS"
+ },
+ {
+ 0x04, 0x00,
+ SenseDevTypes001,
+ "LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE"
+ },
+ {
+ 0x04, 0x01,
+ SenseDevTypes001,
+ "LOGICAL UNIT IS IN PROCESS OF BECOMING READY"
+ },
+ {
+ 0x04, 0x02,
+ SenseDevTypes001,
+ "LOGICAL UNIT NOT READY, INITIALIZING CMD. REQUIRED"
+ },
+ {
+ 0x04, 0x03,
+ SenseDevTypes001,
+ "LOGICAL UNIT NOT READY, MANUAL INTERVENTION REQUIRED"
+ },
+ {
+ 0x04, 0x04,
+ SenseDevTypes010,
+ "LOGICAL UNIT NOT READY, FORMAT IN PROGRESS"
+ },
+ {
+ 0x04, 0x05,
+ SenseDevTypes011,
+ "LOGICAL UNIT NOT READY, REBUILD IN PROGRESS"
+ },
+ {
+ 0x04, 0x06,
+ SenseDevTypes011,
+ "LOGICAL UNIT NOT READY, RECALCULATION IN PROGRESS"
+ },
+ {
+ 0x04, 0x07,
+ SenseDevTypes001,
+ "LOGICAL UNIT NOT READY, OPERATION IN PROGRESS"
+ },
+ {
+ 0x04, 0x08,
+ SenseDevTypes005,
+ "LOGICAL UNIT NOT READY, LONG WRITE IN PROGRESS"
+ },
+ {
+ 0x04, 0x09,
+ SenseDevTypes001,
+ "LOGICAL UNIT NOT READY, SELF-TEST IN PROGRESS"
+ },
+ {
+ 0x04, 0x10,
+ SenseDevTypes012,
+ "auxiliary memory code 2 (99-148) [proposed]"
+ },
+ {
+ 0x05, 0x00,
+ SenseDevTypes013,
+ "LOGICAL UNIT DOES NOT RESPOND TO SELECTION"
+ },
+ {
+ 0x06, 0x00,
+ SenseDevTypes008,
+ "NO REFERENCE POSITION FOUND"
+ },
+ {
+ 0x07, 0x00,
+ SenseDevTypes014,
+ "MULTIPLE PERIPHERAL DEVICES SELECTED"
+ },
+ {
+ 0x08, 0x00,
+ SenseDevTypes013,
+ "LOGICAL UNIT COMMUNICATION FAILURE"
+ },
+ {
+ 0x08, 0x01,
+ SenseDevTypes013,
+ "LOGICAL UNIT COMMUNICATION TIME-OUT"
+ },
+ {
+ 0x08, 0x02,
+ SenseDevTypes013,
+ "LOGICAL UNIT COMMUNICATION PARITY ERROR"
+ },
+ {
+ 0x08, 0x03,
+ SenseDevTypes015,
+ "LOGICAL UNIT COMMUNICATION CRC ERROR (ULTRA-DMA/32)"
+ },
+ {
+ 0x08, 0x04,
+ SenseDevTypes016,
+ "UNREACHABLE COPY TARGET"
+ },
+ {
+ 0x09, 0x00,
+ SenseDevTypes017,
+ "TRACK FOLLOWING ERROR"
+ },
+ {
+ 0x09, 0x01,
+ SenseDevTypes018,
+ "TRACKING SERVO FAILURE"
+ },
+ {
+ 0x09, 0x02,
+ SenseDevTypes018,
+ "FOCUS SERVO FAILURE"
+ },
+ {
+ 0x09, 0x03,
+ SenseDevTypes019,
+ "SPINDLE SERVO FAILURE"
+ },
+ {
+ 0x09, 0x04,
+ SenseDevTypes017,
+ "HEAD SELECT FAULT"
+ },
+ {
+ 0x0A, 0x00,
+ SenseDevTypes001,
+ "ERROR LOG OVERFLOW"
+ },
+ {
+ 0x0B, 0x00,
+ SenseDevTypes001,
+ "WARNING"
+ },
+ {
+ 0x0B, 0x01,
+ SenseDevTypes001,
+ "WARNING - SPECIFIED TEMPERATURE EXCEEDED"
+ },
+ {
+ 0x0B, 0x02,
+ SenseDevTypes001,
+ "WARNING - ENCLOSURE DEGRADED"
+ },
+ {
+ 0x0C, 0x00,
+ SenseDevTypes020,
+ "WRITE ERROR"
+ },
+ {
+ 0x0C, 0x01,
+ SenseDevTypes021,
+ "WRITE ERROR - RECOVERED WITH AUTO REALLOCATION"
+ },
+ {
+ 0x0C, 0x02,
+ SenseDevTypes007,
+ "WRITE ERROR - AUTO REALLOCATION FAILED"
+ },
+ {
+ 0x0C, 0x03,
+ SenseDevTypes007,
+ "WRITE ERROR - RECOMMEND REASSIGNMENT"
+ },
+ {
+ 0x0C, 0x04,
+ SenseDevTypes022,
+ "COMPRESSION CHECK MISCOMPARE ERROR"
+ },
+ {
+ 0x0C, 0x05,
+ SenseDevTypes022,
+ "DATA EXPANSION OCCURRED DURING COMPRESSION"
+ },
+ {
+ 0x0C, 0x06,
+ SenseDevTypes022,
+ "BLOCK NOT COMPRESSIBLE"
+ },
+ {
+ 0x0C, 0x07,
+ SenseDevTypes005,
+ "WRITE ERROR - RECOVERY NEEDED"
+ },
+ {
+ 0x0C, 0x08,
+ SenseDevTypes005,
+ "WRITE ERROR - RECOVERY FAILED"
+ },
+ {
+ 0x0C, 0x09,
+ SenseDevTypes005,
+ "WRITE ERROR - LOSS OF STREAMING"
+ },
+ {
+ 0x0C, 0x0A,
+ SenseDevTypes005,
+ "WRITE ERROR - PADDING BLOCKS ADDED"
+ },
+ {
+ 0x0C, 0x0B,
+ SenseDevTypes012,
+ "auxiliary memory code 4 (99-148) [proposed]"
+ },
+ {
+ 0x10, 0x00,
+ SenseDevTypes007,
+ "ID CRC OR ECC ERROR"
+ },
+ {
+ 0x11, 0x00,
+ SenseDevTypes023,
+ "UNRECOVERED READ ERROR"
+ },
+ {
+ 0x11, 0x01,
+ SenseDevTypes023,
+ "READ RETRIES EXHAUSTED"
+ },
+ {
+ 0x11, 0x02,
+ SenseDevTypes023,
+ "ERROR TOO LONG TO CORRECT"
+ },
+ {
+ 0x11, 0x03,
+ SenseDevTypes024,
+ "MULTIPLE READ ERRORS"
+ },
+ {
+ 0x11, 0x04,
+ SenseDevTypes007,
+ "UNRECOVERED READ ERROR - AUTO REALLOCATE FAILED"
+ },
+ {
+ 0x11, 0x05,
+ SenseDevTypes025,
+ "L-EC UNCORRECTABLE ERROR"
+ },
+ {
+ 0x11, 0x06,
+ SenseDevTypes025,
+ "CIRC UNRECOVERED ERROR"
+ },
+ {
+ 0x11, 0x07,
+ SenseDevTypes026,
+ "DATA RE-SYNCHRONIZATION ERROR"
+ },
+ {
+ 0x11, 0x08,
+ SenseDevTypes002,
+ "INCOMPLETE BLOCK READ"
+ },
+ {
+ 0x11, 0x09,
+ SenseDevTypes002,
+ "NO GAP FOUND"
+ },
+ {
+ 0x11, 0x0A,
+ SenseDevTypes027,
+ "MISCORRECTED ERROR"
+ },
+ {
+ 0x11, 0x0B,
+ SenseDevTypes007,
+ "UNRECOVERED READ ERROR - RECOMMEND REASSIGNMENT"
+ },
+ {
+ 0x11, 0x0C,
+ SenseDevTypes007,
+ "UNRECOVERED READ ERROR - RECOMMEND REWRITE THE DATA"
+ },
+ {
+ 0x11, 0x0D,
+ SenseDevTypes017,
+ "DE-COMPRESSION CRC ERROR"
+ },
+ {
+ 0x11, 0x0E,
+ SenseDevTypes017,
+ "CANNOT DECOMPRESS USING DECLARED ALGORITHM"
+ },
+ {
+ 0x11, 0x0F,
+ SenseDevTypes005,
+ "ERROR READING UPC/EAN NUMBER"
+ },
+ {
+ 0x11, 0x10,
+ SenseDevTypes005,
+ "ERROR READING ISRC NUMBER"
+ },
+ {
+ 0x11, 0x11,
+ SenseDevTypes005,
+ "READ ERROR - LOSS OF STREAMING"
+ },
+ {
+ 0x11, 0x12,
+ SenseDevTypes012,
+ "auxiliary memory code 3 (99-148) [proposed]"
+ },
+ {
+ 0x12, 0x00,
+ SenseDevTypes007,
+ "ADDRESS MARK NOT FOUND FOR ID FIELD"
+ },
+ {
+ 0x13, 0x00,
+ SenseDevTypes007,
+ "ADDRESS MARK NOT FOUND FOR DATA FIELD"
+ },
+ {
+ 0x14, 0x00,
+ SenseDevTypes028,
+ "RECORDED ENTITY NOT FOUND"
+ },
+ {
+ 0x14, 0x01,
+ SenseDevTypes029,
+ "RECORD NOT FOUND"
+ },
+ {
+ 0x14, 0x02,
+ SenseDevTypes002,
+ "FILEMARK OR SETMARK NOT FOUND"
+ },
+ {
+ 0x14, 0x03,
+ SenseDevTypes002,
+ "END-OF-DATA NOT FOUND"
+ },
+ {
+ 0x14, 0x04,
+ SenseDevTypes002,
+ "BLOCK SEQUENCE ERROR"
+ },
+ {
+ 0x14, 0x05,
+ SenseDevTypes030,
+ "RECORD NOT FOUND - RECOMMEND REASSIGNMENT"
+ },
+ {
+ 0x14, 0x06,
+ SenseDevTypes030,
+ "RECORD NOT FOUND - DATA AUTO-REALLOCATED"
+ },
+ {
+ 0x15, 0x00,
+ SenseDevTypes014,
+ "RANDOM POSITIONING ERROR"
+ },
+ {
+ 0x15, 0x01,
+ SenseDevTypes014,
+ "MECHANICAL POSITIONING ERROR"
+ },
+ {
+ 0x15, 0x02,
+ SenseDevTypes029,
+ "POSITIONING ERROR DETECTED BY READ OF MEDIUM"
+ },
+ {
+ 0x16, 0x00,
+ SenseDevTypes007,
+ "DATA SYNCHRONIZATION MARK ERROR"
+ },
+ {
+ 0x16, 0x01,
+ SenseDevTypes007,
+ "DATA SYNC ERROR - DATA REWRITTEN"
+ },
+ {
+ 0x16, 0x02,
+ SenseDevTypes007,
+ "DATA SYNC ERROR - RECOMMEND REWRITE"
+ },
+ {
+ 0x16, 0x03,
+ SenseDevTypes007,
+ "DATA SYNC ERROR - DATA AUTO-REALLOCATED"
+ },
+ {
+ 0x16, 0x04,
+ SenseDevTypes007,
+ "DATA SYNC ERROR - RECOMMEND REASSIGNMENT"
+ },
+ {
+ 0x17, 0x00,
+ SenseDevTypes023,
+ "RECOVERED DATA WITH NO ERROR CORRECTION APPLIED"
+ },
+ {
+ 0x17, 0x01,
+ SenseDevTypes023,
+ "RECOVERED DATA WITH RETRIES"
+ },
+ {
+ 0x17, 0x02,
+ SenseDevTypes029,
+ "RECOVERED DATA WITH POSITIVE HEAD OFFSET"
+ },
+ {
+ 0x17, 0x03,
+ SenseDevTypes029,
+ "RECOVERED DATA WITH NEGATIVE HEAD OFFSET"
+ },
+ {
+ 0x17, 0x04,
+ SenseDevTypes025,
+ "RECOVERED DATA WITH RETRIES AND/OR CIRC APPLIED"
+ },
+ {
+ 0x17, 0x05,
+ SenseDevTypes031,
+ "RECOVERED DATA USING PREVIOUS SECTOR ID"
+ },
+ {
+ 0x17, 0x06,
+ SenseDevTypes007,
+ "RECOVERED DATA WITHOUT ECC - DATA AUTO-REALLOCATED"
+ },
+ {
+ 0x17, 0x07,
+ SenseDevTypes031,
+ "RECOVERED DATA WITHOUT ECC - RECOMMEND REASSIGNMENT"
+ },
+ {
+ 0x17, 0x08,
+ SenseDevTypes031,
+ "RECOVERED DATA WITHOUT ECC - RECOMMEND REWRITE"
+ },
+ {
+ 0x17, 0x09,
+ SenseDevTypes031,
+ "RECOVERED DATA WITHOUT ECC - DATA REWRITTEN"
+ },
+ {
+ 0x18, 0x00,
+ SenseDevTypes029,
+ "RECOVERED DATA WITH ERROR CORRECTION APPLIED"
+ },
+ {
+ 0x18, 0x01,
+ SenseDevTypes031,
+ "RECOVERED DATA WITH ERROR CORR. & RETRIES APPLIED"
+ },
+ {
+ 0x18, 0x02,
+ SenseDevTypes031,
+ "RECOVERED DATA - DATA AUTO-REALLOCATED"
+ },
+ {
+ 0x18, 0x03,
+ SenseDevTypes005,
+ "RECOVERED DATA WITH CIRC"
+ },
+ {
+ 0x18, 0x04,
+ SenseDevTypes005,
+ "RECOVERED DATA WITH L-EC"
+ },
+ {
+ 0x18, 0x05,
+ SenseDevTypes031,
+ "RECOVERED DATA - RECOMMEND REASSIGNMENT"
+ },
+ {
+ 0x18, 0x06,
+ SenseDevTypes031,
+ "RECOVERED DATA - RECOMMEND REWRITE"
+ },
+ {
+ 0x18, 0x07,
+ SenseDevTypes007,
+ "RECOVERED DATA WITH ECC - DATA REWRITTEN"
+ },
+ {
+ 0x19, 0x00,
+ SenseDevTypes032,
+ "DEFECT LIST ERROR"
+ },
+ {
+ 0x19, 0x01,
+ SenseDevTypes032,
+ "DEFECT LIST NOT AVAILABLE"
+ },
+ {
+ 0x19, 0x02,
+ SenseDevTypes032,
+ "DEFECT LIST ERROR IN PRIMARY LIST"
+ },
+ {
+ 0x19, 0x03,
+ SenseDevTypes032,
+ "DEFECT LIST ERROR IN GROWN LIST"
+ },
+ {
+ 0x1A, 0x00,
+ SenseDevTypes001,
+ "PARAMETER LIST LENGTH ERROR"
+ },
+ {
+ 0x1B, 0x00,
+ SenseDevTypes001,
+ "SYNCHRONOUS DATA TRANSFER ERROR"
+ },
+ {
+ 0x1C, 0x00,
+ SenseDevTypes033,
+ "DEFECT LIST NOT FOUND"
+ },
+ {
+ 0x1C, 0x01,
+ SenseDevTypes033,
+ "PRIMARY DEFECT LIST NOT FOUND"
+ },
+ {
+ 0x1C, 0x02,
+ SenseDevTypes033,
+ "GROWN DEFECT LIST NOT FOUND"
+ },
+ {
+ 0x1D, 0x00,
+ SenseDevTypes029,
+ "MISCOMPARE DURING VERIFY OPERATION"
+ },
+ {
+ 0x1E, 0x00,
+ SenseDevTypes007,
+ "RECOVERED ID WITH ECC CORRECTION"
+ },
+ {
+ 0x1F, 0x00,
+ SenseDevTypes032,
+ "PARTIAL DEFECT LIST TRANSFER"
+ },
+ {
+ 0x20, 0x00,
+ SenseDevTypes001,
+ "INVALID COMMAND OPERATION CODE"
+ },
+ {
+ 0x20, 0x01,
+ SenseDevTypes012,
+ "access controls code 1 (99-314) [proposed]"
+ },
+ {
+ 0x20, 0x02,
+ SenseDevTypes012,
+ "access controls code 2 (99-314) [proposed]"
+ },
+ {
+ 0x20, 0x03,
+ SenseDevTypes012,
+ "access controls code 3 (99-314) [proposed]"
+ },
+ {
+ 0x21, 0x00,
+ SenseDevTypes034,
+ "LOGICAL BLOCK ADDRESS OUT OF RANGE"
+ },
+ {
+ 0x21, 0x01,
+ SenseDevTypes034,
+ "INVALID ELEMENT ADDRESS"
+ },
+ {
+ 0x22, 0x00,
+ SenseDevTypes035,
+ "ILLEGAL FUNCTION (USE 20 00, 24 00, OR 26 00)"
+ },
+ {
+ 0x24, 0x00,
+ SenseDevTypes001,
+ "INVALID FIELD IN CDB"
+ },
+ {
+ 0x24, 0x01,
+ SenseDevTypes001,
+ "CDB DECRYPTION ERROR"
+ },
+ {
+ 0x25, 0x00,
+ SenseDevTypes001,
+ "LOGICAL UNIT NOT SUPPORTED"
+ },
+ {
+ 0x26, 0x00,
+ SenseDevTypes001,
+ "INVALID FIELD IN PARAMETER LIST"
+ },
+ {
+ 0x26, 0x01,
+ SenseDevTypes001,
+ "PARAMETER NOT SUPPORTED"
+ },
+ {
+ 0x26, 0x02,
+ SenseDevTypes001,
+ "PARAMETER VALUE INVALID"
+ },
+ {
+ 0x26, 0x03,
+ SenseDevTypes036,
+ "THRESHOLD PARAMETERS NOT SUPPORTED"
+ },
+ {
+ 0x26, 0x04,
+ SenseDevTypes001,
+ "INVALID RELEASE OF PERSISTENT RESERVATION"
+ },
+ {
+ 0x26, 0x05,
+ SenseDevTypes037,
+ "DATA DECRYPTION ERROR"
+ },
+ {
+ 0x26, 0x06,
+ SenseDevTypes016,
+ "TOO MANY TARGET DESCRIPTORS"
+ },
+ {
+ 0x26, 0x07,
+ SenseDevTypes016,
+ "UNSUPPORTED TARGET DESCRIPTOR TYPE CODE"
+ },
+ {
+ 0x26, 0x08,
+ SenseDevTypes016,
+ "TOO MANY SEGMENT DESCRIPTORS"
+ },
+ {
+ 0x26, 0x09,
+ SenseDevTypes016,
+ "UNSUPPORTED SEGMENT DESCRIPTOR TYPE CODE"
+ },
+ {
+ 0x26, 0x0A,
+ SenseDevTypes016,
+ "UNEXPECTED INEXACT SEGMENT"
+ },
+ {
+ 0x26, 0x0B,
+ SenseDevTypes016,
+ "INLINE DATA LENGTH EXCEEDED"
+ },
+ {
+ 0x26, 0x0C,
+ SenseDevTypes016,
+ "INVALID OPERATION FOR COPY SOURCE OR DESTINATION"
+ },
+ {
+ 0x26, 0x0D,
+ SenseDevTypes016,
+ "COPY SEGMENT GRANULARITY VIOLATION"
+ },
+ {
+ 0x27, 0x00,
+ SenseDevTypes029,
+ "WRITE PROTECTED"
+ },
+ {
+ 0x27, 0x01,
+ SenseDevTypes029,
+ "HARDWARE WRITE PROTECTED"
+ },
+ {
+ 0x27, 0x02,
+ SenseDevTypes029,
+ "LOGICAL UNIT SOFTWARE WRITE PROTECTED"
+ },
+ {
+ 0x27, 0x03,
+ SenseDevTypes038,
+ "ASSOCIATED WRITE PROTECT"
+ },
+ {
+ 0x27, 0x04,
+ SenseDevTypes038,
+ "PERSISTENT WRITE PROTECT"
+ },
+ {
+ 0x27, 0x05,
+ SenseDevTypes038,
+ "PERMANENT WRITE PROTECT"
+ },
+ {
+ 0x28, 0x00,
+ SenseDevTypes001,
+ "NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED"
+ },
+ {
+ 0x28, 0x01,
+ SenseDevTypes039,
+ "IMPORT OR EXPORT ELEMENT ACCESSED"
+ },
+ {
+ 0x29, 0x00,
+ SenseDevTypes001,
+ "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED"
+ },
+ {
+ 0x29, 0x01,
+ SenseDevTypes001,
+ "POWER ON OCCURRED"
+ },
+ {
+ 0x29, 0x02,
+ SenseDevTypes001,
+ "SCSI BUS RESET OCCURRED"
+ },
+ {
+ 0x29, 0x03,
+ SenseDevTypes001,
+ "BUS DEVICE RESET FUNCTION OCCURRED"
+ },
+ {
+ 0x29, 0x04,
+ SenseDevTypes001,
+ "DEVICE INTERNAL RESET"
+ },
+ {
+ 0x29, 0x05,
+ SenseDevTypes001,
+ "TRANSCEIVER MODE CHANGED TO SINGLE-ENDED"
+ },
+ {
+ 0x29, 0x06,
+ SenseDevTypes001,
+ "TRANSCEIVER MODE CHANGED TO LVD"
+ },
+ {
+ 0x2A, 0x00,
+ SenseDevTypes013,
+ "PARAMETERS CHANGED"
+ },
+ {
+ 0x2A, 0x01,
+ SenseDevTypes013,
+ "MODE PARAMETERS CHANGED"
+ },
+ {
+ 0x2A, 0x02,
+ SenseDevTypes040,
+ "LOG PARAMETERS CHANGED"
+ },
+ {
+ 0x2A, 0x03,
+ SenseDevTypes036,
+ "RESERVATIONS PREEMPTED"
+ },
+ {
+ 0x2A, 0x04,
+ SenseDevTypes041,
+ "RESERVATIONS RELEASED"
+ },
+ {
+ 0x2A, 0x05,
+ SenseDevTypes041,
+ "REGISTRATIONS PREEMPTED"
+ },
+ {
+ 0x2B, 0x00,
+ SenseDevTypes016,
+ "COPY CANNOT EXECUTE SINCE HOST CANNOT DISCONNECT"
+ },
+ {
+ 0x2C, 0x00,
+ SenseDevTypes001,
+ "COMMAND SEQUENCE ERROR"
+ },
+ {
+ 0x2C, 0x01,
+ SenseDevTypes042,
+ "TOO MANY WINDOWS SPECIFIED"
+ },
+ {
+ 0x2C, 0x02,
+ SenseDevTypes042,
+ "INVALID COMBINATION OF WINDOWS SPECIFIED"
+ },
+ {
+ 0x2C, 0x03,
+ SenseDevTypes005,
+ "CURRENT PROGRAM AREA IS NOT EMPTY"
+ },
+ {
+ 0x2C, 0x04,
+ SenseDevTypes005,
+ "CURRENT PROGRAM AREA IS EMPTY"
+ },
+ {
+ 0x2C, 0x05,
+ SenseDevTypes043,
+ "ILLEGAL POWER CONDITION REQUEST"
+ },
+ {
+ 0x2D, 0x00,
+ SenseDevTypes002,
+ "OVERWRITE ERROR ON UPDATE IN PLACE"
+ },
+ {
+ 0x2E, 0x00,
+ SenseDevTypes044,
+ "ERROR DETECTED BY THIRD PARTY TEMPORARY INITIATOR"
+ },
+ {
+ 0x2E, 0x01,
+ SenseDevTypes044,
+ "THIRD PARTY DEVICE FAILURE"
+ },
+ {
+ 0x2E, 0x02,
+ SenseDevTypes044,
+ "COPY TARGET DEVICE NOT REACHABLE"
+ },
+ {
+ 0x2E, 0x03,
+ SenseDevTypes044,
+ "INCORRECT COPY TARGET DEVICE TYPE"
+ },
+ {
+ 0x2E, 0x04,
+ SenseDevTypes044,
+ "COPY TARGET DEVICE DATA UNDERRUN"
+ },
+ {
+ 0x2E, 0x05,
+ SenseDevTypes044,
+ "COPY TARGET DEVICE DATA OVERRUN"
+ },
+ {
+ 0x2F, 0x00,
+ SenseDevTypes001,
+ "COMMANDS CLEARED BY ANOTHER INITIATOR"
+ },
+ {
+ 0x30, 0x00,
+ SenseDevTypes034,
+ "INCOMPATIBLE MEDIUM INSTALLED"
+ },
+ {
+ 0x30, 0x01,
+ SenseDevTypes029,
+ "CANNOT READ MEDIUM - UNKNOWN FORMAT"
+ },
+ {
+ 0x30, 0x02,
+ SenseDevTypes029,
+ "CANNOT READ MEDIUM - INCOMPATIBLE FORMAT"
+ },
+ {
+ 0x30, 0x03,
+ SenseDevTypes045,
+ "CLEANING CARTRIDGE INSTALLED"
+ },
+ {
+ 0x30, 0x04,
+ SenseDevTypes029,
+ "CANNOT WRITE MEDIUM - UNKNOWN FORMAT"
+ },
+ {
+ 0x30, 0x05,
+ SenseDevTypes029,
+ "CANNOT WRITE MEDIUM - INCOMPATIBLE FORMAT"
+ },
+ {
+ 0x30, 0x06,
+ SenseDevTypes017,
+ "CANNOT FORMAT MEDIUM - INCOMPATIBLE MEDIUM"
+ },
+ {
+ 0x30, 0x07,
+ SenseDevTypes006,
+ "CLEANING FAILURE"
+ },
+ {
+ 0x30, 0x08,
+ SenseDevTypes005,
+ "CANNOT WRITE - APPLICATION CODE MISMATCH"
+ },
+ {
+ 0x30, 0x09,
+ SenseDevTypes005,
+ "CURRENT SESSION NOT FIXATED FOR APPEND"
+ },
+ {
+ 0x31, 0x00,
+ SenseDevTypes029,
+ "MEDIUM FORMAT CORRUPTED"
+ },
+ {
+ 0x31, 0x01,
+ SenseDevTypes046,
+ "FORMAT COMMAND FAILED"
+ },
+ {
+ 0x32, 0x00,
+ SenseDevTypes007,
+ "NO DEFECT SPARE LOCATION AVAILABLE"
+ },
+ {
+ 0x32, 0x01,
+ SenseDevTypes007,
+ "DEFECT LIST UPDATE FAILURE"
+ },
+ {
+ 0x33, 0x00,
+ SenseDevTypes002,
+ "TAPE LENGTH ERROR"
+ },
+ {
+ 0x34, 0x00,
+ SenseDevTypes001,
+ "ENCLOSURE FAILURE"
+ },
+ {
+ 0x35, 0x00,
+ SenseDevTypes001,
+ "ENCLOSURE SERVICES FAILURE"
+ },
+ {
+ 0x35, 0x01,
+ SenseDevTypes001,
+ "UNSUPPORTED ENCLOSURE FUNCTION"
+ },
+ {
+ 0x35, 0x02,
+ SenseDevTypes001,
+ "ENCLOSURE SERVICES UNAVAILABLE"
+ },
+ {
+ 0x35, 0x03,
+ SenseDevTypes001,
+ "ENCLOSURE SERVICES TRANSFER FAILURE"
+ },
+ {
+ 0x35, 0x04,
+ SenseDevTypes001,
+ "ENCLOSURE SERVICES TRANSFER REFUSED"
+ },
+ {
+ 0x36, 0x00,
+ SenseDevTypes047,
+ "RIBBON, INK, OR TONER FAILURE"
+ },
+ {
+ 0x37, 0x00,
+ SenseDevTypes013,
+ "ROUNDED PARAMETER"
+ },
+ {
+ 0x38, 0x00,
+ SenseDevTypes043,
+ "EVENT STATUS NOTIFICATION"
+ },
+ {
+ 0x38, 0x02,
+ SenseDevTypes043,
+ "ESN - POWER MANAGEMENT CLASS EVENT"
+ },
+ {
+ 0x38, 0x04,
+ SenseDevTypes043,
+ "ESN - MEDIA CLASS EVENT"
+ },
+ {
+ 0x38, 0x06,
+ SenseDevTypes043,
+ "ESN - DEVICE BUSY CLASS EVENT"
+ },
+ {
+ 0x39, 0x00,
+ SenseDevTypes040,
+ "SAVING PARAMETERS NOT SUPPORTED"
+ },
+ {
+ 0x3A, 0x00,
+ SenseDevTypes014,
+ "MEDIUM NOT PRESENT"
+ },
+ {
+ 0x3A, 0x01,
+ SenseDevTypes034,
+ "MEDIUM NOT PRESENT - TRAY CLOSED"
+ },
+ {
+ 0x3A, 0x02,
+ SenseDevTypes034,
+ "MEDIUM NOT PRESENT - TRAY OPEN"
+ },
+ {
+ 0x3A, 0x03,
+ SenseDevTypes039,
+ "MEDIUM NOT PRESENT - LOADABLE"
+ },
+ {
+ 0x3A, 0x04,
+ SenseDevTypes039,
+ "MEDIUM NOT PRESENT - MEDIUM AUXILIARY MEMORY ACCESSIBLE"
+ },
+ {
+ 0x3B, 0x00,
+ SenseDevTypes048,
+ "SEQUENTIAL POSITIONING ERROR"
+ },
+ {
+ 0x3B, 0x01,
+ SenseDevTypes002,
+ "TAPE POSITION ERROR AT BEGINNING-OF-MEDIUM"
+ },
+ {
+ 0x3B, 0x02,
+ SenseDevTypes002,
+ "TAPE POSITION ERROR AT END-OF-MEDIUM"
+ },
+ {
+ 0x3B, 0x03,
+ SenseDevTypes047,
+ "TAPE OR ELECTRONIC VERTICAL FORMS UNIT NOT READY"
+ },
+ {
+ 0x3B, 0x04,
+ SenseDevTypes047,
+ "SLEW FAILURE"
+ },
+ {
+ 0x3B, 0x05,
+ SenseDevTypes047,
+ "PAPER JAM"
+ },
+ {
+ 0x3B, 0x06,
+ SenseDevTypes047,
+ "FAILED TO SENSE TOP-OF-FORM"
+ },
+ {
+ 0x3B, 0x07,
+ SenseDevTypes047,
+ "FAILED TO SENSE BOTTOM-OF-FORM"
+ },
+ {
+ 0x3B, 0x08,
+ SenseDevTypes002,
+ "REPOSITION ERROR"
+ },
+ {
+ 0x3B, 0x09,
+ SenseDevTypes042,
+ "READ PAST END OF MEDIUM"
+ },
+ {
+ 0x3B, 0x0A,
+ SenseDevTypes042,
+ "READ PAST BEGINNING OF MEDIUM"
+ },
+ {
+ 0x3B, 0x0B,
+ SenseDevTypes042,
+ "POSITION PAST END OF MEDIUM"
+ },
+ {
+ 0x3B, 0x0C,
+ SenseDevTypes003,
+ "POSITION PAST BEGINNING OF MEDIUM"
+ },
+ {
+ 0x3B, 0x0D,
+ SenseDevTypes034,
+ "MEDIUM DESTINATION ELEMENT FULL"
+ },
+ {
+ 0x3B, 0x0E,
+ SenseDevTypes034,
+ "MEDIUM SOURCE ELEMENT EMPTY"
+ },
+ {
+ 0x3B, 0x0F,
+ SenseDevTypes005,
+ "END OF MEDIUM REACHED"
+ },
+ {
+ 0x3B, 0x11,
+ SenseDevTypes034,
+ "MEDIUM MAGAZINE NOT ACCESSIBLE"
+ },
+ {
+ 0x3B, 0x12,
+ SenseDevTypes034,
+ "MEDIUM MAGAZINE REMOVED"
+ },
+ {
+ 0x3B, 0x13,
+ SenseDevTypes034,
+ "MEDIUM MAGAZINE INSERTED"
+ },
+ {
+ 0x3B, 0x14,
+ SenseDevTypes034,
+ "MEDIUM MAGAZINE LOCKED"
+ },
+ {
+ 0x3B, 0x15,
+ SenseDevTypes034,
+ "MEDIUM MAGAZINE UNLOCKED"
+ },
+ {
+ 0x3B, 0x16,
+ SenseDevTypes005,
+ "MECHANICAL POSITIONING OR CHANGER ERROR"
+ },
+ {
+ 0x3D, 0x00,
+ SenseDevTypes036,
+ "INVALID BITS IN IDENTIFY MESSAGE"
+ },
+ {
+ 0x3E, 0x00,
+ SenseDevTypes001,
+ "LOGICAL UNIT HAS NOT SELF-CONFIGURED YET"
+ },
+ {
+ 0x3E, 0x01,
+ SenseDevTypes001,
+ "LOGICAL UNIT FAILURE"
+ },
+ {
+ 0x3E, 0x02,
+ SenseDevTypes001,
+ "TIMEOUT ON LOGICAL UNIT"
+ },
+ {
+ 0x3E, 0x03,
+ SenseDevTypes001,
+ "LOGICAL UNIT FAILED SELF-TEST"
+ },
+ {
+ 0x3E, 0x04,
+ SenseDevTypes001,
+ "LOGICAL UNIT UNABLE TO UPDATE SELF-TEST LOG"
+ },
+ {
+ 0x3F, 0x00,
+ SenseDevTypes001,
+ "TARGET OPERATING CONDITIONS HAVE CHANGED"
+ },
+ {
+ 0x3F, 0x01,
+ SenseDevTypes001,
+ "MICROCODE HAS BEEN CHANGED"
+ },
+ {
+ 0x3F, 0x02,
+ SenseDevTypes049,
+ "CHANGED OPERATING DEFINITION"
+ },
+ {
+ 0x3F, 0x03,
+ SenseDevTypes001,
+ "INQUIRY DATA HAS CHANGED"
+ },
+ {
+ 0x3F, 0x04,
+ SenseDevTypes050,
+ "COMPONENT DEVICE ATTACHED"
+ },
+ {
+ 0x3F, 0x05,
+ SenseDevTypes050,
+ "DEVICE IDENTIFIER CHANGED"
+ },
+ {
+ 0x3F, 0x06,
+ SenseDevTypes051,
+ "REDUNDANCY GROUP CREATED OR MODIFIED"
+ },
+ {
+ 0x3F, 0x07,
+ SenseDevTypes051,
+ "REDUNDANCY GROUP DELETED"
+ },
+ {
+ 0x3F, 0x08,
+ SenseDevTypes051,
+ "SPARE CREATED OR MODIFIED"
+ },
+ {
+ 0x3F, 0x09,
+ SenseDevTypes051,
+ "SPARE DELETED"
+ },
+ {
+ 0x3F, 0x0A,
+ SenseDevTypes050,
+ "VOLUME SET CREATED OR MODIFIED"
+ },
+ {
+ 0x3F, 0x0B,
+ SenseDevTypes050,
+ "VOLUME SET DELETED"
+ },
+ {
+ 0x3F, 0x0C,
+ SenseDevTypes050,
+ "VOLUME SET DEASSIGNED"
+ },
+ {
+ 0x3F, 0x0D,
+ SenseDevTypes050,
+ "VOLUME SET REASSIGNED"
+ },
+ {
+ 0x3F, 0x0E,
+ SenseDevTypes041,
+ "REPORTED LUNS DATA HAS CHANGED"
+ },
+ {
+ 0x3F, 0x0F,
+ SenseDevTypes001,
+ "ECHO BUFFER OVERWRITTEN"
+ },
+ {
+ 0x3F, 0x10,
+ SenseDevTypes039,
+ "MEDIUM LOADABLE"
+ },
+ {
+ 0x3F, 0x11,
+ SenseDevTypes039,
+ "MEDIUM AUXILIARY MEMORY ACCESSIBLE"
+ },
+ {
+ 0x40, 0x00,
+ SenseDevTypes035,
+ "RAM FAILURE (SHOULD USE 40 NN)"
+ },
+ {
+ 0x40, 0xFF,
+ SenseDevTypes001,
+ "DIAGNOSTIC FAILURE ON COMPONENT NN (80H-FFH)"
+ },
+ {
+ 0x41, 0x00,
+ SenseDevTypes035,
+ "DATA PATH FAILURE (SHOULD USE 40 NN)"
+ },
+ {
+ 0x42, 0x00,
+ SenseDevTypes035,
+ "POWER-ON OR SELF-TEST FAILURE (SHOULD USE 40 NN)"
+ },
+ {
+ 0x43, 0x00,
+ SenseDevTypes001,
+ "MESSAGE ERROR"
+ },
+ {
+ 0x44, 0x00,
+ SenseDevTypes001,
+ "INTERNAL TARGET FAILURE"
+ },
+ {
+ 0x45, 0x00,
+ SenseDevTypes001,
+ "SELECT OR RESELECT FAILURE"
+ },
+ {
+ 0x46, 0x00,
+ SenseDevTypes049,
+ "UNSUCCESSFUL SOFT RESET"
+ },
+ {
+ 0x47, 0x00,
+ SenseDevTypes001,
+ "SCSI PARITY ERROR"
+ },
+ {
+ 0x47, 0x01,
+ SenseDevTypes001,
+ "DATA PHASE CRC ERROR DETECTED"
+ },
+ {
+ 0x47, 0x02,
+ SenseDevTypes001,
+ "SCSI PARITY ERROR DETECTED DURING ST DATA PHASE"
+ },
+ {
+ 0x47, 0x03,
+ SenseDevTypes001,
+ "INFORMATION UNIT CRC ERROR DETECTED"
+ },
+ {
+ 0x47, 0x04,
+ SenseDevTypes001,
+ "ASYNCHRONOUS INFORMATION PROTECTION ERROR DETECTED"
+ },
+ {
+ 0x48, 0x00,
+ SenseDevTypes001,
+ "INITIATOR DETECTED ERROR MESSAGE RECEIVED"
+ },
+ {
+ 0x49, 0x00,
+ SenseDevTypes001,
+ "INVALID MESSAGE ERROR"
+ },
+ {
+ 0x4A, 0x00,
+ SenseDevTypes001,
+ "COMMAND PHASE ERROR"
+ },
+ {
+ 0x4B, 0x00,
+ SenseDevTypes001,
+ "DATA PHASE ERROR"
+ },
+ {
+ 0x4C, 0x00,
+ SenseDevTypes001,
+ "LOGICAL UNIT FAILED SELF-CONFIGURATION"
+ },
+ {
+ 0x4D, 0xFF,
+ SenseDevTypes001,
+ "TAGGED OVERLAPPED COMMANDS (NN = QUEUE TAG)"
+ },
+ {
+ 0x4E, 0x00,
+ SenseDevTypes001,
+ "OVERLAPPED COMMANDS ATTEMPTED"
+ },
+ {
+ 0x50, 0x00,
+ SenseDevTypes002,
+ "WRITE APPEND ERROR"
+ },
+ {
+ 0x50, 0x01,
+ SenseDevTypes002,
+ "WRITE APPEND POSITION ERROR"
+ },
+ {
+ 0x50, 0x02,
+ SenseDevTypes002,
+ "POSITION ERROR RELATED TO TIMING"
+ },
+ {
+ 0x51, 0x00,
+ SenseDevTypes052,
+ "ERASE FAILURE"
+ },
+ {
+ 0x52, 0x00,
+ SenseDevTypes002,
+ "CARTRIDGE FAULT"
+ },
+ {
+ 0x53, 0x00,
+ SenseDevTypes014,
+ "MEDIA LOAD OR EJECT FAILED"
+ },
+ {
+ 0x53, 0x01,
+ SenseDevTypes002,
+ "UNLOAD TAPE FAILURE"
+ },
+ {
+ 0x53, 0x02,
+ SenseDevTypes034,
+ "MEDIUM REMOVAL PREVENTED"
+ },
+ {
+ 0x54, 0x00,
+ SenseDevTypes053,
+ "SCSI TO HOST SYSTEM INTERFACE FAILURE"
+ },
+ {
+ 0x55, 0x00,
+ SenseDevTypes053,
+ "SYSTEM RESOURCE FAILURE"
+ },
+ {
+ 0x55, 0x01,
+ SenseDevTypes033,
+ "SYSTEM BUFFER FULL"
+ },
+ {
+ 0x55, 0x02,
+ SenseDevTypes054,
+ "INSUFFICIENT RESERVATION RESOURCES"
+ },
+ {
+ 0x55, 0x03,
+ SenseDevTypes041,
+ "INSUFFICIENT RESOURCES"
+ },
+ {
+ 0x55, 0x04,
+ SenseDevTypes055,
+ "INSUFFICIENT REGISTRATION RESOURCES"
+ },
+ {
+ 0x55, 0x05,
+ SenseDevTypes012,
+ "access controls code 4 (99-314) [proposed]"
+ },
+ {
+ 0x55, 0x06,
+ SenseDevTypes012,
+ "auxiliary memory code 1 (99-148) [proposed]"
+ },
+ {
+ 0x57, 0x00,
+ SenseDevTypes005,
+ "UNABLE TO RECOVER TABLE-OF-CONTENTS"
+ },
+ {
+ 0x58, 0x00,
+ SenseDevTypes056,
+ "GENERATION DOES NOT EXIST"
+ },
+ {
+ 0x59, 0x00,
+ SenseDevTypes056,
+ "UPDATED BLOCK READ"
+ },
+ {
+ 0x5A, 0x00,
+ SenseDevTypes057,
+ "OPERATOR REQUEST OR STATE CHANGE INPUT"
+ },
+ {
+ 0x5A, 0x01,
+ SenseDevTypes034,
+ "OPERATOR MEDIUM REMOVAL REQUEST"
+ },
+ {
+ 0x5A, 0x02,
+ SenseDevTypes058,
+ "OPERATOR SELECTED WRITE PROTECT"
+ },
+ {
+ 0x5A, 0x03,
+ SenseDevTypes058,
+ "OPERATOR SELECTED WRITE PERMIT"
+ },
+ {
+ 0x5B, 0x00,
+ SenseDevTypes059,
+ "LOG EXCEPTION"
+ },
+ {
+ 0x5B, 0x01,
+ SenseDevTypes059,
+ "THRESHOLD CONDITION MET"
+ },
+ {
+ 0x5B, 0x02,
+ SenseDevTypes059,
+ "LOG COUNTER AT MAXIMUM"
+ },
+ {
+ 0x5B, 0x03,
+ SenseDevTypes059,
+ "LOG LIST CODES EXHAUSTED"
+ },
+ {
+ 0x5C, 0x00,
+ SenseDevTypes060,
+ "RPL STATUS CHANGE"
+ },
+ {
+ 0x5C, 0x01,
+ SenseDevTypes060,
+ "SPINDLES SYNCHRONIZED"
+ },
+ {
+ 0x5C, 0x02,
+ SenseDevTypes060,
+ "SPINDLES NOT SYNCHRONIZED"
+ },
+ {
+ 0x5D, 0x00,
+ SenseDevTypes001,
+ "FAILURE PREDICTION THRESHOLD EXCEEDED"
+ },
+ {
+ 0x5D, 0x01,
+ SenseDevTypes061,
+ "MEDIA FAILURE PREDICTION THRESHOLD EXCEEDED"
+ },
+ {
+ 0x5D, 0x02,
+ SenseDevTypes005,
+ "LOGICAL UNIT FAILURE PREDICTION THRESHOLD EXCEEDED"
+ },
+ {
+ 0x5D, 0x10,
+ SenseDevTypes062,
+ "HARDWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"
+ },
+ {
+ 0x5D, 0x11,
+ SenseDevTypes062,
+ "HARDWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"
+ },
+ {
+ 0x5D, 0x12,
+ SenseDevTypes062,
+ "HARDWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH"
+ },
+ {
+ 0x5D, 0x13,
+ SenseDevTypes062,
+ "HARDWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"
+ },
+ {
+ 0x5D, 0x14,
+ SenseDevTypes062,
+ "HARDWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"
+ },
+ {
+ 0x5D, 0x15,
+ SenseDevTypes062,
+ "HARDWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH"
+ },
+ {
+ 0x5D, 0x16,
+ SenseDevTypes062,
+ "HARDWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH"
+ },
+ {
+ 0x5D, 0x17,
+ SenseDevTypes062,
+ "HARDWARE IMPENDING FAILURE CHANNEL PARAMETRICS"
+ },
+ {
+ 0x5D, 0x18,
+ SenseDevTypes062,
+ "HARDWARE IMPENDING FAILURE CONTROLLER DETECTED"
+ },
+ {
+ 0x5D, 0x19,
+ SenseDevTypes062,
+ "HARDWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE"
+ },
+ {
+ 0x5D, 0x1A,
+ SenseDevTypes062,
+ "HARDWARE IMPENDING FAILURE SEEK TIME PERFORMANCE"
+ },
+ {
+ 0x5D, 0x1B,
+ SenseDevTypes062,
+ "HARDWARE IMPENDING FAILURE SPIN-UP RETRY COUNT"
+ },
+ {
+ 0x5D, 0x1C,
+ SenseDevTypes062,
+ "HARDWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"
+ },
+ {
+ 0x5D, 0x20,
+ SenseDevTypes062,
+ "CONTROLLER IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"
+ },
+ {
+ 0x5D, 0x21,
+ SenseDevTypes062,
+ "CONTROLLER IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"
+ },
+ {
+ 0x5D, 0x22,
+ SenseDevTypes062,
+ "CONTROLLER IMPENDING FAILURE DATA ERROR RATE TOO HIGH"
+ },
+ {
+ 0x5D, 0x23,
+ SenseDevTypes062,
+ "CONTROLLER IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"
+ },
+ {
+ 0x5D, 0x24,
+ SenseDevTypes062,
+ "CONTROLLER IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"
+ },
+ {
+ 0x5D, 0x25,
+ SenseDevTypes062,
+ "CONTROLLER IMPENDING FAILURE ACCESS TIMES TOO HIGH"
+ },
+ {
+ 0x5D, 0x26,
+ SenseDevTypes062,
+ "CONTROLLER IMPENDING FAILURE START UNIT TIMES TOO HIGH"
+ },
+ {
+ 0x5D, 0x27,
+ SenseDevTypes062,
+ "CONTROLLER IMPENDING FAILURE CHANNEL PARAMETRICS"
+ },
+ {
+ 0x5D, 0x28,
+ SenseDevTypes062,
+ "CONTROLLER IMPENDING FAILURE CONTROLLER DETECTED"
+ },
+ {
+ 0x5D, 0x29,
+ SenseDevTypes062,
+ "CONTROLLER IMPENDING FAILURE THROUGHPUT PERFORMANCE"
+ },
+ {
+ 0x5D, 0x2A,
+ SenseDevTypes062,
+ "CONTROLLER IMPENDING FAILURE SEEK TIME PERFORMANCE"
+ },
+ {
+ 0x5D, 0x2B,
+ SenseDevTypes062,
+ "CONTROLLER IMPENDING FAILURE SPIN-UP RETRY COUNT"
+ },
+ {
+ 0x5D, 0x2C,
+ SenseDevTypes062,
+ "CONTROLLER IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"
+ },
+ {
+ 0x5D, 0x30,
+ SenseDevTypes062,
+ "DATA CHANNEL IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"
+ },
+ {
+ 0x5D, 0x31,
+ SenseDevTypes062,
+ "DATA CHANNEL IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"
+ },
+ {
+ 0x5D, 0x32,
+ SenseDevTypes062,
+ "DATA CHANNEL IMPENDING FAILURE DATA ERROR RATE TOO HIGH"
+ },
+ {
+ 0x5D, 0x33,
+ SenseDevTypes062,
+ "DATA CHANNEL IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"
+ },
+ {
+ 0x5D, 0x34,
+ SenseDevTypes062,
+ "DATA CHANNEL IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"
+ },
+ {
+ 0x5D, 0x35,
+ SenseDevTypes062,
+ "DATA CHANNEL IMPENDING FAILURE ACCESS TIMES TOO HIGH"
+ },
+ {
+ 0x5D, 0x36,
+ SenseDevTypes062,
+ "DATA CHANNEL IMPENDING FAILURE START UNIT TIMES TOO HIGH"
+ },
+ {
+ 0x5D, 0x37,
+ SenseDevTypes062,
+ "DATA CHANNEL IMPENDING FAILURE CHANNEL PARAMETRICS"
+ },
+ {
+ 0x5D, 0x38,
+ SenseDevTypes062,
+ "DATA CHANNEL IMPENDING FAILURE CONTROLLER DETECTED"
+ },
+ {
+ 0x5D, 0x39,
+ SenseDevTypes062,
+ "DATA CHANNEL IMPENDING FAILURE THROUGHPUT PERFORMANCE"
+ },
+ {
+ 0x5D, 0x3A,
+ SenseDevTypes062,
+ "DATA CHANNEL IMPENDING FAILURE SEEK TIME PERFORMANCE"
+ },
+ {
+ 0x5D, 0x3B,
+ SenseDevTypes062,
+ "DATA CHANNEL IMPENDING FAILURE SPIN-UP RETRY COUNT"
+ },
+ {
+ 0x5D, 0x3C,
+ SenseDevTypes062,
+ "DATA CHANNEL IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"
+ },
+ {
+ 0x5D, 0x40,
+ SenseDevTypes062,
+ "SERVO IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"
+ },
+ {
+ 0x5D, 0x41,
+ SenseDevTypes062,
+ "SERVO IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"
+ },
+ {
+ 0x5D, 0x42,
+ SenseDevTypes062,
+ "SERVO IMPENDING FAILURE DATA ERROR RATE TOO HIGH"
+ },
+ {
+ 0x5D, 0x43,
+ SenseDevTypes062,
+ "SERVO IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"
+ },
+ {
+ 0x5D, 0x44,
+ SenseDevTypes062,
+ "SERVO IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"
+ },
+ {
+ 0x5D, 0x45,
+ SenseDevTypes062,
+ "SERVO IMPENDING FAILURE ACCESS TIMES TOO HIGH"
+ },
+ {
+ 0x5D, 0x46,
+ SenseDevTypes062,
+ "SERVO IMPENDING FAILURE START UNIT TIMES TOO HIGH"
+ },
+ {
+ 0x5D, 0x47,
+ SenseDevTypes062,
+ "SERVO IMPENDING FAILURE CHANNEL PARAMETRICS"
+ },
+ {
+ 0x5D, 0x48,
+ SenseDevTypes062,
+ "SERVO IMPENDING FAILURE CONTROLLER DETECTED"
+ },
+ {
+ 0x5D, 0x49,
+ SenseDevTypes062,
+ "SERVO IMPENDING FAILURE THROUGHPUT PERFORMANCE"
+ },
+ {
+ 0x5D, 0x4A,
+ SenseDevTypes062,
+ "SERVO IMPENDING FAILURE SEEK TIME PERFORMANCE"
+ },
+ {
+ 0x5D, 0x4B,
+ SenseDevTypes062,
+ "SERVO IMPENDING FAILURE SPIN-UP RETRY COUNT"
+ },
+ {
+ 0x5D, 0x4C,
+ SenseDevTypes062,
+ "SERVO IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"
+ },
+ {
+ 0x5D, 0x50,
+ SenseDevTypes062,
+ "SPINDLE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"
+ },
+ {
+ 0x5D, 0x51,
+ SenseDevTypes062,
+ "SPINDLE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"
+ },
+ {
+ 0x5D, 0x52,
+ SenseDevTypes062,
+ "SPINDLE IMPENDING FAILURE DATA ERROR RATE TOO HIGH"
+ },
+ {
+ 0x5D, 0x53,
+ SenseDevTypes062,
+ "SPINDLE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"
+ },
+ {
+ 0x5D, 0x54,
+ SenseDevTypes062,
+ "SPINDLE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"
+ },
+ {
+ 0x5D, 0x55,
+ SenseDevTypes062,
+ "SPINDLE IMPENDING FAILURE ACCESS TIMES TOO HIGH"
+ },
+ {
+ 0x5D, 0x56,
+ SenseDevTypes062,
+ "SPINDLE IMPENDING FAILURE START UNIT TIMES TOO HIGH"
+ },
+ {
+ 0x5D, 0x57,
+ SenseDevTypes062,
+ "SPINDLE IMPENDING FAILURE CHANNEL PARAMETRICS"
+ },
+ {
+ 0x5D, 0x58,
+ SenseDevTypes062,
+ "SPINDLE IMPENDING FAILURE CONTROLLER DETECTED"
+ },
+ {
+ 0x5D, 0x59,
+ SenseDevTypes062,
+ "SPINDLE IMPENDING FAILURE THROUGHPUT PERFORMANCE"
+ },
+ {
+ 0x5D, 0x5A,
+ SenseDevTypes062,
+ "SPINDLE IMPENDING FAILURE SEEK TIME PERFORMANCE"
+ },
+ {
+ 0x5D, 0x5B,
+ SenseDevTypes062,
+ "SPINDLE IMPENDING FAILURE SPIN-UP RETRY COUNT"
+ },
+ {
+ 0x5D, 0x5C,
+ SenseDevTypes062,
+ "SPINDLE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"
+ },
+ {
+ 0x5D, 0x60,
+ SenseDevTypes062,
+ "FIRMWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"
+ },
+ {
+ 0x5D, 0x61,
+ SenseDevTypes062,
+ "FIRMWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"
+ },
+ {
+ 0x5D, 0x62,
+ SenseDevTypes062,
+ "FIRMWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH"
+ },
+ {
+ 0x5D, 0x63,
+ SenseDevTypes062,
+ "FIRMWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"
+ },
+ {
+ 0x5D, 0x64,
+ SenseDevTypes062,
+ "FIRMWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"
+ },
+ {
+ 0x5D, 0x65,
+ SenseDevTypes062,
+ "FIRMWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH"
+ },
+ {
+ 0x5D, 0x66,
+ SenseDevTypes062,
+ "FIRMWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH"
+ },
+ {
+ 0x5D, 0x67,
+ SenseDevTypes062,
+ "FIRMWARE IMPENDING FAILURE CHANNEL PARAMETRICS"
+ },
+ {
+ 0x5D, 0x68,
+ SenseDevTypes062,
+ "FIRMWARE IMPENDING FAILURE CONTROLLER DETECTED"
+ },
+ {
+ 0x5D, 0x69,
+ SenseDevTypes062,
+ "FIRMWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE"
+ },
+ {
+ 0x5D, 0x6A,
+ SenseDevTypes062,
+ "FIRMWARE IMPENDING FAILURE SEEK TIME PERFORMANCE"
+ },
+ {
+ 0x5D, 0x6B,
+ SenseDevTypes062,
+ "FIRMWARE IMPENDING FAILURE SPIN-UP RETRY COUNT"
+ },
+ {
+ 0x5D, 0x6C,
+ SenseDevTypes062,
+ "FIRMWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"
+ },
+ {
+ 0x5D, 0xFF,
+ SenseDevTypes001,
+ "FAILURE PREDICTION THRESHOLD EXCEEDED (FALSE)"
+ },
+ {
+ 0x5E, 0x00,
+ SenseDevTypes044,
+ "LOW POWER CONDITION ON"
+ },
+ {
+ 0x5E, 0x01,
+ SenseDevTypes044,
+ "IDLE CONDITION ACTIVATED BY TIMER"
+ },
+ {
+ 0x5E, 0x02,
+ SenseDevTypes044,
+ "STANDBY CONDITION ACTIVATED BY TIMER"
+ },
+ {
+ 0x5E, 0x03,
+ SenseDevTypes044,
+ "IDLE CONDITION ACTIVATED BY COMMAND"
+ },
+ {
+ 0x5E, 0x04,
+ SenseDevTypes044,
+ "STANDBY CONDITION ACTIVATED BY COMMAND"
+ },
+ {
+ 0x5E, 0x41,
+ SenseDevTypes043,
+ "POWER STATE CHANGE TO ACTIVE"
+ },
+ {
+ 0x5E, 0x42,
+ SenseDevTypes043,
+ "POWER STATE CHANGE TO IDLE"
+ },
+ {
+ 0x5E, 0x43,
+ SenseDevTypes043,
+ "POWER STATE CHANGE TO STANDBY"
+ },
+ {
+ 0x5E, 0x45,
+ SenseDevTypes043,
+ "POWER STATE CHANGE TO SLEEP"
+ },
+ {
+ 0x5E, 0x47,
+ SenseDevTypes063,
+ "POWER STATE CHANGE TO DEVICE CONTROL"
+ },
+ {
+ 0x60, 0x00,
+ SenseDevTypes042,
+ "LAMP FAILURE"
+ },
+ {
+ 0x61, 0x00,
+ SenseDevTypes042,
+ "VIDEO ACQUISITION ERROR"
+ },
+ {
+ 0x61, 0x01,
+ SenseDevTypes042,
+ "UNABLE TO ACQUIRE VIDEO"
+ },
+ {
+ 0x61, 0x02,
+ SenseDevTypes042,
+ "OUT OF FOCUS"
+ },
+ {
+ 0x62, 0x00,
+ SenseDevTypes042,
+ "SCAN HEAD POSITIONING ERROR"
+ },
+ {
+ 0x63, 0x00,
+ SenseDevTypes005,
+ "END OF USER AREA ENCOUNTERED ON THIS TRACK"
+ },
+ {
+ 0x63, 0x01,
+ SenseDevTypes005,
+ "PACKET DOES NOT FIT IN AVAILABLE SPACE"
+ },
+ {
+ 0x64, 0x00,
+ SenseDevTypes005,
+ "ILLEGAL MODE FOR THIS TRACK"
+ },
+ {
+ 0x64, 0x01,
+ SenseDevTypes005,
+ "INVALID PACKET SIZE"
+ },
+ {
+ 0x65, 0x00,
+ SenseDevTypes001,
+ "VOLTAGE FAULT"
+ },
+ {
+ 0x66, 0x00,
+ SenseDevTypes042,
+ "AUTOMATIC DOCUMENT FEEDER COVER UP"
+ },
+ {
+ 0x66, 0x01,
+ SenseDevTypes042,
+ "AUTOMATIC DOCUMENT FEEDER LIFT UP"
+ },
+ {
+ 0x66, 0x02,
+ SenseDevTypes042,
+ "DOCUMENT JAM IN AUTOMATIC DOCUMENT FEEDER"
+ },
+ {
+ 0x66, 0x03,
+ SenseDevTypes042,
+ "DOCUMENT MISS FEED AUTOMATIC IN DOCUMENT FEEDER"
+ },
+ {
+ 0x67, 0x00,
+ SenseDevTypes064,
+ "CONFIGURATION FAILURE"
+ },
+ {
+ 0x67, 0x01,
+ SenseDevTypes064,
+ "CONFIGURATION OF INCAPABLE LOGICAL UNITS FAILED"
+ },
+ {
+ 0x67, 0x02,
+ SenseDevTypes064,
+ "ADD LOGICAL UNIT FAILED"
+ },
+ {
+ 0x67, 0x03,
+ SenseDevTypes064,
+ "MODIFICATION OF LOGICAL UNIT FAILED"
+ },
+ {
+ 0x67, 0x04,
+ SenseDevTypes064,
+ "EXCHANGE OF LOGICAL UNIT FAILED"
+ },
+ {
+ 0x67, 0x05,
+ SenseDevTypes064,
+ "REMOVE OF LOGICAL UNIT FAILED"
+ },
+ {
+ 0x67, 0x06,
+ SenseDevTypes064,
+ "ATTACHMENT OF LOGICAL UNIT FAILED"
+ },
+ {
+ 0x67, 0x07,
+ SenseDevTypes064,
+ "CREATION OF LOGICAL UNIT FAILED"
+ },
+ {
+ 0x67, 0x08,
+ SenseDevTypes064,
+ "ASSIGN FAILURE OCCURRED"
+ },
+ {
+ 0x67, 0x09,
+ SenseDevTypes064,
+ "MULTIPLY ASSIGNED LOGICAL UNIT"
+ },
+ {
+ 0x68, 0x00,
+ SenseDevTypes064,
+ "LOGICAL UNIT NOT CONFIGURED"
+ },
+ {
+ 0x69, 0x00,
+ SenseDevTypes064,
+ "DATA LOSS ON LOGICAL UNIT"
+ },
+ {
+ 0x69, 0x01,
+ SenseDevTypes064,
+ "MULTIPLE LOGICAL UNIT FAILURES"
+ },
+ {
+ 0x69, 0x02,
+ SenseDevTypes064,
+ "PARITY/DATA MISMATCH"
+ },
+ {
+ 0x6A, 0x00,
+ SenseDevTypes064,
+ "INFORMATIONAL, REFER TO LOG"
+ },
+ {
+ 0x6B, 0x00,
+ SenseDevTypes064,
+ "STATE CHANGE HAS OCCURRED"
+ },
+ {
+ 0x6B, 0x01,
+ SenseDevTypes064,
+ "REDUNDANCY LEVEL GOT BETTER"
+ },
+ {
+ 0x6B, 0x02,
+ SenseDevTypes064,
+ "REDUNDANCY LEVEL GOT WORSE"
+ },
+ {
+ 0x6C, 0x00,
+ SenseDevTypes064,
+ "REBUILD FAILURE OCCURRED"
+ },
+ {
+ 0x6D, 0x00,
+ SenseDevTypes064,
+ "RECALCULATE FAILURE OCCURRED"
+ },
+ {
+ 0x6E, 0x00,
+ SenseDevTypes064,
+ "COMMAND TO LOGICAL UNIT FAILED"
+ },
+ {
+ 0x6F, 0x00,
+ SenseDevTypes005,
+ "COPY PROTECTION KEY EXCHANGE FAILURE - AUTHENTICATION FAILURE"
+ },
+ {
+ 0x6F, 0x01,
+ SenseDevTypes005,
+ "COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT PRESENT"
+ },
+ {
+ 0x6F, 0x02,
+ SenseDevTypes005,
+ "COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT ESTABLISHED"
+ },
+ {
+ 0x6F, 0x03,
+ SenseDevTypes005,
+ "READ OF SCRAMBLED SECTOR WITHOUT AUTHENTICATION"
+ },
+ {
+ 0x6F, 0x04,
+ SenseDevTypes005,
+ "MEDIA REGION CODE IS MISMATCHED TO LOGICAL UNIT REGION"
+ },
+ {
+ 0x6F, 0x05,
+ SenseDevTypes005,
+ "DRIVE REGION MUST BE PERMANENT/REGION RESET COUNT ERROR"
+ },
+ {
+ 0x70, 0xFF,
+ SenseDevTypes002,
+ "DECOMPRESSION EXCEPTION SHORT ALGORITHM ID OF NN"
+ },
+ {
+ 0x71, 0x00,
+ SenseDevTypes002,
+ "DECOMPRESSION EXCEPTION LONG ALGORITHM ID"
+ },
+ {
+ 0x72, 0x00,
+ SenseDevTypes005,
+ "SESSION FIXATION ERROR"
+ },
+ {
+ 0x72, 0x01,
+ SenseDevTypes005,
+ "SESSION FIXATION ERROR WRITING LEAD-IN"
+ },
+ {
+ 0x72, 0x02,
+ SenseDevTypes005,
+ "SESSION FIXATION ERROR WRITING LEAD-OUT"
+ },
+ {
+ 0x72, 0x03,
+ SenseDevTypes005,
+ "SESSION FIXATION ERROR - INCOMPLETE TRACK IN SESSION"
+ },
+ {
+ 0x72, 0x04,
+ SenseDevTypes005,
+ "EMPTY OR PARTIALLY WRITTEN RESERVED TRACK"
+ },
+ {
+ 0x72, 0x05,
+ SenseDevTypes005,
+ "NO MORE TRACK RESERVATIONS ALLOWED"
+ },
+ {
+ 0x73, 0x00,
+ SenseDevTypes005,
+ "CD CONTROL ERROR"
+ },
+ {
+ 0x73, 0x01,
+ SenseDevTypes005,
+ "POWER CALIBRATION AREA ALMOST FULL"
+ },
+ {
+ 0x73, 0x02,
+ SenseDevTypes005,
+ "POWER CALIBRATION AREA IS FULL"
+ },
+ {
+ 0x73, 0x03,
+ SenseDevTypes005,
+ "POWER CALIBRATION AREA ERROR"
+ },
+ {
+ 0x73, 0x04,
+ SenseDevTypes005,
+ "PROGRAM MEMORY AREA UPDATE FAILURE"
+ },
+ {
+ 0x73, 0x05,
+ SenseDevTypes005,
+ "PROGRAM MEMORY AREA IS FULL"
+ },
+ {
+ 0x73, 0x06,
+ SenseDevTypes005,
+ "RMA/PMA IS FULL"
+ },
+};
+
+static int ASCQ_TableSize = 463;
+
+
+#endif
--- /dev/null
+#!/bin/sh
+#
+# ascq_tbl.sh - Translate SCSI t10.org's "asc-num.txt" file of
+# SCSI Additional Sense Code & Qualifiers (ASC/ASCQ's)
+# into something useful in C, creating "ascq_tbl.c" file.
+#
+#*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*#
+
+PREF_INFILE="t10.org/asc-num.txt" # From SCSI t10.org
+PREF_OUTFILE="ascq_tbl.c"
+
+#*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*#
+
+xlate_ascq() {
+ cat | awk '
+ BEGIN {
+ DQ = "\042";
+ OUTFILE = "'"${PREF_OUTFILE}"'";
+ TRUE = 1;
+ FALSE = 0;
+ #debug = TRUE;
+
+ # read and discard all lines up to and including the one that begins
+ # with the "magic token" of "------- -------------- ---"...
+ headers_gone = FALSE;
+ while (!headers_gone) {
+ if (getline <= 0)
+ exit 1;
+ header_line[++hdrs] = $0;
+ if (debug)
+ printf("header_line[%d] = :%s:\n", ++hdrs, $0);
+ if ($0 ~ /^------- -------------- ---/) {
+ headers_gone = TRUE;
+ }
+ }
+ outcount = 0;
+ }
+
+ (NF > 1) {
+ ++outcount;
+ if (debug)
+ printf( "DBG: %s\n", $0 );
+ ASC[outcount] = substr($0,1,2);
+ ASCQ[outcount] = substr($0,5,2);
+ devtypes = substr($0,10,14);
+ gsub(/ /, ".", devtypes);
+ DESCRIP[outcount] = substr($0,26);
+
+ if (!(devtypes in DevTypesVoodoo)) {
+ DevTypesVoodoo[devtypes] = ++voodoo;
+ DevTypesIdx[voodoo] = devtypes;
+ }
+ DEVTYPES[outcount] = DevTypesVoodoo[devtypes];
+
+ # Handle 0xNN exception stuff...
+ if (ASCQ[outcount] == "NN" || ASCQ[outcount] == "nn")
+ ASCQ[outcount] = "FF";
+ }
+
+ END {
+ printf("#ifndef SCSI_ASCQ_TBL_C_INCLUDED\n") > OUTFILE;
+ printf("#define SCSI_ASCQ_TBL_C_INCLUDED\n") >> OUTFILE;
+
+ printf("\n/* AuToMaGiCaLlY generated from: %s'"${FIN}"'%s\n", DQ, DQ) >> OUTFILE;
+ printf(" *******************************************************************************\n") >> OUTFILE;
+ for (i=1; i<=hdrs; i++) {
+ printf(" * %s\n", header_line[i]) >> OUTFILE;
+ }
+ printf(" */\n") >> OUTFILE;
+
+ printf("\n") >> OUTFILE;
+ for (i=1; i<=voodoo; i++) {
+ printf("static char SenseDevTypes%03d[] = %s%s%s;\n", i, DQ, DevTypesIdx[i], DQ) >> OUTFILE;
+ }
+
+ printf("\nstatic ASCQ_Table_t ASCQ_Table[] = {\n") >> OUTFILE;
+ for (i=1; i<=outcount; i++) {
+ printf(" {\n") >> OUTFILE;
+ printf(" 0x%s, 0x%s,\n", ASC[i], ASCQ[i]) >> OUTFILE;
+ printf(" SenseDevTypes%03d,\n", DEVTYPES[i]) >> OUTFILE;
+ printf(" %s%s%s\n", DQ, DESCRIP[i], DQ) >> OUTFILE;
+ printf(" },\n") >> OUTFILE;
+ }
+ printf( "};\n\n" ) >> OUTFILE;
+
+ printf( "static int ASCQ_TableSize = %d;\n\n", outcount ) >> OUTFILE;
+ printf( "Total of %d ASC/ASCQ records generated\n", outcount );
+ printf("\n#endif\n") >> OUTFILE;
+ close(OUTFILE);
+ }'
+ return
+}
+
+#*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*#
+
+# main()
+if [ $# -lt 1 ]; then
+ echo "INFO: No input filename supplied - using: $PREF_INFILE" >&2
+ FIN=$PREF_INFILE
+else
+ FIN="$1"
+ if [ "$FIN" != "$PREF_INFILE" ]; then
+ echo "INFO: Ok, I'll try chewing on '$FIN' for SCSI ASC/ASCQ combos..." >&2
+ fi
+ shift
+fi
+
+cat $FIN | xlate_ascq
+exit 0
--- /dev/null
+/*
+ * linux/drivers/message/fusion/isense.c
+ * Little linux driver / shim that interfaces with the Fusion MPT
+ * Linux base driver to provide english readable strings in SCSI
+ * Error Report logging output. This module implements SCSI-3
+ * Opcode lookup and a sorted table of SCSI-3 ASC/ASCQ strings.
+ *
+ * Copyright (c) 1991-2001 Steven J. Ralston
+ * Written By: Steven J. Ralston
+ * (yes I wrote some of the orig. code back in 1991!)
+ * (mailto:Steve.Ralston@lsil.com)
+ *
+ * $Id: isense.c,v 1.28 2001/01/14 23:11:09 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ 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; version 2 of the License.
+
+ 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.
+
+ NO WARRANTY
+ THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ solely responsible for determining the appropriateness of using and
+ distributing the Program and assumes all risks associated with its
+ exercise of rights under this Agreement, including but not limited to
+ the risks and costs of program errors, damage to or loss of data,
+ programs or equipment, and unavailability or interruption of operations.
+
+ DISCLAIMER OF LIABILITY
+ NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/version.h>
+
+/* Hmmm, avoid undefined spinlock_t on lk-2.2.14-5.0 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+#include <asm/spinlock.h>
+#endif
+
+#define MODULEAUTHOR "Steven J. Ralston"
+#define COPYRIGHT "Copyright (c) 2000 " MODULEAUTHOR
+#include "mptbase.h"
+
+#include "isense.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Private data...
+ */
+
+/*
+ * YIKES! I don't usually #include C source files, but..
+ * The following #include's pulls in our needed ASCQ_Table[] array,
+ * ASCQ_TableSz integer, and ScsiOpcodeString[] array!
+ */
+#include "ascq_tbl.c"
+#include "scsiops.c"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#define my_NAME "SCSI-3 Opcodes & ASC/ASCQ Strings"
+#define my_VERSION MPT_LINUX_VERSION_COMMON
+#define MYNAM "isense"
+
+EXPORT_NO_SYMBOLS;
+MODULE_AUTHOR(MODULEAUTHOR);
+MODULE_DESCRIPTION(my_NAME);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+int __init isense_init(void)
+{
+ show_mptmod_ver(my_NAME, my_VERSION);
+
+ /*
+ * Install our handler
+ */
+ if (mpt_register_ascqops_strings(&ASCQ_Table[0], ASCQ_TableSize, ScsiOpcodeString) != 1)
+ {
+ printk(KERN_ERR MYNAM ": ERROR: Can't register with Fusion MPT base driver!\n");
+ return -EBUSY;
+ }
+ printk(KERN_INFO MYNAM ": Registered SCSI-3 Opcodes & ASC/ASCQ Strings\n");
+ return 0;
+}
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void isense_exit(void)
+{
+#ifdef MODULE
+ mpt_deregister_ascqops_strings();
+#endif
+ printk(KERN_INFO MYNAM ": Deregistered SCSI-3 Opcodes & ASC/ASCQ Strings\n");
+}
+
+module_init(isense_init);
+module_exit(isense_exit);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
--- /dev/null
+#ifndef ISENSE_H_INCLUDED
+#define ISENSE_H_INCLUDED
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#ifdef __KERNEL__
+#include <linux/types.h> /* needed for u8, etc. */
+#include <linux/string.h> /* needed for strcat */
+#include <linux/kernel.h> /* needed for sprintf */
+#else
+ #ifndef U_STUFF_DEFINED
+ #define U_STUFF_DEFINED
+ typedef unsigned char u8;
+ typedef unsigned short u16;
+ typedef unsigned int u32;
+ #endif
+#endif
+
+#include "scsi3.h" /* needed for all things SCSI */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Defines and typedefs...
+ */
+
+#ifdef __KERNEL__
+#define PrintF(x) printk x
+#else
+#define PrintF(x) printf x
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#define RETRY_STATUS ((int) 1)
+#define PUT_STATUS ((int) 0)
+
+/*
+ * A generic structure to hold info about IO request that caused
+ * a Request Sense to be performed, and the resulting Sense Data.
+ */
+typedef struct IO_Info
+{
+ char *DevIDStr; /* String of chars which identifies the device. */
+ u8 *cdbPtr; /* Pointer (Virtual/Logical addr) to CDB bytes of
+ IO request that caused ContAllegianceCond. */
+ u8 *sensePtr; /* Pointer (Virtual/Logical addr) to Sense Data
+ returned by Request Sense operation. */
+ u8 *dataPtr; /* Pointer (Virtual/Logical addr) to Data buffer
+ of IO request caused ContAllegianceCondition. */
+ u8 *inqPtr; /* Pointer (Virtual/Logical addr) to Inquiry Data for
+ IO *Device* that caused ContAllegianceCondition. */
+ u8 SCSIStatus; /* SCSI status byte of IO request that caused
+ Contingent Allegiance Condition. */
+ u8 DoDisplay; /* Shall we display any messages? */
+ u16 rsvd_align1;
+ u32 ComplCode; /* Four-byte OS-dependent completion code. */
+ u32 NotifyL; /* Four-byte OS-dependent notification field. */
+} IO_Info_t;
+
+/*
+ * SCSI Additional Sense Code and Additional Sense Code Qualifier table.
+ */
+typedef struct ASCQ_Table
+{
+ u8 ASC;
+ u8 ASCQ;
+ char *DevTypes;
+ char *Description;
+} ASCQ_Table_t;
+
+#if 0
+/*
+ * SCSI Opcodes table.
+ */
+typedef struct SCSI_OPS_Table
+{
+ u8 OpCode;
+ char *DevTypes;
+ char *ScsiCmndStr;
+} SCSI_OPS_Table_t;
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Public entry point prototypes
+ */
+
+/* in scsiherr.c, needed by mptscsih.c */
+extern int mpt_ScsiHost_ErrorReport(IO_Info_t *ioop);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif
+
--- /dev/null
+/* drivers/message/fusion/linux_compat.h */
+
+#ifndef FUSION_LINUX_COMPAT_H
+#define FUSION_LINUX_COMPAT_H
+/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
+ typedef unsigned int dma_addr_t;
+# endif
+#else
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,42)
+ typedef unsigned int dma_addr_t;
+# endif
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
+/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/* This block snipped from lk-2.2.18/include/linux/init.h { */
+/*
+ * Used for initialization calls..
+ */
+typedef int (*initcall_t)(void);
+typedef void (*exitcall_t)(void);
+
+#define __init_call __attribute__ ((unused,__section__ (".initcall.init")))
+#define __exit_call __attribute__ ((unused,__section__ (".exitcall.exit")))
+
+extern initcall_t __initcall_start, __initcall_end;
+
+#define __initcall(fn) \
+ static initcall_t __initcall_##fn __init_call = fn
+#define __exitcall(fn) \
+ static exitcall_t __exitcall_##fn __exit_call = fn
+
+#ifdef MODULE
+/* These macros create a dummy inline: gcc 2.9x does not count alias
+ as usage, hence the `unused function' warning when __init functions
+ are declared static. We use the dummy __*_module_inline functions
+ both to kill the warning and check the type of the init/cleanup
+ function. */
+typedef int (*__init_module_func_t)(void);
+typedef void (*__cleanup_module_func_t)(void);
+#define module_init(x) \
+ int init_module(void) __attribute__((alias(#x))); \
+ extern inline __init_module_func_t __init_module_inline(void) \
+ { return x; }
+#define module_exit(x) \
+ void cleanup_module(void) __attribute__((alias(#x))); \
+ extern inline __cleanup_module_func_t __cleanup_module_inline(void) \
+ { return x; }
+
+#else
+#define module_init(x) __initcall(x);
+#define module_exit(x) __exitcall(x);
+#endif
+/* } block snipped from lk-2.2.18/include/linux/init.h */
+
+/* Wait queues. */
+#define DECLARE_WAIT_QUEUE_HEAD(name) \
+ struct wait_queue * (name) = NULL
+#define DECLARE_WAITQUEUE(name, task) \
+ struct wait_queue (name) = { (task), NULL }
+
+#if defined(__sparc__) && defined(__sparc_v9__)
+/* The sparc64 ioremap implementation is wrong in 2.2.x,
+ * but fixing it would break all of the drivers which
+ * workaround it. Fixed in 2.3.x onward. -DaveM
+ */
+#define ARCH_IOREMAP(base) ((unsigned long) (base))
+#else
+#define ARCH_IOREMAP(base) ioremap(base)
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#else /* LINUX_VERSION_CODE must be >= KERNEL_VERSION(2,2,18) */
+
+/* No ioremap bugs in >2.3.x kernels. */
+#define ARCH_IOREMAP(base) ioremap(base)
+
+/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) */
+
+
+/* PCI/driver subsystem { */
+#ifndef pci_for_each_dev
+#define pci_for_each_dev(dev) for((dev)=pci_devices; (dev)!=NULL; (dev)=(dev)->next)
+#define pci_peek_next_dev(dev) ((dev)->next ? (dev)->next : NULL)
+#define DEVICE_COUNT_RESOURCE 6
+#define PCI_BASEADDR_FLAGS(idx) base_address[idx]
+#define PCI_BASEADDR_START(idx) base_address[idx] & ~0xFUL
+/*
+ * We have to keep track of the original value using
+ * a temporary, and not by just sticking pdev->base_address[x]
+ * back. pdev->base_address[x] is an opaque cookie that can
+ * be used by the PCI implementation on a given Linux port
+ * for any purpose. -DaveM
+ */
+#define PCI_BASEADDR_SIZE(__pdev, __idx) \
+({ unsigned int size, tmp; \
+ pci_read_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), &tmp); \
+ pci_write_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), 0xffffffff); \
+ pci_read_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), &size); \
+ pci_write_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), tmp); \
+ (4 - size); \
+})
+#else
+#define pci_peek_next_dev(dev) ((dev) != pci_dev_g(&pci_devices) ? pci_dev_g((dev)->global_list.next) : NULL)
+#define PCI_BASEADDR_FLAGS(idx) resource[idx].flags
+#define PCI_BASEADDR_START(idx) resource[idx].start
+#define PCI_BASEADDR_SIZE(dev,idx) (dev)->resource[idx].end - (dev)->resource[idx].start + 1
+#endif /* } ifndef pci_for_each_dev */
+
+
+/* procfs compat stuff... */
+#ifdef CONFIG_PROC_FS
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,28)
+#define CREATE_PROCDIR_ENTRY(x,y) create_proc_entry(x, S_IFDIR, y)
+/* This is a macro so we don't need to pull all the procfs
+ * headers into this file. -DaveM
+ */
+#define create_proc_read_entry(name, mode, base, __read_proc, __data) \
+({ struct proc_dir_entry *__res=create_proc_entry(name,mode,base); \
+ if (__res) { \
+ __res->read_proc=(__read_proc); \
+ __res->data=(__data); \
+ } \
+ __res; \
+})
+#else
+#define CREATE_PROCDIR_ENTRY(x,y) proc_mkdir(x, y)
+#endif
+#endif
+
+/* Compatability for the 2.3.x PCI DMA API. */
+#ifndef PCI_DMA_BIDIRECTIONAL
+/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#define PCI_DMA_BIDIRECTIONAL 0
+#define PCI_DMA_TODEVICE 1
+#define PCI_DMA_FROMDEVICE 2
+#define PCI_DMA_NONE 3
+
+#ifdef __KERNEL__
+#include <asm/page.h>
+/* Pure 2^n version of get_order */
+static __inline__ int __get_order(unsigned long size)
+{
+ int order;
+
+ size = (size-1) >> (PAGE_SHIFT-1);
+ order = -1;
+ do {
+ size >>= 1;
+ order++;
+ } while (size);
+ return order;
+}
+#endif
+
+#define pci_alloc_consistent(hwdev, size, dma_handle) \
+({ void *__ret = (void *)__get_free_pages(GFP_ATOMIC, __get_order(size)); \
+ if (__ret != NULL) { \
+ memset(__ret, 0, size); \
+ *(dma_handle) = virt_to_bus(__ret); \
+ } \
+ __ret; \
+})
+
+#define pci_free_consistent(hwdev, size, vaddr, dma_handle) \
+ free_pages((unsigned long)vaddr, __get_order(size))
+
+#define pci_map_single(hwdev, ptr, size, direction) \
+ virt_to_bus(ptr);
+
+#define pci_unmap_single(hwdev, dma_addr, size, direction) \
+ do { /* Nothing to do */ } while (0)
+
+#define pci_map_sg(hwdev, sg, nents, direction) (nents)
+#define pci_unmap_sg(hwdev, sg, nents, direction) \
+ do { /* Nothing to do */ } while(0)
+
+#define sg_dma_address(sg) (virt_to_bus((sg)->address))
+#define sg_dma_len(sg) ((sg)->length)
+
+/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif /* PCI_DMA_BIDIRECTIONAL */
+
+/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif /* _LINUX_COMPAT_H */
+
--- /dev/null
+/*
+ * Copyright (c) 2000-2001 LSI Logic Corporation. All rights reserved.
+ *
+ * NAME: fc_log.h
+ * SUMMARY: MPI IocLogInfo definitions for the SYMFC9xx chips
+ * DESCRIPTION: Contains the enumerated list of values that may be returned
+ * in the IOCLogInfo field of a MPI Default Reply Message.
+ *
+ * CREATION DATE: 6/02/2000
+ * ID: $Id: fc_log.h,v 4.2 2001/03/01 18:28:59 fibre Exp $
+ */
+
+
+/*
+ * MpiIocLogInfo_t enum
+ *
+ * These 32 bit values are used in the IOCLogInfo field of the MPI reply
+ * messages.
+ * The value is 0xabcccccc where
+ * a = The type of log info as per the MPI spec. Since these codes are
+ * all for Fibre Channel this value will always be 2.
+ * b = Specifies a subclass of the firmware where
+ * 0 = FCP Initiator
+ * 1 = FCP Target
+ * 2 = LAN
+ * 3 = MPI Message Layer
+ * 4 = FC Link
+ * 5 = Context Manager
+ * 6 = Invalid Field Offset
+ * 7 = State Change Info
+ * all others are reserved for future use
+ * c = A specific value within the subclass.
+ *
+ * NOTE: Any new values should be added to the end of each subclass so that the
+ * codes remain consistent across firmware releases.
+ */
+typedef enum _MpiIocLogInfoFc
+{
+ MPI_IOCLOGINFO_FC_INIT_BASE = 0x20000000,
+ MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME = 0x20000001, /* received an out of order frame - unsupported */
+ MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME = 0x20000002, /* bad start of frame primative */
+ MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME = 0x20000003, /* bad end of frame primative */
+ MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN = 0x20000004, /* Receiver hardware detected overrun */
+ MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER = 0x20000005, /* Other errors caught by IOC which require retries */
+ MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD = 0x20000006, /* Main processor could not initialize sub-processor */
+
+ MPI_IOCLOGINFO_FC_TARGET_BASE = 0x21000000,
+ MPI_IOCLOGINFO_FC_TARGET_NO_PDISC = 0x21000001, /* not sent because we are waiting for a PDISC from the initiator */
+ MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN = 0x21000002, /* not sent because we are not logged in to the remote node */
+ MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP = 0x21000003, /* Data Out, Auto Response, not sent due to a LIP */
+ MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP = 0x21000004, /* Data In, Auto Response, not sent due to a LIP */
+ MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA = 0x21000005, /* Data In, Auto Response, missing data frames */
+ MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP = 0x21000006, /* Data Out, No Response, not sent due to a LIP */
+ MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP = 0x21000007, /* Auto-response after a write not sent due to a LIP */
+ MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP = 0x21000008, /* Data In, No Response, not completed due to a LIP */
+ MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA = 0x21000009, /* Data In, No Response, missing data frames */
+ MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP = 0x2100000a, /* Manual Response not sent due to a LIP */
+ MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3 = 0x2100000b, /* not sent because remote node does not support Class 3 */
+ MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID = 0x2100000c, /* not sent because login to remote node not validated */
+ MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND = 0x2100000e, /* cleared from the outbound after a logout */
+ MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN = 0x2100000f, /* cleared waiting for data after a logout */
+
+ MPI_IOCLOGINFO_FC_LAN_BASE = 0x22000000,
+ MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING = 0x22000001, /* Transaction Context Sgl Missing */
+ MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE = 0x22000002, /* Transaction Context found before an EOB */
+ MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET = 0x22000003, /* Transaction Context value has reserved bits set */
+ MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG = 0x22000004, /* Invalid SGL Flags */
+
+ MPI_IOCLOGINFO_FC_MSG_BASE = 0x23000000,
+
+ MPI_IOCLOGINFO_FC_LINK_BASE = 0x24000000,
+ MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT = 0x24000001, /* Loop initialization timed out */
+ MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED = 0x24000002, /* Another system controller already initialized the loop */
+ MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED = 0x24000003, /* Not synchronized to signal or still negotiating (possible cable problem) */
+
+ MPI_IOCLOGINFO_FC_CTX_BASE = 0x25000000,
+
+ MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET = 0x26000000, /* The lower 24 bits give the byte offset of the field in the request message that is invalid. */
+ MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET = 0x26ffffff,
+
+ MPI_IOCLOGINFO_FC_STATE_CHANGE = 0x27000000 /* The lower 24 bits give additional information concerning state change */
+
+} MpiIocLogInfoFc_t;
--- /dev/null
+/*
+ * Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ * Name: MPI.H
+ * Title: MPI Message independent structures and definitions
+ * Creation Date: July 27, 2000
+ *
+ * MPI Version: 01.01.06
+ *
+ * Version History
+ * ---------------
+ *
+ * Date Version Description
+ * -------- -------- ------------------------------------------------------
+ * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000.
+ * 05-24-00 00.10.02 Added MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH definition.
+ * 06-06-00 01.00.01 Update MPI_VERSION_MAJOR and MPI_VERSION_MINOR.
+ * 06-22-00 01.00.02 Added MPI_IOCSTATUS_LAN_ definitions.
+ * Removed LAN_SUSPEND function definition.
+ * Added MPI_MSGFLAGS_CONTINUATION_REPLY definition.
+ * 06-30-00 01.00.03 Added MPI_CONTEXT_REPLY_TYPE_LAN definition.
+ * Added MPI_GET/SET_CONTEXT_REPLY_TYPE macros.
+ * 07-27-00 01.00.04 Added MPI_FAULT_ definitions.
+ * Removed MPI_IOCSTATUS_MSG/DATA_XFER_ERROR definitions.
+ * Added MPI_IOCSTATUS_INTERNAL_ERROR definition.
+ * Added MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH.
+ * 11-02-00 01.01.01 Original release for post 1.0 work.
+ * 12-04-00 01.01.02 Added new function codes.
+ * 01-09-01 01.01.03 Added more definitions to the system interface section
+ * Added MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT.
+ * 01-25-01 01.01.04 Changed MPI_VERSION_MINOR from 0x00 to 0x01.
+ * 02-20-01 01.01.05 Started using MPI_POINTER.
+ * Fixed value for MPI_DIAG_RW_ENABLE.
+ * Added defines for MPI_DIAG_PREVENT_IOC_BOOT and
+ * MPI_DIAG_CLEAR_FLASH_BAD_SIG.
+ * Obsoleted MPI_IOCSTATUS_TARGET_FC_ defines.
+ * 02-27-01 01.01.06 Removed MPI_HOST_INDEX_REGISTER define.
+ * Added function codes for RAID.
+ * --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_H
+#define MPI_H
+
+
+/*****************************************************************************
+*
+* M P I V e r s i o n D e f i n i t i o n s
+*
+*****************************************************************************/
+
+#define MPI_VERSION_MAJOR (0x01)
+#define MPI_VERSION_MINOR (0x01)
+#define MPI_VERSION ((MPI_VERSION_MAJOR << 8) | MPI_VERSION_MINOR)
+
+/* Note: The major versions of 0xe0 through 0xff are reserved */
+
+/*****************************************************************************
+*
+* I O C S t a t e D e f i n i t i o n s
+*
+*****************************************************************************/
+
+#define MPI_IOC_STATE_RESET (0x00000000)
+#define MPI_IOC_STATE_READY (0x10000000)
+#define MPI_IOC_STATE_OPERATIONAL (0x20000000)
+#define MPI_IOC_STATE_FAULT (0x40000000)
+
+#define MPI_IOC_STATE_MASK (0xF0000000)
+#define MPI_IOC_STATE_SHIFT (28)
+
+/* Fault state codes (product independent range 0x8000-0xFFFF) */
+
+#define MPI_FAULT_REQUEST_MESSAGE_PCI_PARITY_ERROR (0x8111)
+#define MPI_FAULT_REQUEST_MESSAGE_PCI_BUS_FAULT (0x8112)
+#define MPI_FAULT_REPLY_MESSAGE_PCI_PARITY_ERROR (0x8113)
+#define MPI_FAULT_REPLY_MESSAGE_PCI_BUS_FAULT (0x8114)
+#define MPI_FAULT_DATA_SEND_PCI_PARITY_ERROR (0x8115)
+#define MPI_FAULT_DATA_SEND_PCI_BUS_FAULT (0x8116)
+#define MPI_FAULT_DATA_RECEIVE_PCI_PARITY_ERROR (0x8117)
+#define MPI_FAULT_DATA_RECEIVE_PCI_BUS_FAULT (0x8118)
+
+
+/*****************************************************************************
+*
+* P C I S y s t e m I n t e r f a c e R e g i s t e r s
+*
+*****************************************************************************/
+
+/* S y s t e m D o o r b e l l */
+#define MPI_DOORBELL_OFFSET (0x00000000)
+#define MPI_DOORBELL_ACTIVE (0x08000000)
+#define MPI_DOORBELL_ACTIVE_SHIFT (27)
+#define MPI_DOORBELL_WHO_INIT_MASK (0x07000000)
+#define MPI_DOORBELL_WHO_INIT_SHIFT (24)
+#define MPI_DOORBELL_FUNCTION_MASK (0xFF000000)
+#define MPI_DOORBELL_FUNCTION_SHIFT (24)
+#define MPI_DOORBELL_ADD_DWORDS_MASK (0x00FF0000)
+#define MPI_DOORBELL_ADD_DWORDS_SHIFT (16)
+#define MPI_DOORBELL_DATA_MASK (0x0000FFFF)
+
+
+#define MPI_WRITE_SEQUENCE_OFFSET (0x00000004)
+#define MPI_WRSEQ_KEY_VALUE_MASK (0x0000000F)
+#define MPI_WRSEQ_1ST_KEY_VALUE (0x04)
+#define MPI_WRSEQ_2ND_KEY_VALUE (0x0B)
+#define MPI_WRSEQ_3RD_KEY_VALUE (0x02)
+#define MPI_WRSEQ_4TH_KEY_VALUE (0x07)
+#define MPI_WRSEQ_5TH_KEY_VALUE (0x0D)
+
+#define MPI_DIAGNOSTIC_OFFSET (0x00000008)
+#define MPI_DIAG_CLEAR_FLASH_BAD_SIG (0x00000400)
+#define MPI_DIAG_PREVENT_IOC_BOOT (0x00000200)
+#define MPI_DIAG_DRWE (0x00000080)
+#define MPI_DIAG_FLASH_BAD_SIG (0x00000040)
+#define MPI_DIAG_RESET_HISTORY (0x00000020)
+#define MPI_DIAG_RW_ENABLE (0x00000010)
+#define MPI_DIAG_RESET_ADAPTER (0x00000004)
+#define MPI_DIAG_DISABLE_ARM (0x00000002)
+#define MPI_DIAG_MEM_ENABLE (0x00000001)
+
+#define MPI_TEST_BASE_ADDRESS_OFFSET (0x0000000C)
+
+#define MPI_DIAG_RW_DATA_OFFSET (0x00000010)
+
+#define MPI_DIAG_RW_ADDRESS_OFFSET (0x00000014)
+
+#define MPI_HOST_INTERRUPT_STATUS_OFFSET (0x00000030)
+#define MPI_HIS_IOP_DOORBELL_STATUS (0x80000000)
+#define MPI_HIS_REPLY_MESSAGE_INTERRUPT (0x00000008)
+#define MPI_HIS_DOORBELL_INTERRUPT (0x00000001)
+
+#define MPI_HOST_INTERRUPT_MASK_OFFSET (0x00000034)
+#define MPI_HIM_RIM (0x00000008)
+#define MPI_HIM_DIM (0x00000001)
+
+#define MPI_REQUEST_QUEUE_OFFSET (0x00000040)
+#define MPI_REQUEST_POST_FIFO_OFFSET (0x00000040)
+
+#define MPI_REPLY_QUEUE_OFFSET (0x00000044)
+#define MPI_REPLY_POST_FIFO_OFFSET (0x00000044)
+#define MPI_REPLY_FREE_FIFO_OFFSET (0x00000044)
+
+
+
+/*****************************************************************************
+*
+* M e s s a g e F r a m e D e s c r i p t o r s
+*
+*****************************************************************************/
+
+#define MPI_REQ_MF_DESCRIPTOR_NB_MASK (0x00000003)
+#define MPI_REQ_MF_DESCRIPTOR_F_BIT (0x00000004)
+#define MPI_REQ_MF_DESCRIPTOR_ADDRESS_MASK (0xFFFFFFF8)
+
+#define MPI_ADDRESS_REPLY_A_BIT (0x80000000)
+#define MPI_ADDRESS_REPLY_ADDRESS_MASK (0x7FFFFFFF)
+
+#define MPI_CONTEXT_REPLY_A_BIT (0x80000000)
+#define MPI_CONTEXT_REPLY_TYPE_MASK (0x60000000)
+#define MPI_CONTEXT_REPLY_TYPE_SCSI_INIT (0x00)
+#define MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET (0x01)
+#define MPI_CONTEXT_REPLY_TYPE_LAN (0x02)
+#define MPI_CONTEXT_REPLY_TYPE_SHIFT (29)
+#define MPI_CONTEXT_REPLY_CONTEXT_MASK (0x1FFFFFFF)
+
+
+/****************************************************************************/
+/* Context Reply macros */
+/****************************************************************************/
+
+#define MPI_GET_CONTEXT_REPLY_TYPE(x) (((x) & MPI_CONTEXT_REPLY_TYPE_MASK) \
+ >> MPI_CONTEXT_REPLY_TYPE_SHIFT)
+
+#define MPI_SET_CONTEXT_REPLY_TYPE(x, typ) \
+ ((x) = ((x) & ~MPI_CONTEXT_REPLY_TYPE_MASK) | \
+ (((typ) << MPI_CONTEXT_REPLY_TYPE_SHIFT) & \
+ MPI_CONTEXT_REPLY_TYPE_MASK))
+
+
+/*****************************************************************************
+*
+* M e s s a g e F u n c t i o n s
+* 0x80 -> 0x8F reserved for private message use per product
+*
+*
+*****************************************************************************/
+
+#define MPI_FUNCTION_SCSI_IO_REQUEST (0x00)
+#define MPI_FUNCTION_SCSI_TASK_MGMT (0x01)
+#define MPI_FUNCTION_IOC_INIT (0x02)
+#define MPI_FUNCTION_IOC_FACTS (0x03)
+#define MPI_FUNCTION_CONFIG (0x04)
+#define MPI_FUNCTION_PORT_FACTS (0x05)
+#define MPI_FUNCTION_PORT_ENABLE (0x06)
+#define MPI_FUNCTION_EVENT_NOTIFICATION (0x07)
+#define MPI_FUNCTION_EVENT_ACK (0x08)
+#define MPI_FUNCTION_FW_DOWNLOAD (0x09)
+#define MPI_FUNCTION_TARGET_CMD_BUFFER_POST (0x0A)
+#define MPI_FUNCTION_TARGET_ASSIST (0x0B)
+#define MPI_FUNCTION_TARGET_STATUS_SEND (0x0C)
+#define MPI_FUNCTION_TARGET_MODE_ABORT (0x0D)
+#define MPI_FUNCTION_TARGET_FC_BUF_POST_LINK_SRVC (0x0E) /* obsolete name */
+#define MPI_FUNCTION_TARGET_FC_RSP_LINK_SRVC (0x0F) /* obsolete name */
+#define MPI_FUNCTION_TARGET_FC_EX_SEND_LINK_SRVC (0x10) /* obsolete name */
+#define MPI_FUNCTION_TARGET_FC_ABORT (0x11) /* obsolete name */
+#define MPI_FUNCTION_FC_LINK_SRVC_BUF_POST (0x0E)
+#define MPI_FUNCTION_FC_LINK_SRVC_RSP (0x0F)
+#define MPI_FUNCTION_FC_EX_LINK_SRVC_SEND (0x10)
+#define MPI_FUNCTION_FC_ABORT (0x11)
+#define MPI_FUNCTION_FW_UPLOAD (0x12)
+#define MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND (0x13)
+#define MPI_FUNCTION_FC_PRIMITIVE_SEND (0x14)
+
+#define MPI_FUNCTION_RAID_VOLUME (0x15)
+#define MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH (0x16)
+
+#define MPI_FUNCTION_LAN_SEND (0x20)
+#define MPI_FUNCTION_LAN_RECEIVE (0x21)
+#define MPI_FUNCTION_LAN_RESET (0x22)
+
+#define MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40)
+#define MPI_FUNCTION_IO_UNIT_RESET (0x41)
+#define MPI_FUNCTION_HANDSHAKE (0x42)
+#define MPI_FUNCTION_REPLY_FRAME_REMOVAL (0x43)
+
+
+
+/*****************************************************************************
+*
+* S c a t t e r G a t h e r E l e m e n t s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/* Simple element structures */
+/****************************************************************************/
+
+typedef struct _SGE_SIMPLE32
+{
+ U32 FlagsLength;
+ U32 Address;
+} SGE_SIMPLE32, MPI_POINTER PTR_SGE_SIMPLE32,
+ SGESimple32_t, MPI_POINTER pSGESimple32_t;
+
+typedef struct _SGE_SIMPLE64
+{
+ U32 FlagsLength;
+ U64 Address;
+} SGE_SIMPLE64, MPI_POINTER PTR_SGE_SIMPLE64,
+ SGESimple64_t, MPI_POINTER pSGESimple64_t;
+
+typedef struct _SGE_SIMPLE_UNION
+{
+ U32 FlagsLength;
+ union
+ {
+ U32 Address32;
+ U64 Address64;
+ }u;
+} SGESimpleUnion_t, MPI_POINTER pSGESimpleUnion_t,
+ SGE_SIMPLE_UNION, MPI_POINTER PTR_SGE_SIMPLE_UNION;
+
+/****************************************************************************/
+/* Chain element structures */
+/****************************************************************************/
+
+typedef struct _SGE_CHAIN32
+{
+ U16 Length;
+ U8 NextChainOffset;
+ U8 Flags;
+ U32 Address;
+} SGE_CHAIN32, MPI_POINTER PTR_SGE_CHAIN32,
+ SGEChain32_t, MPI_POINTER pSGEChain32_t;
+
+typedef struct _SGE_CHAIN64
+{
+ U16 Length;
+ U8 NextChainOffset;
+ U8 Flags;
+ U64 Address;
+} SGE_CHAIN64, MPI_POINTER PTR_SGE_CHAIN64,
+ SGEChain64_t, MPI_POINTER pSGEChain64_t;
+
+typedef struct _SGE_CHAIN_UNION
+{
+ U16 Length;
+ U8 NextChainOffset;
+ U8 Flags;
+ union
+ {
+ U32 Address32;
+ U64 Address64;
+ }u;
+} SGE_CHAIN_UNION, MPI_POINTER PTR_SGE_CHAIN_UNION,
+ SGEChainUnion_t, MPI_POINTER pSGEChainUnion_t;
+
+/****************************************************************************/
+/* Transaction Context element */
+/****************************************************************************/
+
+typedef struct _SGE_TRANSACTION32
+{
+ U8 Reserved;
+ U8 ContextSize;
+ U8 DetailsLength;
+ U8 Flags;
+ U32 TransactionContext[1];
+ U32 TransactionDetails[1];
+} SGE_TRANSACTION32, MPI_POINTER PTR_SGE_TRANSACTION32,
+ SGETransaction32_t, MPI_POINTER pSGETransaction32_t;
+
+typedef struct _SGE_TRANSACTION64
+{
+ U8 Reserved;
+ U8 ContextSize;
+ U8 DetailsLength;
+ U8 Flags;
+ U32 TransactionContext[2];
+ U32 TransactionDetails[1];
+} SGE_TRANSACTION64, MPI_POINTER PTR_SGE_TRANSACTION64,
+ SGETransaction64_t, MPI_POINTER pSGETransaction64_t;
+
+typedef struct _SGE_TRANSACTION96
+{
+ U8 Reserved;
+ U8 ContextSize;
+ U8 DetailsLength;
+ U8 Flags;
+ U32 TransactionContext[3];
+ U32 TransactionDetails[1];
+} SGE_TRANSACTION96, MPI_POINTER PTR_SGE_TRANSACTION96,
+ SGETransaction96_t, MPI_POINTER pSGETransaction96_t;
+
+typedef struct _SGE_TRANSACTION128
+{
+ U8 Reserved;
+ U8 ContextSize;
+ U8 DetailsLength;
+ U8 Flags;
+ U32 TransactionContext[4];
+ U32 TransactionDetails[1];
+} SGE_TRANSACTION128, MPI_POINTER PTR_SGE_TRANSACTION128,
+ SGETransaction_t128, MPI_POINTER pSGETransaction_t128;
+
+typedef struct _SGE_TRANSACTION_UNION
+{
+ U8 Reserved;
+ U8 ContextSize;
+ U8 DetailsLength;
+ U8 Flags;
+ union
+ {
+ U32 TransactionContext32[1];
+ U32 TransactionContext64[2];
+ U32 TransactionContext96[3];
+ U32 TransactionContext128[4];
+ }u;
+ U32 TransactionDetails[1];
+} SGE_TRANSACTION_UNION, MPI_POINTER PTR_SGE_TRANSACTION_UNION,
+ SGETransactionUnion_t, MPI_POINTER pSGETransactionUnion_t;
+
+
+/****************************************************************************/
+/* SGE IO types union for IO SGL's */
+/****************************************************************************/
+
+typedef struct _SGE_IO_UNION
+{
+ union
+ {
+ SGE_SIMPLE_UNION Simple;
+ SGE_CHAIN_UNION Chain;
+ } u;
+} SGE_IO_UNION, MPI_POINTER PTR_SGE_IO_UNION,
+ SGEIOUnion_t, MPI_POINTER pSGEIOUnion_t;
+
+/****************************************************************************/
+/* SGE union for SGL's with Simple and Transaction elements */
+/****************************************************************************/
+
+typedef struct _SGE_TRANS_SIMPLE_UNION
+{
+ union
+ {
+ SGE_SIMPLE_UNION Simple;
+ SGE_TRANSACTION_UNION Transaction;
+ } u;
+} SGE_TRANS_SIMPLE_UNION, MPI_POINTER PTR_SGE_TRANS_SIMPLE_UNION,
+ SGETransSimpleUnion_t, MPI_POINTER pSGETransSimpleUnion_t;
+
+/****************************************************************************/
+/* All SGE types union */
+/****************************************************************************/
+
+typedef struct _SGE_MPI_UNION
+{
+ union
+ {
+ SGE_SIMPLE_UNION Simple;
+ SGE_CHAIN_UNION Chain;
+ SGE_TRANSACTION_UNION Transaction;
+ } u;
+} SGE_MPI_UNION, MPI_POINTER PTR_SGE_MPI_UNION,
+ MPI_SGE_UNION_t, MPI_POINTER pMPI_SGE_UNION_t,
+ SGEAllUnion_t, MPI_POINTER pSGEAllUnion_t;
+
+
+/****************************************************************************/
+/* SGE field definition and masks */
+/****************************************************************************/
+
+/* Flags field bit definitions */
+
+#define MPI_SGE_FLAGS_LAST_ELEMENT (0x80)
+#define MPI_SGE_FLAGS_END_OF_BUFFER (0x40)
+#define MPI_SGE_FLAGS_ELEMENT_TYPE_MASK (0x30)
+#define MPI_SGE_FLAGS_LOCAL_ADDRESS (0x08)
+#define MPI_SGE_FLAGS_DIRECTION (0x04)
+#define MPI_SGE_FLAGS_ADDRESS_SIZE (0x02)
+#define MPI_SGE_FLAGS_END_OF_LIST (0x01)
+
+#define MPI_SGE_FLAGS_SHIFT (24)
+
+#define MPI_SGE_LENGTH_MASK (0x00FFFFFF)
+#define MPI_SGE_CHAIN_LENGTH_MASK (0x0000FFFF)
+
+/* Element Type */
+
+#define MPI_SGE_FLAGS_TRANSACTION_ELEMENT (0x00)
+#define MPI_SGE_FLAGS_SIMPLE_ELEMENT (0x10)
+#define MPI_SGE_FLAGS_CHAIN_ELEMENT (0x30)
+#define MPI_SGE_FLAGS_ELEMENT_MASK (0x30)
+
+/* Address location */
+
+#define MPI_SGE_FLAGS_SYSTEM_ADDRESS (0x00)
+
+/* Direction */
+
+#define MPI_SGE_FLAGS_IOC_TO_HOST (0x00)
+#define MPI_SGE_FLAGS_HOST_TO_IOC (0x04)
+
+/* Address Size */
+
+#define MPI_SGE_FLAGS_32_BIT_ADDRESSING (0x00)
+#define MPI_SGE_FLAGS_64_BIT_ADDRESSING (0x02)
+
+/* Context Size */
+
+#define MPI_SGE_FLAGS_32_BIT_CONTEXT (0x00)
+#define MPI_SGE_FLAGS_64_BIT_CONTEXT (0x02)
+#define MPI_SGE_FLAGS_96_BIT_CONTEXT (0x04)
+#define MPI_SGE_FLAGS_128_BIT_CONTEXT (0x06)
+
+#define MPI_SGE_CHAIN_OFFSET_MASK (0x00FF0000)
+#define MPI_SGE_CHAIN_OFFSET_SHIFT (16)
+
+
+/****************************************************************************/
+/* SGE operation Macros */
+/****************************************************************************/
+
+ /* SIMPLE FlagsLength manipulations... */
+#define MPI_SGE_SET_FLAGS(f) ((U32)(f) << MPI_SGE_FLAGS_SHIFT)
+#define MPI_SGE_GET_FLAGS(fl) (((fl) & ~MPI_SGE_LENGTH_MASK) >> MPI_SGE_FLAGS_SHIFT)
+#define MPI_SGE_LENGTH(fl) ((fl) & MPI_SGE_LENGTH_MASK)
+#define MPI_SGE_CHAIN_LENGTH(fl) ((fl) & MPI_SGE_CHAIN_LENGTH_MASK)
+
+#define MPI_SGE_SET_FLAGS_LENGTH(f,l) (MPI_SGE_SET_FLAGS(f) | MPI_SGE_LENGTH(l))
+
+#define MPI_pSGE_GET_FLAGS(psg) MPI_SGE_GET_FLAGS((psg)->FlagsLength)
+#define MPI_pSGE_GET_LENGTH(psg) MPI_SGE_LENGTH((psg)->FlagsLength)
+#define MPI_pSGE_SET_FLAGS_LENGTH(psg,f,l) (psg)->FlagsLength = MPI_SGE_SET_FLAGS_LENGTH(f,l)
+ /* CAUTION - The following are READ-MODIFY-WRITE! */
+#define MPI_pSGE_SET_FLAGS(psg,f) (psg)->FlagsLength |= MPI_SGE_SET_FLAGS(f)
+#define MPI_pSGE_SET_LENGTH(psg,l) (psg)->FlagsLength |= MPI_SGE_LENGTH(l)
+
+#define MPI_GET_CHAIN_OFFSET(x) ((x&MPI_SGE_CHAIN_OFFSET_MASK)>>MPI_SGE_CHAIN_OFFSET_SHIFT)
+
+
+
+/*****************************************************************************
+*
+* S t a n d a r d M e s s a g e S t r u c t u r e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/* Standard message request header for all request messages */
+/****************************************************************************/
+
+typedef struct _MSG_REQUEST_HEADER
+{
+ U8 Reserved[2]; /* function specific */
+ U8 ChainOffset;
+ U8 Function;
+ U8 Reserved1[3]; /* function specific */
+ U8 MsgFlags;
+ U32 MsgContext;
+} MSG_REQUEST_HEADER, MPI_POINTER PTR_MSG_REQUEST_HEADER,
+ MPIHeader_t, MPI_POINTER pMPIHeader_t;
+
+
+/****************************************************************************/
+/* Default Reply */
+/****************************************************************************/
+
+typedef struct _MSG_DEFAULT_REPLY
+{
+ U8 Reserved[2]; /* function specific */
+ U8 MsgLength;
+ U8 Function;
+ U8 Reserved1[3]; /* function specific */
+ U8 MsgFlags;
+ U32 MsgContext;
+ U8 Reserved2[2]; /* function specific */
+ U16 IOCStatus;
+ U32 IOCLogInfo;
+} MSG_DEFAULT_REPLY, MPI_POINTER PTR_MSG_DEFAULT_REPLY,
+ MPIDefaultReply_t, MPI_POINTER pMPIDefaultReply_t;
+
+
+/* MsgFlags definition for all replies */
+
+#define MPI_MSGFLAGS_CONTINUATION_REPLY (0x80)
+
+
+/*****************************************************************************
+*
+* I O C S t a t u s V a l u e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/* Common IOCStatus values for all replies */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_SUCCESS (0x0000)
+#define MPI_IOCSTATUS_INVALID_FUNCTION (0x0001)
+#define MPI_IOCSTATUS_BUSY (0x0002)
+#define MPI_IOCSTATUS_INVALID_SGL (0x0003)
+#define MPI_IOCSTATUS_INTERNAL_ERROR (0x0004)
+#define MPI_IOCSTATUS_RESERVED (0x0005)
+#define MPI_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006)
+#define MPI_IOCSTATUS_INVALID_FIELD (0x0007)
+#define MPI_IOCSTATUS_INVALID_STATE (0x0008)
+
+/****************************************************************************/
+/* Config IOCStatus values */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020)
+#define MPI_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021)
+#define MPI_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022)
+#define MPI_IOCSTATUS_CONFIG_INVALID_DATA (0x0023)
+#define MPI_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024)
+#define MPI_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025)
+
+/****************************************************************************/
+/* SCSIIO Reply (SPI & FCP) initiator values */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040)
+#define MPI_IOCSTATUS_SCSI_INVALID_BUS (0x0041)
+#define MPI_IOCSTATUS_SCSI_INVALID_TARGETID (0x0042)
+#define MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043)
+#define MPI_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044)
+#define MPI_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045)
+#define MPI_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046)
+#define MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047)
+#define MPI_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048)
+#define MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049)
+#define MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004A)
+#define MPI_IOCSTATUS_SCSI_IOC_TERMINATED (0x004B)
+#define MPI_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C)
+
+/****************************************************************************/
+/* SCSI (SPI & FCP) target values */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_TARGET_PRIORITY_IO (0x0060)
+#define MPI_IOCSTATUS_TARGET_INVALID_PORT (0x0061)
+#define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX (0x0062)
+#define MPI_IOCSTATUS_TARGET_ABORTED (0x0063)
+#define MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE (0x0064)
+#define MPI_IOCSTATUS_TARGET_NO_CONNECTION (0x0065)
+#define MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH (0x006A)
+#define MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT (0x006B)
+
+/****************************************************************************/
+/* Additional FCP target values */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_TARGET_FC_ABORTED (0x0066) /* obsolete */
+#define MPI_IOCSTATUS_TARGET_FC_RX_ID_INVALID (0x0067) /* obsolete */
+#define MPI_IOCSTATUS_TARGET_FC_DID_INVALID (0x0068) /* obsolete */
+#define MPI_IOCSTATUS_TARGET_FC_NODE_LOGGED_OUT (0x0069) /* obsolete */
+
+/****************************************************************************/
+/* Fibre Channel Direct Access values */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_FC_ABORTED (0x0066)
+#define MPI_IOCSTATUS_FC_RX_ID_INVALID (0x0067)
+#define MPI_IOCSTATUS_FC_DID_INVALID (0x0068)
+#define MPI_IOCSTATUS_FC_NODE_LOGGED_OUT (0x0069)
+
+/****************************************************************************/
+/* LAN values */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND (0x0080)
+#define MPI_IOCSTATUS_LAN_DEVICE_FAILURE (0x0081)
+#define MPI_IOCSTATUS_LAN_TRANSMIT_ERROR (0x0082)
+#define MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED (0x0083)
+#define MPI_IOCSTATUS_LAN_RECEIVE_ERROR (0x0084)
+#define MPI_IOCSTATUS_LAN_RECEIVE_ABORTED (0x0085)
+#define MPI_IOCSTATUS_LAN_PARTIAL_PACKET (0x0086)
+#define MPI_IOCSTATUS_LAN_CANCELED (0x0087)
+
+
+/****************************************************************************/
+/* IOCStatus flag to indicate that log info is available */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE (0x8000)
+#define MPI_IOCSTATUS_MASK (0x7FFF)
+
+/****************************************************************************/
+/* LogInfo Types */
+/****************************************************************************/
+
+#define MPI_IOCLOGINFO_TYPE_MASK (0xF0000000)
+#define MPI_IOCLOGINFO_TYPE_NONE (0x00)
+#define MPI_IOCLOGINFO_TYPE_SCSI (0x01)
+#define MPI_IOCLOGINFO_TYPE_FC (0x02)
+#define MPI_IOCLOGINFO_LOG_DATA_MASK (0x0FFFFFFF)
+
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ * Name: MPI_CNFG.H
+ * Title: MPI Config message, structures, and Pages
+ * Creation Date: July 27, 2000
+ *
+ * MPI Version: 01.01.09
+ *
+ * Version History
+ * ---------------
+ *
+ * Date Version Description
+ * -------- -------- ------------------------------------------------------
+ * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000.
+ * 06-06-00 01.00.01 Update version number for 1.0 release.
+ * 06-08-00 01.00.02 Added _PAGEVERSION definitions for all pages.
+ * Added FcPhLowestVersion, FcPhHighestVersion, Reserved2
+ * fields to FC_DEVICE_0 page, updated the page version.
+ * Changed _FREE_RUNNING_CLOCK to _PACING_TRANSFERS in
+ * SCSI_PORT_0, SCSI_DEVICE_0 and SCSI_DEVICE_1 pages
+ * and updated the page versions.
+ * Added _RESPONSE_ID_MASK definition to SCSI_PORT_1
+ * page and updated the page version.
+ * Added Information field and _INFO_PARAMS_NEGOTIATED
+ * definitionto SCSI_DEVICE_0 page.
+ * 06-22-00 01.00.03 Removed batch controls from LAN_0 page and updated the
+ * page version.
+ * Added BucketsRemaining to LAN_1 page, redefined the
+ * state values, and updated the page version.
+ * Revised bus width definitions in SCSI_PORT_0,
+ * SCSI_DEVICE_0 and SCSI_DEVICE_1 pages.
+ * 06-30-00 01.00.04 Added MaxReplySize to LAN_1 page and updated the page
+ * version.
+ * Moved FC_DEVICE_0 PageAddress description to spec.
+ * 07-27-00 01.00.05 Corrected the SubsystemVendorID and SubsystemID field
+ * widths in IOC_0 page and updated the page version.
+ * 11-02-00 01.01.01 Original release for post 1.0 work
+ * Added Manufacturing pages, IO Unit Page 2, SCSI SPI
+ * Port Page 2, FC Port Page 4, FC Port Page 5
+ * 11-15-00 01.01.02 Interim changes to match proposals
+ * 12-04-00 01.01.03 Config page changes to match MPI rev 1.00.01.
+ * 12-05-00 01.01.04 Modified config page actions.
+ * 01-09-01 01.01.05 Added defines for page address formats.
+ * Data size for Manufacturing pages 2 and 3 no longer
+ * defined here.
+ * Io Unit Page 2 size is fixed at 4 adapters and some
+ * flags were changed.
+ * SCSI Port Page 2 Device Settings modified.
+ * New fields added to FC Port Page 0 and some flags
+ * cleaned up.
+ * Removed impedance flash from FC Port Page 1.
+ * Added FC Port pages 6 and 7.
+ * 01-25-01 01.01.06 Added MaxInitiators field to FcPortPage0.
+ * 01-29-01 01.01.07 Changed some defines to make them 32 character unique.
+ * Added some LinkType defines for FcPortPage0.
+ * 02-20-01 01.01.08 Started using MPI_POINTER.
+ * 02-27-01 01.01.09 Replaced MPI_CONFIG_PAGETYPE_SCSI_LUN with
+ * MPI_CONFIG_PAGETYPE_RAID_VOLUME.
+ * Added definitions and structures for IOC Page 2 and
+ * RAID Volume Page 2.
+ * --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_CNFG_H
+#define MPI_CNFG_H
+
+
+/*****************************************************************************
+*
+* C o n f i g M e s s a g e a n d S t r u c t u r e s
+*
+*****************************************************************************/
+
+typedef struct _CONFIG_PAGE_HEADER
+{
+ U8 PageVersion;
+ U8 PageLength;
+ U8 PageNumber;
+ U8 PageType;
+} fCONFIG_PAGE_HEADER, MPI_POINTER PTR_CONFIG_PAGE_HEADER,
+ ConfigPageHeader_t, MPI_POINTER pConfigPageHeader_t;
+
+typedef union _CONFIG_PAGE_HEADER_UNION
+{
+ ConfigPageHeader_t Struct;
+ U8 Bytes[4];
+ U16 Word16[2];
+ U32 Word32;
+} ConfigPageHeaderUnion, MPI_POINTER pConfigPageHeaderUnion,
+ fCONFIG_PAGE_HEADER_UNION, MPI_POINTER PTR_CONFIG_PAGE_HEADER_UNION;
+
+
+/****************************************************************************/
+/* PageType field values */
+/****************************************************************************/
+#define MPI_CONFIG_PAGEATTR_READ_ONLY (0x00)
+#define MPI_CONFIG_PAGEATTR_CHANGEABLE (0x10)
+#define MPI_CONFIG_PAGEATTR_PERSISTENT (0x20)
+#define MPI_CONFIG_PAGEATTR_MASK (0xF0)
+
+#define MPI_CONFIG_PAGETYPE_IO_UNIT (0x00)
+#define MPI_CONFIG_PAGETYPE_IOC (0x01)
+#define MPI_CONFIG_PAGETYPE_BIOS (0x02)
+#define MPI_CONFIG_PAGETYPE_SCSI_PORT (0x03)
+#define MPI_CONFIG_PAGETYPE_SCSI_DEVICE (0x04)
+#define MPI_CONFIG_PAGETYPE_FC_PORT (0x05)
+#define MPI_CONFIG_PAGETYPE_FC_DEVICE (0x06)
+#define MPI_CONFIG_PAGETYPE_LAN (0x07)
+#define MPI_CONFIG_PAGETYPE_RAID_VOLUME (0x08)
+#define MPI_CONFIG_PAGETYPE_MANUFACTURING (0x09)
+#define MPI_CONFIG_PAGETYPE_MASK (0x0F)
+
+#define MPI_CONFIG_TYPENUM_MASK (0x0FFF)
+
+
+/****************************************************************************
+ * PageAddres field values
+ ****************************************************************************/
+#define MPI_SCSI_PORT_PGAD_PORT_MASK (0x000000FF)
+
+#define MPI_SCSI_DEVICE_TARGET_ID_MASK (0x000000FF)
+#define MPI_SCSI_DEVICE_TARGET_ID_SHIFT (0)
+#define MPI_SCSI_DEVICE_BUS_MASK (0x0000FF00)
+#define MPI_SCSI_DEVICE_BUS_SHIFT (8)
+
+#define MPI_SCSI_LUN_TARGET_ID_MASK (0x000000FF)
+#define MPI_SCSI_LUN_TARGET_ID_SHIFT (0)
+#define MPI_SCSI_LUN_BUS_MASK (0x0000FF00)
+#define MPI_SCSI_LUN_BUS_SHIFT (8)
+#define MPI_SCSI_LUN_LUN_MASK (0x00FF0000)
+#define MPI_SCSI_LUN_LUN_SHIFT (16)
+
+#define MPI_FC_PORT_PGAD_PORT_MASK (0xF0000000)
+#define MPI_FC_PORT_PGAD_PORT_SHIFT (28)
+#define MPI_FC_PORT_PGAD_FORM_MASK (0x0F000000)
+#define MPI_FC_PORT_PGAD_FORM_INDEX (0x01000000)
+#define MPI_FC_PORT_PGAD_INDEX_MASK (0x0000FFFF)
+#define MPI_FC_PORT_PGAD_INDEX_SHIFT (0)
+
+#define MPI_FC_DEVICE_PGAD_PORT_MASK (0xF0000000)
+#define MPI_FC_DEVICE_PGAD_PORT_SHIFT (28)
+#define MPI_FC_DEVICE_PGAD_FORM_MASK (0x0F000000)
+#define MPI_FC_DEVICE_PGAD_FORM_NEXT_DID (0x00000000)
+#define MPI_FC_DEVICE_PGAD_ND_PORT_MASK (0xF0000000)
+#define MPI_FC_DEVICE_PGAD_ND_PORT_SHIFT (28)
+#define MPI_FC_DEVICE_PGAD_ND_DID_MASK (0x00FFFFFF)
+#define MPI_FC_DEVICE_PGAD_ND_DID_SHIFT (0)
+#define MPI_FC_DEVICE_PGAD_FORM_BUS_TID (0x01000000)
+#define MPI_FC_DEVICE_PGAD_BT_BUS_MASK (0x0000FF00)
+#define MPI_FC_DEVICE_PGAD_BT_BUS_SHIFT (8)
+#define MPI_FC_DEVICE_PGAD_BT_TID_MASK (0x000000FF)
+#define MPI_FC_DEVICE_PGAD_BT_TID_SHIFT (0)
+
+
+/****************************************************************************/
+/* Config Request Message */
+/****************************************************************************/
+typedef struct _MSG_CONFIG
+{
+ U8 Action;
+ U8 Reserved;
+ U8 ChainOffset;
+ U8 Function;
+ U8 Reserved1[3];
+ U8 MsgFlags;
+ U32 MsgContext;
+ U8 Reserved2[8];
+ fCONFIG_PAGE_HEADER Header;
+ U32 PageAddress;
+ SGE_IO_UNION PageBufferSGE;
+} MSG_CONFIG, MPI_POINTER PTR_MSG_CONFIG,
+ Config_t, MPI_POINTER pConfig_t;
+
+
+/****************************************************************************/
+/* Action field values */
+/****************************************************************************/
+#define MPI_CONFIG_ACTION_PAGE_HEADER (0x00)
+/*#define MPI_CONFIG_ACTION_PAGE_READ (0x01) *//* obsolete */
+#define MPI_CONFIG_ACTION_PAGE_READ_CURRENT (0x01)
+/*#define MPI_CONFIG_ACTION_PAGE_WRITE (0x02) *//* obsolete */
+#define MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT (0x02)
+#define MPI_CONFIG_ACTION_PAGE_DEFAULT (0x03)
+/*#define MPI_CONFIG_ACTION_PAGE_WRITE_COMMIT (0x04) */ /* obsolete */
+#define MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM (0x04)
+#define MPI_CONFIG_ACTION_PAGE_READ_DEFAULT (0x05)
+#define MPI_CONFIG_ACTION_PAGE_READ_NVRAM (0x06)
+
+
+/* Config Reply Message */
+typedef struct _MSG_CONFIG_REPLY
+{
+ U8 Action;
+ U8 Reserved;
+ U8 MsgLength;
+ U8 Function;
+ U8 Reserved1[3];
+ U8 MsgFlags;
+ U32 MsgContext;
+ U8 Reserved2[2];
+ U16 IOCStatus;
+ U32 IOCLogInfo;
+ fCONFIG_PAGE_HEADER Header;
+} MSG_CONFIG_REPLY, MPI_POINTER PTR_MSG_CONFIG_REPLY,
+ ConfigReply_t, MPI_POINTER pConfigReply_t;
+
+
+
+/*****************************************************************************
+*
+* C o n f i g u r a t i o n P a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/* Manufacturing Config pages */
+/****************************************************************************/
+#define MPI_MANUFACTPAGE_DEVICEID_FC909 (0x0621)
+#define MPI_MANUFACTPAGE_DEVICEID_FC919 (0x0624)
+#define MPI_MANUFACTPAGE_DEVICEID_FC929 (0x0622)
+#define MPI_MANUFACTPAGE_DEVID_53C1030 (0x0030)
+#define MPI_MANUFACTPAGE_DEVID_53C1030ZC (0x0031)
+#define MPI_MANUFACTPAGE_DEVID_53C1035 (0x0035)
+
+typedef struct _CONFIG_PAGE_MANUFACTURING_0
+{
+ fCONFIG_PAGE_HEADER Header;
+ U8 ChipName[16];
+ U8 ChipRevision[8];
+ U8 BoardName[16];
+ U8 BoardAssembly[16];
+ U8 BoardTracerNumber[16];
+
+} fCONFIG_PAGE_MANUFACTURING_0, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_0,
+ ManufacturingPage0_t, MPI_POINTER pManufacturingPage0_t;
+
+#define MPI_MANUFACTURING0_PAGEVERSION (0x00)
+
+
+typedef struct _CONFIG_PAGE_MANUFACTURING_1
+{
+ fCONFIG_PAGE_HEADER Header;
+ U8 VPD[256];
+} fCONFIG_PAGE_MANUFACTURING_1, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_1,
+ ManufacturingPage1_t, MPI_POINTER pManufacturingPage1_t;
+
+#define MPI_MANUFACTURING1_PAGEVERSION (0x00)
+
+
+typedef struct _MPI_CHIP_REVISION_ID
+{
+ U16 DeviceID;
+ U8 PCIRevisionID;
+ U8 Reserved;
+} MPI_CHIP_REVISION_ID, MPI_POINTER PTR_MPI_CHIP_REVISION_ID,
+ MpiChipRevisionId_t, MPI_POINTER pMpiChipRevisionId_t;
+
+
+typedef struct _CONFIG_PAGE_MANUFACTURING_2
+{
+ fCONFIG_PAGE_HEADER Header;
+ MPI_CHIP_REVISION_ID ChipId;
+ U32 HwSettings[1];
+} fCONFIG_PAGE_MANUFACTURING_2, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_2,
+ ManufacturingPage2_t, MPI_POINTER pManufacturingPage2_t;
+
+#define MPI_MANUFACTURING2_PAGEVERSION (0x00)
+
+
+typedef struct _CONFIG_PAGE_MANUFACTURING_3
+{
+ fCONFIG_PAGE_HEADER Header;
+ MPI_CHIP_REVISION_ID ChipId;
+ U32 Info[1];
+} fCONFIG_PAGE_MANUFACTURING_3, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_3,
+ ManufacturingPage3_t, MPI_POINTER pManufacturingPage3_t;
+
+#define MPI_MANUFACTURING3_PAGEVERSION (0x00)
+
+
+/****************************************************************************/
+/* IO Unit Config Pages */
+/****************************************************************************/
+
+typedef struct _CONFIG_PAGE_IO_UNIT_0
+{
+ fCONFIG_PAGE_HEADER Header;
+ U64 UniqueValue;
+} fCONFIG_PAGE_IO_UNIT_0, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_0,
+ IOUnitPage0_t, MPI_POINTER pIOUnitPage0_t;
+
+#define MPI_IOUNITPAGE0_PAGEVERSION (0x00)
+
+
+typedef struct _CONFIG_PAGE_IO_UNIT_1
+{
+ fCONFIG_PAGE_HEADER Header;
+ U32 Flags;
+} fCONFIG_PAGE_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_1,
+ IOUnitPage1_t, MPI_POINTER pIOUnitPage1_t;
+
+#define MPI_IOUNITPAGE1_PAGEVERSION (0x00)
+
+#define MPI_IOUNITPAGE1_MULTI_FUNCTION (0x00000000)
+#define MPI_IOUNITPAGE1_SINGLE_FUNCTION (0x00000001)
+#define MPI_IOUNITPAGE1_MULTI_PATHING (0x00000002)
+#define MPI_IOUNITPAGE1_SINGLE_PATHING (0x00000000)
+
+#define MPI_IOUNITPAGE1_FORCE_32 (0x00000080)
+
+
+typedef struct _MPI_ADAPTER_INFO
+{
+ U8 PciBusNumber;
+ U8 PciDeviceAndFunctionNumber;
+ U16 AdapterFlags;
+} MPI_ADAPTER_INFO, MPI_POINTER PTR_MPI_ADAPTER_INFO,
+ MpiAdapterInfo_t, MPI_POINTER pMpiAdapterInfo_t;
+
+#define MPI_ADAPTER_INFO_FLAGS_EMBEDDED (0x0001)
+#define MPI_ADAPTER_INFO_FLAGS_INIT_STATUS (0x0002)
+
+typedef struct _CONFIG_PAGE_IO_UNIT_2
+{
+ fCONFIG_PAGE_HEADER Header;
+ U32 Flags;
+ U32 BiosVersion;
+ MPI_ADAPTER_INFO AdapterOrder[4];
+} fCONFIG_PAGE_IO_UNIT_2, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_2,
+ IOUnitPage2_t, MPI_POINTER pIOUnitPage2_t;
+
+#define MPI_IOUNITPAGE2_PAGEVERSION (0x00)
+
+#define MPI_IOUNITPAGE2_FLAGS_RAID_DISABLE (0x00000001)
+#define MPI_IOUNITPAGE2_FLAGS_PAUSE_ON_ERROR (0x00000002)
+#define MPI_IOUNITPAGE2_FLAGS_VERBOSE_ENABLE (0x00000004)
+#define MPI_IOUNITPAGE2_FLAGS_COLOR_VIDEO_DISABLE (0x00000008)
+#define MPI_IOUNITPAGE2_FLAGS_DONT_HOOK_INT_40 (0x00000010)
+
+
+/****************************************************************************/
+/* IOC Config Pages */
+/****************************************************************************/
+
+typedef struct _CONFIG_PAGE_IOC_0
+{
+ fCONFIG_PAGE_HEADER Header;
+ U32 TotalNVStore;
+ U32 FreeNVStore;
+ U16 VendorID;
+ U16 DeviceID;
+ U8 RevisionID;
+ U8 Reserved[3];
+ U32 ClassCode;
+ U16 SubsystemVendorID;
+ U16 SubsystemID;
+} fCONFIG_PAGE_IOC_0, MPI_POINTER PTR_CONFIG_PAGE_IOC_0,
+ IOCPage0_t, MPI_POINTER pIOCPage0_t;
+
+#define MPI_IOCPAGE0_PAGEVERSION (0x01)
+
+typedef struct _CONFIG_PAGE_IOC_1
+{
+ fCONFIG_PAGE_HEADER Header;
+ U32 Flags;
+ U32 CoalescingTimeout;
+ U8 CoalescingDepth;
+ U8 Reserved[3];
+} fCONFIG_PAGE_IOC_1, MPI_POINTER PTR_CONFIG_PAGE_IOC_1,
+ IOCPage1_t, MPI_POINTER pIOCPage1_t;
+
+#define MPI_IOCPAGE1_PAGEVERSION (0x00)
+
+#define MPI_IOCPAGE1_REPLY_COALESCING (0x00000001)
+
+typedef struct _CONFIG_PAGE_IOC_2_RAID_VOL
+{
+ U8 VolumeTargetID;
+ U8 VolumeBus;
+ U16 Reserved;
+ U8 VolumeVersionMinor;
+ U8 VolumeVersionMajor;
+ U8 VolumeRaidType;
+ U8 Reserved1;
+} fCONFIG_PAGE_IOC_2_RAID_VOL, MPI_POINTER PTR_CONFIG_PAGE_IOC_2_RAID_VOL,
+ ConfigPageIoc2RaidVol_t, MPI_POINTER pConfigPageIoc2RaidVol_t;
+
+typedef struct _CONFIG_PAGE_IOC_2
+{
+ fCONFIG_PAGE_HEADER Header;
+ U32 CapabilitiesFlags;
+ U8 NumActiveVolumes;
+ U8 MaxVolumes;
+ U16 Reserved;
+ fCONFIG_PAGE_IOC_2_RAID_VOL RaidVolume[1];
+} fCONFIG_PAGE_IOC_2, MPI_POINTER PTR_CONFIG_PAGE_IOC_2,
+ IOCPage2_t, MPI_POINTER pIOCPage2_t;
+
+#define MPI_IOCPAGE2_PAGEVERSION (0x00)
+
+/* IOC Page 2 Capabilities flags */
+
+#define MPI_IOCPAGE2_CAP_FLAGS_RAID_0_SUPPORT (0x00000001)
+#define MPI_IOCPAGE2_CAP_FLAGS_RAID_1_SUPPORT (0x00000002)
+#define MPI_IOCPAGE2_CAP_FLAGS_LSI_MIRROR_SUPPORT (0x00000004)
+#define MPI_IOCPAGE2_CAP_FLAGS_RAID_5_SUPPORT (0x00000008)
+#define MPI_IOCPAGE2_CAP_FLAGS_RAID_10_SUPPORT (0x00000010)
+
+/* IOC Page 2 Volume RAID Type values */
+
+#define MPI_IOCPAGE2_VOL_TYPE_RAID_0 (0x00)
+#define MPI_IOCPAGE2_VOL_TYPE_RAID_1 (0x01)
+#define MPI_IOCPAGE2_VOL_TYPE_LSI_MIRROR (0x02)
+#define MPI_IOCPAGE2_VOL_TYPE_RAID_5 (0x05)
+#define MPI_IOCPAGE2_VOL_TYPE_RAID_10 (0x0A)
+
+
+/****************************************************************************/
+/* SCSI Port Config Pages */
+/****************************************************************************/
+
+typedef struct _CONFIG_PAGE_SCSI_PORT_0
+{
+ fCONFIG_PAGE_HEADER Header;
+ U32 Capabilities;
+ U32 PhysicalInterface;
+} fCONFIG_PAGE_SCSI_PORT_0, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_0,
+ SCSIPortPage0_t, MPI_POINTER pSCSIPortPage0_t;
+
+#define MPI_SCSIPORTPAGE0_PAGEVERSION (0x01)
+
+#define MPI_SCSIPORTPAGE0_CAP_IU (0x00000001)
+#define MPI_SCSIPORTPAGE0_CAP_DT (0x00000002)
+#define MPI_SCSIPORTPAGE0_CAP_QAS (0x00000004)
+#define MPI_SCSIPORTPAGE0_CAP_PACING_TRANSFERS (0x00000008)
+#define MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK (0x0000FF00)
+#define MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK (0x00FF0000)
+#define MPI_SCSIPORTPAGE0_CAP_WIDE (0x20000000)
+#define MPI_SCSIPORTPAGE0_CAP_AIP (0x80000000)
+
+#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK (0x00000003)
+#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD (0x01)
+#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE (0x02)
+#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_LVD (0x03)
+
+typedef struct _CONFIG_PAGE_SCSI_PORT_1
+{
+ fCONFIG_PAGE_HEADER Header;
+ U32 Configuration;
+} fCONFIG_PAGE_SCSI_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_1,
+ SCSIPortPage1_t, MPI_POINTER pSCSIPortPage1_t;
+
+#define MPI_SCSIPORTPAGE1_PAGEVERSION (0x01)
+
+#define MPI_SCSIPORTPAGE1_CFG_PORT_SCSI_ID_MASK (0x000000FF)
+#define MPI_SCSIPORTPAGE1_CFG_PORT_RESPONSE_ID_MASK (0xFFFF0000)
+
+typedef struct _MPI_DEVICE_INFO
+{
+ U8 Timeout;
+ U8 SyncFactor;
+ U16 DeviceFlags;
+} MPI_DEVICE_INFO, MPI_POINTER PTR_MPI_DEVICE_INFO,
+ MpiDeviceInfo_t, MPI_POINTER pMpiDeviceInfo_t;
+
+typedef struct _CONFIG_PAGE_SCSI_PORT_2
+{
+ fCONFIG_PAGE_HEADER Header;
+ U32 PortFlags;
+ U32 PortSettings;
+ MPI_DEVICE_INFO DeviceSettings[16];
+} fCONFIG_PAGE_SCSI_PORT_2, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_2,
+ SCSIPortPage2_t, MPI_POINTER pSCSIPortPage2_t;
+
+#define MPI_SCSIPORTPAGE2_PAGEVERSION (0x01)
+
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_SCAN_HIGH_TO_LOW (0x00000001)
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_PARITY_ENABLE (0x00000002)
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET (0x00000004)
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_ALTERNATE_CHS (0x00000008)
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_TERMINATION_DISABLE (0x00000010)
+
+#define MPI_SCSIPORTPAGE2_PORT_HOST_ID_MASK (0x0000000F)
+#define MPI_SCSIPORTPAGE2_PORT_MASK_INIT_HBA (0x00000030)
+#define MPI_SCSIPORTPAGE2_PORT_DISABLE_INIT_HBA (0x00000000)
+#define MPI_SCSIPORTPAGE2_PORT_BIOS_INIT_HBA (0x00000010)
+#define MPI_SCSIPORTPAGE2_PORT_OS_INIT_HBA (0x00000020)
+#define MPI_SCSIPORTPAGE2_PORT_BIOS_OS_INIT_HBA (0x00000030)
+#define MPI_SCSIPORTPAGE2_PORT_REMOVABLE_MEDIA (0x000000C0)
+#define MPI_SCSIPORTPAGE2_PORT_SPINUP_DELAY_MASK (0x00000F00)
+#define MPI_SCSIPORTPAGE2_PORT_MASK_NEGO_MASTER_SETTINGS (0x00003000)
+#define MPI_SCSIPORTPAGE2_PORT_NEGO_MASTER_SETTINGS (0x00000000)
+#define MPI_SCSIPORTPAGE2_PORT_NONE_MASTER_SETTINGS (0x00000001)
+#define MPI_SCSIPORTPAGE2_PORT_ALL_MASTER_SETTINGS (0x00000003)
+
+#define MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE (0x00000001)
+#define MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE (0x00000002)
+#define MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE (0x00000004)
+#define MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE (0x00000008)
+#define MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE (0x00000010)
+#define MPI_SCSIPORTPAGE2_DEVICE_BOOT_CHOICE (0x00000020)
+
+
+/****************************************************************************/
+/* SCSI Target Device Config Pages */
+/****************************************************************************/
+
+typedef struct _CONFIG_PAGE_SCSI_DEVICE_0
+{
+ fCONFIG_PAGE_HEADER Header;
+ U32 NegotiatedParameters;
+ U32 Information;
+} fCONFIG_PAGE_SCSI_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_0,
+ SCSIDevicePage0_t, MPI_POINTER pSCSIDevicePage0_t;
+
+#define MPI_SCSIDEVPAGE0_PAGEVERSION (0x01)
+
+#define MPI_SCSIDEVPAGE0_NP_IU (0x00000001)
+#define MPI_SCSIDEVPAGE0_NP_DT (0x00000002)
+#define MPI_SCSIDEVPAGE0_NP_QAS (0x00000004)
+#define MPI_SCSIDEVPAGE0_NP_PACING_TRANSFERS (0x00000008)
+#define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK (0x0000FF00)
+#define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK (0x00FF0000)
+#define MPI_SCSIDEVPAGE0_NP_WIDE (0x20000000)
+#define MPI_SCSIDEVPAGE0_NP_AIP (0x80000000)
+
+#define MPI_SCSIDEVPAGE0_INFO_PARAMS_NEGOTIATED (0x00000001)
+
+typedef struct _CONFIG_PAGE_SCSI_DEVICE_1
+{
+ fCONFIG_PAGE_HEADER Header;
+ U32 RequestedParameters;
+ U32 DomainValidation;
+ U32 Configuration;
+} fCONFIG_PAGE_SCSI_DEVICE_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_1,
+ SCSIDevicePage1_t, MPI_POINTER pSCSIDevicePage1_t;
+
+#define MPI_SCSIDEVPAGE1_PAGEVERSION (0x01)
+
+#define MPI_SCSIDEVPAGE1_RP_IU (0x00000001)
+#define MPI_SCSIDEVPAGE1_RP_DT (0x00000002)
+#define MPI_SCSIDEVPAGE1_RP_QAS (0x00000004)
+#define MPI_SCSIDEVPAGE1_RP_PACING_TRANSFERS (0x00000008)
+#define MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK (0x0000FF00)
+#define MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK (0x00FF0000)
+#define MPI_SCSIDEVPAGE1_RP_WIDE (0x20000000)
+#define MPI_SCSIDEVPAGE1_RP_AIP (0x80000000)
+
+#define MPI_SCSIDEVPAGE1_DV_LVD_DRIVE_STRENGTH_MASK (0x00000003)
+#define MPI_SCSIDEVPAGE1_DV_SE_SLEW_RATE_MASK (0x00000300)
+
+#define MPI_SCSIDEVPAGE1_CONF_PPR_ALLOWED (0x00000001)
+
+/****************************************************************************/
+/* FC Port Config Pages */
+/****************************************************************************/
+
+typedef struct _CONFIG_PAGE_FC_PORT_0
+{
+ fCONFIG_PAGE_HEADER Header;
+ U32 Flags;
+ U8 MPIPortNumber;
+ U8 LinkType;
+ U8 PortState;
+ U8 Reserved;
+ U32 PortIdentifier;
+ U64 WWNN;
+ U64 WWPN;
+ U32 SupportedServiceClass;
+ U32 SupportedSpeeds;
+ U32 CurrentSpeed;
+ U32 MaxFrameSize;
+ U64 FabricWWNN;
+ U64 FabricWWPN;
+ U32 DiscoveredPortsCount;
+ U32 MaxInitiators;
+} fCONFIG_PAGE_FC_PORT_0, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_0,
+ FCPortPage0_t, MPI_POINTER pFCPortPage0_t;
+
+#define MPI_FCPORTPAGE0_PAGEVERSION (0x01)
+
+#define MPI_FCPORTPAGE0_FLAGS_PROT_MASK (0x0000000F)
+#define MPI_FCPORTPAGE0_FLAGS_PROT_FCP_INIT (MPI_PORTFACTS_PROTOCOL_INITIATOR)
+#define MPI_FCPORTPAGE0_FLAGS_PROT_FCP_TARG (MPI_PORTFACTS_PROTOCOL_TARGET)
+#define MPI_FCPORTPAGE0_FLAGS_PROT_LAN (MPI_PORTFACTS_PROTOCOL_LAN)
+#define MPI_FCPORTPAGE0_FLAGS_PROT_LOGBUSADDR (MPI_PORTFACTS_PROTOCOL_LOGBUSADDR)
+
+#define MPI_FCPORTPAGE0_FLAGS_ALIAS_ALPA_SUPPORTED (0x00000010)
+#define MPI_FCPORTPAGE0_FLAGS_ALIAS_WWN_SUPPORTED (0x00000020)
+#define MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID (0x00000030)
+
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK (0x00000700)
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_POINT_TO_POINT (0x00000000)
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_PRIVATE_LOOP (0x00000100)
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_FABRIC_DIRECT (0x00000200)
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_PUBLIC_LOOP (0x00000300)
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT (0x00000700)
+
+#define MPI_FCPORTPAGE0_LTYPE_RESERVED (0x00)
+#define MPI_FCPORTPAGE0_LTYPE_OTHER (0x01)
+#define MPI_FCPORTPAGE0_LTYPE_UNKNOWN (0x02)
+#define MPI_FCPORTPAGE0_LTYPE_COPPER (0x03)
+#define MPI_FCPORTPAGE0_LTYPE_SINGLE_1300 (0x04)
+#define MPI_FCPORTPAGE0_LTYPE_SINGLE_1500 (0x05)
+#define MPI_FCPORTPAGE0_LTYPE_50_LASER_MULTI (0x06)
+#define MPI_FCPORTPAGE0_LTYPE_50_LED_MULTI (0x07)
+#define MPI_FCPORTPAGE0_LTYPE_62_LASER_MULTI (0x08)
+#define MPI_FCPORTPAGE0_LTYPE_62_LED_MULTI (0x09)
+#define MPI_FCPORTPAGE0_LTYPE_MULTI_LONG_WAVE (0x0A)
+#define MPI_FCPORTPAGE0_LTYPE_MULTI_SHORT_WAVE (0x0B)
+#define MPI_FCPORTPAGE0_LTYPE_LASER_SHORT_WAVE (0x0C)
+#define MPI_FCPORTPAGE0_LTYPE_LED_SHORT_WAVE (0x0D)
+#define MPI_FCPORTPAGE0_LTYPE_1300_LONG_WAVE (0x0E)
+#define MPI_FCPORTPAGE0_LTYPE_1500_LONG_WAVE (0x0F)
+
+#define MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN (0x01) /*(SNIA)HBA_PORTSTATE_UNKNOWN 1 Unknown */
+#define MPI_FCPORTPAGE0_PORTSTATE_ONLINE (0x02) /*(SNIA)HBA_PORTSTATE_ONLINE 2 Operational */
+#define MPI_FCPORTPAGE0_PORTSTATE_OFFLINE (0x03) /*(SNIA)HBA_PORTSTATE_OFFLINE 3 User Offline */
+#define MPI_FCPORTPAGE0_PORTSTATE_BYPASSED (0x04) /*(SNIA)HBA_PORTSTATE_BYPASSED 4 Bypassed */
+#define MPI_FCPORTPAGE0_PORTSTATE_DIAGNOST (0x05) /*(SNIA)HBA_PORTSTATE_DIAGNOSTICS 5 In diagnostics mode */
+#define MPI_FCPORTPAGE0_PORTSTATE_LINKDOWN (0x06) /*(SNIA)HBA_PORTSTATE_LINKDOWN 6 Link Down */
+#define MPI_FCPORTPAGE0_PORTSTATE_ERROR (0x07) /*(SNIA)HBA_PORTSTATE_ERROR 7 Port Error */
+#define MPI_FCPORTPAGE0_PORTSTATE_LOOPBACK (0x08) /*(SNIA)HBA_PORTSTATE_LOOPBACK 8 Loopback */
+
+#define MPI_FCPORTPAGE0_SUPPORT_CLASS_1 (0x00000001)
+#define MPI_FCPORTPAGE0_SUPPORT_CLASS_2 (0x00000002)
+#define MPI_FCPORTPAGE0_SUPPORT_CLASS_3 (0x00000004)
+
+#define MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED (0x00000001) /* (SNIA)HBA_PORTSPEED_1GBIT 1 1 GBit/sec */
+#define MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED (0x00000002) /* (SNIA)HBA_PORTSPEED_2GBIT 2 2 GBit/sec */
+#define MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED (0x00000004) /* (SNIA)HBA_PORTSPEED_10GBIT 4 10 GBit/sec */
+
+#define MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED
+#define MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED
+#define MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_1
+{
+ fCONFIG_PAGE_HEADER Header;
+ U32 Flags;
+ U64 NoSEEPROMWWNN;
+ U64 NoSEEPROMWWPN;
+ U8 HardALPA;
+ U8 LinkConfig;
+ U8 TopologyConfig;
+ U8 Reserved;
+} fCONFIG_PAGE_FC_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_1,
+ FCPortPage1_t, MPI_POINTER pFCPortPage1_t;
+
+#define MPI_FCPORTPAGE1_PAGEVERSION (0x01)
+
+#define MPI_FCPORTPAGE1_FLAGS_SORT_BY_DID (0x00000001)
+#define MPI_FCPORTPAGE1_FLAGS_SORT_BY_WWN (0x00000000)
+
+#define MPI_FCPORTPAGE1_FLAGS_PROT_MASK (0xF0000000)
+#define MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT (28)
+#define MPI_FCPORTPAGE1_FLAGS_PROT_FCP_INIT ((U32)MPI_PORTFACTS_PROTOCOL_INITIATOR << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT)
+#define MPI_FCPORTPAGE1_FLAGS_PROT_FCP_TARG ((U32)MPI_PORTFACTS_PROTOCOL_TARGET << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT)
+#define MPI_FCPORTPAGE1_FLAGS_PROT_LAN ((U32)MPI_PORTFACTS_PROTOCOL_LAN << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT)
+#define MPI_FCPORTPAGE1_FLAGS_PROT_LOGBUSADDR ((U32)MPI_PORTFACTS_PROTOCOL_LOGBUSADDR << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT)
+
+#define MPI_FCPORTPAGE1_HARD_ALPA_NOT_USED (0xFF)
+
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_MASK (0x0F)
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_1GIG (0x00)
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_2GIG (0x01)
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_4GIG (0x02)
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_10GIG (0x03)
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_AUTO (0x0F)
+
+#define MPI_FCPORTPAGE1_TOPOLGY_MASK (0x0F)
+#define MPI_FCPORTPAGE1_TOPOLGY_NLPORT (0x01)
+#define MPI_FCPORTPAGE1_TOPOLGY_NPORT (0x02)
+#define MPI_FCPORTPAGE1_TOPOLGY_AUTO (0x0F)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_2
+{
+ fCONFIG_PAGE_HEADER Header;
+ U8 NumberActive;
+ U8 ALPA[126];
+ U8 Reserved;
+} fCONFIG_PAGE_FC_PORT_2, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_2,
+ FCPortPage2_t, MPI_POINTER pFCPortPage2_t;
+
+#define MPI_FCPORTPAGE2_PAGEVERSION (0x00)
+
+
+typedef struct _FC_PORT_PERSISTENT
+{
+ U64 WWNN;
+ U64 WWPN;
+ U8 TargetID;
+ U8 Bus;
+ U16 Flags;
+} FC_PORT_PERSISTENT, MPI_POINTER PTR_FC_PORT_PERSISTENT,
+ PersistentData_t, MPI_POINTER pPersistentData_t;
+
+#define MPI_PERSISTENT_FLAGS_SHIFT (16)
+#define MPI_PERSISTENT_FLAGS_ENTRY_VALID (0x0001)
+#define MPI_PERSISTENT_FLAGS_SCAN_ID (0x0002)
+#define MPI_PERSISTENT_FLAGS_SCAN_LUNS (0x0004)
+#define MPI_PERSISTENT_FLAGS_BOOT_DEVICE (0x0008)
+
+typedef struct _CONFIG_PAGE_FC_PORT_3
+{
+ fCONFIG_PAGE_HEADER Header;
+ FC_PORT_PERSISTENT Entry[1];
+} fCONFIG_PAGE_FC_PORT_3, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_3,
+ FCPortPage3_t, MPI_POINTER pFCPortPage3_t;
+
+#define MPI_FCPORTPAGE3_PAGEVERSION (0x00)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_4
+{
+ fCONFIG_PAGE_HEADER Header;
+ U32 PortFlags;
+ U32 PortSettings;
+} fCONFIG_PAGE_FC_PORT_4, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_4,
+ FCPortPage4_t, MPI_POINTER pFCPortPage4_t;
+
+#define MPI_FCPORTPAGE4_PAGEVERSION (0x00)
+
+#define MPI_FCPORTPAGE4_PORT_FLAGS_ALTERNATE_CHS (0x00000008)
+
+#define MPI_FCPORTPAGE4_PORT_MASK_INIT_HBA (0x00000030)
+#define MPI_FCPORTPAGE4_PORT_DISABLE_INIT_HBA (0x00000000)
+#define MPI_FCPORTPAGE4_PORT_BIOS_INIT_HBA (0x00000010)
+#define MPI_FCPORTPAGE4_PORT_OS_INIT_HBA (0x00000020)
+#define MPI_FCPORTPAGE4_PORT_BIOS_OS_INIT_HBA (0x00000030)
+#define MPI_FCPORTPAGE4_PORT_REMOVABLE_MEDIA (0x000000C0)
+#define MPI_FCPORTPAGE4_PORT_SPINUP_DELAY_MASK (0x00000F00)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_5_ALIAS_INFO
+{
+ U8 Flags;
+ U8 AliasAlpa;
+ U16 Reserved;
+ U64 AliasWWNN;
+ U64 AliasWWPN;
+} fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5_ALIAS_INFO,
+ FcPortPage5AliasInfo_t, MPI_POINTER pFcPortPage5AliasInfo_t;
+
+typedef struct _CONFIG_PAGE_FC_PORT_5
+{
+ fCONFIG_PAGE_HEADER Header;
+ fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO AliasInfo[1];
+} fCONFIG_PAGE_FC_PORT_5, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5,
+ FCPortPage5_t, MPI_POINTER pFCPortPage5_t;
+
+#define MPI_FCPORTPAGE5_PAGEVERSION (0x00)
+
+#define MPI_FCPORTPAGE5_FLAGS_ALIAS_ALPA_VALID (0x01)
+#define MPI_FCPORTPAGE5_FLAGS_ALIAS_WWN_VALID (0x02)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_6
+{
+ fCONFIG_PAGE_HEADER Header;
+ U32 Reserved;
+ U64 TimeSinceReset;
+ U64 TxFrames;
+ U64 RxFrames;
+ U64 TxWords;
+ U64 RxWords;
+ U64 LipCount;
+ U64 NosCount;
+ U64 ErrorFrames;
+ U64 DumpedFrames;
+ U64 LinkFailureCount;
+ U64 LossOfSyncCount;
+ U64 LossOfSignalCount;
+ U64 PrimativeSeqErrCount;
+ U64 InvalidTxWordCount;
+ U64 InvalidCrcCount;
+ U64 FcpInitiatorIoCount;
+} fCONFIG_PAGE_FC_PORT_6, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_6,
+ FCPortPage6_t, MPI_POINTER pFCPortPage6_t;
+
+#define MPI_FCPORTPAGE6_PAGEVERSION (0x00)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_7
+{
+ fCONFIG_PAGE_HEADER Header;
+ U32 Reserved;
+ U8 PortSymbolicName[256];
+} fCONFIG_PAGE_FC_PORT_7, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_7,
+ FCPortPage7_t, MPI_POINTER pFCPortPage7_t;
+
+#define MPI_FCPORTPAGE7_PAGEVERSION (0x00)
+
+
+/****************************************************************************/
+/* FC Device Config Pages */
+/****************************************************************************/
+
+typedef struct _CONFIG_PAGE_FC_DEVICE_0
+{
+ fCONFIG_PAGE_HEADER Header;
+ U64 WWNN;
+ U64 WWPN;
+ U32 PortIdentifier;
+ U8 Protocol;
+ U8 Flags;
+ U16 BBCredit;
+ U16 MaxRxFrameSize;
+ U8 Reserved1;
+ U8 PortNumber;
+ U8 FcPhLowestVersion;
+ U8 FcPhHighestVersion;
+ U8 CurrentTargetID;
+ U8 CurrentBus;
+} fCONFIG_PAGE_FC_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_FC_DEVICE_0,
+ FCDevicePage0_t, MPI_POINTER pFCDevicePage0_t;
+
+#define MPI_FC_DEVICE_PAGE0_PAGEVERSION (0x02)
+
+#define MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID (0x01)
+
+#define MPI_FC_DEVICE_PAGE0_PROT_IP (0x01)
+#define MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET (0x02)
+#define MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR (0x04)
+
+#define MPI_FC_DEVICE_PAGE0_PGAD_PORT_MASK (MPI_FC_DEVICE_PGAD_PORT_MASK)
+#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_MASK (MPI_FC_DEVICE_PGAD_FORM_MASK)
+#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_NEXT_DID (MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
+#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_BUS_TID (MPI_FC_DEVICE_PGAD_FORM_BUS_TID)
+#define MPI_FC_DEVICE_PAGE0_PGAD_DID_MASK (MPI_FC_DEVICE_PGAD_ND_DID_MASK)
+#define MPI_FC_DEVICE_PAGE0_PGAD_BUS_MASK (MPI_FC_DEVICE_PGAD_BT_BUS_MASK)
+#define MPI_FC_DEVICE_PAGE0_PGAD_BUS_SHIFT (MPI_FC_DEVICE_PGAD_BT_BUS_SHIFT)
+#define MPI_FC_DEVICE_PAGE0_PGAD_TID_MASK (MPI_FC_DEVICE_PGAD_BT_TID_MASK)
+
+
+/****************************************************************************/
+/* RAID Volume Config Pages */
+/****************************************************************************/
+
+typedef struct _RAIDVOL2_EM_PHYS_ID
+{
+ U8 TargetID;
+ U8 Bus;
+ U8 IocNumber;
+ U8 PhysDiskNumber;
+ U8 Reserved[8];
+ U8 PhysicalDiskIdentifier[16];
+ U8 ProductId[16];
+ U8 InfoOffset0;
+ U8 InfoSize0;
+ U8 InfoOffset1;
+ U8 InfoSize1;
+ U8 Info[32];
+} RAIDVOL2_EM_PHYS_ID, MPI_POINTER PTR_RAIDVOL2_EM_PHYS_ID,
+ RaidVol2EmPhysicalID_t, MPI_POINTER pRaidVol2EmPhysicalID_t;
+
+typedef struct _RAIDVOL2_EM_DISK_INFO
+{
+ U32 DiskStatus;
+ U32 DeviceSettings;
+ U16 ErrorCount;
+ U16 Reserved;
+ U8 ErrorCdbByte;
+ U8 ErrorSenseKey;
+ U8 ErrorASC;
+ U8 ErrorASCQ;
+ U16 SmartCount;
+ U8 SmartASC;
+ U8 SmartASCQ;
+} RAIDVOL2_EM_DISK_INFO, MPI_POINTER PTR_RAIDVOL2_EM_DISK_INFO,
+ RaidVol2EmDiskInfo_t, MPI_POINTER pRaidVol2EmDiskInfo_t;
+
+/* RAID Volume 2 EM Physical Disk DiskStatus flags */
+
+#define MPI_RAIDVOLPAGE2_PHYS_DISK_PRIMARY (0x00000001)
+#define MPI_RAIDVOLPAGE2_PHYS_DISK_SECONDARY (0x00000002)
+#define MPI_RAIDVOLPAGE2_PHYS_DISK_HOT_SPARE (0x00000004)
+#define MPI_RAIDVOLPAGE2_PHYS_DISK_OUT_OF_SYNC (0x00000008)
+#define MPI_RAIDVOLPAGE2_PHYS_DISK_OFFLINE (0x00000010)
+#define MPI_RAIDVOLPAGE2_PHYS_DISK_NOT_RESPONDING (0x00000020)
+
+typedef struct _RAIDVOL2_EM_PHYSICAL_DISK
+{
+ RAIDVOL2_EM_PHYS_ID Id;
+ RAIDVOL2_EM_DISK_INFO Info;
+} RAIDVOL2_EM_PHYSICAL_DISK, MPI_POINTER PTR_RAIDVOL2_EM_PHYSICAL_DISK,
+ RaidVol2EmPhysicalDisk_t, MPI_POINTER pRaidVol2EmPhysicalDisk_t;
+
+#define MPI_RAIDVOLPAGE2_MAX_DISKS (3)
+
+typedef struct _CONFIG_PAGE_RAID_VOL_2
+{
+ fCONFIG_PAGE_HEADER Header;
+ U32 VolumeStatus;
+ U32 VolumeSettings;
+ U32 Reserved;
+ U64 MaxLba;
+ U32 BlockSize;
+ U8 InquirySize;
+ U8 NumPhysicalDisks;
+ U16 Reserved1;
+ U8 InquiryData[56];
+ RAIDVOL2_EM_PHYSICAL_DISK EMPhysicalDisk[MPI_RAIDVOLPAGE2_MAX_DISKS];
+} fCONFIG_PAGE_RAID_VOL_2, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_2,
+ RaidVolumePage2_t, MPI_POINTER pRaidVolumePage2_t;
+
+#define MPI_RAIDVOLPAGE2_PAGEVERSION (0x00)
+
+/* RAID Volume Page 2 VolumeStatus defines */
+
+#define MPI_RAIDVOLPAGE2_STATUS_ENABLED (0x00000001)
+#define MPI_RAIDVOLPAGE2_STATUS_QUIESCED (0x00000002)
+#define MPI_RAIDVOLPAGE2_STATUS_RESYNC_IN_PROGRESS (0x00000004)
+#define MPI_RAIDVOLPAGE2_STATUS_DEGRADED (0x00000008)
+
+/* RAID Volume Page 2 VolumeSettings defines */
+
+#define MPI_RAIDVOLPAGE2_SETTING_WRITE_CACHING_ENABLE (0x00000001)
+#define MPI_RAIDVOLPAGE2_SETTING_OFFLINE_ON_SMART (0x00000002)
+#define MPI_RAIDVOLPAGE2_SETTING_AUTO_CONFIGURE (0x00000004)
+
+
+/****************************************************************************/
+/* LAN Config Pages */
+/****************************************************************************/
+
+typedef struct _CONFIG_PAGE_LAN_0
+{
+ ConfigPageHeader_t Header;
+ U16 TxRxModes;
+ U16 Reserved;
+ U32 PacketPrePad;
+} fCONFIG_PAGE_LAN_0, MPI_POINTER PTR_CONFIG_PAGE_LAN_0,
+ LANPage0_t, MPI_POINTER pLANPage0_t;
+
+#define MPI_LAN_PAGE0_PAGEVERSION (0x01)
+
+#define MPI_LAN_PAGE0_RETURN_LOOPBACK (0x0000)
+#define MPI_LAN_PAGE0_SUPPRESS_LOOPBACK (0x0001)
+#define MPI_LAN_PAGE0_LOOPBACK_MASK (0x0001)
+
+typedef struct _CONFIG_PAGE_LAN_1
+{
+ ConfigPageHeader_t Header;
+ U16 Reserved;
+ U8 CurrentDeviceState;
+ U8 Reserved1;
+ U32 MinPacketSize;
+ U32 MaxPacketSize;
+ U32 HardwareAddressLow;
+ U32 HardwareAddressHigh;
+ U32 MaxWireSpeedLow;
+ U32 MaxWireSpeedHigh;
+ U32 BucketsRemaining;
+ U32 MaxReplySize;
+ U32 NegWireSpeedHigh;
+ U32 NegWireSpeedLow;
+} fCONFIG_PAGE_LAN_1, MPI_POINTER PTR_CONFIG_PAGE_LAN_1,
+ LANPage1_t, MPI_POINTER pLANPage1_t;
+
+#define MPI_LAN_PAGE1_PAGEVERSION (0x03)
+
+#define MPI_LAN_PAGE1_DEV_STATE_RESET (0x00)
+#define MPI_LAN_PAGE1_DEV_STATE_OPERATIONAL (0x01)
+
+#endif
+
--- /dev/null
+/*
+ * Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ * Name: MPI_FC.H
+ * Title: MPI Fibre Channel messages and structures
+ * Creation Date: June 12, 2000
+ *
+ * MPI Version: 01.01.05
+ *
+ * Version History
+ * ---------------
+ *
+ * Date Version Description
+ * -------- -------- ------------------------------------------------------
+ * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000.
+ * 06-06-00 01.00.01 Update version number for 1.0 release.
+ * 06-12-00 01.00.02 Added _MSG_FC_ABORT_REPLY structure.
+ * 11-02-00 01.01.01 Original release for post 1.0 work
+ * 12-04-00 01.01.02 Added messages for Common Transport Send and
+ * Primitive Send.
+ * 01-09-01 01.01.03 Modifed some of the new flags to have an MPI prefix
+ * and modified the FcPrimitiveSend flags.
+ * 01-25-01 01.01.04 Move InitiatorIndex in LinkServiceRsp reply to a larger
+ * field.
+ * Added FC_ABORT_TYPE_CT_SEND_REQUEST and
+ * FC_ABORT_TYPE_EXLINKSEND_REQUEST for FcAbort request.
+ * Added MPI_FC_PRIM_SEND_FLAGS_STOP_SEND.
+ * 02-20-01 01.01.05 Started using MPI_POINTER.
+ * --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_FC_H
+#define MPI_FC_H
+
+
+/*****************************************************************************
+*
+* F C T a r g e t M o d e M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/* Link Service Buffer Post messages */
+/****************************************************************************/
+
+typedef struct _MSG_LINK_SERVICE_BUFFER_POST_REQUEST
+{
+ U8 BufferPostFlags; /* 00h */
+ U8 BufferCount; /* 01h */
+ U8 ChainOffset; /* 02h */
+ U8 Function; /* 03h */
+ U16 Reserved; /* 04h */
+ U8 Reserved1; /* 06h */
+ U8 MsgFlags; /* 07h */
+ U32 MsgContext; /* 08h */
+ SGE_TRANS_SIMPLE_UNION SGL;
+} MSG_LINK_SERVICE_BUFFER_POST_REQUEST,
+ MPI_POINTER PTR_MSG_LINK_SERVICE_BUFFER_POST_REQUEST,
+ LinkServiceBufferPostRequest_t, MPI_POINTER pLinkServiceBufferPostRequest_t;
+
+#define LINK_SERVICE_BUFFER_POST_FLAGS_PORT_MASK (0x01)
+
+typedef struct _WWNFORMAT
+{
+ U32 PortNameHigh; /* 00h */
+ U32 PortNameLow; /* 04h */
+ U32 NodeNameHigh; /* 08h */
+ U32 NodeNameLow; /* 0Ch */
+} WWNFORMAT,
+ WwnFormat_t;
+
+/* Link Service Buffer Post Reply */
+typedef struct _MSG_LINK_SERVICE_BUFFER_POST_REPLY
+{
+ U8 Flags; /* 00h */
+ U8 Reserved; /* 01h */
+ U8 MsgLength; /* 02h */
+ U8 Function; /* 03h */
+ U16 Reserved1; /* 04h */
+ U8 PortNumber; /* 06h */
+ U8 MsgFlags; /* 07h */
+ U32 MsgContext; /* 08h */
+ U16 Reserved2; /* 0Ch */
+ U16 IOCStatus; /* 0Eh */
+ U32 IOCLogInfo; /* 10h */
+ U32 TransferLength; /* 14h */
+ U32 TransactionContext; /* 18h */
+ U32 Rctl_Did; /* 1Ch */
+ U32 Csctl_Sid; /* 20h */
+ U32 Type_Fctl; /* 24h */
+ U16 SeqCnt; /* 28h */
+ U8 Dfctl; /* 2Ah */
+ U8 SeqId; /* 2Bh */
+ U16 Rxid; /* 2Ch */
+ U16 Oxid; /* 2Eh */
+ U32 Parameter; /* 30h */
+ WWNFORMAT Wwn; /* 34h */
+} MSG_LINK_SERVICE_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_LINK_SERVICE_BUFFER_POST_REPLY,
+ LinkServiceBufferPostReply_t, MPI_POINTER pLinkServiceBufferPostReply_t;
+
+#define MPI_LS_BUF_POST_REPLY_FLAG_NO_RSP_NEEDED (0x80)
+
+#define MPI_FC_DID_MASK (0x00FFFFFF)
+#define MPI_FC_DID_SHIFT (0)
+#define MPI_FC_RCTL_MASK (0xFF000000)
+#define MPI_FC_RCTL_SHIFT (24)
+#define MPI_FC_SID_MASK (0x00FFFFFF)
+#define MPI_FC_SID_SHIFT (0)
+#define MPI_FC_CSCTL_MASK (0xFF000000)
+#define MPI_FC_CSCTL_SHIFT (24)
+#define MPI_FC_FCTL_MASK (0x00FFFFFF)
+#define MPI_FC_FCTL_SHIFT (0)
+#define MPI_FC_TYPE_MASK (0xFF000000)
+#define MPI_FC_TYPE_SHIFT (24)
+
+/* obsolete name for the above */
+#define FCP_TARGET_DID_MASK (0x00FFFFFF)
+#define FCP_TARGET_DID_SHIFT (0)
+#define FCP_TARGET_RCTL_MASK (0xFF000000)
+#define FCP_TARGET_RCTL_SHIFT (24)
+#define FCP_TARGET_SID_MASK (0x00FFFFFF)
+#define FCP_TARGET_SID_SHIFT (0)
+#define FCP_TARGET_CSCTL_MASK (0xFF000000)
+#define FCP_TARGET_CSCTL_SHIFT (24)
+#define FCP_TARGET_FCTL_MASK (0x00FFFFFF)
+#define FCP_TARGET_FCTL_SHIFT (0)
+#define FCP_TARGET_TYPE_MASK (0xFF000000)
+#define FCP_TARGET_TYPE_SHIFT (24)
+
+
+/****************************************************************************/
+/* Link Service Response messages */
+/****************************************************************************/
+
+typedef struct _MSG_LINK_SERVICE_RSP_REQUEST
+{
+ U8 RspFlags; /* 00h */
+ U8 Reserved; /* 01h */
+ U8 ChainOffset; /* 02h */
+ U8 Function; /* 03h */
+ U16 Reserved1; /* 04h */
+ U8 Reserved2; /* 06h */
+ U8 MsgFlags; /* 07h */
+ U32 MsgContext; /* 08h */
+ U32 Rctl_Did; /* 0Ch */
+ U32 Csctl_Sid; /* 10h */
+ U32 Type_Fctl; /* 14h */
+ U16 SeqCnt; /* 18h */
+ U8 Dfctl; /* 1Ah */
+ U8 SeqId; /* 1Bh */
+ U16 Rxid; /* 1Ch */
+ U16 Oxid; /* 1Eh */
+ U32 Parameter; /* 20h */
+ SGE_SIMPLE_UNION SGL; /* 24h */
+} MSG_LINK_SERVICE_RSP_REQUEST, MPI_POINTER PTR_MSG_LINK_SERVICE_RSP_REQUEST,
+ LinkServiceRspRequest_t, MPI_POINTER pLinkServiceRspRequest_t;
+
+#define LINK_SERVICE_RSP_FLAGS_IMMEDIATE (0x80)
+#define LINK_SERVICE_RSP_FLAGS_PORT_MASK (0x01)
+
+
+/* Link Service Response Reply */
+typedef struct _MSG_LINK_SERVICE_RSP_REPLY
+{
+ U16 Reserved; /* 00h */
+ U8 MsgLength; /* 02h */
+ U8 Function; /* 03h */
+ U16 Reserved1; /* 04h */
+ U8 Reserved2; /* 06h */
+ U8 MsgFlags; /* 07h */
+ U32 MsgContext; /* 08h */
+ U16 Reserved3; /* 0Ch */
+ U16 IOCStatus; /* 0Eh */
+ U32 IOCLogInfo; /* 10h */
+ U32 InitiatorIndex; /* 14h */
+} MSG_LINK_SERVICE_RSP_REPLY, MPI_POINTER PTR_MSG_LINK_SERVICE_RSP_REPLY,
+ LinkServiceRspReply_t, MPI_POINTER pLinkServiceRspReply_t;
+
+
+/****************************************************************************/
+/* Extended Link Service Send messages */
+/****************************************************************************/
+
+typedef struct _MSG_EXLINK_SERVICE_SEND_REQUEST
+{
+ U8 SendFlags; /* 00h */
+ U8 Reserved; /* 01h */
+ U8 ChainOffset; /* 02h */
+ U8 Function; /* 03h */
+ U32 MsgFlags_Did; /* 04h */
+ U32 MsgContext; /* 08h */
+ U32 ElsCommandCode; /* 0Ch */
+ SGE_SIMPLE_UNION SGL; /* 10h */
+} MSG_EXLINK_SERVICE_SEND_REQUEST, MPI_POINTER PTR_MSG_EXLINK_SERVICE_SEND_REQUEST,
+ ExLinkServiceSendRequest_t, MPI_POINTER pExLinkServiceSendRequest_t;
+
+#define EX_LINK_SERVICE_SEND_DID_MASK (0x00FFFFFF)
+#define EX_LINK_SERVICE_SEND_DID_SHIFT (0)
+#define EX_LINK_SERVICE_SEND_MSGFLAGS_MASK (0xFF000000)
+#define EX_LINK_SERVICE_SEND_MSGFLAGS_SHIFT (24)
+
+
+/* Extended Link Service Send Reply */
+typedef struct _MSG_EXLINK_SERVICE_SEND_REPLY
+{
+ U16 Reserved; /* 00h */
+ U8 MsgLength; /* 02h */
+ U8 Function; /* 03h */
+ U16 Reserved1; /* 04h */
+ U8 Reserved2; /* 06h */
+ U8 MsgFlags; /* 07h */
+ U32 MsgContext; /* 08h */
+ U16 Reserved3; /* 0Ch */
+ U16 IOCStatus; /* 0Eh */
+ U32 IOCLogInfo; /* 10h */
+ U32 ResponseLength; /* 14h */
+} MSG_EXLINK_SERVICE_SEND_REPLY, MPI_POINTER PTR_MSG_EXLINK_SERVICE_SEND_REPLY,
+ ExLinkServiceSendReply_t, MPI_POINTER pExLinkServiceSendReply_t;
+
+/****************************************************************************/
+/* FC Abort messages */
+/****************************************************************************/
+
+typedef struct _MSG_FC_ABORT_REQUEST
+{
+ U8 AbortFlags; /* 00h */
+ U8 AbortType; /* 01h */
+ U8 ChainOffset; /* 02h */
+ U8 Function; /* 03h */
+ U16 Reserved1; /* 04h */
+ U8 Reserved2; /* 06h */
+ U8 MsgFlags; /* 07h */
+ U32 MsgContext; /* 08h */
+ U32 TransactionContextToAbort; /* 0Ch */
+} MSG_FC_ABORT_REQUEST, MPI_POINTER PTR_MSG_FC_ABORT_REQUEST,
+ FcAbortRequest_t, MPI_POINTER pFcAbortRequest_t;
+
+#define FC_ABORT_FLAG_PORT_MASK (0x01)
+
+#define FC_ABORT_TYPE_ALL_FC_BUFFERS (0x00)
+#define FC_ABORT_TYPE_EXACT_FC_BUFFER (0x01)
+#define FC_ABORT_TYPE_CT_SEND_REQUEST (0x02)
+#define FC_ABORT_TYPE_EXLINKSEND_REQUEST (0x03)
+
+/* FC Abort Reply */
+typedef struct _MSG_FC_ABORT_REPLY
+{
+ U16 Reserved; /* 00h */
+ U8 MsgLength; /* 02h */
+ U8 Function; /* 03h */
+ U16 Reserved1; /* 04h */
+ U8 Reserved2; /* 06h */
+ U8 MsgFlags; /* 07h */
+ U32 MsgContext; /* 08h */
+ U16 Reserved3; /* 0Ch */
+ U16 IOCStatus; /* 0Eh */
+ U32 IOCLogInfo; /* 10h */
+} MSG_FC_ABORT_REPLY, MPI_POINTER PTR_MSG_FC_ABORT_REPLY,
+ FcAbortReply_t, MPI_POINTER pFcAbortReply_t;
+
+
+/****************************************************************************/
+/* FC Common Transport Send messages */
+/****************************************************************************/
+
+typedef struct _MSG_FC_COMMON_TRANSPORT_SEND_REQUEST
+{
+ U8 SendFlags; /* 00h */
+ U8 Reserved; /* 01h */
+ U8 ChainOffset; /* 02h */
+ U8 Function; /* 03h */
+ U32 MsgFlags_Did; /* 04h */
+ U32 MsgContext; /* 08h */
+ U16 CTCommandCode; /* 0Ch */
+ U8 FsType; /* 0Eh */
+ U8 Reserved1; /* 0Fh */
+ SGE_SIMPLE_UNION SGL; /* 10h */
+} MSG_FC_COMMON_TRANSPORT_SEND_REQUEST,
+ MPI_POINTER PTR_MSG_FC_COMMON_TRANSPORT_SEND_REQUEST,
+ FcCommonTransportSendRequest_t, MPI_POINTER pFcCommonTransportSendRequest_t;
+
+#define MPI_FC_CT_SEND_DID_MASK (0x00FFFFFF)
+#define MPI_FC_CT_SEND_DID_SHIFT (0)
+#define MPI_FC_CT_SEND_MSGFLAGS_MASK (0xFF000000)
+#define MPI_FC_CT_SEND_MSGFLAGS_SHIFT (24)
+
+
+/* FC Common Transport Send Reply */
+typedef struct _MSG_FC_COMMON_TRANSPORT_SEND_REPLY
+{
+ U16 Reserved; /* 00h */
+ U8 MsgLength; /* 02h */
+ U8 Function; /* 03h */
+ U16 Reserved1; /* 04h */
+ U8 Reserved2; /* 06h */
+ U8 MsgFlags; /* 07h */
+ U32 MsgContext; /* 08h */
+ U16 Reserved3; /* 0Ch */
+ U16 IOCStatus; /* 0Eh */
+ U32 IOCLogInfo; /* 10h */
+ U32 ResponseLength; /* 14h */
+} MSG_FC_COMMON_TRANSPORT_SEND_REPLY, MPI_POINTER PTR_MSG_FC_COMMON_TRANSPORT_SEND_REPLY,
+ FcCommonTransportSendReply_t, MPI_POINTER pFcCommonTransportSendReply_t;
+
+
+/****************************************************************************/
+/* FC Primitive Send messages */
+/****************************************************************************/
+
+typedef struct _MSG_FC_PRIMITIVE_SEND_REQUEST
+{
+ U8 SendFlags; /* 00h */
+ U8 Reserved; /* 01h */
+ U8 ChainOffset; /* 02h */
+ U8 Function; /* 03h */
+ U16 Reserved1; /* 04h */
+ U8 Reserved2; /* 06h */
+ U8 MsgFlags; /* 07h */
+ U32 MsgContext; /* 08h */
+ U8 FcPrimitive[4]; /* 0Ch */
+} MSG_FC_PRIMITIVE_SEND_REQUEST, MPI_POINTER PTR_MSG_FC_PRIMITIVE_SEND_REQUEST,
+ FcPrimitiveSendRequest_t, MPI_POINTER pFcPrimitiveSendRequest_t;
+
+#define MPI_FC_PRIM_SEND_FLAGS_PORT_MASK (0x01)
+#define MPI_FC_PRIM_SEND_FLAGS_STOP_SEND (0x08)
+#define MPI_FC_PRIM_SEND_FLAGS_SEND_ONCE (0x10)
+#define MPI_FC_PRIM_SEND_FLAGS_SEND_AROUND (0x20)
+#define MPI_FC_PRIM_SEND_FLAGS_UNTIL_FULL (0x40)
+#define MPI_FC_PRIM_SEND_FLAGS_FOREVER (0x80)
+
+/* FC Primitive Send Reply */
+typedef struct _MSG_FC_PRIMITIVE_SEND_REPLY
+{
+ U8 SendFlags; /* 00h */
+ U8 Reserved; /* 01h */
+ U8 MsgLength; /* 02h */
+ U8 Function; /* 03h */
+ U16 Reserved1; /* 04h */
+ U8 Reserved2; /* 06h */
+ U8 MsgFlags; /* 07h */
+ U32 MsgContext; /* 08h */
+ U16 Reserved3; /* 0Ch */
+ U16 IOCStatus; /* 0Eh */
+ U32 IOCLogInfo; /* 10h */
+} MSG_FC_PRIMITIVE_SEND_REPLY, MPI_POINTER PTR_MSG_FC_PRIMITIVE_SEND_REPLY,
+ FcPrimitiveSendReply_t, MPI_POINTER pFcPrimitiveSendReply_t;
+
+#endif
+
--- /dev/null
+
+ ==============================
+ MPI Header File Change History
+ ==============================
+
+ Copyright (c) 2000-2001 LSI Logic Corporation.
+
+ ---------------------------------------
+ Header Set Release Version: 01.01.08
+ Header Set Release Date: 02-27-01
+ ---------------------------------------
+
+ Filename Current version Prior version
+ ---------- --------------- -------------
+ mpi.h 01.01.06 01.01.05
+ mpi_ioc.h 01.01.05 01.01.04
+ mpi_cnfg.h 01.01.09 01.01.08
+ mpi_init.h 01.01.03 01.01.03
+ mpi_targ.h 01.01.03 01.01.03
+ mpi_fc.h 01.01.05 01.01.05
+ mpi_lan.h 01.01.02 01.01.02
+ mpi_raid.h 01.01.01 none
+ mpi_type.h 01.01.02 01.01.02
+ mpi_history.txt 01.01.08 01.01.07
+
+
+ * Date Version Description
+ * -------- -------- ------------------------------------------------------
+
+mpi.h
+ * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000.
+ * 05-24-00 00.10.02 Added MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH definition.
+ * 06-06-00 01.00.01 Update MPI_VERSION_MAJOR and MPI_VERSION_MINOR.
+ * 06-22-00 01.00.02 Added MPI_IOCSTATUS_LAN_ definitions.
+ * Removed LAN_SUSPEND function definition.
+ * Added MPI_MSGFLAGS_CONTINUATION_REPLY definition.
+ * 06-30-00 01.00.03 Added MPI_CONTEXT_REPLY_TYPE_LAN definition.
+ * Added MPI_GET/SET_CONTEXT_REPLY_TYPE macros.
+ * 07-27-00 01.00.04 Added MPI_FAULT_ definitions.
+ * Removed MPI_IOCSTATUS_MSG/DATA_XFER_ERROR definitions.
+ * Added MPI_IOCSTATUS_INTERNAL_ERROR definition.
+ * Added MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH.
+ * 11-02-00 01.01.01 Original release for post 1.0 work
+ * 12-04-00 01.01.02 Added new function codes.
+ * 01-09-01 01.01.03 Added more definitions to the system interface section
+ * Added MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT.
+ * 01-25-01 01.01.04 Changed MPI_VERSION_MINOR from 0x00 to 0x01.
+ * 02-20-01 01.01.05 Started using MPI_POINTER.
+ * Added defines for MPI_DIAG_PREVENT_IOC_BOOT and
+ * MPI_DIAG_CLEAR_FLASH_BAD_SIG.
+ * Obsoleted MPI_IOCSTATUS_TARGET_FC_ defines.
+ * 02-27-01 01.01.06 Removed MPI_HOST_INDEX_REGISTER define.
+ * Added function codes for RAID.
+ * --------------------------------------------------------------------------
+
+mpi_ioc.h
+ * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000.
+ * 05-24-00 00.10.02 Added _MSG_IOC_INIT_REPLY structure.
+ * 06-06-00 01.00.01 Added CurReplyFrameSize field to _MSG_IOC_FACTS_REPLY.
+ * 06-12-00 01.00.02 Added _MSG_PORT_ENABLE_REPLY structure.
+ * Added _MSG_EVENT_ACK_REPLY structure.
+ * Added _MSG_FW_DOWNLOAD_REPLY structure.
+ * Added _MSG_TOOLBOX_REPLY structure.
+ * 06-30-00 01.00.03 Added MaxLanBuckets to _PORT_FACT_REPLY structure.
+ * 07-27-00 01.00.04 Added _EVENT_DATA structure definitions for _SCSI,
+ * _LINK_STATUS, _LOOP_STATE and _LOGOUT.
+ * 08-11-00 01.00.05 Switched positions of MsgLength and Function fields in
+ * _MSG_EVENT_ACK_REPLY structure to match specification.
+ * 11-02-00 01.01.01 Original release for post 1.0 work
+ * Added a value for Manufacturer to WhoInit
+ * 12-04-00 01.01.02 Modified IOCFacts reply, added FWUpload messages, and
+ * removed toolbox message.
+ * 01-09-01 01.01.03 Added event enabled and disabled defines.
+ * Added structures for FwHeader and DataHeader.
+ * Added ImageType to FwUpload reply.
+ * 02-20-01 01.01.04 Started using MPI_POINTER.
+ * 02-27-01 01.01.05 Added event for RAID status change and its event data.
+ * Added IocNumber field to MSG_IOC_FACTS_REPLY.
+ * --------------------------------------------------------------------------
+
+mpi_cnfg.h
+ * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000.
+ * 06-06-00 01.00.01 Update version number for 1.0 release.
+ * 06-08-00 01.00.02 Added _PAGEVERSION definitions for all pages.
+ * Added FcPhLowestVersion, FcPhHighestVersion, Reserved2
+ * fields to FC_DEVICE_0 page, updated the page version.
+ * Changed _FREE_RUNNING_CLOCK to _PACING_TRANSFERS in
+ * SCSI_PORT_0, SCSI_DEVICE_0 and SCSI_DEVICE_1 pages
+ * and updated the page versions.
+ * Added _RESPONSE_ID_MASK definition to SCSI_PORT_1
+ * page and updated the page version.
+ * Added Information field and _INFO_PARAMS_NEGOTIATED
+ * definitionto SCSI_DEVICE_0 page.
+ * 06-22-00 01.00.03 Removed batch controls from LAN_0 page and updated the
+ * page version.
+ * Added BucketsRemaining to LAN_1 page, redefined the
+ * state values, and updated the page version.
+ * Revised bus width definitions in SCSI_PORT_0,
+ * SCSI_DEVICE_0 and SCSI_DEVICE_1 pages.
+ * 06-30-00 01.00.04 Added MaxReplySize to LAN_1 page and updated the page
+ * version.
+ * Moved FC_DEVICE_0 PageAddress description to spec.
+ * 07-27-00 01.00.05 Corrected the SubsystemVendorID and SubsystemID field
+ * widths in IOC_0 page and updated the page version.
+ * 11-02-00 01.01.01 Original release for post 1.0 work
+ * Added Manufacturing pages, IO Unit Page 2, SCSI SPI
+ * Port Page 2, FC Port Page 4, FC Port Page 5
+ * 12-04-00 01.01.03 Config page changes to match MPI rev 1.00.01.
+ * 12-05-00 01.01.04 Modified config page actions.
+ * 01-09-01 01.01.05 Added defines for page address formats.
+ * Data size for Manufacturing pages 2 and 3 no longer
+ * defined here.
+ * Io Unit Page 2 size is fixed at 4 adapters and some
+ * flags were changed.
+ * SCSI Port Page 2 Device Settings modified.
+ * New fields added to FC Port Page 0 and some flags
+ * cleaned up.
+ * Removed impedance flash from FC Port Page 1.
+ * Added FC Port pages 6 and 7.
+ * 01-25-01 01.01.06 Added MaxInitiators field to FcPortPage0.
+ * 01-29-01 01.01.07 Changed some defines to make them 32 character unique.
+ * Added some LinkType defines for FcPortPage0.
+ * 02-20-01 01.01.08 Started using MPI_POINTER.
+ * 02-27-01 01.01.09 Replaced MPI_CONFIG_PAGETYPE_SCSI_LUN with
+ * MPI_CONFIG_PAGETYPE_RAID_VOLUME.
+ * Added definitions and structures for IOC Page 2 and
+ * RAID Volume Page 2.
+ * --------------------------------------------------------------------------
+
+mpi_init.h
+ * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000.
+ * 05-24-00 00.10.02 Added SenseBufferLength to _MSG_SCSI_IO_REPLY.
+ * 06-06-00 01.00.01 Update version number for 1.0 release.
+ * 06-08-00 01.00.02 Added MPI_SCSI_RSP_INFO_ definitions.
+ * 11-02-00 01.01.01 Original release for post 1.0 work
+ * 12-04-00 01.01.02 Added MPI_SCSIIO_CONTROL_NO_DISCONNECT.
+ * 02-20-01 01.01.03 Started using MPI_POINTER.
+ * --------------------------------------------------------------------------
+
+mpi_targ.h
+ * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000.
+ * 06-06-00 01.00.01 Update version number for 1.0 release.
+ * 06-22-00 01.00.02 Added _MSG_TARGET_CMD_BUFFER_POST_REPLY structure.
+ * Corrected DECSRIPTOR typo to DESCRIPTOR.
+ * 11-02-00 01.01.01 Original release for post 1.0 work
+ * Modified target mode to use IoIndex instead of
+ * HostIndex and IocIndex. Added Alias.
+ * 01-09-01 01.01.02 Added defines for TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER
+ * and TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER.
+ * 02-20-01 01.01.03 Started using MPI_POINTER.
+ * Added structures for MPI_TARGET_SCSI_SPI_CMD_BUFFER and
+ * MPI_TARGET_FCP_CMD_BUFFER.
+ * --------------------------------------------------------------------------
+
+mpi_fc.h
+ * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000.
+ * 06-06-00 01.00.01 Update version number for 1.0 release.
+ * 06-12-00 01.00.02 Added _MSG_FC_ABORT_REPLY structure.
+ * 11-02-00 01.01.01 Original release for post 1.0 work
+ * 12-04-00 01.01.02 Added messages for Common Transport Send and
+ * Primitive Send.
+ * 01-09-01 01.01.03 Modifed some of the new flags to have an MPI prefix
+ * and modified the FcPrimitiveSend flags.
+ * 01-25-01 01.01.04 Move InitiatorIndex in LinkServiceRsp reply to a larger
+ * field.
+ * Added FC_ABORT_TYPE_CT_SEND_REQUEST and
+ * FC_ABORT_TYPE_EXLINKSEND_REQUEST for FcAbort request.
+ * Added MPI_FC_PRIM_SEND_FLAGS_STOP_SEND.
+ * 02-20-01 01.01.05 Started using MPI_POINTER.
+ * --------------------------------------------------------------------------
+
+mpi_lan.h
+ * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000.
+ * 05-24-00 00.10.02 Added LANStatus field to _MSG_LAN_SEND_REPLY.
+ * Added LANStatus field to _MSG_LAN_RECEIVE_POST_REPLY.
+ * Moved ListCount field in _MSG_LAN_RECEIVE_POST_REPLY.
+ * 06-06-00 01.00.01 Update version number for 1.0 release.
+ * 06-12-00 01.00.02 Added MPI_ to BUCKETSTATUS_ definitions.
+ * 06-22-00 01.00.03 Major changes to match new LAN definition in 1.0 spec.
+ * 06-30-00 01.00.04 Added Context Reply definitions per revised proposal.
+ * Changed transaction context usage to bucket/buffer.
+ * 07-05-00 01.00.05 Removed LAN_RECEIVE_POST_BUCKET_CONTEXT_MASK definition
+ * to lan private header file
+ * 11-02-00 01.01.01 Original release for post 1.0 work
+ * 02-20-01 01.01.02 Started using MPI_POINTER.
+ * --------------------------------------------------------------------------
+
+mpi_raid.h
+ * 02-27-01 01.01.01 Original release for this file.
+ * --------------------------------------------------------------------------
+
+mpi_type.h
+ * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000.
+ * 06-06-00 01.00.01 Update version number for 1.0 release.
+ * 11-02-00 01.01.01 Original release for post 1.0 work
+ * 02-20-01 01.01.02 Added define and ifdef for MPI_POINTER.
+ * --------------------------------------------------------------------------
+
+mpi_history.txt Parts list history
+
+Filename 01.01.08 01.01.07 01.01.06 01.01.05 01.01.04
+---------- -------- -------- -------- -------- --------
+mpi.h 01.01.06 01.01.05 01.01.04 01.01.04 01.01.03
+mpi_ioc.h 01.01.05 01.01.04 01.01.03 01.01.03 01.01.03
+mpi_cnfg.h 01.01.09 01.01.08 01.01.07 01.01.06 01.01.05
+mpi_init.h 01.01.03 01.01.03 01.01.02 01.01.02 01.01.02
+mpi_targ.h 01.01.03 01.01.03 01.01.02 01.01.02 01.01.02
+mpi_fc.h 01.01.05 01.01.05 01.01.04 01.01.04 01.01.03
+mpi_lan.h 01.01.02 01.01.02 01.01.01 01.01.01 01.01.01
+mpi_raid.h 01.01.01
+mpi_type.h 01.01.02 01.01.02 01.01.01 01.01.01 01.01.01
+
+Filename 01.01.03 01.01.02 01.01.01 01.00.07 01.00.06 01.00.05
+---------- -------- -------- -------- -------- -------- --------
+mpi.h 01.01.02 01.01.02 01.01.01 01.00.04 01.00.04 01.00.03
+mpi_ioc.h 01.01.02 01.01.02 01.01.01 01.00.05 01.00.04 01.00.03
+mpi_cnfg.h 01.01.04 01.01.03 01.01.01 01.00.05 01.00.05 01.00.04
+mpi_init.h 01.01.02 01.01.02 01.01.01 01.00.02 01.00.02 01.00.02
+mpi_targ.h 01.01.01 01.01.01 01.01.01 01.00.02 01.00.02 01.00.02
+mpi_fc.h 01.01.02 01.01.02 01.01.01 01.00.02 01.00.02 01.00.02
+mpi_lan.h 01.01.01 01.01.01 01.01.01 01.00.05 01.00.05 01.00.05
+mpi_type.h 01.01.01 01.01.01 01.01.01 01.00.01 01.00.01 01.00.01
+
+Filename 01.00.04 01.00.03 01.00.02 01.00.01 00.10.02 00.10.01
+---------- -------- -------- -------- -------- -------- --------
+mpi.h 01.00.02 01.00.01 01.00.01 01.00.01 00.10.02 00.10.01
+mpi_ioc.h 01.00.02 01.00.02 01.00.01 01.00.01 00.10.02 00.10.01
+mpi_cnfg.h 01.00.03 01.00.02 01.00.02 01.00.01 00.10.01 00.10.01
+mpi_init.h 01.00.02 01.00.02 01.00.02 01.00.01 00.10.02 00.10.01
+mpi_targ.h 01.00.02 01.00.01 01.00.01 01.00.01 00.10.01 00.10.01
+mpi_fc.h 01.00.02 01.00.02 01.00.01 01.00.01 00.10.01 00.10.01
+mpi_lan.h 01.00.03 01.00.02 01.00.01 01.00.01 00.10.02 00.10.01
+mpi_type.h 01.00.01 01.00.01 01.00.01 01.00.01 00.10.01 00.10.01
+
+
+ * --------------------------------------------------------------------------
+
--- /dev/null
+/*
+ * Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ * Name: MPI_INIT.H
+ * Title: MPI initiator mode messages and structures
+ * Creation Date: June 8, 2000
+ *
+ * MPI Version: 01.01.03
+ *
+ * Version History
+ * ---------------
+ *
+ * Date Version Description
+ * -------- -------- ------------------------------------------------------
+ * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000.
+ * 05-24-00 00.10.02 Added SenseBufferLength to _MSG_SCSI_IO_REPLY.
+ * 06-06-00 01.00.01 Update version number for 1.0 release.
+ * 06-08-00 01.00.02 Added MPI_SCSI_RSP_INFO_ definitions.
+ * 11-02-00 01.01.01 Original release for post 1.0 work.
+ * 12-04-00 01.01.02 Added MPI_SCSIIO_CONTROL_NO_DISCONNECT.
+ * 02-20-01 01.01.03 Started using MPI_POINTER.
+ * --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_INIT_H
+#define MPI_INIT_H
+
+
+/*****************************************************************************
+*
+* S C S I I n i t i a t o r M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/* SCSI IO messages and assocaited structures */
+/****************************************************************************/
+
+typedef struct _MSG_SCSI_IO_REQUEST
+{
+ U8 TargetID;
+ U8 Bus;
+ U8 ChainOffset;
+ U8 Function;
+ U8 CDBLength;
+ U8 SenseBufferLength;
+ U8 Reserved;
+ U8 MsgFlags;
+ U32 MsgContext;
+ U8 LUN[8];
+ U32 Control;
+ U8 CDB[16];
+ U32 DataLength;
+ U32 SenseBufferLowAddr;
+ SGE_IO_UNION SGL;
+} MSG_SCSI_IO_REQUEST, MPI_POINTER PTR_MSG_SCSI_IO_REQUEST,
+ SCSIIORequest_t, MPI_POINTER pSCSIIORequest_t;
+
+
+/* SCSIO MsgFlags bits */
+
+#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH (0x01)
+#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32 (0x00)
+#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 (0x01)
+#define MPI_SCSIIO_MSGFLGS_SENSE_LOCATION (0x02)
+#define MPI_SCSIIO_MSGFLGS_SENSE_LOC_HOST (0x00)
+#define MPI_SCSIIO_MSGFLGS_SENSE_LOC_IOC (0x02)
+
+/* SCSIIO LUN fields */
+
+#define MPI_SCSIIO_LUN_FIRST_LEVEL_ADDRESSING (0x0000FFFF)
+#define MPI_SCSIIO_LUN_SECOND_LEVEL_ADDRESSING (0xFFFF0000)
+#define MPI_SCSIIO_LUN_THIRD_LEVEL_ADDRESSING (0x0000FFFF)
+#define MPI_SCSIIO_LUN_FOURTH_LEVEL_ADDRESSING (0xFFFF0000)
+#define MPI_SCSIIO_LUN_LEVEL_1_WORD (0xFF00)
+#define MPI_SCSIIO_LUN_LEVEL_1_DWORD (0x0000FF00)
+
+/* SCSIO Control bits */
+
+#define MPI_SCSIIO_CONTROL_DATADIRECTION_MASK (0x03000000)
+#define MPI_SCSIIO_CONTROL_NODATATRANSFER (0x00000000)
+#define MPI_SCSIIO_CONTROL_WRITE (0x01000000)
+#define MPI_SCSIIO_CONTROL_READ (0x02000000)
+
+#define MPI_SCSIIO_CONTROL_ADDCDBLEN_MASK (0x3C000000)
+#define MPI_SCSIIO_CONTROL_ADDCDBLEN_SHIFT (26)
+
+#define MPI_SCSIIO_CONTROL_TASKATTRIBUTE_MASK (0x00000700)
+#define MPI_SCSIIO_CONTROL_SIMPLEQ (0x00000000)
+#define MPI_SCSIIO_CONTROL_HEADOFQ (0x00000100)
+#define MPI_SCSIIO_CONTROL_ORDEREDQ (0x00000200)
+#define MPI_SCSIIO_CONTROL_ACAQ (0x00000400)
+#define MPI_SCSIIO_CONTROL_UNTAGGED (0x00000500)
+#define MPI_SCSIIO_CONTROL_NO_DISCONNECT (0x00000700)
+
+#define MPI_SCSIIO_CONTROL_TASKMANAGE_MASK (0x00FF0000)
+#define MPI_SCSIIO_CONTROL_OBSOLETE (0x00800000)
+#define MPI_SCSIIO_CONTROL_CLEAR_ACA_RSV (0x00400000)
+#define MPI_SCSIIO_CONTROL_TARGET_RESET (0x00200000)
+#define MPI_SCSIIO_CONTROL_LUN_RESET_RSV (0x00100000)
+#define MPI_SCSIIO_CONTROL_RESERVED (0x00080000)
+#define MPI_SCSIIO_CONTROL_CLR_TASK_SET_RSV (0x00040000)
+#define MPI_SCSIIO_CONTROL_ABORT_TASK_SET (0x00020000)
+#define MPI_SCSIIO_CONTROL_RESERVED2 (0x00010000)
+
+
+/* SCSIIO reply structure */
+typedef struct _MSG_SCSI_IO_REPLY
+{
+ U8 TargetID;
+ U8 Bus;
+ U8 MsgLength;
+ U8 Function;
+ U8 CDBLength;
+ U8 SenseBufferLength;
+ U8 Reserved;
+ U8 MsgFlags;
+ U32 MsgContext;
+ U8 SCSIStatus;
+ U8 SCSIState;
+ U16 IOCStatus;
+ U32 IOCLogInfo;
+ U32 TransferCount;
+ U32 SenseCount;
+ U32 ResponseInfo;
+} MSG_SCSI_IO_REPLY, MPI_POINTER PTR_MSG_SCSI_IO_REPLY,
+ SCSIIOReply_t, MPI_POINTER pSCSIIOReply_t;
+
+
+/* SCSIIO Reply SCSIStatus values (SAM-2 status codes) */
+
+#define MPI_SCSI_STATUS_SUCCESS (0x00)
+#define MPI_SCSI_STATUS_CHECK_CONDITION (0x02)
+#define MPI_SCSI_STATUS_CONDITION_MET (0x04)
+#define MPI_SCSI_STATUS_BUSY (0x08)
+#define MPI_SCSI_STATUS_INTERMEDIATE (0x10)
+#define MPI_SCSI_STATUS_INTERMEDIATE_CONDMET (0x14)
+#define MPI_SCSI_STATUS_RESERVATION_CONFLICT (0x18)
+#define MPI_SCSI_STATUS_COMMAND_TERMINATED (0x22)
+#define MPI_SCSI_STATUS_TASK_SET_FULL (0x28)
+#define MPI_SCSI_STATUS_ACA_ACTIVE (0x30)
+
+
+/* SCSIIO Reply SCSIState values */
+
+#define MPI_SCSI_STATE_AUTOSENSE_VALID (0x01)
+#define MPI_SCSI_STATE_AUTOSENSE_FAILED (0x02)
+#define MPI_SCSI_STATE_NO_SCSI_STATUS (0x04)
+#define MPI_SCSI_STATE_TERMINATED (0x08)
+#define MPI_SCSI_STATE_RESPONSE_INFO_VALID (0x10)
+
+/* SCSIIO Reply ResponseInfo values */
+/* (FCP-1 RSP_CODE values and SPI-3 Packetized Failure codes) */
+
+#define MPI_SCSI_RSP_INFO_FUNCTION_COMPLETE (0x00000000)
+#define MPI_SCSI_RSP_INFO_FCP_BURST_LEN_ERROR (0x01000000)
+#define MPI_SCSI_RSP_INFO_CMND_FIELDS_INVALID (0x02000000)
+#define MPI_SCSI_RSP_INFO_FCP_DATA_RO_ERROR (0x03000000)
+#define MPI_SCSI_RSP_INFO_TASK_MGMT_UNSUPPORTED (0x04000000)
+#define MPI_SCSI_RSP_INFO_TASK_MGMT_FAILED (0x05000000)
+#define MPI_SCSI_RSP_INFO_SPI_LQ_INVALID_TYPE (0x06000000)
+
+
+/****************************************************************************/
+/* SCSI Task Management messages */
+/****************************************************************************/
+
+typedef struct _MSG_SCSI_TASK_MGMT
+{
+ U8 TargetID;
+ U8 Bus;
+ U8 ChainOffset;
+ U8 Function;
+ U8 Reserved;
+ U8 TaskType;
+ U8 Reserved1;
+ U8 MsgFlags;
+ U32 MsgContext;
+ U8 LUN[8];
+ U32 Reserved2[7];
+ U32 TaskMsgContext;
+} MSG_SCSI_TASK_MGMT, MPI_POINTER PTR_SCSI_TASK_MGMT,
+ SCSITaskMgmt_t, MPI_POINTER pSCSITaskMgmt_t;
+
+/* TaskType values */
+
+#define MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x00000001)
+#define MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET (0x00000002)
+#define MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x00000003)
+#define MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS (0x00000004)
+
+/* MsgFlags bits */
+#define MPI_SCSITASKMGMT_MSGFLAGS_LIP_RESET_OPTION (0x00000002)
+
+/* SCSI Task Management Reply */
+typedef struct _MSG_SCSI_TASK_MGMT_REPLY
+{
+ U8 TargetID;
+ U8 Bus;
+ U8 MsgLength;
+ U8 Function;
+ U8 Reserved;
+ U8 TaskType;
+ U8 Reserved1;
+ U8 MsgFlags;
+ U32 MsgContext;
+ U8 Reserved2[2];
+ U16 IOCStatus;
+ U32 IOCLogInfo;
+ U32 TerminationCount;
+} MSG_SCSI_TASK_MGMT_REPLY, MPI_POINTER PTR_MSG_SCSI_TASK_MGMT_REPLY,
+ SCSITaskMgmtReply_t, MPI_POINTER pSCSITaskMgmtReply_t;
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ * Name: MPI_IOC.H
+ * Title: MPI IOC, Port, Event, FW Load, and ToolBox messages
+ * Creation Date: August 11, 2000
+ *
+ * MPI Version: 01.01.05
+ *
+ * Version History
+ * ---------------
+ *
+ * Date Version Description
+ * -------- -------- ------------------------------------------------------
+ * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000.
+ * 05-24-00 00.10.02 Added _MSG_IOC_INIT_REPLY structure.
+ * 06-06-00 01.00.01 Added CurReplyFrameSize field to _MSG_IOC_FACTS_REPLY.
+ * 06-12-00 01.00.02 Added _MSG_PORT_ENABLE_REPLY structure.
+ * Added _MSG_EVENT_ACK_REPLY structure.
+ * Added _MSG_FW_DOWNLOAD_REPLY structure.
+ * Added _MSG_TOOLBOX_REPLY structure.
+ * 06-30-00 01.00.03 Added MaxLanBuckets to _PORT_FACT_REPLY structure.
+ * 07-27-00 01.00.04 Added _EVENT_DATA structure definitions for _SCSI,
+ * _LINK_STATUS, _LOOP_STATE and _LOGOUT.
+ * 08-11-00 01.00.05 Switched positions of MsgLength and Function fields in
+ * _MSG_EVENT_ACK_REPLY structure to match specification.
+ * 11-02-00 01.01.01 Original release for post 1.0 work.
+ * Added a value for Manufacturer to WhoInit.
+ * 12-04-00 01.01.02 Modified IOCFacts reply, added FWUpload messages, and
+ * removed toolbox message.
+ * 01-09-01 01.01.03 Added event enabled and disabled defines.
+ * Added structures for FwHeader and DataHeader.
+ * Added ImageType to FwUpload reply.
+ * 02-20-01 01.01.04 Started using MPI_POINTER.
+ * 02-27-01 01.01.05 Added event for RAID status change and its event data.
+ * Added IocNumber field to MSG_IOC_FACTS_REPLY.
+ * --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_IOC_H
+#define MPI_IOC_H
+
+
+/*****************************************************************************
+*
+* I O C M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/* IOCInit message */
+/****************************************************************************/
+
+typedef struct _MSG_IOC_INIT
+{
+ U8 WhoInit;
+ U8 Reserved;
+ U8 ChainOffset;
+ U8 Function;
+ U8 Flags;
+ U8 MaxDevices;
+ U8 MaxBuses;
+ U8 MsgFlags;
+ U32 MsgContext;
+ U16 ReplyFrameSize;
+ U8 Reserved1[2];
+ U32 HostMfaHighAddr;
+ U32 SenseBufferHighAddr;
+} MSG_IOC_INIT, MPI_POINTER PTR_MSG_IOC_INIT,
+ IOCInit_t, MPI_POINTER pIOCInit_t;
+
+typedef struct _MSG_IOC_INIT_REPLY
+{
+ U8 WhoInit;
+ U8 Reserved;
+ U8 MsgLength;
+ U8 Function;
+ U8 Flags;
+ U8 MaxDevices;
+ U8 MaxBuses;
+ U8 MsgFlags;
+ U32 MsgContext;
+ U16 Reserved2;
+ U16 IOCStatus;
+ U32 IOCLogInfo;
+} MSG_IOC_INIT_REPLY, MPI_POINTER PTR_MSG_IOC_INIT_REPLY,
+ IOCInitReply_t, MPI_POINTER pIOCInitReply_t;
+
+/* WhoInit values */
+
+#define MPI_WHOINIT_NO_ONE (0x00)
+#define MPI_WHOINIT_SYSTEM_BIOS (0x01)
+#define MPI_WHOINIT_ROM_BIOS (0x02)
+#define MPI_WHOINIT_PCI_PEER (0x03)
+#define MPI_WHOINIT_HOST_DRIVER (0x04)
+#define MPI_WHOINIT_MANUFACTURER (0x05)
+
+
+/****************************************************************************/
+/* IOC Facts message */
+/****************************************************************************/
+
+typedef struct _MSG_IOC_FACTS
+{
+ U8 Reserved[2];
+ U8 ChainOffset;
+ U8 Function;
+ U8 Reserved1[3];
+ U8 MsgFlags;
+ U32 MsgContext;
+} MSG_IOC_FACTS, MPI_POINTER PTR_IOC_FACTS,
+ IOCFacts_t, MPI_POINTER pIOCFacts_t;
+
+/* IOC Facts Reply */
+
+typedef struct _MSG_IOC_FACTS_REPLY
+{
+ U16 MsgVersion;
+ U8 MsgLength;
+ U8 Function;
+ U16 Reserved;
+ U8 IOCNumber;
+ U8 MsgFlags;
+ U32 MsgContext;
+ U16 Reserved2;
+ U16 IOCStatus;
+ U32 IOCLogInfo;
+ U8 MaxChainDepth;
+ U8 WhoInit;
+ U8 BlockSize;
+ U8 Flags;
+ U16 ReplyQueueDepth;
+ U16 RequestFrameSize;
+ U16 FWVersion;
+ U16 ProductID;
+ U32 CurrentHostMfaHighAddr;
+ U16 GlobalCredits;
+ U8 NumberOfPorts;
+ U8 EventState;
+ U32 CurrentSenseBufferHighAddr;
+ U16 CurReplyFrameSize;
+ U8 MaxDevices;
+ U8 MaxBuses;
+ U32 FWImageSize;
+ U32 DataImageSize;
+} MSG_IOC_FACTS_REPLY, MPI_POINTER PTR_MSG_IOC_FACTS_REPLY,
+ IOCFactsReply_t, MPI_POINTER pIOCFactsReply_t;
+
+#define MPI_IOCFACTS_MSGVERSION_MAJOR_MASK (0xFF00)
+#define MPI_IOCFACTS_MSGVERSION_MINOR_MASK (0x00FF)
+
+#define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT (0x01)
+#define MPI_IOCFACTS_FLAGS_DATA_IMAGE_UPLOAD (0x02)
+
+#define MPI_IOCFACTS_EVENTSTATE_DISABLED (0x00)
+#define MPI_IOCFACTS_EVENTSTATE_ENABLED (0x01)
+
+
+
+/*****************************************************************************
+*
+* P o r t M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/* Port Facts message and Reply */
+/****************************************************************************/
+
+typedef struct _MSG_PORT_FACTS
+{
+ U8 Reserved[2];
+ U8 ChainOffset;
+ U8 Function;
+ U8 Reserved1[2];
+ U8 PortNumber;
+ U8 MsgFlags;
+ U32 MsgContext;
+} MSG_PORT_FACTS, MPI_POINTER PTR_MSG_PORT_FACTS,
+ PortFacts_t, MPI_POINTER pPortFacts_t;
+
+typedef struct _MSG_PORT_FACTS_REPLY
+{
+ U16 Reserved;
+ U8 MsgLength;
+ U8 Function;
+ U16 Reserved1;
+ U8 PortNumber;
+ U8 MsgFlags;
+ U32 MsgContext;
+ U16 Reserved2;
+ U16 IOCStatus;
+ U32 IOCLogInfo;
+ U8 Reserved3;
+ U8 PortType;
+ U16 MaxDevices;
+ U16 PortSCSIID;
+ U16 ProtocolFlags;
+ U16 MaxPostedCmdBuffers;
+ U16 MaxPersistentIDs;
+ U16 MaxLanBuckets;
+ U16 Reserved4;
+ U32 Reserved5;
+} MSG_PORT_FACTS_REPLY, MPI_POINTER PTR_MSG_PORT_FACTS_REPLY,
+ PortFactsReply_t, MPI_POINTER pPortFactsReply_t;
+
+
+/* PortTypes values */
+
+#define MPI_PORTFACTS_PORTTYPE_INACTIVE (0x00)
+#define MPI_PORTFACTS_PORTTYPE_SCSI (0x01)
+#define MPI_PORTFACTS_PORTTYPE_FC (0x10)
+
+/* ProtocolFlags values */
+
+#define MPI_PORTFACTS_PROTOCOL_LOGBUSADDR (0x01)
+#define MPI_PORTFACTS_PROTOCOL_LAN (0x02)
+#define MPI_PORTFACTS_PROTOCOL_TARGET (0x04)
+#define MPI_PORTFACTS_PROTOCOL_INITIATOR (0x08)
+
+
+/****************************************************************************/
+/* Port Enable Message */
+/****************************************************************************/
+
+typedef struct _MSG_PORT_ENABLE
+{
+ U8 Reserved[2];
+ U8 ChainOffset;
+ U8 Function;
+ U8 Reserved1[2];
+ U8 PortNumber;
+ U8 MsgFlags;
+ U32 MsgContext;
+} MSG_PORT_ENABLE, MPI_POINTER PTR_MSG_PORT_ENABLE,
+ PortEnable_t, MPI_POINTER pPortEnable_t;
+
+typedef struct _MSG_PORT_ENABLE_REPLY
+{
+ U8 Reserved[2];
+ U8 MsgLength;
+ U8 Function;
+ U8 Reserved1[2];
+ U8 PortNumber;
+ U8 MsgFlags;
+ U32 MsgContext;
+ U16 Reserved2;
+ U16 IOCStatus;
+ U32 IOCLogInfo;
+} MSG_PORT_ENABLE_REPLY, MPI_POINTER PTR_MSG_PORT_ENABLE_REPLY,
+ PortEnableReply_t, MPI_POINTER pPortEnableReply_t;
+
+
+/*****************************************************************************
+*
+* E v e n t M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/* Event Notification messages */
+/****************************************************************************/
+
+typedef struct _MSG_EVENT_NOTIFY
+{
+ U8 Switch;
+ U8 Reserved;
+ U8 ChainOffset;
+ U8 Function;
+ U8 Reserved1[3];
+ U8 MsgFlags;
+ U32 MsgContext;
+} MSG_EVENT_NOTIFY, MPI_POINTER PTR_MSG_EVENT_NOTIFY,
+ EventNotification_t, MPI_POINTER pEventNotification_t;
+
+/* Event Notification Reply */
+
+typedef struct _MSG_EVENT_NOTIFY_REPLY
+{
+ U16 EventDataLength;
+ U8 MsgLength;
+ U8 Function;
+ U8 Reserved1[2];
+ U8 AckRequired;
+ U8 MsgFlags;
+ U32 MsgContext;
+ U8 Reserved2[2];
+ U16 IOCStatus;
+ U32 IOCLogInfo;
+ U32 Event;
+ U32 EventContext;
+ U32 Data[1];
+} MSG_EVENT_NOTIFY_REPLY, MPI_POINTER PTR_MSG_EVENT_NOTIFY_REPLY,
+ EventNotificationReply_t, MPI_POINTER pEventNotificationReply_t;
+
+/* Event Acknowledge */
+
+typedef struct _MSG_EVENT_ACK
+{
+ U8 Reserved[2];
+ U8 ChainOffset;
+ U8 Function;
+ U8 Reserved1[3];
+ U8 MsgFlags;
+ U32 MsgContext;
+ U32 Event;
+ U32 EventContext;
+} MSG_EVENT_ACK, MPI_POINTER PTR_MSG_EVENT_ACK,
+ EventAck_t, MPI_POINTER pEventAck_t;
+
+typedef struct _MSG_EVENT_ACK_REPLY
+{
+ U8 Reserved[2];
+ U8 MsgLength;
+ U8 Function;
+ U8 Reserved1[3];
+ U8 MsgFlags;
+ U32 MsgContext;
+ U16 Reserved2;
+ U16 IOCStatus;
+ U32 IOCLogInfo;
+} MSG_EVENT_ACK_REPLY, MPI_POINTER PTR_MSG_EVENT_ACK_REPLY,
+ EventAckReply_t, MPI_POINTER pEventAckReply_t;
+
+
+/* Switch */
+
+#define MPI_EVENT_NOTIFICATION_SWITCH_OFF (0x00)
+#define MPI_EVENT_NOTIFICATION_SWITCH_ON (0x01)
+
+/* Event */
+
+#define MPI_EVENT_NONE (0x00000000)
+#define MPI_EVENT_LOG_DATA (0x00000001)
+#define MPI_EVENT_STATE_CHANGE (0x00000002)
+#define MPI_EVENT_UNIT_ATTENTION (0x00000003)
+#define MPI_EVENT_IOC_BUS_RESET (0x00000004)
+#define MPI_EVENT_EXT_BUS_RESET (0x00000005)
+#define MPI_EVENT_RESCAN (0x00000006)
+#define MPI_EVENT_LINK_STATUS_CHANGE (0x00000007)
+#define MPI_EVENT_LOOP_STATE_CHANGE (0x00000008)
+#define MPI_EVENT_LOGOUT (0x00000009)
+#define MPI_EVENT_EVENT_CHANGE (0x0000000A)
+#define MPI_EVENT_RAID_STATUS_CHANGE (0x0000000B)
+
+/* AckRequired field values */
+
+#define MPI_EVENT_NOTIFICATION_ACK_NOT_REQUIRED (0x00)
+#define MPI_EVENT_NOTIFICATION_ACK_REQUIRED (0x01)
+
+/* SCSI Event data for Port, Bus and Device forms) */
+
+typedef struct _EVENT_DATA_SCSI
+{
+ U8 TargetID;
+ U8 BusPort;
+ U16 Reserved;
+} EVENT_DATA_SCSI, MPI_POINTER PTR_EVENT_DATA_SCSI,
+ EventDataScsi_t, MPI_POINTER pEventDataScsi_t;
+
+/* MPI Link Status Change Event data */
+
+typedef struct _EVENT_DATA_LINK_STATUS
+{
+ U8 State;
+ U8 Reserved;
+ U16 Reserved1;
+ U8 Reserved2;
+ U8 Port;
+ U16 Reserved3;
+} EVENT_DATA_LINK_STATUS, MPI_POINTER PTR_EVENT_DATA_LINK_STATUS,
+ EventDataLinkStatus_t, MPI_POINTER pEventDataLinkStatus_t;
+
+#define MPI_EVENT_LINK_STATUS_FAILURE (0x00000000)
+#define MPI_EVENT_LINK_STATUS_ACTIVE (0x00000001)
+
+/* MPI Loop State Change Event data */
+
+typedef struct _EVENT_DATA_LOOP_STATE
+{
+ U8 Character4;
+ U8 Character3;
+ U8 Type;
+ U8 Reserved;
+ U8 Reserved1;
+ U8 Port;
+ U16 Reserved2;
+} EVENT_DATA_LOOP_STATE, MPI_POINTER PTR_EVENT_DATA_LOOP_STATE,
+ EventDataLoopState_t, MPI_POINTER pEventDataLoopState_t;
+
+#define MPI_EVENT_LOOP_STATE_CHANGE_LIP (0x0001)
+#define MPI_EVENT_LOOP_STATE_CHANGE_LPE (0x0002)
+#define MPI_EVENT_LOOP_STATE_CHANGE_LPB (0x0003)
+
+/* MPI LOGOUT Event data */
+
+typedef struct _EVENT_DATA_LOGOUT
+{
+ U32 NPortID;
+ U8 Reserved;
+ U8 Port;
+ U16 Reserved1;
+} EVENT_DATA_LOGOUT, MPI_POINTER PTR_EVENT_DATA_LOGOUT,
+ EventDataLogout_t, MPI_POINTER pEventDataLogout_t;
+
+/* MPI RAID Status Change Event data */
+
+typedef struct _EVENT_DATA_RAID_STATUS_CHANGE
+{
+ U8 VolumeTargetID;
+ U8 VolumeBus;
+ U8 ReasonCode;
+ U8 PhysDiskNum;
+ U8 ASC;
+ U8 ASCQ;
+ U16 Reserved;
+} EVENT_DATA_RAID_STATUS_CHANGE, MPI_POINTER PTR_EVENT_DATA_RAID_STATUS_CHANGE,
+ MpiEventDataRaidStatusChange_t, MPI_POINTER pMpiEventDataRaidStatusChange_t;
+
+
+/* MPI RAID Status Change Event data ReasonCode values */
+
+#define MPI_EVENT_RAID_DATA_RC_VOLUME_OPTIMAL (0x00)
+#define MPI_EVENT_RAID_DATA_RC_VOLUME_DEGRADED (0x01)
+#define MPI_EVENT_RAID_DATA_RC_STARTED_RESYNC (0x02)
+#define MPI_EVENT_RAID_DATA_RC_DISK_ADDED (0x03)
+#define MPI_EVENT_RAID_DATA_RC_DISK_NOT_RESPONDING (0x04)
+#define MPI_EVENT_RAID_DATA_RC_SMART_DATA (0x05)
+
+
+/*****************************************************************************
+*
+* F i r m w a r e L o a d M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/* Firmware Download message and associated structures */
+/****************************************************************************/
+
+typedef struct _MSG_FW_DOWNLOAD
+{
+ U8 ImageType;
+ U8 Reserved;
+ U8 ChainOffset;
+ U8 Function;
+ U8 Reserved1[3];
+ U8 MsgFlags;
+ U32 MsgContext;
+ SGE_MPI_UNION SGL;
+} MSG_FW_DOWNLOAD, MPI_POINTER PTR_MSG_FW_DOWNLOAD,
+ FWDownload_t, MPI_POINTER pFWDownload_t;
+
+#define MPI_FW_DOWNLOAD_ITYPE_RESERVED (0x00)
+#define MPI_FW_DOWNLOAD_ITYPE_FW (0x01)
+#define MPI_FW_DOWNLOAD_ITYPE_BIOS (0x02)
+
+
+typedef struct _FWDownloadTCSGE
+{
+ U8 Reserved;
+ U8 ContextSize;
+ U8 DetailsLength;
+ U8 Flags;
+ U32 Reserved1;
+ U32 ImageOffset;
+ U32 ImageSize;
+} FW_DOWNLOAD_TCSGE, MPI_POINTER PTR_FW_DOWNLOAD_TCSGE,
+ FWDownloadTCSGE_t, MPI_POINTER pFWDownloadTCSGE_t;
+
+/* Firmware Download reply */
+typedef struct _MSG_FW_DOWNLOAD_REPLY
+{
+ U8 ImageType;
+ U8 Reserved;
+ U8 MsgLength;
+ U8 Function;
+ U8 Reserved1[3];
+ U8 MsgFlags;
+ U32 MsgContext;
+ U16 Reserved2;
+ U16 IOCStatus;
+ U32 IOCLogInfo;
+} MSG_FW_DOWNLOAD_REPLY, MPI_POINTER PTR_MSG_FW_DOWNLOAD_REPLY,
+ FWDownloadReply_t, MPI_POINTER pFWDownloadReply_t;
+
+
+/****************************************************************************/
+/* Firmware Upload message and associated structures */
+/****************************************************************************/
+
+typedef struct _MSG_FW_UPLOAD
+{
+ U8 ImageType;
+ U8 Reserved;
+ U8 ChainOffset;
+ U8 Function;
+ U8 Reserved1[3];
+ U8 MsgFlags;
+ U32 MsgContext;
+ SGE_MPI_UNION SGL;
+} MSG_FW_UPLOAD, MPI_POINTER PTR_MSG_FW_UPLOAD,
+ FWUpload_t, MPI_POINTER pFWUpload_t;
+
+#define MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM (0x00)
+#define MPI_FW_UPLOAD_ITYPE_FW_FLASH (0x01)
+#define MPI_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02)
+#define MPI_FW_UPLOAD_ITYPE_DATA_IOC_MEM (0x03)
+
+typedef struct _FWUploadTCSGE
+{
+ U8 Reserved;
+ U8 ContextSize;
+ U8 DetailsLength;
+ U8 Flags;
+ U32 Reserved1;
+ U32 ImageOffset;
+ U32 ImageSize;
+} FW_UPLOAD_TCSGE, MPI_POINTER PTR_FW_UPLOAD_TCSGE,
+ FWUploadTCSGE_t, MPI_POINTER pFWUploadTCSGE_t;
+
+/* Firmware Upload reply */
+typedef struct _MSG_FW_UPLOAD_REPLY
+{
+ U8 ImageType;
+ U8 Reserved;
+ U8 MsgLength;
+ U8 Function;
+ U8 Reserved1[3];
+ U8 MsgFlags;
+ U32 MsgContext;
+ U16 Reserved2;
+ U16 IOCStatus;
+ U32 IOCLogInfo;
+ U32 ActualImageSize;
+} MSG_FW_UPLOAD_REPLY, MPI_POINTER PTR_MSG_FW_UPLOAD_REPLY,
+ FWUploadReply_t, MPI_POINTER pFWUploadReply_t;
+
+
+typedef struct _MPI_FW_HEADER
+{
+ U32 ArmBranchInstruction0;
+ U32 Signature0;
+ U32 Signature1;
+ U32 Signature2;
+ U32 ArmBranchInstruction1;
+ U32 ArmBranchInstruction2;
+ U32 Reserved;
+ U32 Checksum;
+ U16 VendorId;
+ U16 ProductId;
+ U16 FwVersion;
+ U16 Reserved1;
+ U32 SeqCodeVersion;
+ U32 ImageSize;
+ U32 Reserved2;
+ U32 LoadStartAddress;
+ U32 IopResetVectorValue;
+ U32 IopResetRegAddr;
+ U32 VersionNameWhat;
+ U8 VersionName[32];
+ U32 VendorNameWhat;
+ U8 VendorName[32];
+} MPI_FW_HEADER, MPI_POINTER PTR_MPI_FW_HEADER,
+ MpiFwHeader_t, MPI_POINTER pMpiFwHeader_t;
+
+#define MPI_FW_HEADER_WHAT_SIGNATURE (0x29232840)
+
+
+typedef struct _MPI_DATA_HEADER
+{
+ U32 Signature;
+ U16 FunctionNumber;
+ U16 Length;
+ U32 Checksum;
+ U32 LoadStartAddress;
+} MPI_DATA_HEADER, MPI_POINTER PTR_MPI_DATA_HEADER,
+ MpiDataHeader_t, MPI_POINTER pMpiDataHeader_t;
+
+#define MPI_DATA_HEADER_SIGNATURE (0x43504147)
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ * Name: MPI_LAN.H
+ * Title: MPI LAN messages and structures
+ * Creation Date: June 30, 2000
+ *
+ * MPI Version: 01.01.02
+ *
+ * Version History
+ * ---------------
+ *
+ * Date Version Description
+ * -------- -------- ------------------------------------------------------
+ * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000.
+ * 05-24-00 00.10.02 Added LANStatus field to _MSG_LAN_SEND_REPLY.
+ * Added LANStatus field to _MSG_LAN_RECEIVE_POST_REPLY.
+ * Moved ListCount field in _MSG_LAN_RECEIVE_POST_REPLY.
+ * 06-06-00 01.00.01 Update version number for 1.0 release.
+ * 06-12-00 01.00.02 Added MPI_ to BUCKETSTATUS_ definitions.
+ * 06-22-00 01.00.03 Major changes to match new LAN definition in 1.0 spec.
+ * 06-30-00 01.00.04 Added Context Reply definitions per revised proposal.
+ * Changed transaction context usage to bucket/buffer.
+ * 07-05-00 01.00.05 Removed LAN_RECEIVE_POST_BUCKET_CONTEXT_MASK definition
+ * to lan private header file
+ * 11-02-00 01.01.01 Original release for post 1.0 work
+ * 02-20-01 01.01.02 Started using MPI_POINTER.
+ * --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_LAN_H
+#define MPI_LAN_H
+
+
+/******************************************************************************
+*
+* L A N M e s s a g e s
+*
+*******************************************************************************/
+
+/* LANSend messages */
+
+typedef struct _MSG_LAN_SEND_REQUEST
+{
+ U16 Reserved;
+ U8 ChainOffset;
+ U8 Function;
+ U16 Reserved2;
+ U8 PortNumber;
+ U8 MsgFlags;
+ U32 MsgContext;
+ SGE_MPI_UNION SG_List[1];
+} MSG_LAN_SEND_REQUEST, MPI_POINTER PTR_MSG_LAN_SEND_REQUEST,
+ LANSendRequest_t, MPI_POINTER pLANSendRequest_t;
+
+
+typedef struct _MSG_LAN_SEND_REPLY
+{
+ U16 Reserved;
+ U8 MsgLength;
+ U8 Function;
+ U8 Reserved2;
+ U8 NumberOfContexts;
+ U8 PortNumber;
+ U8 MsgFlags;
+ U32 MsgContext;
+ U16 Reserved3;
+ U16 IOCStatus;
+ U32 IOCLogInfo;
+ U32 BufferContext;
+} MSG_LAN_SEND_REPLY, MPI_POINTER PTR_MSG_LAN_SEND_REPLY,
+ LANSendReply_t, MPI_POINTER pLANSendReply_t;
+
+
+/* LANReceivePost */
+
+typedef struct _MSG_LAN_RECEIVE_POST_REQUEST
+{
+ U16 Reserved;
+ U8 ChainOffset;
+ U8 Function;
+ U16 Reserved2;
+ U8 PortNumber;
+ U8 MsgFlags;
+ U32 MsgContext;
+ U32 BucketCount;
+ SGE_MPI_UNION SG_List[1];
+} MSG_LAN_RECEIVE_POST_REQUEST, MPI_POINTER PTR_MSG_LAN_RECEIVE_POST_REQUEST,
+ LANReceivePostRequest_t, MPI_POINTER pLANReceivePostRequest_t;
+
+
+typedef struct _MSG_LAN_RECEIVE_POST_REPLY
+{
+ U16 Reserved;
+ U8 MsgLength;
+ U8 Function;
+ U8 Reserved2;
+ U8 NumberOfContexts;
+ U8 PortNumber;
+ U8 MsgFlags;
+ U32 MsgContext;
+ U16 Reserved3;
+ U16 IOCStatus;
+ U32 IOCLogInfo;
+ U32 BucketsRemaining;
+ U32 PacketOffset;
+ U32 PacketLength;
+ U32 BucketContext[1];
+} MSG_LAN_RECEIVE_POST_REPLY, MPI_POINTER PTR_MSG_LAN_RECEIVE_POST_REPLY,
+ LANReceivePostReply_t, MPI_POINTER pLANReceivePostReply_t;
+
+
+/* LANReset */
+
+typedef struct _MSG_LAN_RESET_REQUEST
+{
+ U16 Reserved;
+ U8 ChainOffset;
+ U8 Function;
+ U16 Reserved2;
+ U8 PortNumber;
+ U8 MsgFlags;
+ U32 MsgContext;
+} MSG_LAN_RESET_REQUEST, MPI_POINTER PTR_MSG_LAN_RESET_REQUEST,
+ LANResetRequest_t, MPI_POINTER pLANResetRequest_t;
+
+
+typedef struct _MSG_LAN_RESET_REPLY
+{
+ U16 Reserved;
+ U8 MsgLength;
+ U8 Function;
+ U16 Reserved2;
+ U8 PortNumber;
+ U8 MsgFlags;
+ U32 MsgContext;
+ U16 Reserved3;
+ U16 IOCStatus;
+ U32 IOCLogInfo;
+} MSG_LAN_RESET_REPLY, MPI_POINTER PTR_MSG_LAN_RESET_REPLY,
+ LANResetReply_t, MPI_POINTER pLANResetReply_t;
+
+
+/****************************************************************************/
+/* LAN Context Reply defines and macros */
+/****************************************************************************/
+
+#define LAN_REPLY_PACKET_LENGTH_MASK (0x0000FFFF)
+#define LAN_REPLY_PACKET_LENGTH_SHIFT (0)
+#define LAN_REPLY_BUCKET_CONTEXT_MASK (0x07FF0000)
+#define LAN_REPLY_BUCKET_CONTEXT_SHIFT (16)
+#define LAN_REPLY_BUFFER_CONTEXT_MASK (0x07FFFFFF)
+#define LAN_REPLY_BUFFER_CONTEXT_SHIFT (0)
+#define LAN_REPLY_FORM_MASK (0x18000000)
+#define LAN_REPLY_FORM_RECEIVE_SINGLE (0x00)
+#define LAN_REPLY_FORM_RECEIVE_MULTIPLE (0x01)
+#define LAN_REPLY_FORM_SEND_SINGLE (0x02)
+#define LAN_REPLY_FORM_MESSAGE_CONTEXT (0x03)
+#define LAN_REPLY_FORM_SHIFT (27)
+
+#define GET_LAN_PACKET_LENGTH(x) (((x) & LAN_REPLY_PACKET_LENGTH_MASK) \
+ >> LAN_REPLY_PACKET_LENGTH_SHIFT)
+
+#define SET_LAN_PACKET_LENGTH(x, lth) \
+ ((x) = ((x) & ~LAN_REPLY_PACKET_LENGTH_MASK) | \
+ (((lth) << LAN_REPLY_PACKET_LENGTH_SHIFT) & \
+ LAN_REPLY_PACKET_LENGTH_MASK))
+
+#define GET_LAN_BUCKET_CONTEXT(x) (((x) & LAN_REPLY_BUCKET_CONTEXT_MASK) \
+ >> LAN_REPLY_BUCKET_CONTEXT_SHIFT)
+
+#define SET_LAN_BUCKET_CONTEXT(x, ctx) \
+ ((x) = ((x) & ~LAN_REPLY_BUCKET_CONTEXT_MASK) | \
+ (((ctx) << LAN_REPLY_BUCKET_CONTEXT_SHIFT) & \
+ LAN_REPLY_BUCKET_CONTEXT_MASK))
+
+#define GET_LAN_BUFFER_CONTEXT(x) (((x) & LAN_REPLY_BUFFER_CONTEXT_MASK) \
+ >> LAN_REPLY_BUFFER_CONTEXT_SHIFT)
+
+#define SET_LAN_BUFFER_CONTEXT(x, ctx) \
+ ((x) = ((x) & ~LAN_REPLY_BUFFER_CONTEXT_MASK) | \
+ (((ctx) << LAN_REPLY_BUFFER_CONTEXT_SHIFT) & \
+ LAN_REPLY_BUFFER_CONTEXT_MASK))
+
+#define GET_LAN_FORM(x) (((x) & LAN_REPLY_FORM_MASK) \
+ >> LAN_REPLY_FORM_SHIFT)
+
+#define SET_LAN_FORM(x, frm) \
+ ((x) = ((x) & ~LAN_REPLY_FORM_MASK) | \
+ (((frm) << LAN_REPLY_FORM_SHIFT) & \
+ LAN_REPLY_FORM_MASK))
+
+
+/****************************************************************************/
+/* LAN Current Device State defines */
+/****************************************************************************/
+
+#define MPI_LAN_DEVICE_STATE_RESET (0x00)
+#define MPI_LAN_DEVICE_STATE_OPERATIONAL (0x01)
+
+
+#endif
+
--- /dev/null
+/*
+ * Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ * Name: MPI_TARG.H
+ * Title: MPI Target mode messages and structures
+ * Creation Date: June 22, 2000
+ *
+ * MPI Version: 01.01.03
+ *
+ * Version History
+ * ---------------
+ *
+ * Date Version Description
+ * -------- -------- ------------------------------------------------------
+ * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000.
+ * 06-06-00 01.00.01 Update version number for 1.0 release.
+ * 06-22-00 01.00.02 Added _MSG_TARGET_CMD_BUFFER_POST_REPLY structure.
+ * Corrected DECSRIPTOR typo to DESCRIPTOR.
+ * 11-02-00 01.01.01 Original release for post 1.0 work
+ * Modified target mode to use IoIndex instead of
+ * HostIndex and IocIndex. Added Alias.
+ * 01-09-01 01.01.02 Added defines for TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER
+ * and TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER.
+ * 02-20-01 01.01.03 Started using MPI_POINTER.
+ * Added structures for MPI_TARGET_SCSI_SPI_CMD_BUFFER and
+ * MPI_TARGET_FCP_CMD_BUFFER.
+ * --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_TARG_H
+#define MPI_TARG_H
+
+
+/******************************************************************************
+*
+* S C S I T a r g e t M e s s a g e s
+*
+*******************************************************************************/
+
+typedef struct _CMD_BUFFER_DESCRIPTOR
+{
+ U16 IoIndex;
+ U16 Reserved;
+ union
+ {
+ U32 PhysicalAddress32;
+ U64 PhysicalAddress64;
+ } u;
+} CMD_BUFFER_DESCRIPTOR, MPI_POINTER PTR_CMD_BUFFER_DESCRIPTOR,
+ CmdBufferDescriptor_t, MPI_POINTER pCmdBufferDescriptor_t;
+
+
+/****************************************************************************/
+/* Target Command Buffer Post Request */
+/****************************************************************************/
+
+typedef struct _MSG_TARGET_CMD_BUFFER_POST_REQUEST
+{
+ U8 BufferPostFlags;
+ U8 BufferCount;
+ U8 ChainOffset;
+ U8 Function;
+ U8 BufferLength;
+ U8 Reserved;
+ U8 Reserved1;
+ U8 MsgFlags;
+ U32 MsgContext;
+ CMD_BUFFER_DESCRIPTOR Buffer[1];
+} MSG_TARGET_CMD_BUFFER_POST_REQUEST, MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_REQUEST,
+ TargetCmdBufferPostRequest_t, MPI_POINTER pTargetCmdBufferPostRequest_t;
+
+#define CMD_BUFFER_POST_FLAGS_PORT_MASK (0x01)
+#define CMD_BUFFER_POST_FLAGS_ADDR_MODE_MASK (0x80)
+#define CMD_BUFFER_POST_FLAGS_ADDR_MODE_32 (0)
+#define CMD_BUFFER_POST_FLAGS_ADDR_MODE_64 (1)
+#define CMD_BUFFER_POST_FLAGS_64_BIT_ADDR (0x80)
+
+#define CMD_BUFFER_POST_IO_INDEX_MASK (0x00003FFF)
+
+
+typedef struct _MSG_TARGET_CMD_BUFFER_POST_REPLY
+{
+ U8 BufferPostFlags;
+ U8 BufferCount;
+ U8 MsgLength;
+ U8 Function;
+ U8 BufferLength;
+ U8 Reserved;
+ U8 Reserved1;
+ U8 MsgFlags;
+ U32 MsgContext;
+ U16 Reserved2;
+ U16 IOCStatus;
+ U32 IOCLogInfo;
+} MSG_TARGET_CMD_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_REPLY,
+ TargetCmdBufferPostReply_t, MPI_POINTER pTargetCmdBufferPostReply_t;
+
+
+typedef struct _MSG_PRIORITY_CMD_RECEIVED_REPLY
+{
+ U16 Reserved;
+ U8 MsgLength;
+ U8 Function;
+ U16 Reserved1;
+ U8 Reserved2;
+ U8 MsgFlags;
+ U32 MsgContext;
+ U8 PriorityReason;
+ U8 Reserved3;
+ U16 IOCStatus;
+ U32 IOCLogInfo;
+ U32 ReplyWord;
+} MSG_PRIORITY_CMD_RECEIVED_REPLY, MPI_POINTER PTR_MSG_PRIORITY_CMD_RECEIVED_REPLY,
+ PriorityCommandReceivedReply_t, MPI_POINTER pPriorityCommandReceivedReply_t;
+
+#define PRIORITY_REASON_NO_DISCONNECT (0x00)
+#define PRIORITY_REASON_SCSI_TASK_MANAGEMENT (0x01)
+#define PRIORITY_REASON_UNKNOWN (0xFF)
+
+
+typedef struct _MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY
+{
+ U16 Reserved;
+ U8 MsgLength;
+ U8 Function;
+ U16 Reserved1;
+ U8 Reserved2;
+ U8 MsgFlags;
+ U32 MsgContext;
+ U16 Reserved3;
+ U16 IOCStatus;
+ U32 IOCLogInfo;
+ U32 ReplyWord;
+} MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY,
+ MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY,
+ TargetCmdBufferPostErrorReply_t, MPI_POINTER pTargetCmdBufferPostErrorReply_t;
+
+
+typedef struct _MPI_TARGET_FCP_CMD_BUFFER
+{
+ U8 FcpLun[8];
+ U8 FcpCntl[4];
+ U8 FcpCdb[16];
+ U32 FcpDl;
+} MPI_TARGET_FCP_CMD_BUFFER, MPI_POINTER PTR_MPI_TARGET_FCP_CMD_BUFFER,
+ MpiTargetFcpCmdBuffer, MPI_POINTER pMpiTargetFcpCmdBuffer;
+
+
+typedef struct _MPI_TARGET_SCSI_SPI_CMD_BUFFER
+{
+ /* SPI L_Q information unit */
+ U8 L_QType;
+ U8 Reserved;
+ U16 Tag;
+ U8 LogicalUnitNumber[8];
+ U32 DataLength;
+ /* SPI command information unit */
+ U8 ReservedFirstByteOfCommandIU;
+ U8 TaskAttribute;
+ U8 TaskManagementFlags;
+ U8 AdditionalCDBLength;
+ U8 CDB[16];
+} MPI_TARGET_SCSI_SPI_CMD_BUFFER,
+ MPI_POINTER PTR_MPI_TARGET_SCSI_SPI_CMD_BUFFER,
+ MpiTargetScsiSpiCmdBuffer, MPI_POINTER pMpiTargetScsiSpiCmdBuffer;
+
+
+/****************************************************************************/
+/* Target Assist Request */
+/****************************************************************************/
+
+typedef struct _MSG_TARGET_ASSIST_REQUEST
+{
+ U8 StatusCode;
+ U8 TargetAssistFlags;
+ U8 ChainOffset;
+ U8 Function;
+ U16 QueueTag;
+ U8 Reserved;
+ U8 MsgFlags;
+ U32 MsgContext;
+ U32 ReplyWord;
+ U8 LUN[8];
+ U32 RelativeOffset;
+ U32 DataLength;
+ SGE_IO_UNION SGL[1];
+} MSG_TARGET_ASSIST_REQUEST, MPI_POINTER PTR_MSG_TARGET_ASSIST_REQUEST,
+ TargetAssistRequest_t, MPI_POINTER pTargetAssistRequest_t;
+
+#define TARGET_ASSIST_FLAGS_DATA_DIRECTION (0x01)
+#define TARGET_ASSIST_FLAGS_AUTO_STATUS (0x02)
+#define TARGET_ASSIST_FLAGS_HIGH_PRIORITY (0x04)
+#define TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER (0x80)
+
+
+typedef struct _MSG_TARGET_ERROR_REPLY
+{
+ U16 Reserved;
+ U8 MsgLength;
+ U8 Function;
+ U16 Reserved1;
+ U8 Reserved2;
+ U8 MsgFlags;
+ U32 MsgContext;
+ U16 Reserved3;
+ U16 IOCStatus;
+ U32 IOCLogInfo;
+ U32 ReplyWord;
+ U32 TransferCount;
+} MSG_TARGET_ERROR_REPLY, MPI_POINTER PTR_MSG_TARGET_ERROR_REPLY,
+ TargetErrorReply_t, MPI_POINTER pTargetErrorReply_t;
+
+
+/****************************************************************************/
+/* Target Status Send Request */
+/****************************************************************************/
+
+typedef struct _MSG_TARGET_STATUS_SEND_REQUEST
+{
+ U8 StatusCode;
+ U8 StatusFlags;
+ U8 ChainOffset;
+ U8 Function;
+ U16 QueueTag;
+ U8 Reserved;
+ U8 MsgFlags;
+ U32 MsgContext;
+ U32 ReplyWord;
+ U8 LUN[8];
+ SGE_SIMPLE_UNION StatusDataSGE;
+} MSG_TARGET_STATUS_SEND_REQUEST, MPI_POINTER PTR_MSG_TARGET_STATUS_SEND_REQUEST,
+ TargetStatusSendRequest_t, MPI_POINTER pTargetStatusSendRequest_t;
+
+#define TARGET_STATUS_SEND_FLAGS_AUTO_GOOD_STATUS (0x01)
+#define TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER (0x80)
+
+
+/****************************************************************************/
+/* Target Mode Abort Request */
+/****************************************************************************/
+
+typedef struct _MSG_TARGET_MODE_ABORT_REQUEST
+{
+ U8 AbortType;
+ U8 Reserved;
+ U8 ChainOffset;
+ U8 Function;
+ U16 Reserved1;
+ U8 Reserved2;
+ U8 MsgFlags;
+ U32 MsgContext;
+ U32 ReplyWord;
+ U32 MsgContextToAbort;
+} MSG_TARGET_MODE_ABORT, MPI_POINTER PTR_MSG_TARGET_MODE_ABORT,
+ TargetModeAbort_t, MPI_POINTER pTargetModeAbort_t;
+
+#define TARGET_MODE_ABORT_TYPE_ALL_CMD_BUFFERS (0x00)
+#define TARGET_MODE_ABORT_TYPE_ALL_IO (0x01)
+#define TARGET_MODE_ABORT_TYPE_EXACT_IO (0x02)
+#define TARGET_MODE_ABORT_TYPE_EXACT_IO_REQUEST (0x03)
+
+/* Target Mode Abort Reply */
+
+typedef struct _MSG_TARGET_MODE_ABORT_REPLY
+{
+ U16 Reserved;
+ U8 MsgLength;
+ U8 Function;
+ U16 Reserved1;
+ U8 Reserved2;
+ U8 MsgFlags;
+ U32 MsgContext;
+ U16 Reserved3;
+ U16 IOCStatus;
+ U32 IOCLogInfo;
+ U32 AbortCount;
+} MSG_TARGET_MODE_ABORT_REPLY, MPI_POINTER PTR_MSG_TARGET_MODE_ABORT_REPLY,
+ TargetModeAbortReply_t, MPI_POINTER pTargetModeAbortReply_t;
+
+
+/****************************************************************************/
+/* Target Mode Context Reply */
+/****************************************************************************/
+
+#define TARGET_MODE_REPLY_IO_INDEX_MASK (0x00003FFF)
+#define TARGET_MODE_REPLY_IO_INDEX_SHIFT (0)
+#define TARGET_MODE_REPLY_INITIATOR_INDEX_MASK (0x03FFC000)
+#define TARGET_MODE_REPLY_INITIATOR_INDEX_SHIFT (14)
+#define TARGET_MODE_REPLY_ALIAS_MASK (0x0C000000)
+#define TARGET_MODE_REPLY_ALIAS_SHIFT (26)
+#define TARGET_MODE_REPLY_PORT_MASK (0x10000000)
+#define TARGET_MODE_REPLY_PORT_SHIFT (28)
+
+
+#define GET_IO_INDEX(x) (((x) & TARGET_MODE_REPLY_IO_INDEX_MASK) \
+ >> TARGET_MODE_REPLY_IO_INDEX_SHIFT)
+
+#define SET_IO_INDEX(t, i) \
+ ((t) = ((t) & ~TARGET_MODE_REPLY_IO_INDEX_MASK) | \
+ (((i) << TARGET_MODE_REPLY_IO_INDEX_SHIFT) & \
+ TARGET_MODE_REPLY_IO_INDEX_MASK))
+
+#define GET_INITIATOR_INDEX(x) (((x) & TARGET_MODE_REPLY_INITIATOR_INDEX_MASK) \
+ >> TARGET_MODE_REPLY_INITIATOR_INDEX_SHIFT)
+
+#define SET_INITIATOR_INDEX(t, ii) \
+ ((t) = ((t) & ~TARGET_MODE_REPLY_INITIATOR_INDEX_MASK) | \
+ (((ii) << TARGET_MODE_REPLY_INITIATOR_INDEX_SHIFT) & \
+ TARGET_MODE_REPLY_INITIATOR_INDEX_MASK))
+
+#define GET_ALIAS(x) (((x) & TARGET_MODE_REPLY_ALIAS_MASK) \
+ >> TARGET_MODE_REPLY_ALIAS_SHIFT)
+
+#define SET_ALIAS(t, a) ((t) = ((t) & ~TARGET_MODE_REPLY_ALIAS_MASK) | \
+ (((a) << TARGET_MODE_REPLY_ALIAS_SHIFT) & \
+ TARGET_MODE_REPLY_ALIAS_MASK))
+
+#define GET_PORT(x) (((x) & TARGET_MODE_REPLY_PORT_MASK) \
+ >> TARGET_MODE_REPLY_PORT_SHIFT)
+
+#define SET_PORT(t, p) ((t) = ((t) & ~TARGET_MODE_REPLY_PORT_MASK) | \
+ (((p) << TARGET_MODE_REPLY_PORT_SHIFT) & \
+ TARGET_MODE_REPLY_PORT_MASK))
+
+
+#endif
+
--- /dev/null
+/*
+ * Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ * Name: MPI_TYPE.H
+ * Title: MPI Basic type definitions
+ * Creation Date: June 6, 2000
+ *
+ * MPI Version: 01.01.02
+ *
+ * Version History
+ * ---------------
+ *
+ * Date Version Description
+ * -------- -------- ------------------------------------------------------
+ * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000.
+ * 06-06-00 01.00.01 Update version number for 1.0 release.
+ * 11-02-00 01.01.01 Original release for post 1.0 work
+ * 02-20-01 01.01.02 Added define and ifdef for MPI_POINTER.
+ * --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_TYPE_H
+#define MPI_TYPE_H
+
+
+/*******************************************************************************
+ * Define MPI_POINTER if it hasn't already been defined. By default MPI_POINTER
+ * is defined to be a near pointer. MPI_POINTER can be defined as a far pointer
+ * by defining MPI_POINTER as "far *" before this header file is included.
+ */
+#ifndef MPI_POINTER
+#define MPI_POINTER *
+#endif
+
+
+/*****************************************************************************
+*
+* B a s i c T y p e s
+*
+*****************************************************************************/
+
+typedef signed char S8;
+typedef unsigned char U8;
+typedef signed short S16;
+typedef unsigned short U16;
+
+
+#if defined(unix) || defined(__arm) || defined(ALPHA)
+
+ typedef signed int S32;
+ typedef unsigned int U32;
+
+#else
+
+ typedef signed long S32;
+ typedef unsigned long U32;
+
+#endif
+
+
+typedef struct _S64
+{
+ U32 Low;
+ S32 High;
+} S64;
+
+typedef struct _U64
+{
+ U32 Low;
+ U32 High;
+} U64;
+
+
+/****************************************************************************/
+/* Pointers */
+/****************************************************************************/
+
+typedef S8 *PS8;
+typedef U8 *PU8;
+typedef S16 *PS16;
+typedef U16 *PU16;
+typedef S32 *PS32;
+typedef U32 *PU32;
+typedef S64 *PS64;
+typedef U64 *PU64;
+
+
+#endif
+
--- /dev/null
+/*
+ * linux/drivers/message/fusion/mptbase.c
+ * High performance SCSI + LAN / Fibre Channel device drivers.
+ * This is the Fusion MPT base driver which supports multiple
+ * (SCSI + LAN) specialized protocol drivers.
+ * For use with PCI chip/adapter(s):
+ * LSIFC9xx/LSI409xx Fibre Channel
+ * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ * Credits:
+ * There are lots of people not mentioned below that deserve credit
+ * and thanks but won't get it here - sorry in advance that you
+ * got overlooked.
+ *
+ * This driver would not exist if not for Alan Cox's development
+ * of the linux i2o driver.
+ *
+ * A special thanks to Noah Romer (LSI Logic) for tons of work
+ * and tough debugging on the LAN driver, especially early on;-)
+ * And to Roger Hickerson (LSI Logic) for tirelessly supporting
+ * this driver project.
+ *
+ * All manner of help from Stephen Shirron (LSI Logic):
+ * low-level FC analysis, debug + various fixes in FCxx firmware,
+ * initial port to alpha platform, various driver code optimizations,
+ * being a faithful sounding board on all sorts of issues & ideas,
+ * etc.
+ *
+ * A huge debt of gratitude is owed to David S. Miller (DaveM)
+ * for fixing much of the stupid and broken stuff in the early
+ * driver while porting to sparc64 platform. THANK YOU!
+ *
+ * Special thanks goes to the I2O LAN driver people at the
+ * University of Helsinki, who, unbeknownst to them, provided
+ * the inspiration and initial structure for this driver.
+ *
+ * A really huge debt of gratitude is owed to Eddie C. Dost
+ * for gobs of hard work fixing and optimizing LAN code.
+ * THANK YOU!
+ *
+ * Copyright (c) 1999-2001 LSI Logic Corporation
+ * Originally By: Steven J. Ralston
+ * (mailto:Steve.Ralston@lsil.com)
+ *
+ * $Id: mptbase.c,v 1.47 2001/03/22 10:32:23 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ 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; version 2 of the License.
+
+ 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.
+
+ NO WARRANTY
+ THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ solely responsible for determining the appropriateness of using and
+ distributing the Program and assumes all risks associated with its
+ exercise of rights under this Agreement, including but not limited to
+ the risks and costs of program errors, damage to or loss of data,
+ programs or equipment, and unavailability or interruption of operations.
+
+ DISCLAIMER OF LIABILITY
+ NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <asm/io.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include "mptbase.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#define my_NAME "Fusion MPT base driver"
+#define my_VERSION MPT_LINUX_VERSION_COMMON
+#define MYNAM "mptbase"
+
+MODULE_AUTHOR(MODULEAUTHOR);
+MODULE_DESCRIPTION(my_NAME);
+
+/*
+ * cmd line parameters
+ */
+MODULE_PARM(PortIo, "0-1i");
+MODULE_PARM_DESC(PortIo, "[0]=Use mmap, 1=Use port io");
+MODULE_PARM(HardReset, "0-1i");
+MODULE_PARM_DESC(HardReset, "0=Disable HardReset, [1]=Enable HardReset");
+static int PortIo = 0;
+static int HardReset = 1;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Public data...
+ */
+int mpt_lan_index = 0;
+int mpt_stm_index = 0;
+
+void *mpt_v_ASCQ_TablePtr = NULL;
+const char **mpt_ScsiOpcodesPtr = NULL;
+int mpt_ASCQ_TableSz = 0;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Private data...
+ */
+ /* Adapter lookup table */
+static MPT_ADAPTER *mpt_adapters[MPT_MAX_ADAPTERS] = {0};
+static MPT_ADAPTER_TRACKER MptAdapters;
+ /* Callback lookup table */
+static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
+ /* Protocol driver class lookup table */
+static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
+ /* Event handler lookup table */
+static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
+
+static int FusionInitCalled = 0;
+static int mpt_base_index = -1;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Forward protos...
+ */
+static void mpt_interrupt(int irq, void *bus_id, struct pt_regs *r);
+static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
+
+static int mpt_adapter_install(struct pci_dev *pdev);
+static void mpt_detect_929_bound_ports(MPT_ADAPTER *this, struct pci_dev *pdev);
+static void mpt_adapter_disable(MPT_ADAPTER *ioc);
+static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
+
+static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
+static u32 GetIocState(MPT_ADAPTER *ioc, int cooked);
+static int GetIocFacts(MPT_ADAPTER *ioc);
+static int GetPortFacts(MPT_ADAPTER *ioc);
+static int SendIocInit(MPT_ADAPTER *ioc);
+static int SendPortEnable(MPT_ADAPTER *ioc, int portnum);
+static int mpt_fc9x9_reset(MPT_ADAPTER *ioc);
+static int KickStart(MPT_ADAPTER *ioc);
+static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type);
+static int PrimeIocFifos(MPT_ADAPTER *ioc);
+static int HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply);
+static int WaitForDoorbellAck(MPT_ADAPTER *ioc);
+static int WaitForDoorbellInt(MPT_ADAPTER *ioc);
+static int WaitForDoorbellReply(MPT_ADAPTER *ioc);
+static int GetLanConfigPages(MPT_ADAPTER *ioc);
+static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
+static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
+
+static int procmpt_create(void);
+#ifdef CONFIG_PROC_FS
+static int procmpt_destroy(void);
+#endif
+static int procmpt_read_summary(char *page, char **start, off_t off, int count, int *eof, void *data);
+static int procmpt_read_dbg(char *page, char **start, off_t off, int count, int *eof, void *data);
+/*static int procmpt_info(char *buf, char **start, off_t offset, int len);*/
+
+static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
+static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
+static void mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info);
+
+static struct proc_dir_entry *procmpt_root_dir = NULL;
+
+int fusion_init(void);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* 20000207 -sralston
+ * GRRRRR... IOSpace (port i/o) register access (for the 909) is back!
+ * 20000517 -sralston
+ * Let's trying going back to default mmap register access...
+ */
+
+static inline u32 CHIPREG_READ32(volatile u32 *a)
+{
+ if (PortIo)
+ return inl((unsigned long)a);
+ else
+ return readl(a);
+}
+
+static inline void CHIPREG_WRITE32(volatile u32 *a, u32 v)
+{
+ if (PortIo)
+ outl(v, (unsigned long)a);
+ else
+ writel(v, a);
+}
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
+ * @irq: irq number (not used)
+ * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
+ * @r: pt_regs pointer (not used)
+ *
+ * This routine is registered via the request_irq() kernel API call,
+ * and handles all interrupts generated from a specific MPT adapter
+ * (also referred to as a IO Controller or IOC).
+ * This routine must clear the interrupt from the adapter and does
+ * so by reading the reply FIFO. Multiple replies may be processed
+ * per single call to this routine; up to MPT_MAX_REPLIES_PER_ISR
+ * which is currently set to 32 in mptbase.h.
+ *
+ * This routine handles register-level access of the adapter but
+ * dispatches (calls) a protocol-specific callback routine to handle
+ * the protocol-specific details of the MPT request completion.
+ */
+static void
+mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
+{
+ MPT_ADAPTER *ioc;
+ MPT_FRAME_HDR *mf;
+ MPT_FRAME_HDR *mr;
+ u32 pa;
+ u32 *m;
+ int req_idx;
+ int cb_idx;
+ int type;
+ int freeme;
+ int count = 0;
+
+ ioc = bus_id;
+
+ /*
+ * Drain the reply FIFO!
+ *
+ * NOTES: I've seen up to 10 replies processed in this loop, so far...
+ * Update: I've seen up to 9182 replies processed in this loop! ??
+ * Update: Limit ourselves to processing max of N replies
+ * (bottom of loop).
+ */
+ while (1) {
+
+ if ((pa = CHIPREG_READ32(&ioc->chip->ReplyFifo)) == 0xFFFFFFFF)
+ return;
+
+ cb_idx = 0;
+ freeme = 0;
+
+ /*
+ * Check for non-TURBO reply!
+ */
+ if (pa & MPI_ADDRESS_REPLY_A_BIT) {
+ dma_addr_t reply_dma_addr;
+ u16 ioc_stat;
+
+ /* non-TURBO reply! Hmmm, something may be up...
+ * Newest turbo reply mechanism; get address
+ * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
+ */
+ reply_dma_addr = (pa = (pa << 1));
+
+ /* Map DMA address of reply header to cpu address. */
+ m = (u32 *) ((u8 *)ioc->reply_frames +
+ (reply_dma_addr - ioc->reply_frames_dma));
+
+ mr = (MPT_FRAME_HDR *) m;
+ req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
+ cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
+ mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
+
+ dprintk((KERN_INFO MYNAM ": %s: Got non-TURBO reply=%p\n",
+ ioc->name, mr));
+ DBG_DUMP_REPLY_FRAME(mr)
+
+ /* NEW! 20010301 -sralston
+ * Check/log IOC log info
+ */
+ ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
+ if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
+ u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
+ if ((int)ioc->chip_type <= (int)FC929)
+ mpt_fc_log_info(ioc, log_info);
+ else
+ mpt_sp_log_info(ioc, log_info);
+ }
+ } else {
+ /*
+ * Process turbo (context) reply...
+ */
+ dirqprintk((KERN_INFO MYNAM ": %s: Got TURBO reply(=%08x)\n", ioc->name, pa));
+ type = (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT);
+ if (type == MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET) {
+ cb_idx = mpt_stm_index;
+ mf = NULL;
+ mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
+ } else if (type == MPI_CONTEXT_REPLY_TYPE_LAN) {
+ cb_idx = mpt_lan_index;
+ /*
+ * BUG FIX! 20001218 -sralston
+ * Blind set of mf to NULL here was fatal
+ * after lan_reply says "freeme"
+ * Fix sort of combined with an optimization here;
+ * added explicit check for case where lan_reply
+ * was just returning 1 and doing nothing else.
+ * For this case skip the callback, but set up
+ * proper mf value first here:-)
+ */
+ if ((pa & 0x58000000) == 0x58000000) {
+ req_idx = pa & 0x0000FFFF;
+ mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
+ freeme = 1;
+ /*
+ * IMPORTANT! Invalidate the callback!
+ */
+ cb_idx = 0;
+ } else {
+ mf = NULL;
+ }
+ mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
+ } else {
+ req_idx = pa & 0x0000FFFF;
+ cb_idx = (pa & 0x00FF0000) >> 16;
+ mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
+ mr = NULL;
+ }
+ pa = 0; /* No reply flush! */
+ }
+
+ /* Check for (valid) IO callback! */
+ if (cb_idx) {
+ /* Do the callback! */
+ freeme = (*(MptCallbacks[cb_idx]))(ioc, mf, mr);
+ }
+
+ if (pa) {
+ /* Flush (non-TURBO) reply with a WRITE! */
+ CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
+ }
+
+ if (freeme) {
+ unsigned long flags;
+
+ /* Put Request back on FreeQ! */
+ spin_lock_irqsave(&ioc->FreeQlock, flags);
+ Q_ADD_TAIL(&ioc->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+ }
+
+ count++;
+ dirqprintk((KERN_INFO MYNAM ": %s: ISR processed frame #%d\n", ioc->name, count));
+ mb();
+
+ if (count >= MPT_MAX_REPLIES_PER_ISR) {
+ dirqprintk((KERN_INFO MYNAM ": %s: ISR processed %d replies.",
+ ioc->name, count));
+ dirqprintk((" Giving this ISR a break!\n"));
+ return;
+ }
+
+ } /* drain reply FIFO */
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * mpt_base_reply - MPT base driver's callback routine; all base driver
+ * "internal" request/reply processing is routed here.
+ * Currently used for EventNotification and EventAck handling.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @mf: Pointer to original MPT request frame
+ * @reply: Pointer to MPT reply frame (NULL if TurboReply)
+ *
+ * Returns 1 indicating original alloc'd request frame ptr
+ * should be freed, or 0 if it shouldn't.
+ */
+static int
+mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
+{
+ int freereq = 1;
+ u8 func;
+
+ dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply() called\n", ioc->name));
+
+ if ((mf == NULL) ||
+ (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
+ printk(KERN_ERR MYNAM ": %s: ERROR - NULL or BAD request frame ptr! (=%p)\n",
+ ioc->name, mf);
+ return 1;
+ }
+
+ if (reply == NULL) {
+ dprintk((KERN_ERR MYNAM ": %s: ERROR - Unexpected NULL Event (turbo?) reply!\n",
+ ioc->name));
+ return 1;
+ }
+
+ if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
+ dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
+ DBG_DUMP_REQUEST_FRAME_HDR(mf)
+ }
+
+ func = reply->u.hdr.Function;
+ dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply, Function=%02Xh\n",
+ ioc->name, func));
+
+ if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
+ EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
+ int evHandlers = 0;
+ int results;
+
+ results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
+ if (results != evHandlers) {
+ /* CHECKME! Any special handling needed here? */
+ dprintk((KERN_WARNING MYNAM ": %s: Hmmm... Called %d event handlers, sum results = %d\n",
+ ioc->name, evHandlers, results));
+ }
+
+ /*
+ * Hmmm... It seems that EventNotificationReply is an exception
+ * to the rule of one reply per request.
+ */
+ if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
+ freereq = 0;
+#ifdef CONFIG_PROC_FS
+// LogEvent(ioc, pEvReply);
+#endif
+ } else if (func == MPI_FUNCTION_EVENT_ACK) {
+ dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply, EventAck reply received\n",
+ ioc->name));
+ } else {
+ printk(KERN_ERR MYNAM ": %s: ERROR - Unexpected msg function (=%02Xh) reply received!\n",
+ ioc->name, func);
+ }
+
+ /*
+ * Conditionally tell caller to free the original
+ * EventNotification/EventAck/unexpected request frame!
+ */
+ return freereq;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mpt_register - Register protocol-specific main callback handler.
+ * @cbfunc: callback function pointer
+ * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
+ *
+ * This routine is called by a protocol-specific driver (SCSI host,
+ * LAN, SCSI target) to register it's reply callback routine. Each
+ * protocol-specific driver must do this before it will be able to
+ * use any IOC resources, such as obtaining request frames.
+ *
+ * NOTES: The SCSI protocol driver currently calls this routine twice
+ * in order to register separate callbacks; one for "normal" SCSI IO
+ * and another for MptScsiTaskMgmt requests.
+ *
+ * Returns a positive integer valued "handle" in the
+ * range (and S.O.D. order) {7,6,...,1} if successful.
+ * Any non-positive return value (including zero!) should be considered
+ * an error by the caller.
+ */
+int
+mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
+{
+ int r = -1;
+ int i;
+
+#ifndef MODULE
+ /*
+ * Handle possibility of the mptscsih_detect() routine getting
+ * called *before* fusion_init!
+ */
+ if (!FusionInitCalled) {
+ dprintk((KERN_INFO MYNAM ": Hmmm, calling fusion_init from mpt_register!\n"));
+ /*
+ * NOTE! We'll get recursion here, as fusion_init()
+ * calls mpt_register()!
+ */
+ fusion_init();
+ FusionInitCalled++;
+ }
+#endif
+
+ /*
+ * Search for empty callback slot in this order: {7,6,...,1}
+ * (slot/handle 0 is reserved!)
+ */
+ for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
+ if (MptCallbacks[i] == NULL) {
+ MptCallbacks[i] = cbfunc;
+ MptDriverClass[i] = dclass;
+ MptEvHandlers[i] = NULL;
+ r = i;
+ if (cbfunc != mpt_base_reply) {
+ MOD_INC_USE_COUNT;
+ }
+ break;
+ }
+ }
+
+ return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mpt_deregister - Deregister a protocol drivers resources.
+ * @cb_idx: previously registered callback handle
+ *
+ * Each protocol-specific driver should call this routine when it's
+ * module is unloaded.
+ */
+void
+mpt_deregister(int cb_idx)
+{
+ if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
+ MptCallbacks[cb_idx] = NULL;
+ MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
+ MptEvHandlers[cb_idx] = NULL;
+ if (cb_idx != mpt_base_index) {
+ MOD_DEC_USE_COUNT;
+ }
+ }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mpt_event_register - Register protocol-specific event callback
+ * handler.
+ * @cb_idx: previously registered (via mpt_register) callback handle
+ * @ev_cbfunc: callback function
+ *
+ * This routine can be called by one or more protocol-specific drivers
+ * if/when they choose to be notified of MPT events.
+ *
+ * Returns 0 for success.
+ */
+int
+mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
+{
+ if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+ return -1;
+
+ MptEvHandlers[cb_idx] = ev_cbfunc;
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mpt_event_deregister - Deregister protocol-specific event callback
+ * handler.
+ * @cb_idx: previously registered callback handle
+ *
+ * Each protocol-specific driver should call this routine
+ * when it does not (or can no longer) handle events,
+ * or when it's module is unloaded.
+ */
+void
+mpt_event_deregister(int cb_idx)
+{
+ if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+ return;
+
+ MptEvHandlers[cb_idx] = NULL;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
+ * allocated per MPT adapter.
+ * @handle: Handle of registered MPT protocol driver
+ * @iocid: IOC unique identifier (integer)
+ *
+ * Returns pointer to a MPT request frame or %NULL if none are available.
+ */
+MPT_FRAME_HDR*
+mpt_get_msg_frame(int handle, int iocid)
+{
+ MPT_FRAME_HDR *mf = NULL;
+ MPT_ADAPTER *iocp;
+ unsigned long flags;
+
+ /* validate handle and ioc identifier */
+ iocp = mpt_adapters[iocid];
+ spin_lock_irqsave(&iocp->FreeQlock, flags);
+ if (! Q_IS_EMPTY(&iocp->FreeQ)) {
+ int req_offset;
+
+ mf = iocp->FreeQ.head;
+ Q_DEL_ITEM(&mf->u.frame.linkage);
+ mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
+ req_offset = (u8 *)mf - (u8 *)iocp->req_frames;
+ /* u16! */
+ mf->u.frame.hwhdr.msgctxu.fld.req_idx =
+ cpu_to_le16(req_offset / iocp->req_sz);
+ mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
+ }
+ spin_unlock_irqrestore(&iocp->FreeQlock, flags);
+ dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
+ iocp->name, handle, iocid, mf));
+ return mf;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mpt_put_msg_frame - Send a protocol specific MPT request frame
+ * to a IOC.
+ * @handle: Handle of registered MPT protocol driver
+ * @iocid: IOC unique identifier (integer)
+ * @mf: Pointer to MPT request frame
+ *
+ * This routine posts a MPT request frame to the request post FIFO of a
+ * specific MPT adapter.
+ */
+void
+mpt_put_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf)
+{
+ MPT_ADAPTER *iocp;
+
+ iocp = mpt_adapters[iocid];
+ if (iocp != NULL) {
+ dma_addr_t mf_dma_addr;
+ int req_offset;
+
+ /* ensure values are reset properly! */
+ mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
+ req_offset = (u8 *)mf - (u8 *)iocp->req_frames;
+ /* u16! */
+ mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_offset / iocp->req_sz);
+ mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
+
+#ifdef MPT_DEBUG_MSG_FRAME
+ {
+ u32 *m = mf->u.frame.hwhdr.__hdr;
+ int i, n;
+
+ printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
+ iocp->name, m);
+ n = iocp->req_sz/4 - 1;
+ while (m[n] == 0)
+ n--;
+ for (i=0; i<=n; i++) {
+ if (i && ((i%8)==0))
+ printk("\n" KERN_INFO " ");
+ printk(" %08x", le32_to_cpu(m[i]));
+ }
+ printk("\n");
+ }
+#endif
+
+ mf_dma_addr = iocp->req_frames_dma + req_offset;
+ CHIPREG_WRITE32(&iocp->chip->RequestFifo, mf_dma_addr);
+ }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
+ * @handle: Handle of registered MPT protocol driver
+ * @iocid: IOC unique identifier (integer)
+ * @mf: Pointer to MPT request frame
+ *
+ * This routine places a MPT request frame back on the MPT adapter's
+ * FreeQ.
+ */
+void
+mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf)
+{
+ MPT_ADAPTER *iocp;
+ unsigned long flags;
+
+ iocp = mpt_adapters[iocid];
+ if (iocp != NULL) {
+ /* Put Request back on FreeQ! */
+ spin_lock_irqsave(&iocp->FreeQlock, flags);
+ Q_ADD_TAIL(&iocp->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+ spin_unlock_irqrestore(&iocp->FreeQlock, flags);
+ }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mpt_send_handshake_request - Send MPT request via doorbell
+ * handshake method.
+ * @handle: Handle of registered MPT protocol driver
+ * @iocid: IOC unique identifier (integer)
+ * @reqBytes: Size of the request in bytes
+ * @req: Pointer to MPT request frame
+ *
+ * This routine is used exclusively by mptscsih to send MptScsiTaskMgmt
+ * requests since they are required to be sent via doorbell handshake.
+ *
+ * NOTE: It is the callers responsibility to byte-swap fields in the
+ * request which are greater than 1 byte in size.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req)
+{
+ MPT_ADAPTER *iocp;
+ int r = 0;
+
+ iocp = mpt_adapters[iocid];
+ if (iocp != NULL) {
+ u8 *req_as_bytes;
+ int i;
+
+ /*
+ * Emulate what mpt_put_msg_frame() does /wrt to sanity
+ * setting cb_idx/req_idx. But ONLY if this request
+ * is in proper (pre-alloc'd) request buffer range...
+ */
+ i = MFPTR_2_MPT_INDEX(iocp,(MPT_FRAME_HDR*)req);
+ if (reqBytes >= 12 && i >= 0 && i < iocp->req_depth) {
+ MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
+ mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(i);
+ mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
+ }
+
+ /* Make sure there are no doorbells */
+ CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
+
+ CHIPREG_WRITE32(&iocp->chip->Doorbell,
+ ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
+ ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
+
+ /* Wait for IOC doorbell int */
+ if ((i = WaitForDoorbellInt(iocp)) < 0) {
+ /* FIXME! Recovery action(s)? */
+ /*i = unresponsive_ioc(i);*/
+ return i;
+ }
+
+ dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
+ iocp->name, i));
+
+ CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
+
+ if ((r = WaitForDoorbellAck(iocp)) < 0)
+ return -2;
+
+ /* Send request via doorbell handshake */
+ req_as_bytes = (u8 *) req;
+ for (i = 0; i < reqBytes/4; i++) {
+ u32 word;
+
+ word = ((req_as_bytes[(i*4) + 0] << 0) |
+ (req_as_bytes[(i*4) + 1] << 8) |
+ (req_as_bytes[(i*4) + 2] << 16) |
+ (req_as_bytes[(i*4) + 3] << 24));
+ CHIPREG_WRITE32(&iocp->chip->Doorbell, word);
+ if ((r = WaitForDoorbellAck(iocp)) < 0) {
+ r = -3;
+ break;
+ }
+ }
+
+ /* Make sure there are no doorbells */
+ CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
+
+ }
+
+ return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mpt_adapter_find_first - Find first MPT adapter pointer.
+ *
+ * Returns first MPT adapter pointer or %NULL if no MPT adapters
+ * are present.
+ */
+MPT_ADAPTER *
+mpt_adapter_find_first(void)
+{
+ MPT_ADAPTER *this = NULL;
+
+ if (! Q_IS_EMPTY(&MptAdapters))
+ this = MptAdapters.head;
+
+ return this;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mpt_adapter_find_next - Find next MPT adapter pointer.
+ * @prev: Pointer to previous MPT adapter
+ *
+ * Returns next MPT adapter pointer or %NULL if there are no more.
+ */
+MPT_ADAPTER *
+mpt_adapter_find_next(MPT_ADAPTER *prev)
+{
+ MPT_ADAPTER *next = NULL;
+
+ if (prev && (prev->forw != (MPT_ADAPTER*)&MptAdapters.head))
+ next = prev->forw;
+
+ return next;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mpt_pci_scan - Scan PCI devices for MPT adapters.
+ *
+ * Returns count of MPT adapters found, keying off of PCI vendor and
+ * device_id's.
+ */
+int __init
+mpt_pci_scan(void)
+{
+ struct pci_dev *pdev;
+ struct pci_dev *pdev2;
+ int found = 0;
+ int count = 0;
+ int r;
+
+ dprintk((KERN_INFO MYNAM ": Checking for MPT adapters...\n"));
+
+ /*
+ * NOTE: The 929 (I believe) will appear as 2 separate PCI devices,
+ * one for each channel.
+ */
+ pci_for_each_dev(pdev) {
+ pdev2 = NULL;
+ if (pdev->vendor != 0x1000)
+ continue;
+
+ if ((pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC909) &&
+ (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC929) &&
+#if 0
+ /* FIXME! FC919 */
+ (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC919) &&
+ /* FIXME! C103x family */
+ (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030) &&
+ (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030_ZC) &&
+ (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1035) &&
+#endif
+ 1) {
+ dprintk((KERN_INFO MYNAM ": Skipping LSI device=%04xh\n", pdev->device));
+ continue;
+ }
+
+ /* GRRRRR
+ * 929 dual function devices may be presented in Func 1,0 order,
+ * but we'd really really rather have them in Func 0,1 order.
+ * Do some kind of look ahead here...
+ */
+ if (pdev->devfn & 1) {
+ pdev2 = pci_peek_next_dev(pdev);
+ if (pdev2 && (pdev2->vendor == 0x1000) &&
+ (PCI_SLOT(pdev2->devfn) == PCI_SLOT(pdev->devfn)) &&
+ (pdev2->device == MPI_MANUFACTPAGE_DEVICEID_FC929) &&
+ (pdev2->bus->number == pdev->bus->number) &&
+ !(pdev2->devfn & 1)) {
+ dprintk((KERN_INFO MYNAM ": MPT adapter found: PCI bus/dfn=%02x/%02xh, class=%08x, id=%xh\n",
+ pdev2->bus->number, pdev2->devfn, pdev2->class, pdev2->device));
+ found++;
+ if ((r = mpt_adapter_install(pdev2)) == 0)
+ count++;
+ } else {
+ pdev2 = NULL;
+ }
+ }
+
+ dprintk((KERN_INFO MYNAM ": MPT adapter found: PCI bus/dfn=%02x/%02xh, class=%08x, id=%xh\n",
+ pdev->bus->number, pdev->devfn, pdev->class, pdev->device));
+ found++;
+ if ((r = mpt_adapter_install(pdev)) == 0)
+ count++;
+
+ if (pdev2)
+ pdev = pdev2;
+ }
+
+ printk(KERN_INFO MYNAM ": %d MPT adapter%s found, %d installed.\n",
+ found, (found==1) ? "" : "s", count);
+
+ if (count == 0)
+ return -ENODEV;
+
+#ifdef CONFIG_PROC_FS
+ if (procmpt_create() != 0)
+ printk(KERN_WARNING MYNAM ": WARNING! - %s creation failed!\n",
+ MPT_PROCFS_MPTBASEDIR);
+#endif
+
+ return count;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mpt_verify_adapter - Given a unique IOC identifier, set pointer to
+ * the associated MPT adapter structure.
+ * @iocid: IOC unique identifier (integer)
+ * @iocpp: Pointer to pointer to IOC adapter
+ *
+ * Returns iocid and sets iocpp.
+ */
+int
+mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
+{
+ MPT_ADAPTER *p;
+
+ *iocpp = NULL;
+ if (iocid >= MPT_MAX_ADAPTERS)
+ return -1;
+
+ p = mpt_adapters[iocid];
+ if (p == NULL)
+ return -1;
+
+ *iocpp = p;
+ return iocid;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mpt_adapter_install - Install a PCI intelligent MPT adapter.
+ * @pdev: Pointer to pci_dev structure
+ *
+ * This routine performs all the steps necessary to bring the IOC of
+ * a MPT adapter to a OPERATIONAL state. This includes registering
+ * memory regions, registering the interrupt, and allocating request
+ * and reply memory pools.
+ *
+ * This routine also pre-fetches the LAN MAC address of a Fibre Channel
+ * MPT adapter.
+ *
+ * Returns 0 for success, non-zero for failure.
+ *
+ * TODO: Add support for polled controllers
+ */
+static int __init
+mpt_adapter_install(struct pci_dev *pdev)
+{
+ MPT_ADAPTER *ioc;
+ char *myname;
+ u8 *mem;
+ unsigned long mem_phys;
+ unsigned long port;
+ u32 msize;
+ u32 psize;
+ u32 ioc_state;
+ int i;
+ int r = -ENODEV;
+ int cntdn;
+ int len;
+ int statefault = 0;
+
+ ioc = kmalloc(sizeof(MPT_ADAPTER), GFP_KERNEL);
+ if (ioc == NULL) {
+ printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
+ return -ENOMEM;
+ }
+ memset(ioc, 0, sizeof(*ioc));
+ ioc->req_sz = MPT_REQ_SIZE; /* avoid div by zero! */
+ ioc->alloc_total = sizeof(MPT_ADAPTER);
+
+ ioc->pcidev = pdev;
+
+ /* Find lookup slot. GRRRR... */
+ for (i=0; i < MPT_MAX_ADAPTERS; i++) {
+ if (mpt_adapters[i] == NULL) {
+ ioc->id = i; /* Assign adapter unique id (lookup) */
+ break;
+ }
+ }
+ if (i == MPT_MAX_ADAPTERS) {
+ printk(KERN_ERR MYNAM ": ERROR - mpt_adapters[%d] table overflow!\n", i);
+ kfree(ioc);
+ return -ENFILE;
+ }
+
+ mem_phys = msize = 0;
+ port = psize = 0;
+ for (i=0; i < DEVICE_COUNT_RESOURCE; i++) {
+ if (pdev->PCI_BASEADDR_FLAGS(i) & PCI_BASE_ADDRESS_SPACE_IO) {
+ /* Get I/O space! */
+ port = pdev->PCI_BASEADDR_START(i);
+ psize = PCI_BASEADDR_SIZE(pdev,i);
+ } else {
+ /* Get memmap */
+ mem_phys = pdev->PCI_BASEADDR_START(i);
+ msize = PCI_BASEADDR_SIZE(pdev,i);
+ break;
+ }
+ }
+ ioc->mem_size = msize;
+
+ if (i == DEVICE_COUNT_RESOURCE) {
+ printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n");
+ kfree(ioc);
+ return -EINVAL;
+ }
+
+ dprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize));
+ dprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize));
+ dprintk((KERN_INFO MYNAM ": Using %s register access method\n", PortIo ? "PortIo" : "MemMap"));
+
+ mem = NULL;
+ if (! PortIo) {
+ /* Get logical ptr for PciMem0 space */
+ /*mem = ioremap(mem_phys, msize);*/
+ mem = ioremap(mem_phys, 0x100);
+ if (mem == NULL) {
+ printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
+ kfree(ioc);
+ return -EINVAL;
+ }
+ ioc->memmap = mem;
+ }
+ dprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
+
+ if (PortIo) {
+ u8 *pmem = (u8*)port;
+ ioc->mem_phys = port;
+ ioc->chip = (SYSIF_REGS*)pmem;
+ } else {
+ ioc->mem_phys = mem_phys;
+ ioc->chip = (SYSIF_REGS*)mem;
+ }
+
+ ioc->chip_type = FCUNK;
+ if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
+ ioc->chip_type = FC909;
+ ioc->prod_name = "LSIFC909";
+ }
+ else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
+ ioc->chip_type = FC929;
+ ioc->prod_name = "LSIFC929";
+ }
+#if 0
+ else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
+ ioc->chip_type = C1030;
+ ioc->prod_name = "LSIFC919";
+ }
+ else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_53C1030) {
+ ioc->chip_type = C1030;
+ ioc->prod_name = "LSI53C1030";
+ }
+#endif
+
+ myname = "iocN";
+ len = strlen(myname);
+ memcpy(ioc->name, myname, len+1);
+ ioc->name[len-1] = '0' + ioc->id;
+
+ Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR);
+ spin_lock_init(&ioc->FreeQlock);
+
+ /* Disable all! */
+ CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
+ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+ ioc->active = 0;
+
+ ioc->pci_irq = -1;
+ if (pdev->irq) {
+ r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc);
+
+ if (r < 0) {
+ printk(KERN_ERR MYNAM ": %s: ERROR - Unable to allocate interrupt %d!\n",
+ ioc->name, pdev->irq);
+ iounmap(mem);
+ kfree(ioc);
+ return -EBUSY;
+ }
+
+ ioc->pci_irq = pdev->irq;
+
+ pci_set_master(pdev); /* ?? */
+
+ dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq));
+ }
+
+ /* tack onto tail of our MPT adapter list */
+ Q_ADD_TAIL(&MptAdapters, ioc, MPT_ADAPTER);
+
+ /* Set lookup ptr. */
+ mpt_adapters[ioc->id] = ioc;
+
+ /* NEW! 20010220 -sralston
+ * Check for "929 bound ports" to reduce redundant resets.
+ */
+ if (ioc->chip_type == FC929)
+ mpt_detect_929_bound_ports(ioc, pdev);
+
+ /* Get current [raw] IOC state */
+ ioc_state = GetIocState(ioc, 0);
+ dhsprintk((KERN_INFO MYNAM ": %s initial [raw] state=%08x\n", ioc->name, ioc_state));
+
+ /*
+ * Check to see if IOC got left/stuck in doorbell handshake
+ * grip of death. If so, hard reset the IOC.
+ */
+ if (ioc_state & MPI_DOORBELL_ACTIVE) {
+ statefault = 1;
+ printk(KERN_WARNING MYNAM ": %s: Uh-oh, unexpected doorbell active!\n",
+ ioc->name);
+ }
+
+ /*
+ * Check to see if IOC is in FAULT state.
+ * If so, hard reset the IOC.
+ */
+ if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
+ statefault = 2;
+ printk(KERN_WARNING MYNAM ": %s: Uh-oh, IOC is in FAULT state!!!\n",
+ ioc->name);
+ printk(KERN_WARNING " FAULT code = %04xh\n",
+ ioc_state & MPI_DOORBELL_DATA_MASK);
+ }
+
+ if (HardReset || statefault) {
+ if ((r = KickStart(ioc)) != 0) {
+ r = -ENODEV;
+ goto ioc_up_fail;
+ }
+ }
+
+ /*
+ * Loop here waiting for IOC to come READY.
+ */
+ i = 0;
+ cntdn = HZ * 10;
+ while ((ioc_state = GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
+ if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
+ /*
+ * BIOS or previous driver load left IOC in OP state.
+ * Reset messaging FIFOs.
+ */
+ dprintk((KERN_WARNING MYNAM ": %s: Sending IOC msg unit reset!\n", ioc->name));
+ if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET)) != 0) {
+ printk(KERN_ERR MYNAM ": %s: ERROR - IOC msg unit reset failed!\n", ioc->name);
+ r = -ENODEV;
+ goto ioc_up_fail;
+ }
+ } else if (ioc_state == MPI_IOC_STATE_RESET) {
+ /*
+ * Something is wrong. Try to get IOC back
+ * to a known state.
+ */
+ dprintk((KERN_WARNING MYNAM ": %s: Sending IO unit reset!\n", ioc->name));
+ if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET)) != 0) {
+ printk(KERN_ERR MYNAM ": %s: ERROR - IO unit reset failed!\n", ioc->name);
+ r = -ENODEV;
+ goto ioc_up_fail;
+ }
+ }
+
+ i++; cntdn--;
+ if (!cntdn) {
+ printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
+ ioc->name, (i+5)/HZ);
+ r = -ETIME;
+ goto ioc_up_fail;
+ }
+
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ }
+
+ if (statefault) {
+ printk(KERN_WARNING MYNAM ": %s: Whew! Recovered from %s\n",
+ ioc->name, statefault==1 ? "stuck handshake" : "IOC FAULT");
+ }
+
+ /* Enable! (reply interrupt) */
+ CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM));
+ ioc->active = 1;
+
+ /* Get IOC facts! (first time, ioc->facts0 and ioc->pfacts0) */
+ if ((r = GetIocFacts(ioc)) != 0)
+ goto ioc_up_fail;
+
+ /* Does IocFacts.EventState need any looking at / attention here? */
+
+ if ((r = SendIocInit(ioc)) != 0)
+ goto ioc_up_fail;
+
+ /*
+ * Prime reply & request queues!
+ * (mucho alloc's)
+ */
+ if ((r = PrimeIocFifos(ioc)) != 0)
+ goto ioc_up_fail;
+
+ /* Get IOC facts again! (2nd time, ioc->factsN and ioc->pfactsN) */
+ if ((r = GetIocFacts(ioc)) != 0)
+ goto ioc_up_fail;
+
+ /* Does IocFacts.EventState need any looking at / attention here? */
+
+ MptDisplayIocCapabilities(ioc);
+
+ if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+ /*
+ * Pre-fetch the ports LAN MAC address!
+ * (LANPage1_t stuff)
+ */
+ (void) GetLanConfigPages(ioc);
+#ifdef MPT_DEBUG
+ {
+ u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
+ dprintk((KERN_INFO MYNAM ": %s: LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+ ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
+ }
+#endif
+ }
+
+ /* NEW! 20010120 -sralston
+ * Enable MPT base driver management of EventNotification
+ * and EventAck handling.
+ */
+ (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
+
+ return 0;
+
+ioc_up_fail:
+ //Q_DEL_ITEM(ioc);
+ //mpt_adapter_dispose(ioc);
+ mpt_adapter_disable(ioc);
+ return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * mpt_detect_929_bound_ports - Search for PCI bus/dev_function
+ * which matches PCI bus/dev_function (+/-1) for newly discovered 929.
+ * @ioc: Pointer to MPT adapter structure
+ * @pdev: Pointer to (struct pci_dev) structure
+ *
+ * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
+ * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
+ */
+static void
+mpt_detect_929_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
+{
+ MPT_ADAPTER *ioc_srch = mpt_adapter_find_first();
+ unsigned int match_lo, match_hi;
+
+ match_lo = pdev->devfn-1;
+ match_hi = pdev->devfn+1;
+ dprintk((KERN_INFO MYNAM ": %s: PCI bus/devfn=%x/%x, searching for devfn match on %x or %x\n",
+ ioc->name, pdev->bus->number, pdev->devfn, match_lo, match_hi));
+
+ while (ioc_srch != NULL) {
+ struct pci_dev *_pcidev = ioc_srch->pcidev;
+
+ if ( (_pcidev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) &&
+ (_pcidev->bus->number == pdev->bus->number) &&
+ (_pcidev->devfn == match_lo || _pcidev->devfn == match_hi) ) {
+ /* Paranoia checks */
+ if (ioc->alt_ioc != NULL) {
+ printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
+ ioc->name, ioc->alt_ioc->name);
+ break;
+ } else if (ioc_srch->alt_ioc != NULL) {
+ printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
+ ioc_srch->name, ioc_srch->alt_ioc->name);
+ break;
+ }
+ dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
+ ioc->name, ioc_srch->name));
+ ioc_srch->alt_ioc = ioc;
+ ioc->alt_ioc = ioc_srch;
+ ioc->sod_reset = ioc->alt_ioc->sod_reset;
+ ioc->last_kickstart = ioc->alt_ioc->last_kickstart;
+ break;
+ }
+ ioc_srch = mpt_adapter_find_next(ioc_srch);
+ }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * mpt_adapter_disable - Disable misbehaving MPT adapter.
+ * @this: Pointer to MPT adapter structure
+ */
+static void
+mpt_adapter_disable(MPT_ADAPTER *this)
+{
+ if (this != NULL) {
+ int sz;
+
+ /* Disable adapter interrupts! */
+ CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF);
+ /* Clear any lingering interrupt */
+ CHIPREG_WRITE32(&this->chip->IntStatus, 0);
+ this->active = 0;
+
+ if (this->reply_alloc != NULL) {
+ sz = (this->reply_sz * this->reply_depth) + 128;
+ pci_free_consistent(this->pcidev, sz,
+ this->reply_alloc, this->reply_alloc_dma);
+ this->reply_frames = NULL;
+ this->reply_alloc = NULL;
+ this->alloc_total -= sz;
+ }
+
+ if (this->req_alloc != NULL) {
+ sz = (this->req_sz * this->req_depth) + 128;
+ /*
+ * Rounding UP to nearest 4-kB boundary here...
+ */
+ sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
+ pci_free_consistent(this->pcidev, sz,
+ this->req_alloc, this->req_alloc_dma);
+ this->req_frames = NULL;
+ this->req_alloc = NULL;
+ this->alloc_total -= sz;
+ }
+
+ if (this->sense_buf_pool != NULL) {
+ sz = (this->req_depth * 256);
+ pci_free_consistent(this->pcidev, sz,
+ this->sense_buf_pool, this->sense_buf_pool_dma);
+ this->sense_buf_pool = NULL;
+ this->alloc_total -= sz;
+ }
+ }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * mpt_adapter_dispose - Free all resources associated with a MPT
+ * adapter.
+ * @this: Pointer to MPT adapter structure
+ *
+ * This routine unregisters h/w resources and frees all alloc'd memory
+ * associated with a MPT adapter structure.
+ */
+static void
+mpt_adapter_dispose(MPT_ADAPTER *this)
+{
+ if (this != NULL) {
+ int sz_first, sz_last;
+
+ sz_first = this->alloc_total;
+
+ mpt_adapter_disable(this);
+
+ if (this->pci_irq != -1) {
+ free_irq(this->pci_irq, this);
+ this->pci_irq = -1;
+ }
+
+ if (this->memmap != NULL)
+ iounmap((u8 *) this->memmap);
+
+#if defined(CONFIG_MTRR) && 0
+ if (this->mtrr_reg > 0) {
+ mtrr_del(this->mtrr_reg, 0, 0);
+ dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", this->name));
+ }
+#endif
+
+ /* Zap the adapter lookup ptr! */
+ mpt_adapters[this->id] = NULL;
+
+ sz_last = this->alloc_total;
+ dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
+ this->name, sz_first-sz_last+(int)sizeof(*this), sz_first));
+ kfree(this);
+ }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * MptDisplayIocCapabilities - Disply IOC's capacilities.
+ * @ioc: Pointer to MPT adapter structure
+ */
+static void
+MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
+{
+ int i = 0;
+
+ printk(KERN_INFO "%s: ", ioc->name);
+ if (ioc->prod_name && strlen(ioc->prod_name) > 3)
+ printk("%s: ", ioc->prod_name+3);
+ printk("Capabilities={");
+
+ if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
+ printk("Initiator");
+ i++;
+ }
+
+ if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
+ printk("%sTarget", i ? "," : "");
+ i++;
+ }
+
+ if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+ printk("%sLAN", i ? "," : "");
+ i++;
+ }
+
+#if 0
+ /*
+ * This would probably evoke more questions than it's worth
+ */
+ if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
+ printk("%sLogBusAddr", i ? "," : "");
+ i++;
+ }
+#endif
+
+ printk("}\n");
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * GetIocState - Get the current state of a MPT adapter.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @cooked: Request raw or cooked IOC state
+ *
+ * Returns all IOC Doorbell register bits if cooked==0, else just the
+ * Doorbell bits in MPI_IOC_STATE_MASK.
+ */
+static u32
+GetIocState(MPT_ADAPTER *ioc, int cooked)
+{
+ u32 s, sc;
+
+ /* Get! */
+ s = CHIPREG_READ32(&ioc->chip->Doorbell);
+ dprintk((KERN_INFO MYNAM ": %s: raw state = %08x\n", ioc->name, s));
+ sc = s & MPI_IOC_STATE_MASK;
+
+ /* Save! */
+ ioc->last_state = sc;
+
+ return cooked ? sc : s;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * GetIocFacts - Send IOCFacts request to MPT adapter.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+GetIocFacts(MPT_ADAPTER *ioc)
+{
+ IOCFacts_t get_facts;
+ IOCFactsReply_t *facts;
+ int r;
+ int req_sz;
+ int reply_sz;
+ u32 status;
+
+ /* IOC *must* NOT be in RESET state! */
+ if (ioc->last_state == MPI_IOC_STATE_RESET) {
+ printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
+ ioc->name,
+ ioc->last_state );
+ return -44;
+ }
+
+ facts = &ioc->facts0;
+ /* Nth (2,3,...) time thru? (been here, done that?) */
+ if (ioc->facts0.Function == MPI_FUNCTION_IOC_FACTS) {
+ facts = &ioc->factsN;
+ }
+
+ /* Destination (reply area)... */
+ reply_sz = sizeof(*facts);
+ memset(facts, 0, reply_sz);
+
+ /* Request area (get_facts on the stack right now!) */
+ req_sz = sizeof(get_facts);
+ memset(&get_facts, 0, req_sz);
+
+ get_facts.Function = MPI_FUNCTION_IOC_FACTS;
+ /* Assert: All other get_facts fields are zero! */
+
+ dprintk((KERN_INFO MYNAM ": %s: Sending IocFacts%s request\n",
+ ioc->name, facts == &ioc->facts0 ? "0" : "N" ));
+
+ /* No non-zero fields in the get_facts request are greater than
+ * 1 byte in size, so we can just fire it off as is.
+ */
+ r = HandShakeReqAndReply(ioc,
+ req_sz, (u32*)&get_facts,
+ reply_sz, (u16*)facts);
+ if (r != 0)
+ return r;
+
+ /*
+ * Now byte swap the necessary fields before any further
+ * inspection of reply contents.
+ *
+ * But need to do some sanity checks on MsgLength (byte) field
+ * to make sure we don't zero IOC's req_sz!
+ */
+ /* Did we get a valid reply? */
+ if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
+ facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
+ facts->MsgContext = le32_to_cpu(facts->MsgContext);
+ facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
+ facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
+ status = facts->IOCStatus & MPI_IOCSTATUS_MASK;
+ /* CHECKME! IOCStatus, IOCLogInfo */
+
+ facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
+ facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
+ facts->FWVersion = le16_to_cpu(facts->FWVersion);
+ facts->ProductID = le16_to_cpu(facts->ProductID);
+ facts->CurrentHostMfaHighAddr =
+ le32_to_cpu(facts->CurrentHostMfaHighAddr);
+ facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
+ facts->CurrentSenseBufferHighAddr =
+ le32_to_cpu(facts->CurrentSenseBufferHighAddr);
+ facts->CurReplyFrameSize =
+ le16_to_cpu(facts->CurReplyFrameSize);
+
+ /*
+ * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
+ * Older MPI-1.00.xx struct had 13 dwords, and enlarged
+ * to 14 in MPI-1.01.0x.
+ */
+ if (facts->MsgLength >= sizeof(IOCFactsReply_t)/sizeof(u32) && facts->MsgVersion > 0x0100) {
+ facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
+ facts->DataImageSize = le32_to_cpu(facts->DataImageSize);
+ }
+
+ if (facts->RequestFrameSize) {
+ /*
+ * Set values for this IOC's REQUEST queue size & depth...
+ */
+ ioc->req_sz = MIN(MPT_REQ_SIZE, facts->RequestFrameSize * 4);
+
+ /*
+ * Set values for this IOC's REPLY queue size & depth...
+ *
+ * BUG? FIX? 20000516 -nromer & sralston
+ * GRRR... The following did not translate well from MPI v0.09:
+ * ioc->reply_sz = MIN(MPT_REPLY_SIZE, facts->ReplySize * 4);
+ * to 0.10:
+ * ioc->reply_sz = MIN(MPT_REPLY_SIZE, facts->BlockSize * 4);
+ * Was trying to minimally optimize to smallest possible reply size
+ * (and greatly reduce kmalloc size). But LAN may need larger reply?
+ *
+ * So for now, just set reply size to request size. FIXME?
+ */
+ ioc->reply_sz = ioc->req_sz;
+ } else {
+ /* Something is wrong! */
+ printk(KERN_ERR MYNAM ": %s: ERROR - IOC reported invalid 0 request size!\n",
+ ioc->name);
+ ioc->req_sz = MPT_REQ_SIZE;
+ ioc->reply_sz = MPT_REPLY_SIZE;
+ return -55;
+ }
+ ioc->req_depth = MIN(MPT_REQ_DEPTH, facts->GlobalCredits);
+ ioc->reply_depth = MIN(MPT_REPLY_DEPTH, facts->ReplyQueueDepth);
+
+ dprintk((KERN_INFO MYNAM ": %s: reply_sz=%3d, reply_depth=%4d\n",
+ ioc->name, ioc->reply_sz, ioc->reply_depth));
+ dprintk((KERN_INFO MYNAM ": %s: req_sz =%3d, req_depth =%4d\n",
+ ioc->name, ioc->req_sz, ioc->req_depth));
+
+ /* Get port facts! */
+ if ( (r = GetPortFacts(ioc)) != 0 )
+ return r;
+ } else {
+ printk(KERN_ERR MYNAM ": %s: ERROR - Invalid IOC facts reply!\n",
+ ioc->name);
+ return -66;
+ }
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * GetPortFacts - Send PortFacts request to MPT adapter.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+GetPortFacts(MPT_ADAPTER *ioc)
+{
+ PortFacts_t get_pfacts;
+ PortFactsReply_t *pfacts;
+ int i;
+ int req_sz;
+ int reply_sz;
+
+ /* IOC *must* NOT be in RESET state! */
+ if (ioc->last_state == MPI_IOC_STATE_RESET) {
+ printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
+ ioc->name,
+ ioc->last_state );
+ return -4;
+ }
+
+ pfacts = &ioc->pfacts0;
+ /* Nth (2,3,...) time thru? (been here, done that?) */
+ if (ioc->pfacts0.Function == MPI_FUNCTION_PORT_FACTS) {
+ pfacts = &ioc->pfactsN;
+ }
+
+ /* Destination (reply area)... */
+ reply_sz = sizeof(*pfacts);
+ memset(pfacts, 0, reply_sz);
+
+ /* Request area (get_pfacts on the stack right now!) */
+ req_sz = sizeof(get_pfacts);
+ memset(&get_pfacts, 0, req_sz);
+
+ get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
+ /* Assert: All other get_pfacts fields are zero! */
+
+ dprintk((KERN_INFO MYNAM ": %s: Sending PortFacts%s request\n",
+ ioc->name, pfacts == &ioc->pfacts0 ? "0" : "N" ));
+
+ /* No non-zero fields in the get_pfacts request are greater than
+ * 1 byte in size, so we can just fire it off as is.
+ */
+ i = HandShakeReqAndReply(ioc, req_sz, (u32*)&get_pfacts,
+ reply_sz, (u16*)pfacts);
+ if (i != 0)
+ return i;
+
+ /* Did we get a valid reply? */
+
+ /* Now byte swap the necessary fields in the response. */
+ pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
+ pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
+ pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
+ pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
+ pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
+ pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
+ pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
+ pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
+ pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * SendIocInit - Send IOCInit request to MPT adapter.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ *
+ * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+SendIocInit(MPT_ADAPTER *ioc)
+{
+ IOCInit_t ioc_init;
+ MPIDefaultReply_t init_reply;
+ u32 state;
+ int r;
+ int count;
+ int cntdn;
+
+ memset(&ioc_init, 0, sizeof(ioc_init));
+ memset(&init_reply, 0, sizeof(init_reply));
+
+ ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
+/* ioc_init.ChainOffset = 0; */
+ ioc_init.Function = MPI_FUNCTION_IOC_INIT;
+/* ioc_init.Flags = 0; */
+
+ /*ioc_init.MaxDevices = 16;*/
+ ioc_init.MaxDevices = 255;
+/* ioc_init.MaxBuses = 16; */
+ ioc_init.MaxBuses = 1;
+
+/* ioc_init.MsgFlags = 0; */
+/* ioc_init.MsgContext = cpu_to_le32(0x00000000); */
+ ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
+ ioc_init.HostMfaHighAddr = cpu_to_le32(0); /* Say we 32-bit! for now */
+
+ dprintk((KERN_INFO MYNAM ": %s: Sending IOCInit (req @ %p)\n", ioc->name, &ioc_init));
+
+ r = HandShakeReqAndReply(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
+ sizeof(MPIDefaultReply_t), (u16*)&init_reply);
+ if (r != 0)
+ return r;
+
+ /* No need to byte swap the multibyte fields in the reply
+ * since we don't even look at it's contents.
+ */
+
+ if ((r = SendPortEnable(ioc, 0)) != 0)
+ return r;
+
+ /* YIKES! SUPER IMPORTANT!!!
+ * Poll IocState until _OPERATIONAL while IOC is doing
+ * LoopInit and TargetDiscovery!
+ */
+ count = 0;
+ cntdn = HZ * 60; /* chg'd from 30 to 60 seconds */
+ state = GetIocState(ioc, 1);
+ while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+
+ if (!cntdn) {
+ printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_OP state timeout(%d)!\n",
+ ioc->name, (count+5)/HZ);
+ return -9;
+ }
+
+ state = GetIocState(ioc, 1);
+ count++;
+ }
+ dhsprintk((KERN_INFO MYNAM ": %s: INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
+ ioc->name, count));
+
+ return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * SendPortEnable - Send PortEnable request to MPT adapter port.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @portnum: Port number to enable
+ *
+ * Send PortEnable to bring IOC to OPERATIONAL state.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+SendPortEnable(MPT_ADAPTER *ioc, int portnum)
+{
+ PortEnable_t port_enable;
+ MPIDefaultReply_t reply_buf;
+ int i;
+ int req_sz;
+ int reply_sz;
+
+ /* Destination... */
+ reply_sz = sizeof(MPIDefaultReply_t);
+ memset(&reply_buf, 0, reply_sz);
+
+ req_sz = sizeof(PortEnable_t);
+ memset(&port_enable, 0, req_sz);
+
+ port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
+ port_enable.PortNumber = portnum;
+/* port_enable.ChainOffset = 0; */
+/* port_enable.MsgFlags = 0; */
+/* port_enable.MsgContext = 0; */
+
+ dprintk((KERN_INFO MYNAM ": %s: Sending Port(%d)Enable (req @ %p)\n",
+ ioc->name, portnum, &port_enable));
+
+ i = HandShakeReqAndReply(ioc, req_sz, (u32*)&port_enable,
+ reply_sz, (u16*)&reply_buf);
+ if (i != 0)
+ return i;
+
+ /* We do not even look at the reply, so we need not
+ * swap the multi-byte fields.
+ */
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * KickStart - Perform hard reset of MPT adapter.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ *
+ * This routine places MPT adapter in diagnostic mode via the
+ * WriteSequence register, and then performs a hard reset of adapter
+ * via the Diagnostic register.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+KickStart(MPT_ADAPTER *ioc)
+{
+ int r;
+ u32 ioc_state;
+ int cnt = 0;
+
+ dprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
+
+ if (ioc->chip_type == FC909) {
+ r = mpt_fc9x9_reset(ioc);
+ } else if (ioc->chip_type == FC929) {
+ unsigned long delta;
+
+ delta = jiffies - ioc->last_kickstart;
+ dprintk((KERN_INFO MYNAM ": %s: 929 KickStart, last=%ld, delta = %ld\n",
+ ioc->name, ioc->last_kickstart, delta));
+ if ((ioc->sod_reset == 0) || (delta >= 10*HZ))
+ r = mpt_fc9x9_reset(ioc);
+ else {
+ dprintk((KERN_INFO MYNAM ": %s: Skipping KickStart (delta=%ld)!\n",
+ ioc->name, delta));
+ return 0;
+ }
+ /* TODO! Add FC919!
+ } else if (ioc->chip_type == FC919) {
+ */
+ /* TODO! Add C1030!
+ } else if (ioc->chip_type == C1030) {
+ */
+ } else {
+ printk(KERN_ERR MYNAM ": %s: ERROR - Bad chip_type (0x%x)\n",
+ ioc->name, ioc->chip_type);
+ return -5;
+ }
+
+ if (r != 0)
+ return -r;
+
+ dprintk((KERN_INFO MYNAM ": %s: Diagnostic reset successful\n",
+ ioc->name));
+
+ for (cnt=0; cnt<HZ*20; cnt++) {
+ if ((ioc_state = GetIocState(ioc, 1)) == MPI_IOC_STATE_READY) {
+ dprintk((KERN_INFO MYNAM ": %s: KickStart successful! (cnt=%d)\n",
+ ioc->name, cnt));
+ return 0;
+ }
+ /* udelay(10000) ? */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ }
+
+ printk(KERN_ERR MYNAM ": %s: ERROR - Failed to come READY after reset!\n",
+ ioc->name);
+ return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * mpt_fc9x9_reset - Perform hard reset of FC9x9 adapter.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ *
+ * This routine places FC9x9 adapter in diagnostic mode via the
+ * WriteSequence register, and then performs a hard reset of adapter
+ * via the Diagnostic register.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+mpt_fc9x9_reset(MPT_ADAPTER *ioc)
+{
+ u32 diagval;
+
+ /* Use "Diagnostic reset" method! (only thing available!) */
+
+ /*
+ * Extra read to handle 909 B.0 chip problem with reset
+ * logic not finishing the RAM access before hard reset hits.
+ * (? comment taken from NT SYMMPI source)
+ */
+ (void) CHIPREG_READ32(&ioc->chip->Fubar);
+
+ /*
+ * Write magic sequence to WriteSequence register.
+ * But, send 0x0F first to insure a reset to the beginning of the sequence.
+ */
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_KEY_VALUE_MASK);
+
+ /* Now write magic sequence */
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
+ dprintk((KERN_INFO MYNAM ": %s: Wrote magic DiagWriteEn sequence\n",
+ ioc->name));
+
+ /* Now hit the reset bit in the Diagnostic register */
+ CHIPREG_WRITE32(&ioc->chip->Diagnostic, MPI_DIAG_RESET_ADAPTER);
+
+ udelay(100);
+
+ if ((diagval = CHIPREG_READ32(&ioc->chip->Diagnostic)) &
+ (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_DISABLE_ARM)) {
+ printk(KERN_ERR MYNAM ": %s: ERROR - Diagnostic reset FAILED!\n",
+ ioc->name);
+ return -9;
+ }
+
+ /* TODO!
+ * Cleanup all event stuff for this IOC;
+ * re-issue EventNotification request if needed.
+ */
+ if (ioc->factsN.Function)
+ ioc->factsN.EventState = 0;
+
+ /* NEW! 20010220 -sralston
+ * Try to avoid redundant resets of the 929.
+ */
+ ioc->sod_reset++;
+ ioc->last_kickstart = jiffies;
+ if (ioc->alt_ioc) {
+ ioc->alt_ioc->sod_reset = ioc->sod_reset;
+ ioc->alt_ioc->last_kickstart = ioc->last_kickstart;
+ }
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * SendIocReset - Send IOCReset request to MPT adapter.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @reset_type: reset type, expected values are
+ * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
+ *
+ * Send IOCReset request to the MPT adapter.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+SendIocReset(MPT_ADAPTER *ioc, u8 reset_type)
+{
+ int r;
+
+ printk(KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
+ ioc->name, reset_type);
+ CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
+ if ((r = WaitForDoorbellAck(ioc)) < 0)
+ return r;
+
+ /* TODO!
+ * Cleanup all event stuff for this IOC; re-issue EventNotification
+ * request if needed.
+ */
+ if (ioc->factsN.Function)
+ ioc->factsN.EventState = 0;
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * PrimeIocFifos - Initialize IOC request and reply FIFOs.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ *
+ * This routine allocates memory for the MPT reply and request frame
+ * pools, and primes the IOC reply FIFO with reply frames.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+PrimeIocFifos(MPT_ADAPTER *ioc)
+{
+ MPT_FRAME_HDR *mf;
+ unsigned long b;
+ dma_addr_t aligned_mem_dma;
+ u8 *mem, *aligned_mem;
+ int i, sz;
+
+ /* Prime reply FIFO... */
+
+ if (ioc->reply_frames == NULL) {
+ sz = (ioc->reply_sz * ioc->reply_depth) + 128;
+ mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->reply_alloc_dma);
+ if (mem == NULL)
+ goto out_fail;
+
+ memset(mem, 0, sz);
+ ioc->alloc_total += sz;
+ ioc->reply_alloc = mem;
+ dprintk((KERN_INFO MYNAM ": %s.reply_alloc @ %p[%08x], sz=%d bytes\n",
+ ioc->name, mem, ioc->reply_alloc_dma, sz));
+
+ b = (unsigned long) mem;
+ b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */
+ aligned_mem = (u8 *) b;
+ ioc->reply_frames = (MPT_FRAME_HDR *) aligned_mem;
+ ioc->reply_frames_dma =
+ (ioc->reply_alloc_dma + (aligned_mem - mem));
+ aligned_mem_dma = ioc->reply_frames_dma;
+ dprintk((KERN_INFO MYNAM ": %s.reply_frames @ %p[%08x]\n",
+ ioc->name, aligned_mem, aligned_mem_dma));
+
+ for (i = 0; i < ioc->reply_depth; i++) {
+ /* Write each address to the IOC! */
+ CHIPREG_WRITE32(&ioc->chip->ReplyFifo, aligned_mem_dma);
+ aligned_mem_dma += ioc->reply_sz;
+ }
+ }
+
+
+ /* Request FIFO - WE manage this! */
+
+ if (ioc->req_frames == NULL) {
+ sz = (ioc->req_sz * ioc->req_depth) + 128;
+ /*
+ * Rounding UP to nearest 4-kB boundary here...
+ */
+ sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
+
+ mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->req_alloc_dma);
+ if (mem == NULL)
+ goto out_fail;
+
+ memset(mem, 0, sz);
+ ioc->alloc_total += sz;
+ ioc->req_alloc = mem;
+ dprintk((KERN_INFO MYNAM ": %s.req_alloc @ %p[%08x], sz=%d bytes\n",
+ ioc->name, mem, ioc->req_alloc_dma, sz));
+
+ b = (unsigned long) mem;
+ b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */
+ aligned_mem = (u8 *) b;
+ ioc->req_frames = (MPT_FRAME_HDR *) aligned_mem;
+ ioc->req_frames_dma =
+ (ioc->req_alloc_dma + (aligned_mem - mem));
+ aligned_mem_dma = ioc->req_frames_dma;
+
+ dprintk((KERN_INFO MYNAM ": %s.req_frames @ %p[%08x]\n",
+ ioc->name, aligned_mem, aligned_mem_dma));
+
+ for (i = 0; i < ioc->req_depth; i++) {
+ mf = (MPT_FRAME_HDR *) aligned_mem;
+
+ /* Queue REQUESTs *internally*! */
+ Q_ADD_TAIL(&ioc->FreeQ.head, &mf->u.frame.linkage, MPT_FRAME_HDR);
+ aligned_mem += ioc->req_sz;
+ }
+
+#if defined(CONFIG_MTRR) && 0
+ /*
+ * Enable Write Combining MTRR for IOC's memory region.
+ * (at least as much as we can; "size and base must be
+ * multiples of 4 kiB"
+ */
+ ioc->mtrr_reg = mtrr_add(ioc->req_alloc_dma,
+ sz,
+ MTRR_TYPE_WRCOMB, 1);
+ dprintk((KERN_INFO MYNAM ": %s: MTRR region registered (base:size=%08x:%x)\n",
+ ioc->name, ioc->req_alloc_dma,
+ sz ));
+#endif
+
+ }
+
+ if (ioc->sense_buf_pool == NULL) {
+ sz = (ioc->req_depth * 256);
+ ioc->sense_buf_pool =
+ pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
+ if (ioc->sense_buf_pool == NULL)
+ goto out_fail;
+
+ ioc->alloc_total += sz;
+ }
+
+ return 0;
+
+out_fail:
+ if (ioc->reply_alloc != NULL) {
+ sz = (ioc->reply_sz * ioc->reply_depth) + 128;
+ pci_free_consistent(ioc->pcidev,
+ sz,
+ ioc->reply_alloc, ioc->reply_alloc_dma);
+ ioc->reply_frames = NULL;
+ ioc->reply_alloc = NULL;
+ ioc->alloc_total -= sz;
+ }
+ if (ioc->req_alloc != NULL) {
+ sz = (ioc->req_sz * ioc->req_depth) + 128;
+ /*
+ * Rounding UP to nearest 4-kB boundary here...
+ */
+ sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
+ pci_free_consistent(ioc->pcidev,
+ sz,
+ ioc->req_alloc, ioc->req_alloc_dma);
+#if defined(CONFIG_MTRR) && 0
+ if (ioc->mtrr_reg > 0) {
+ mtrr_del(ioc->mtrr_reg, 0, 0);
+ dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n",
+ ioc->name));
+ }
+#endif
+ ioc->req_frames = NULL;
+ ioc->req_alloc = NULL;
+ ioc->alloc_total -= sz;
+ }
+ if (ioc->sense_buf_pool != NULL) {
+ sz = (ioc->req_depth * 256);
+ pci_free_consistent(ioc->pcidev,
+ sz,
+ ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
+ ioc->sense_buf_pool = NULL;
+ }
+ return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * HandShakeReqAndReply - Send MPT request to and receive reply from
+ * IOC via doorbell handshake method.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @reqBytes: Size of the request in bytes
+ * @req: Pointer to MPT request frame
+ * @replyBytes: Expected size of the reply in bytes
+ * @u16reply: Pointer to area where reply should be written
+ *
+ * NOTES: It is the callers responsibility to byte-swap fields in the
+ * request which are greater than 1 byte in size. It is also the
+ * callers responsibility to byte-swap response fields which are
+ * greater than 1 byte in size.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply)
+{
+ MPIDefaultReply_t *mptReply;
+ int failcnt = 0;
+ int t;
+
+ /*
+ * Get ready to cache a handshake reply
+ */
+ ioc->hs_reply_idx = 0;
+ mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
+ mptReply->MsgLength = 0;
+
+ /*
+ * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
+ * then tell IOC that we want to handshake a request of N words.
+ * (WRITE u32val to Doorbell reg).
+ */
+ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+ CHIPREG_WRITE32(&ioc->chip->Doorbell,
+ ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
+ ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
+
+ /*
+ * Wait for IOC's doorbell handshake int
+ */
+ if ((t = WaitForDoorbellInt(ioc)) < 0)
+ failcnt++;
+
+ dhsprintk((KERN_INFO MYNAM ": %s: HandShake request start, WaitCnt=%d%s\n",
+ ioc->name, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
+
+ /*
+ * Clear doorbell int (WRITE 0 to IntStatus reg),
+ * then wait for IOC to ACKnowledge that it's ready for
+ * our handshake request.
+ */
+ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+ if (!failcnt && (t = WaitForDoorbellAck(ioc)) < 0)
+ failcnt++;
+
+ if (!failcnt) {
+ int i;
+ u8 *req_as_bytes = (u8 *) req;
+
+ /*
+ * Stuff request words via doorbell handshake,
+ * with ACK from IOC for each.
+ */
+ for (i = 0; !failcnt && i < reqBytes/4; i++) {
+ u32 word = ((req_as_bytes[(i*4) + 0] << 0) |
+ (req_as_bytes[(i*4) + 1] << 8) |
+ (req_as_bytes[(i*4) + 2] << 16) |
+ (req_as_bytes[(i*4) + 3] << 24));
+
+ CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
+ if ((t = WaitForDoorbellAck(ioc)) < 0)
+ failcnt++;
+ }
+
+ dmfprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
+ DBG_DUMP_REQUEST_FRAME_HDR(req)
+
+ dhsprintk((KERN_INFO MYNAM ": %s: HandShake request post done, WaitCnt=%d%s\n",
+ ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
+
+ /*
+ * Wait for completion of doorbell handshake reply from the IOC
+ */
+ if (!failcnt && (t = WaitForDoorbellReply(ioc)) < 0)
+ failcnt++;
+
+ /*
+ * Copy out the cached reply...
+ */
+ for(i=0; i < MIN(replyBytes/2,mptReply->MsgLength*2); i++)
+ u16reply[i] = ioc->hs_reply[i];
+ } else {
+ return -99;
+ }
+
+ return -failcnt;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit
+ * in it's IntStatus register.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ *
+ * This routine waits (up to ~30 seconds max) for IOC doorbell
+ * handshake ACKnowledge.
+ *
+ * Returns a negative value on failure, else wait loop count.
+ */
+static int
+WaitForDoorbellAck(MPT_ADAPTER *ioc)
+{
+ int cntdn = HZ * 30; /* ~30 seconds */
+ int count = 0;
+ u32 intstat;
+
+ while (--cntdn) {
+ intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+ if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
+ break;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ count++;
+ }
+
+ if (cntdn) {
+ dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell ACK (cnt=%d)\n",
+ ioc->name, count));
+ return count;
+ }
+
+ printk(KERN_ERR MYNAM ": %s: ERROR - Doorbell ACK timeout(%d)!\n",
+ ioc->name, (count+5)/HZ);
+ return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit
+ * in it's IntStatus register.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ *
+ * This routine waits (up to ~30 seconds max) for IOC doorbell interrupt.
+ *
+ * Returns a negative value on failure, else wait loop count.
+ */
+static int
+WaitForDoorbellInt(MPT_ADAPTER *ioc)
+{
+ int cntdn = HZ * 30; /* ~30 seconds */
+ int count = 0;
+ u32 intstat;
+
+ while (--cntdn) {
+ intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+ if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
+ break;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ count++;
+ }
+
+ if (cntdn) {
+ dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell INT (cnt=%d)\n",
+ ioc->name, count));
+ return count;
+ }
+
+ printk(KERN_ERR MYNAM ": %s: ERROR - Doorbell INT timeout(%d)!\n",
+ ioc->name, (count+5)/HZ);
+ return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * WaitForDoorbellReply - Wait for and capture a IOC handshake reply.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ *
+ * This routine polls the IOC for a handshake reply, 16 bits at a time.
+ * Reply is cached to IOC private area large enough to hold a maximum
+ * of 128 bytes of reply data.
+ *
+ * Returns a negative value on failure, else size of reply in WORDS.
+ */
+static int
+WaitForDoorbellReply(MPT_ADAPTER *ioc)
+{
+ int u16cnt = 0;
+ int failcnt = 0;
+ int t;
+ u16 *hs_reply = ioc->hs_reply;
+ volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
+ u16 hword;
+
+ hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
+
+ /*
+ * Get first two u16's so we can look at IOC's intended reply MsgLength
+ */
+ for (u16cnt=0; !failcnt && u16cnt < 2; u16cnt++) {
+ if ((t = WaitForDoorbellInt(ioc)) < 0)
+ failcnt++;
+ hs_reply[u16cnt] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
+ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+ }
+
+ dhsprintk((KERN_INFO MYNAM ": %s: First handshake reply word=%08x%s\n",
+ ioc->name, le32_to_cpu(*(u32 *)hs_reply),
+ failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
+
+ /*
+ * If no error (and IOC said MsgLength is > 0), piece together
+ * reply 16 bits at a time.
+ */
+ for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
+ if ((t = WaitForDoorbellInt(ioc)) < 0)
+ failcnt++;
+ hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
+ /* don't overflow our IOC hs_reply[] buffer! */
+ if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
+ hs_reply[u16cnt] = hword;
+ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+ }
+
+ if (!failcnt && (t = WaitForDoorbellInt(ioc)) < 0)
+ failcnt++;
+ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+
+ if (failcnt) {
+ printk(KERN_ERR MYNAM ": %s: ERROR - Handshake reply failure!\n",
+ ioc->name);
+ return -failcnt;
+ }
+#if 0
+ else if (u16cnt != (2 * mptReply->MsgLength)) {
+ return -101;
+ }
+ else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
+ return -102;
+ }
+#endif
+
+ dmfprintk((KERN_INFO MYNAM ": %s: Got Handshake reply:\n", ioc->name));
+ DBG_DUMP_REPLY_FRAME(mptReply)
+
+ dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell REPLY (sz=%d)\n",
+ ioc->name, u16cnt/2));
+ return u16cnt/2;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * GetLanConfigPages - Fetch LANConfig pages.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+GetLanConfigPages(MPT_ADAPTER *ioc)
+{
+ Config_t config_req;
+ ConfigReply_t config_reply;
+ LANPage0_t *page0;
+ dma_addr_t page0_dma;
+ LANPage1_t *page1;
+ dma_addr_t page1_dma;
+ int i;
+ int req_sz;
+ int reply_sz;
+ int data_sz;
+
+/* LANPage0 */
+ /* Immediate destination (reply area)... */
+ reply_sz = sizeof(config_reply);
+ memset(&config_reply, 0, reply_sz);
+
+ /* Ultimate destination... */
+ page0 = &ioc->lan_cnfg_page0;
+ data_sz = sizeof(*page0);
+ memset(page0, 0, data_sz);
+
+ /* Request area (config_req on the stack right now!) */
+ req_sz = sizeof(config_req);
+ memset(&config_req, 0, req_sz);
+ config_req.Function = MPI_FUNCTION_CONFIG;
+ config_req.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+ /* config_req.Header.PageVersion = 0; */
+ /* config_req.Header.PageLength = 0; */
+ config_req.Header.PageNumber = 0;
+ config_req.Header.PageType = MPI_CONFIG_PAGETYPE_LAN;
+ /* config_req.PageAddress = 0; */
+ config_req.PageBufferSGE.u.Simple.FlagsLength = cpu_to_le32(
+ ((MPI_SGE_FLAGS_LAST_ELEMENT |
+ MPI_SGE_FLAGS_END_OF_BUFFER |
+ MPI_SGE_FLAGS_END_OF_LIST |
+ MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI_SGE_FLAGS_SYSTEM_ADDRESS |
+ MPI_SGE_FLAGS_32_BIT_ADDRESSING |
+ MPI_SGE_FLAGS_32_BIT_CONTEXT) << MPI_SGE_FLAGS_SHIFT) |
+ (u32)data_sz
+ );
+ page0_dma = pci_map_single(ioc->pcidev, page0, data_sz, PCI_DMA_FROMDEVICE);
+ config_req.PageBufferSGE.u.Simple.u.Address32 = cpu_to_le32(page0_dma);
+
+ dprintk((KERN_INFO MYNAM ": %s: Sending Config request LAN_PAGE_0\n",
+ ioc->name));
+
+ i = HandShakeReqAndReply(ioc, req_sz, (u32*)&config_req,
+ reply_sz, (u16*)&config_reply);
+ pci_unmap_single(ioc->pcidev, page0_dma, data_sz, PCI_DMA_FROMDEVICE);
+ if (i != 0)
+ return i;
+
+ /* Now byte swap the necessary LANPage0 fields */
+
+/* LANPage1 */
+ /* Immediate destination (reply area)... */
+ reply_sz = sizeof(config_reply);
+ memset(&config_reply, 0, reply_sz);
+
+ /* Ultimate destination... */
+ page1 = &ioc->lan_cnfg_page1;
+ data_sz = sizeof(*page1);
+ memset(page1, 0, data_sz);
+
+ /* Request area (config_req on the stack right now!) */
+ req_sz = sizeof(config_req);
+ memset(&config_req, 0, req_sz);
+ config_req.Function = MPI_FUNCTION_CONFIG;
+ config_req.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+ /* config_req.Header.PageVersion = 0; */
+ /* config_req.Header.PageLength = 0; */
+ config_req.Header.PageNumber = 1;
+ config_req.Header.PageType = MPI_CONFIG_PAGETYPE_LAN;
+ /* config_req.PageAddress = 0; */
+ config_req.PageBufferSGE.u.Simple.FlagsLength = cpu_to_le32(
+ ((MPI_SGE_FLAGS_LAST_ELEMENT |
+ MPI_SGE_FLAGS_END_OF_BUFFER |
+ MPI_SGE_FLAGS_END_OF_LIST |
+ MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI_SGE_FLAGS_SYSTEM_ADDRESS |
+ MPI_SGE_FLAGS_32_BIT_ADDRESSING |
+ MPI_SGE_FLAGS_32_BIT_CONTEXT) << MPI_SGE_FLAGS_SHIFT) |
+ (u32)data_sz
+ );
+ page1_dma = pci_map_single(ioc->pcidev, page1, data_sz, PCI_DMA_FROMDEVICE);
+ config_req.PageBufferSGE.u.Simple.u.Address32 = cpu_to_le32(page1_dma);
+
+ dprintk((KERN_INFO MYNAM ": %s: Sending Config request LAN_PAGE_1\n",
+ ioc->name));
+
+ i = HandShakeReqAndReply(ioc, req_sz, (u32*)&config_req,
+ reply_sz, (u16*)&config_reply);
+ pci_unmap_single(ioc->pcidev, page1_dma, data_sz, PCI_DMA_FROMDEVICE);
+ if (i != 0)
+ return i;
+
+ /* Now byte swap the necessary LANPage1 fields */
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * SendEventNotification - Send EventNotification (on or off) request
+ * to MPT adapter.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @EvSwitch: Event switch flags
+ */
+static int
+SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
+{
+ EventNotification_t *evnp;
+
+ evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc->id);
+ if (evnp == NULL) {
+ dprintk((KERN_WARNING MYNAM ": %s: WARNING - Unable to allocate a event request frame!\n",
+ ioc->name));
+ return 0;
+ }
+ memset(evnp, 0, sizeof(*evnp));
+
+ dprintk((KERN_INFO MYNAM ": %s: Sending EventNotification(%d)\n", ioc->name, EvSwitch));
+
+ evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
+ evnp->ChainOffset = 0;
+ evnp->MsgFlags = 0;
+ evnp->Switch = EvSwitch;
+
+ mpt_put_msg_frame(mpt_base_index, ioc->id, (MPT_FRAME_HDR *)evnp);
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * SendEventAck - Send EventAck request to MPT adapter.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @evnp: Pointer to original EventNotification request
+ */
+static int
+SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
+{
+ EventAck_t *pAck;
+
+ if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) {
+ printk(KERN_WARNING MYNAM ": %s: WARNING - Unable to allocate event ACK request frame!\n",
+ ioc->name);
+ return -1;
+ }
+ memset(pAck, 0, sizeof(*pAck));
+
+ dprintk((KERN_INFO MYNAM ": %s: Sending EventAck\n", ioc->name));
+
+ pAck->Function = MPI_FUNCTION_EVENT_ACK;
+ pAck->ChainOffset = 0;
+ pAck->MsgFlags = 0;
+ pAck->Event = evnp->Event;
+ pAck->EventContext = evnp->EventContext;
+
+ mpt_put_msg_frame(mpt_base_index, ioc->id, (MPT_FRAME_HDR *)pAck);
+
+ return 0;
+}
+
+#ifdef CONFIG_PROC_FS /* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
+ */
+
+#define PROC_MPT_READ_RETURN(page,start,off,count,eof,len) \
+{ \
+ len -= off; \
+ if (len < count) { \
+ *eof = 1; \
+ if (len <= 0) \
+ return 0; \
+ } else \
+ len = count; \
+ *start = page + off; \
+ return len; \
+}
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+procmpt_create(void)
+{
+ MPT_ADAPTER *ioc;
+ struct proc_dir_entry *ent;
+ int errcnt = 0;
+
+ /*
+ * BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt"
+ * (single level) to multi level (e.g. "driver/message/fusion")
+ * something here needs to change. -sralston
+ */
+ procmpt_root_dir = CREATE_PROCDIR_ENTRY(MPT_PROCFS_MPTBASEDIR, NULL);
+ if (procmpt_root_dir == NULL)
+ return -ENOTDIR;
+
+ if ((ioc = mpt_adapter_find_first()) != NULL) {
+ ent = create_proc_read_entry(MPT_PROCFS_SUMMARY_NODE, 0, NULL, procmpt_read_summary, NULL);
+ if (ent == NULL) {
+ printk(KERN_WARNING MYNAM ": WARNING - Could not create %s entry!\n",
+ MPT_PROCFS_SUMMARY_PATHNAME);
+ errcnt++;
+ }
+ }
+
+ while (ioc != NULL) {
+ char pname[32];
+ int namelen;
+ /*
+ * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
+ */
+ namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
+ if ((ent = CREATE_PROCDIR_ENTRY(pname, NULL)) != NULL) {
+ /*
+ * And populate it with: "summary" and "dbg" file entries.
+ */
+ (void) sprintf(pname+namelen, "/summary");
+ ent = create_proc_read_entry(pname, 0, NULL, procmpt_read_summary, ioc);
+ if (ent == NULL) {
+ errcnt++;
+ printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n",
+ ioc->name, pname);
+ }
+//#ifdef MPT_DEBUG
+ /* DEBUG aid! */
+ (void) sprintf(pname+namelen, "/dbg");
+ ent = create_proc_read_entry(pname, 0, NULL, procmpt_read_dbg, ioc);
+ if (ent == NULL) {
+ errcnt++;
+ printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n",
+ ioc->name, pname);
+ }
+//#endif
+ } else {
+ errcnt++;
+ printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n",
+ ioc->name, pname);
+
+ }
+
+ ioc = mpt_adapter_find_next(ioc);
+ }
+
+ if (errcnt) {
+// remove_proc_entry("mpt", 0);
+ return -ENOTDIR;
+ }
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+procmpt_destroy(void)
+{
+ MPT_ADAPTER *ioc;
+
+ /*
+ * BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt"
+ * (single level) to multi level (e.g. "driver/message/fusion")
+ * something here needs to change. -sralston
+ */
+
+ ioc = mpt_adapter_find_first();
+ if (ioc != NULL) {
+ remove_proc_entry(MPT_PROCFS_SUMMARY_NODE, 0);
+ }
+
+ while (ioc != NULL) {
+ char pname[32];
+ int namelen;
+ /*
+ * Tear down each "/proc/mpt/iocN" subdirectory.
+ */
+ namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
+ (void) sprintf(pname+namelen, "/summary");
+ remove_proc_entry(pname, 0);
+//#ifdef MPT_DEBUG
+ (void) sprintf(pname+namelen, "/dbg");
+ remove_proc_entry(pname, 0);
+//#endif
+ (void) sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
+ remove_proc_entry(pname, 0);
+
+ ioc = mpt_adapter_find_next(ioc);
+ }
+
+ if (atomic_read((atomic_t *)&procmpt_root_dir->count) == 0) {
+ remove_proc_entry(MPT_PROCFS_MPTBASEDIR, 0);
+ return 0;
+ }
+
+ return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * procmpt_read_summary - Handle read request from /proc/mpt/summary
+ * or from /proc/mpt/iocN/summary.
+ * @page: Pointer to area to write information
+ * @start: Pointer to start pointer
+ * @off: Offset to start writing
+ * @count:
+ * @eof: Pointer to EOF integer
+ * @data: Pointer
+ *
+ * Returns numbers of characters written to process performing the read.
+ */
+static int
+procmpt_read_summary(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ MPT_ADAPTER *ioc;
+ char *out = page;
+ int len;
+
+ if (data == NULL)
+ ioc = mpt_adapter_find_first();
+ else
+ ioc = data;
+
+// Too verbose!
+// out += sprintf(out, "Attached Fusion MPT I/O Controllers:%s\n", ioc ? "" : " none");
+
+ while (ioc) {
+ int more = 0;
+
+// Too verbose!
+// mpt_print_ioc_facts(ioc, out, &more, 0);
+ mpt_print_ioc_summary(ioc, out, &more, 0);
+
+ out += more;
+ if ((out-page) >= count) {
+ break;
+ }
+
+ if (data == NULL)
+ ioc = mpt_adapter_find_next(ioc);
+ else
+ ioc = NULL; /* force exit for iocN */
+ }
+ len = out - page;
+
+ PROC_MPT_READ_RETURN(page,start,off,count,eof,len);
+}
+
+// debug aid!
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * procmpt_read_dbg - Handle read request from /proc/mpt/iocN/dbg.
+ * @page: Pointer to area to write information
+ * @start: Pointer to start pointer
+ * @off: Offset to start writing
+ * @count:
+ * @eof: Pointer to EOF integer
+ * @data: Pointer
+ *
+ * Returns numbers of characters written to process performing the read.
+ */
+static int
+procmpt_read_dbg(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ MPT_ADAPTER *ioc;
+ char *out = page;
+ int len;
+
+ ioc = data;
+
+ while (ioc) {
+ int more = 0;
+
+ mpt_print_ioc_facts(ioc, out, &more, 0);
+
+ out += more;
+ if ((out-page) >= count) {
+ break;
+ }
+ ioc = NULL;
+ }
+ len = out - page;
+
+ PROC_MPT_READ_RETURN(page,start,off,count,eof,len);
+}
+#endif /* CONFIG_PROC_FS } */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
+{
+ if ((ioc->facts0.FWVersion & 0xF000) == 0xE000)
+ sprintf(buf, " (Exp %02d%02d)",
+ (ioc->facts0.FWVersion & 0x0F00) >> 8, /* Month */
+ ioc->facts0.FWVersion & 0x001F); /* Day */
+ else
+ buf[0] ='\0';
+
+ /* insider hack! */
+ if (ioc->facts0.FWVersion & 0x0080) {
+ strcat(buf, " [MDBG]");
+ }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @buffer: Pointer to buffer where IOC summary info should be written
+ * @size: Pointer to number of bytes we wrote (set by this routine)
+ * @len: Offset at which to start writing in buffer
+ *
+ * This routine writes (english readable) ASCII text, which represents
+ * a summary of IOC information, to a buffer.
+ */
+void
+mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len)
+{
+ char expVer[32];
+ int y;
+
+
+ mpt_get_fw_exp_ver(expVer, ioc);
+
+ /*
+ * Shorter summary of attached ioc's...
+ */
+ y = sprintf(buffer+len, "%s: %s, %s%04xh%s, Ports=%d, MaxQ=%d",
+ ioc->name,
+ ioc->prod_name,
+ MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
+ ioc->facts0.FWVersion,
+ expVer,
+ ioc->facts0.NumberOfPorts,
+ ioc->req_depth);
+
+ if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+ u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
+ y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
+ a[5], a[4], a[3], a[2], a[1], a[0]);
+ }
+
+ if (!ioc->active)
+ y += sprintf(buffer+len+y, " (disabled)");
+
+ y += sprintf(buffer+len+y, "\n");
+
+ *size = y;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mpt_print_ioc_facts - Write ASCII summary of IOC facts to a buffer.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @buffer: Pointer to buffer where IOC facts should be written
+ * @size: Pointer to number of bytes we wrote (set by this routine)
+ * @len: Offset at which to start writing in buffer
+ *
+ * This routine writes (english readable) ASCII text, which represents
+ * a summary of the IOC facts, to a buffer.
+ */
+void
+mpt_print_ioc_facts(MPT_ADAPTER *ioc, char *buffer, int *size, int len)
+{
+ char expVer[32];
+ char iocName[16];
+ int sz;
+ int y;
+
+
+ mpt_get_fw_exp_ver(expVer, ioc);
+
+ strcpy(iocName, ioc->name);
+ y = sprintf(buffer+len, "%s:\n", iocName);
+
+ y += sprintf(buffer+len+y, " ProductID = 0x%04x\n", ioc->facts0.ProductID);
+ y += sprintf(buffer+len+y, " PortNumber = %d (of %d)\n",
+ ioc->pfacts0.PortNumber+1,
+ ioc->facts0.NumberOfPorts);
+ if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+ u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
+ y += sprintf(buffer+len+y, " LanAddr = 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
+ a[5], a[4], a[3], a[2], a[1], a[0]);
+ }
+ y += sprintf(buffer+len+y, " FWVersion = 0x%04x%s\n", ioc->facts0.FWVersion, expVer);
+ y += sprintf(buffer+len+y, " MsgVersion = 0x%04x\n", ioc->facts0.MsgVersion);
+ y += sprintf(buffer+len+y, " WhoInit = 0x%02x\n", ioc->facts0.WhoInit);
+ y += sprintf(buffer+len+y, " EventState = 0x%02x\n", ioc->facts0.EventState);
+ y += sprintf(buffer+len+y, " CurrentHostMfaHighAddr = 0x%08x\n",
+ ioc->facts0.CurrentHostMfaHighAddr);
+ y += sprintf(buffer+len+y, " CurrentSenseBufferHighAddr = 0x%08x\n",
+ ioc->facts0.CurrentSenseBufferHighAddr);
+ y += sprintf(buffer+len+y, " MaxChainDepth = 0x%02x frames\n", ioc->facts0.MaxChainDepth);
+ y += sprintf(buffer+len+y, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts0.BlockSize);
+
+ y += sprintf(buffer+len+y, " RequestFrames @ 0x%p (Dma @ 0x%08x)\n",
+ ioc->req_alloc, ioc->req_alloc_dma);
+ /*
+ * Rounding UP to nearest 4-kB boundary here...
+ */
+ sz = (ioc->req_sz * ioc->req_depth) + 128;
+ sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
+ y += sprintf(buffer+len+y, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
+ ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
+ y += sprintf(buffer+len+y, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
+ 4*ioc->facts0.RequestFrameSize,
+ ioc->facts0.GlobalCredits);
+
+ y += sprintf(buffer+len+y, " ReplyFrames @ 0x%p (Dma @ 0x%08x)\n",
+ ioc->reply_alloc, ioc->reply_alloc_dma);
+ sz = (ioc->reply_sz * ioc->reply_depth) + 128;
+ y += sprintf(buffer+len+y, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
+ ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
+ y += sprintf(buffer+len+y, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
+ ioc->factsN.CurReplyFrameSize,
+ ioc->facts0.ReplyQueueDepth);
+
+ *size = y;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static char *
+EventDescriptionStr(u8 event, u32 evData0)
+{
+ char *ds = NULL;
+
+ switch(event) {
+ case MPI_EVENT_NONE:
+ ds = "None";
+ break;
+ case MPI_EVENT_LOG_DATA:
+ ds = "Log Data";
+ break;
+ case MPI_EVENT_STATE_CHANGE:
+ ds = "State Change";
+ break;
+ case MPI_EVENT_UNIT_ATTENTION:
+ ds = "Unit Attention";
+ break;
+ case MPI_EVENT_IOC_BUS_RESET:
+ ds = "IOC Bus Reset";
+ break;
+ case MPI_EVENT_EXT_BUS_RESET:
+ ds = "External Bus Reset";
+ break;
+ case MPI_EVENT_RESCAN:
+ ds = "Bus Rescan Event";
+ /* Ok, do we need to do anything here? As far as
+ I can tell, this is when a new device gets added
+ to the loop. */
+ break;
+ case MPI_EVENT_LINK_STATUS_CHANGE:
+ if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
+ ds = "Link Status(FAILURE) Change";
+ else
+ ds = "Link Status(ACTIVE) Change";
+ break;
+ case MPI_EVENT_LOOP_STATE_CHANGE:
+ if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
+ ds = "Loop State(LIP) Change";
+ else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
+ ds = "Loop State(LPE) Change"; /* ??? */
+ else
+ ds = "Loop State(LPB) Change"; /* ??? */
+ break;
+ case MPI_EVENT_LOGOUT:
+ ds = "Logout";
+ break;
+ case MPI_EVENT_EVENT_CHANGE:
+ if (evData0)
+ ds = "Events(ON) Change";
+ else
+ ds = "Events(OFF) Change";
+ break;
+ /*
+ * MPT base "custom" events may be added here...
+ */
+ default:
+ ds = "Unknown";
+ break;
+ }
+ return ds;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * ProcessEventNotification - Route a received EventNotificationReply to
+ * all currently regeistered event handlers.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @pEventReply: Pointer to EventNotification reply frame
+ * @evHandlers: Pointer to integer, number of event handlers
+ *
+ * Returns sum of event handlers return values.
+ */
+static int
+ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
+{
+ u16 evDataLen;
+ u32 evData0 = 0;
+// u32 evCtx;
+ int i;
+ int r = 0;
+ int handlers = 0;
+ char *evStr;
+ u8 event;
+
+ /*
+ * Do platform normalization of values
+ */
+ event = le32_to_cpu(pEventReply->Event) & 0xFF;
+// evCtx = le32_to_cpu(pEventReply->EventContext);
+ evDataLen = le16_to_cpu(pEventReply->EventDataLength);
+ if (evDataLen) {
+ evData0 = le32_to_cpu(pEventReply->Data[0]);
+ }
+
+ evStr = EventDescriptionStr(event, evData0);
+ dprintk((KERN_INFO MYNAM ": %s: MPT event (%s=%02Xh) detected!\n",
+ ioc->name,
+ evStr,
+ event));
+
+#if defined(MPT_DEBUG) || defined(MPT_DEBUG_EVENTS)
+ printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
+ for (i = 0; i < evDataLen; i++)
+ printk(" %08x", le32_to_cpu(pEventReply->Data[i]));
+ printk("\n");
+#endif
+
+ /*
+ * Do general / base driver event processing
+ */
+ switch(event) {
+ case MPI_EVENT_NONE: /* 00 */
+ case MPI_EVENT_LOG_DATA: /* 01 */
+ case MPI_EVENT_STATE_CHANGE: /* 02 */
+ case MPI_EVENT_UNIT_ATTENTION: /* 03 */
+ case MPI_EVENT_IOC_BUS_RESET: /* 04 */
+ case MPI_EVENT_EXT_BUS_RESET: /* 05 */
+ case MPI_EVENT_RESCAN: /* 06 */
+ case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
+ case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
+ case MPI_EVENT_LOGOUT: /* 09 */
+ default:
+ break;
+ case MPI_EVENT_EVENT_CHANGE: /* 0A */
+ if (evDataLen) {
+ u8 evState = evData0 & 0xFF;
+
+ /* CHECKME! What if evState unexpectedly says OFF (0)? */
+
+ /* Update EventState field in cached IocFacts */
+ if (ioc->factsN.Function) {
+ ioc->factsN.EventState = evState;
+ }
+ }
+ break;
+ }
+
+ /*
+ * Call each currently registered protocol event handler.
+ */
+ for (i=MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
+ if (MptEvHandlers[i]) {
+ dprintk((KERN_INFO MYNAM ": %s: Routing Event to event handler #%d\n",
+ ioc->name, i));
+ r += (*(MptEvHandlers[i]))(ioc, pEventReply);
+ handlers++;
+ }
+ }
+ /* FIXME? Examine results here? */
+
+ /*
+ * If needed, send (a single) EventAck.
+ */
+ if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
+ if ((i = SendEventAck(ioc, pEventReply)) != 0) {
+ }
+ }
+
+ *evHandlers = handlers;
+ return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @log_info: U32 LogInfo reply word from the IOC
+ *
+ * Refer to lsi/fc_log.h.
+ */
+static void
+mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
+{
+ static char *subcl_str[8] = {
+ "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
+ "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
+ };
+ char *desc = "unknown";
+ u8 subcl = (log_info >> 24) & 0x7;
+ u32 SubCl = log_info & 0x27000000;
+
+ switch(log_info) {
+/* FCP Initiator */
+ case MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME:
+ desc = "Received an out of order frame - unsupported";
+ break;
+ case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME:
+ desc = "Bad start of frame primative";
+ break;
+ case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME:
+ desc = "Bad end of frame primative";
+ break;
+ case MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN:
+ desc = "Receiver hardware detected overrun";
+ break;
+ case MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER:
+ desc = "Other errors caught by IOC which require retries";
+ break;
+ case MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD:
+ desc = "Main processor could not initialize sub-processor";
+ break;
+/* FC Target */
+ case MPI_IOCLOGINFO_FC_TARGET_NO_PDISC:
+ desc = "Not sent because we are waiting for a PDISC from the initiator";
+ break;
+ case MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN:
+ desc = "Not sent because we are not logged in to the remote node";
+ break;
+ case MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP:
+ desc = "Data Out, Auto Response, not sent due to a LIP";
+ break;
+ case MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP:
+ desc = "Data In, Auto Response, not sent due to a LIP";
+ break;
+ case MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA:
+ desc = "Data In, Auto Response, missing data frames";
+ break;
+ case MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP:
+ desc = "Data Out, No Response, not sent due to a LIP";
+ break;
+ case MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP:
+ desc = "Auto-response after a write not sent due to a LIP";
+ break;
+ case MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP:
+ desc = "Data In, No Response, not completed due to a LIP";
+ break;
+ case MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA:
+ desc = "Data In, No Response, missing data frames";
+ break;
+ case MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP:
+ desc = "Manual Response not sent due to a LIP";
+ break;
+ case MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3:
+ desc = "Not sent because remote node does not support Class 3";
+ break;
+ case MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID:
+ desc = "Not sent because login to remote node not validated";
+ break;
+ case MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND:
+ desc = "Cleared from the outbound after a logout";
+ break;
+ case MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN:
+ desc = "Cleared waiting for data after a logout";
+ break;
+/* LAN */
+ case MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING:
+ desc = "Transaction Context Sgl Missing";
+ break;
+ case MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE:
+ desc = "Transaction Context found before an EOB";
+ break;
+ case MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET:
+ desc = "Transaction Context value has reserved bits set";
+ break;
+ case MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG:
+ desc = "Invalid SGL Flags";
+ break;
+/* FC Link */
+ case MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT:
+ desc = "Loop initialization timed out";
+ break;
+ case MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED:
+ desc = "Another system controller already initialized the loop";
+ break;
+ case MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED:
+ desc = "Not synchronized to signal or still negotiating (possible cable problem)";
+ break;
+ }
+
+ printk(KERN_INFO MYNAM ": %s: LogInfo(0x%08x): SubCl={%s}",
+ ioc->name, log_info, subcl_str[subcl]);
+ if (SubCl == MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET)
+ printk(", byte_offset=%d\n", log_info & MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET);
+ else if (SubCl == MPI_IOCLOGINFO_FC_STATE_CHANGE)
+ printk("\n"); /* StateChg in LogInfo & 0x00FFFFFF, above */
+ else
+ printk("\n" KERN_INFO " %s\n", desc);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * mpt_sp_log_info - Log information returned from SCSI Parallel IOC.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @mr: Pointer to MPT reply frame
+ * @log_info: U32 LogInfo word from the IOC
+ *
+ * Refer to lsi/sp_log.h.
+ */
+static void
+mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info)
+{
+ /* FIXME! */
+ printk(KERN_INFO MYNAM ": %s: LogInfo(0x%08x)\n", ioc->name, log_info);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mpt_register_ascqops_strings - Register SCSI ASC/ASCQ and SCSI
+ * OpCode strings from the (optional) isense module.
+ * @ascqTable: Pointer to ASCQ_Table_t structure
+ * @ascqtbl_sz: Number of entries in ASCQ_Table
+ * @opsTable: Pointer to array of SCSI OpCode strings (char pointers)
+ *
+ * Specialized driver registration routine for the isense driver.
+ */
+int
+mpt_register_ascqops_strings(/*ASCQ_Table_t*/void *ascqTable, int ascqtbl_sz, const char **opsTable)
+{
+ int r = 0;
+
+ if (ascqTable && ascqtbl_sz && opsTable) {
+ mpt_v_ASCQ_TablePtr = ascqTable;
+ mpt_ASCQ_TableSz = ascqtbl_sz;
+ mpt_ScsiOpcodesPtr = opsTable;
+ printk(KERN_INFO MYNAM ": English readable SCSI-3 strings enabled:-)\n");
+ r = 1;
+ }
+ MOD_INC_USE_COUNT;
+ return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mpt_deregister_ascqops_strings - Deregister SCSI ASC/ASCQ and SCSI
+ * OpCode strings from the isense driver.
+ *
+ * Specialized driver deregistration routine for the isense driver.
+ */
+void
+mpt_deregister_ascqops_strings(void)
+{
+ mpt_v_ASCQ_TablePtr = NULL;
+ mpt_ASCQ_TableSz = 0;
+ mpt_ScsiOpcodesPtr = NULL;
+ printk(KERN_INFO MYNAM ": English readable SCSI-3 strings disabled)-:\n");
+ MOD_DEC_USE_COUNT;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+EXPORT_SYMBOL(mpt_register);
+EXPORT_SYMBOL(mpt_deregister);
+EXPORT_SYMBOL(mpt_event_register);
+EXPORT_SYMBOL(mpt_event_deregister);
+EXPORT_SYMBOL(mpt_get_msg_frame);
+EXPORT_SYMBOL(mpt_put_msg_frame);
+EXPORT_SYMBOL(mpt_free_msg_frame);
+EXPORT_SYMBOL(mpt_send_handshake_request);
+EXPORT_SYMBOL(mpt_adapter_find_first);
+EXPORT_SYMBOL(mpt_adapter_find_next);
+EXPORT_SYMBOL(mpt_verify_adapter);
+EXPORT_SYMBOL(mpt_print_ioc_summary);
+EXPORT_SYMBOL(mpt_lan_index);
+EXPORT_SYMBOL(mpt_stm_index);
+
+EXPORT_SYMBOL(mpt_register_ascqops_strings);
+EXPORT_SYMBOL(mpt_deregister_ascqops_strings);
+EXPORT_SYMBOL(mpt_v_ASCQ_TablePtr);
+EXPORT_SYMBOL(mpt_ASCQ_TableSz);
+EXPORT_SYMBOL(mpt_ScsiOpcodesPtr);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * fusion_init - Fusion MPT base driver initialization routine.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int __init fusion_init(void)
+{
+ int i;
+
+ if (FusionInitCalled++) {
+ dprintk((KERN_INFO MYNAM ": INFO - Driver late-init entry point called\n"));
+ return 0;
+ }
+
+ show_mptmod_ver(my_NAME, my_VERSION);
+ printk(KERN_INFO COPYRIGHT "\n");
+
+ Q_INIT(&MptAdapters, MPT_ADAPTER); /* set to empty */
+ for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
+ MptCallbacks[i] = NULL;
+ MptDriverClass[i] = MPTUNKNOWN_DRIVER;
+ MptEvHandlers[i] = NULL;
+ }
+
+ /* NEW! 20010120 -sralston
+ * Register ourselves (mptbase) in order to facilitate
+ * EventNotification handling.
+ */
+ mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
+
+ if ((i = mpt_pci_scan()) < 0)
+ return i;
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * fusion_exit - Perform driver unload cleanup.
+ *
+ * This routine frees all resources associated with each MPT adapter
+ * and removes all %MPT_PROCFS_MPTBASEDIR entries.
+ */
+static void fusion_exit(void)
+{
+ MPT_ADAPTER *this;
+ int i;
+
+ dprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
+
+ /*
+ * Paranoia; disable interrupts on all MPT adapters.
+ */
+ for (i=0; i<MPT_MAX_ADAPTERS; i++) {
+ if ((this = mpt_adapters[i]) != NULL) {
+ /* Disable adapter interrupts! */
+ CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF);
+ /* Clear any lingering interrupt */
+ CHIPREG_WRITE32(&this->chip->IntStatus, 0);
+ this->active = 0;
+ }
+ }
+
+ /* Whups? 20010120 -sralston
+ * Moved this *above* removal of all MptAdapters!
+ */
+#ifdef CONFIG_PROC_FS
+ procmpt_destroy();
+#endif
+
+ while (! Q_IS_EMPTY(&MptAdapters)) {
+ this = MptAdapters.head;
+ Q_DEL_ITEM(this);
+ mpt_adapter_dispose(this);
+ }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+module_init(fusion_init);
+module_exit(fusion_exit);
--- /dev/null
+/*
+ * linux/drivers/message/fusion/mptbase.h
+ * High performance SCSI + LAN / Fibre Channel device drivers.
+ * For use with PCI chip/adapter(s):
+ * LSIFC9xx/LSI409xx Fibre Channel
+ * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ * Credits:
+ * (see mptbase.c)
+ *
+ * Copyright (c) 1999-2001 LSI Logic Corporation
+ * Originally By: Steven J. Ralston
+ * (mailto:Steve.Ralston@lsil.com)
+ *
+ * $Id: mptbase.h,v 1.38 2001/03/22 10:54:30 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ 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; version 2 of the License.
+
+ 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.
+
+ NO WARRANTY
+ THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ solely responsible for determining the appropriateness of using and
+ distributing the Program and assumes all risks associated with its
+ exercise of rights under this Agreement, including but not limited to
+ the risks and costs of program errors, damage to or loss of data,
+ programs or equipment, and unavailability or interruption of operations.
+
+ DISCLAIMER OF LIABILITY
+ NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef MPTBASE_H_INCLUDED
+#define MPTBASE_H_INCLUDED
+/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include "linux_compat.h" /* linux-2.2.x (vs. -2.4.x) tweaks */
+
+#include "lsi/mpi_type.h"
+#include "lsi/mpi.h" /* Fusion MPI(nterface) basic defs */
+#include "lsi/mpi_ioc.h" /* Fusion MPT IOC(ontroller) defs */
+#include "lsi/mpi_cnfg.h" /* IOC configuration support */
+#include "lsi/mpi_init.h" /* SCSI Host (initiator) protocol support */
+#include "lsi/mpi_lan.h" /* LAN over FC protocol support */
+
+//#include "lsi/mpi_fc.h" /* Fibre Channel (lowlevel) support */
+//#include "lsi/mpi_targ.h" /* SCSI/FCP Target protcol support */
+#include "lsi/fc_log.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#ifndef MODULEAUTHOR
+#define MODULEAUTHOR "LSI Logic Corporation"
+#endif
+
+#ifndef COPYRIGHT
+#define COPYRIGHT "Copyright (c) 1999-2001 " MODULEAUTHOR
+#endif
+
+#define MPT_LINUX_VERSION_COMMON "1.00.11"
+#define MPT_LINUX_VERSION_EXP "0.09.66-EXP"
+#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-1.00.11"
+#define WHAT_MAGIC_STRING "@" "(" "#" ")"
+
+#define show_mptmod_ver(s,ver) \
+ printk(KERN_INFO "%s %s\n", s, ver);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Fusion MPT(linux) driver configurable stuff...
+ */
+#define MPT_MAX_ADAPTERS 16
+#define MPT_MAX_PROTOCOL_DRIVERS 8
+
+#define MPT_MISCDEV_BASENAME "mptctl"
+#define MPT_MISCDEV_PATHNAME "/dev/" MPT_MISCDEV_BASENAME
+
+#define MPT_PROCFS_MPTBASEDIR "mpt"
+ /* chg it to "driver/fusion" ? */
+#define MPT_PROCFS_SUMMARY_NODE MPT_PROCFS_MPTBASEDIR "/summary"
+#define MPT_PROCFS_SUMMARY_PATHNAME "/proc/" MPT_PROCFS_SUMMARY_NODE
+#define MPT_FW_REV_MAGIC_ID_STRING "FwRev="
+
+#ifdef __KERNEL__ /* { */
+#define MPT_MAX_REQ_DEPTH 1023
+#define MPT_REQ_DEPTH 256
+#define MPT_MIN_REQ_DEPTH 128
+
+#define MPT_MAX_REPLY_DEPTH MPT_MAX_REQ_DEPTH
+#define MPT_REPLY_DEPTH 128
+#define MPT_MIN_REPLY_DEPTH 8
+#define MPT_MAX_REPLIES_PER_ISR 32
+
+#define MPT_MAX_FRAME_SIZE 128
+#define MPT_REQ_SIZE 128
+#define MPT_REPLY_SIZE 128
+
+#define MPT_SG_BUCKETS_PER_HUNK 1
+
+#ifdef MODULE
+#define MPT_REQ_DEPTH_RANGE_STR __MODULE_STRING(MPT_MIN_REQ_DEPTH) "-" __MODULE_STRING(MPT_MAX_REQ_DEPTH)
+#define MPT_REPLY_DEPTH_RANGE_STR __MODULE_STRING(MPT_MIN_REPLY_DEPTH) "-" __MODULE_STRING(MPT_MAX_REPLY_DEPTH)
+#define MPT_REPLY_SIZE_RANGE_STR __MODULE_STRING(MPT_MIN_REPLY_SIZE) "-" __MODULE_STRING(MPT_MAX_FRAME_SIZE)
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * MPT protocol driver defs...
+ */
+typedef enum {
+ MPTBASE_DRIVER, /* MPT base class */
+ MPTCTL_DRIVER, /* MPT ioctl class */
+ MPTSCSIH_DRIVER, /* MPT SCSI host (initiator) class */
+ MPTLAN_DRIVER, /* MPT LAN class */
+ MPTSTM_DRIVER, /* MPT SCSI target mode class */
+ MPTUNKNOWN_DRIVER
+} MPT_DRIVER_CLASS;
+
+/*
+ * MPT adapter / port / bus / device info structures...
+ */
+
+typedef union _MPT_FRAME_TRACKER {
+ struct {
+ struct _MPT_FRAME_HDR *forw;
+ struct _MPT_FRAME_HDR *back;
+ u32 arg1;
+ void *argp1;
+ } linkage;
+ /*
+ * NOTE: On non-32-bit systems, where pointers are LARGE,
+ * using the linkage pointers destroys our sacred MsgContext
+ * field contents. But we don't care anymore because these
+ * are now reset in mpt_put_msg_frame() just prior to sending
+ * a request off to the IOC.
+ */
+ struct {
+ u32 __hdr[2];
+ /*
+ * The following _MUST_ match the location of the
+ * MsgContext field in the MPT message headers.
+ */
+ union {
+ u32 MsgContext;
+ struct {
+ u16 req_idx; /* Request index */
+ u8 cb_idx; /* callback function index */
+ u8 rsvd;
+ } fld;
+ } msgctxu;
+ } hwhdr;
+} MPT_FRAME_TRACKER;
+
+/*
+ * We might want to view/access a frame as:
+ * 1) generic request header
+ * 2) SCSIIORequest
+ * 3) SCSIIOReply
+ * 4) MPIDefaultReply
+ * 5) frame tracker
+ */
+typedef struct _MPT_FRAME_HDR {
+ union {
+ MPIHeader_t hdr;
+ SCSIIORequest_t scsireq;
+ SCSIIOReply_t sreply;
+ MPIDefaultReply_t reply;
+ MPT_FRAME_TRACKER frame;
+ } u;
+} MPT_FRAME_HDR;
+
+typedef struct _MPT_Q_TRACKER {
+ MPT_FRAME_HDR *head;
+ MPT_FRAME_HDR *tail;
+} MPT_Q_TRACKER;
+
+
+typedef struct _MPT_SGL_HDR {
+ SGESimple32_t sge[1];
+} MPT_SGL_HDR;
+
+typedef struct _MPT_SGL64_HDR {
+ SGESimple64_t sge[1];
+} MPT_SGL64_HDR;
+
+
+typedef struct _Q_ITEM {
+ struct _Q_ITEM *forw;
+ struct _Q_ITEM *back;
+} Q_ITEM;
+
+typedef struct _Q_TRACKER {
+ struct _Q_ITEM *head;
+ struct _Q_ITEM *tail;
+} Q_TRACKER;
+
+
+/*
+ * Chip-specific stuff...
+ */
+
+typedef enum {
+ FC909 = 0x0909,
+ FC919 = 0x0919,
+ FC929 = 0x0929,
+ C1030 = 0x1030,
+ FCUNK = 0xFBAD
+} CHIP_TYPE;
+
+/*
+ * System interface register set
+ */
+
+typedef struct _SYSIF_REGS
+{
+ u32 Doorbell; /* 00 System<->IOC Doorbell reg */
+ u32 WriteSequence; /* 04 Write Sequence register */
+ u32 Diagnostic; /* 08 Diagnostic register */
+ u32 TestBase; /* 0C Test Base Address */
+ u32 Reserved1[8]; /* 10-2F reserved for future use */
+ u32 IntStatus; /* 30 Interrupt Status */
+ u32 IntMask; /* 34 Interrupt Mask */
+ u32 Reserved2[2]; /* 38-3F reserved for future use */
+ u32 RequestFifo; /* 40 Request Post/Free FIFO */
+ u32 ReplyFifo; /* 44 Reply Post/Free FIFO */
+ u32 Reserved3[2]; /* 48-4F reserved for future use */
+ u32 HostIndex; /* 50 Host Index register */
+ u32 Reserved4[15]; /* 54-8F */
+ u32 Fubar; /* 90 For Fubar usage */
+ u32 Reserved5[27]; /* 94-FF */
+} SYSIF_REGS;
+
+/*
+ * NOTE: Use MPI_{DOORBELL,WRITESEQ,DIAG}_xxx defs in lsi/mpi.h
+ * in conjunction with SYSIF_REGS accesses!
+ */
+
+
+typedef struct _MPT_ADAPTER
+{
+ struct _MPT_ADAPTER *forw;
+ struct _MPT_ADAPTER *back;
+ int id; /* Unique adapter id {0,1,2,...} */
+ int pci_irq;
+ IOCFactsReply_t facts0;
+ IOCFactsReply_t factsN;
+ char name[32]; /* "iocN" */
+ char *prod_name; /* "LSIFC9x9" */
+ u32 mem_phys; /* == f4020000 (mmap) */
+ volatile SYSIF_REGS *chip; /* == c8817000 (mmap) */
+ CHIP_TYPE chip_type;
+ int mem_size;
+ int alloc_total;
+ u32 last_state;
+ int active;
+ int sod_reset;
+ unsigned long last_kickstart;
+ PortFactsReply_t pfacts0;
+ PortFactsReply_t pfactsN;
+ LANPage0_t lan_cnfg_page0;
+ LANPage1_t lan_cnfg_page1;
+ u8 *reply_alloc; /* Reply frames alloc ptr */
+ dma_addr_t reply_alloc_dma;
+ MPT_FRAME_HDR *reply_frames; /* Reply frames - rounded up! */
+ dma_addr_t reply_frames_dma;
+ int reply_depth;
+ int reply_sz;
+ /* We (host driver) get to manage our own RequestQueue! */
+ u8 *req_alloc; /* Request frames alloc ptr */
+ dma_addr_t req_alloc_dma;
+ MPT_FRAME_HDR *req_frames; /* Request msg frames for PULL mode! */
+ dma_addr_t req_frames_dma;
+ int req_depth;
+ int req_sz;
+ spinlock_t FreeQlock;
+ MPT_Q_TRACKER FreeQ;
+ /* Pool of SCSI sense buffers for commands coming from
+ * the SCSI mid-layer. We have one 256 byte sense buffer
+ * for each REQ entry.
+ */
+ u8 *sense_buf_pool;
+ dma_addr_t sense_buf_pool_dma;
+ int hs_reply_idx;
+ u32 hs_req[MPT_MAX_FRAME_SIZE/sizeof(u32)];
+ u16 hs_reply[MPT_MAX_FRAME_SIZE/sizeof(u16)];
+ struct pci_dev *pcidev;
+ struct _MPT_ADAPTER *alt_ioc;
+/* atomic_t userCnt; */
+ u8 *memmap;
+ int mtrr_reg;
+ struct Scsi_Host *sh;
+ struct proc_dir_entry *ioc_dentry;
+} MPT_ADAPTER;
+
+
+typedef struct _MPT_ADAPTER_TRACKER {
+ MPT_ADAPTER *head;
+ MPT_ADAPTER *tail;
+} MPT_ADAPTER_TRACKER;
+
+/*
+ * New return value convention:
+ * 1 = Ok to free associated request frame
+ * 0 = not Ok ...
+ */
+typedef int (*MPT_CALLBACK)(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
+typedef int (*MPT_EVHANDLER)(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply);
+
+/*
+ * Fibre Channel (SCSI) target device...
+ */
+typedef struct _FC_TARGET {
+ struct _FC_TARGET *forw;
+ struct _FC_TARGET *back;
+ int bus_id;
+ int target_id;
+ int lun_exists[32];
+ u8 inquiry_data[36];
+ u8 last_sense[256];
+} FC_TARGET;
+
+typedef struct _FCDEV_TRACKER {
+ FC_TARGET *head;
+ FC_TARGET *tail;
+} FCDEV_TRACKER;
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Funky (private) macros...
+ */
+#ifdef MPT_DEBUG
+#define dprintk(x) printk x
+#else
+#define dprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_HANDSHAKE
+#define dhsprintk(x) printk x
+#else
+#define dhsprintk(x)
+#endif
+
+#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME)
+#define dmfprintk(x) printk x
+#else
+#define dmfprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_IRQ
+#define dirqprintk(x) printk x
+#else
+#define dirqprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_EVENTS
+#define deventprintk(x) printk x
+#else
+#define deventprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_SPINLOCK
+#define dslprintk(x) printk x
+#else
+#define dslprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_SG
+#define dsgprintk(x) printk x
+#else
+#define dsgprintk(x)
+#endif
+
+
+#define MPT_INDEX_2_MFPTR(ioc,idx) \
+ (MPT_FRAME_HDR*)( (u8*)(ioc)->req_frames + (ioc)->req_sz * (idx) )
+
+#define MFPTR_2_MPT_INDEX(ioc,mf) \
+ (int)( ((u8*)mf - (u8*)(ioc)->req_frames) / (ioc)->req_sz )
+
+#define Q_INIT(q,type) (q)->head = (q)->tail = (type*)(q)
+#define Q_IS_EMPTY(q) ((Q_ITEM*)(q)->head == (Q_ITEM*)(q))
+
+#define Q_ADD_TAIL(qt,i,type) { \
+ Q_TRACKER *_qt = (Q_TRACKER*)(qt); \
+ Q_ITEM *oldTail = _qt->tail; \
+ (i)->forw = (type*)_qt; \
+ (i)->back = (type*)oldTail; \
+ oldTail->forw = (Q_ITEM*)(i); \
+ _qt->tail = (Q_ITEM*)(i); \
+}
+
+#define Q_ADD_HEAD(qt,i,type) { \
+ Q_TRACKER *_qt = (Q_TRACKER*)(qt); \
+ Q_ITEM *oldHead = _qt->head; \
+ (i)->forw = (type*)oldHead; \
+ (i)->back = (type*)_qt; \
+ oldHead->back = (Q_ITEM*)(i); \
+ _qt->head = (Q_ITEM*)(i); \
+}
+
+#define Q_DEL_ITEM(i) { \
+ Q_ITEM *_forw = (Q_ITEM*)(i)->forw; \
+ Q_ITEM *_back = (Q_ITEM*)(i)->back; \
+ _back->forw = _forw; \
+ _forw->back = _back; \
+}
+
+
+#define SWAB4(value) \
+ (u32)( (((value) & 0x000000ff) << 24) \
+ | (((value) & 0x0000ff00) << 8) \
+ | (((value) & 0x00ff0000) >> 8) \
+ | (((value) & 0xff000000) >> 24) )
+
+
+#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME)
+#define DBG_DUMP_REPLY_FRAME(mfp) \
+ { u32 *m = (u32 *)(mfp); \
+ int i, n = (le32_to_cpu(m[0]) & 0x00FF0000) >> 16; \
+ printk(KERN_INFO " "); \
+ for (i=0; i<n; i++) \
+ printk(" %08x", le32_to_cpu(m[i])); \
+ printk("\n"); \
+ }
+#define DBG_DUMP_REQUEST_FRAME_HDR(mfp) \
+ { int i, n = 3; \
+ u32 *m = (u32 *)(mfp); \
+ printk(KERN_INFO " "); \
+ for (i=0; i<n; i++) \
+ printk(" %08x", le32_to_cpu(m[i])); \
+ printk("\n"); \
+ }
+#else
+#define DBG_DUMP_REPLY_FRAME(mfp)
+#define DBG_DUMP_REQUEST_FRAME_HDR(mfp)
+#endif
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif /* } __KERNEL__ */
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*
+ * MPT Control IOCTLs and structures
+ */
+#define MPT_MAGIC_NUMBER 'm'
+#define MPTRWPERF _IOWR(MPT_MAGIC_NUMBER,0,struct mpt_raw_r_w)
+#define MPTRWPERF_CHK _IOR(MPT_MAGIC_NUMBER,13,struct mpt_raw_r_w)
+#define MPTRWPERF_RESET _IOR(MPT_MAGIC_NUMBER,14,struct mpt_raw_r_w)
+#define MPTFWDOWNLOAD _IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer)
+#define MPTSCSICMD _IOWR(MPT_MAGIC_NUMBER,16,struct mpt_scsi_cmd)
+
+/*
+ * Define something *vague* enough that caller doesn't
+ * really need to know anything about device parameters
+ * (blk_size, capacity, etc.)
+ */
+struct mpt_raw_r_w {
+ unsigned int iocnum; /* IOC unit number */
+ unsigned int port; /* IOC port number */
+ unsigned int target; /* SCSI Target */
+ unsigned int lun; /* SCSI LUN */
+ unsigned int iters; /* N iterations */
+ unsigned short nblks; /* number of blocks per IO */
+ unsigned short qdepth; /* max Q depth on this device */
+ unsigned char range; /* 0-100% of FULL disk capacity, 0=use (nblks X iters) */
+ unsigned char skip; /* % of disk to skip */
+ unsigned char rdwr; /* 0-100%, 0=pure ReaDs, 100=pure WRites */
+ unsigned char seqran; /* 0-100%, 0=pure SEQential, 100=pure RANdom */
+ unsigned int cache_sz; /* In Kb! Optimize hits to N Kb cache size */
+};
+
+struct mpt_fw_xfer {
+ unsigned int iocnum; /* IOC unit number */
+/* u8 flags;*/ /* Message flags - bit field */
+ unsigned int fwlen;
+ void *bufp; /* Pointer to firmware buffer */
+};
+
+struct mpt_scsi_cmd {
+ unsigned int iocnum; /* IOC unit number */
+ unsigned int port; /* IOC port number */
+ unsigned int target; /* SCSI Target */
+ unsigned int lun; /* SCSI LUN */
+ SCSIIORequest_t scsi_req;
+ SCSIIOReply_t scsi_reply;
+};
+
+struct mpt_ioctl_sanity {
+ unsigned int iocnum;
+};
+
+#ifdef __KERNEL__ /* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*
+ * Public entry points...
+ */
+extern int mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass);
+extern void mpt_deregister(int cb_idx);
+extern int mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc);
+extern void mpt_event_deregister(int cb_idx);
+extern int mpt_register_ascqops_strings(/*ASCQ_Table_t*/void *ascqTable, int ascqtbl_sz, const char **opsTable);
+extern void mpt_deregister_ascqops_strings(void);
+extern MPT_FRAME_HDR *mpt_get_msg_frame(int handle, int iocid);
+extern void mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf);
+extern void mpt_put_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf);
+extern int mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req);
+extern int mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp);
+extern MPT_ADAPTER *mpt_adapter_find_first(void);
+extern MPT_ADAPTER *mpt_adapter_find_next(MPT_ADAPTER *prev);
+extern void mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len);
+extern void mpt_print_ioc_facts(MPT_ADAPTER *ioc, char *buf, int *size, int len);
+
+/*
+ * Public data decl's...
+ */
+extern int mpt_lan_index; /* needed by mptlan.c */
+extern int mpt_stm_index; /* needed by mptstm.c */
+
+extern void *mpt_v_ASCQ_TablePtr;
+extern const char **mpt_ScsiOpcodesPtr;
+extern int mpt_ASCQ_TableSz;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif /* } __KERNEL__ */
+
+/*
+ * More (public) macros...
+ */
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef offsetof
+#define offsetof(t, m) ((size_t) (&((t *)0)->m))
+#endif
+
+#if defined(__alpha__) || defined(__sparc_v9__)
+#define CAST_U32_TO_PTR(x) ((void *)(u64)x)
+#define CAST_PTR_TO_U32(x) ((u32)(u64)x)
+#else
+#define CAST_U32_TO_PTR(x) ((void *)x)
+#define CAST_PTR_TO_U32(x) ((u32)x)
+#endif
+
+#define MPT_PROTOCOL_FLAGS_c_c_c_c(pflags) \
+ ((pflags) & MPI_PORTFACTS_PROTOCOL_INITIATOR) ? 'I' : 'i', \
+ ((pflags) & MPI_PORTFACTS_PROTOCOL_TARGET) ? 'T' : 't', \
+ ((pflags) & MPI_PORTFACTS_PROTOCOL_LAN) ? 'L' : 'l', \
+ ((pflags) & MPI_PORTFACTS_PROTOCOL_LOGBUSADDR) ? 'B' : 'b'
+
+/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif
+
--- /dev/null
+/*
+ * linux/drivers/message/fusion/mptctl.c
+ * Fusion MPT misc device (ioctl) driver.
+ * For use with PCI chip/adapter(s):
+ * LSIFC9xx/LSI409xx Fibre Channel
+ * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ * Credits:
+ * This driver would not exist if not for Alan Cox's development
+ * of the linux i2o driver.
+ *
+ * A huge debt of gratitude is owed to David S. Miller (DaveM)
+ * for fixing much of the stupid and broken stuff in the early
+ * driver while porting to sparc64 platform. THANK YOU!
+ *
+ * A big THANKS to Eddie C. Dost for fixing the ioctl path
+ * and most importantly f/w download on sparc64 platform!
+ * (plus Eddie's other helpful hints and insights)
+ *
+ * Thanks to Arnaldo Carvalho de Melo for finding and patching
+ * a potential memory leak in mpt_ioctl_do_fw_download(),
+ * and for some kmalloc insight:-)
+ *
+ * (see also mptbase.c)
+ *
+ * Copyright (c) 1999-2001 LSI Logic Corporation
+ * Originally By: Steven J. Ralston, Noah Romer
+ * (mailto:Steve.Ralston@lsil.com)
+ *
+ * $Id: mptctl.c,v 1.23 2001/03/21 19:42:31 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ 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; version 2 of the License.
+
+ 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.
+
+ NO WARRANTY
+ THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ solely responsible for determining the appropriateness of using and
+ distributing the Program and assumes all risks associated with its
+ exercise of rights under this Agreement, including but not limited to
+ the risks and costs of program errors, damage to or loss of data,
+ programs or equipment, and unavailability or interruption of operations.
+
+ DISCLAIMER OF LIABILITY
+ NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/miscdevice.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <linux/proc_fs.h>
+
+#define COPYRIGHT "Copyright (c) 1999-2001 LSI Logic Corporation"
+#define MODULEAUTHOR "Steven J. Ralston, Noah Romer"
+#include "mptbase.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#define my_NAME "Fusion MPT misc device (ioctl) driver"
+#define my_VERSION MPT_LINUX_VERSION_COMMON
+#define MYNAM "mptctl"
+
+EXPORT_NO_SYMBOLS;
+MODULE_AUTHOR(MODULEAUTHOR);
+MODULE_DESCRIPTION(my_NAME);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+static int mptctl_id = -1;
+static int rwperf_reset = 0;
+static struct semaphore mptctl_syscall_sem_ioc[MPT_MAX_ADAPTERS];
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+static int mpt_ioctl_rwperf(unsigned long arg);
+static int mpt_ioctl_rwperf_status(unsigned long arg);
+static int mpt_ioctl_rwperf_reset(unsigned long arg);
+static int mpt_ioctl_fw_download(unsigned long arg);
+static int mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen);
+static int mpt_ioctl_scsi_cmd(unsigned long arg);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Scatter gather list (SGL) sizes and limits...
+ */
+//#define MAX_SCSI_FRAGS 9
+#define MAX_FRAGS_SPILL1 9
+#define MAX_FRAGS_SPILL2 15
+#define FRAGS_PER_BUCKET (MAX_FRAGS_SPILL2 + 1)
+
+//#define MAX_CHAIN_FRAGS 64
+//#define MAX_CHAIN_FRAGS (15+15+15+16)
+#define MAX_CHAIN_FRAGS (4 * MAX_FRAGS_SPILL2 + 1)
+
+// Define max sg LIST bytes ( == (#frags + #chains) * 8 bytes each)
+// Works out to: 592d bytes! (9+1)*8 + 4*(15+1)*8
+// ^----------------- 80 + 512
+#define MAX_SGL_BYTES ((MAX_FRAGS_SPILL1 + 1 + (4 * FRAGS_PER_BUCKET)) * 8)
+
+/* linux only seems to ever give 128kB MAX contiguous (GFP_USER) mem bytes */
+#define MAX_KMALLOC_SZ (128*1024)
+
+struct buflist {
+ u8 *kptr;
+ int len;
+};
+
+#define myMAX_TARGETS (1<<4)
+#define myMAX_LUNS (1<<3)
+#define myMAX_T_MASK (myMAX_TARGETS-1)
+#define myMAX_L_MASK (myMAX_LUNS-1)
+static u8 DevInUse[myMAX_TARGETS][myMAX_LUNS] = {{0,0}};
+static u32 DevIosCount[myMAX_TARGETS][myMAX_LUNS] = {{0,0}};
+
+static u32 fwReplyBuffer[16];
+static pMPIDefaultReply_t ReplyMsg = NULL;
+
+/* some private forw protos */
+static SGESimple32_t *kbuf_alloc_2_sgl( int bytes, u32 dir, int *frags,
+ struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);
+static void kfree_sgl( SGESimple32_t *sgl, dma_addr_t sgl_dma,
+ struct buflist *buflist, MPT_ADAPTER *ioc);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mptctl_syscall_down - Down the MPT adapter syscall semaphore.
+ * @ioc: Pointer to MPT adapter
+ * @nonblock: boolean, non-zero if O_NONBLOCK is set
+ *
+ * All of the mptctl commands can potentially sleep, which is illegal
+ * with a spinlock held, thus we perform mutual exclusion here.
+ *
+ * Returns negative errno on error, or zero for success.
+ */
+static inline int
+mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
+{
+ dprintk((KERN_INFO MYNAM "::mpt_syscall_down(%p,%d) called\n", ioc, nonblock));
+
+ if (nonblock) {
+ if (down_trylock(&mptctl_syscall_sem_ioc[ioc->id]))
+ return -EAGAIN;
+ } else {
+ if (down_interruptible(&mptctl_syscall_sem_ioc[ioc->id]))
+ return -ERESTARTSYS;
+ }
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * This is the callback for any message we have posted. The message itself
+ * will be returned to the message pool when we return from the IRQ
+ *
+ * This runs in irq context so be short and sweet.
+ */
+static int
+mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
+{
+ u8 targ;
+
+ //dprintk((KERN_DEBUG MYNAM ": Got mptctl_reply()!\n"));
+
+ if (req && req->u.hdr.Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
+ targ = req->u.scsireq.TargetID & myMAX_T_MASK;
+ DevIosCount[targ][0]--;
+ } else if (reply && req && req->u.hdr.Function == MPI_FUNCTION_FW_DOWNLOAD) {
+ // NOTE: Expects/requires non-Turbo reply!
+ dprintk((KERN_INFO MYNAM ": Caching MPI_FUNCTION_FW_DOWNLOAD reply!\n"));
+ memcpy(fwReplyBuffer, reply, MIN(sizeof(fwReplyBuffer), 4*reply->u.reply.MsgLength));
+ ReplyMsg = (pMPIDefaultReply_t) fwReplyBuffer;
+ }
+
+ return 1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static loff_t
+mptctl_llseek(struct file *file, loff_t offset, int origin)
+{
+ return -ESPIPE;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static ssize_t
+mptctl_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+ printk(KERN_ERR MYNAM ": ioctl WRITE not yet supported\n");
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static ssize_t
+mptctl_read(struct file *file, char *buf, size_t count, loff_t *ptr)
+{
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * MPT ioctl handler
+ */
+static int
+mpt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct mpt_ioctl_sanity *usanity = (struct mpt_ioctl_sanity *) arg;
+ struct mpt_ioctl_sanity ksanity;
+ int iocnum;
+ unsigned iocnumX;
+ int nonblock = (file->f_flags & O_NONBLOCK);
+ int ret;
+ MPT_ADAPTER *iocp = NULL;
+
+ dprintk((KERN_INFO MYNAM "::mpt_ioctl() called\n"));
+
+ if (copy_from_user(&ksanity, usanity, sizeof(ksanity))) {
+ printk(KERN_ERR "%s::mpt_ioctl() @%d - "
+ "Unable to copy mpt_ioctl_sanity data @ %p\n",
+ __FILE__, __LINE__, (void*)usanity);
+ return -EFAULT;
+ }
+ ret = -ENXIO; /* (-6) No such device or address */
+
+ /* Verify intended MPT adapter */
+ iocnumX = ksanity.iocnum & 0xFF;
+ if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
+ (iocp == NULL)) {
+ printk(KERN_ERR "%s::mpt_ioctl() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnumX);
+ return -ENODEV;
+ }
+
+ if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
+ return ret;
+
+ dprintk((KERN_INFO MYNAM "::mpt_ioctl() - Using %s\n", iocp->name));
+
+ switch(cmd) {
+ case MPTRWPERF:
+ ret = mpt_ioctl_rwperf(arg);
+ break;
+ case MPTRWPERF_CHK:
+ ret = mpt_ioctl_rwperf_status(arg);
+ break;
+ case MPTRWPERF_RESET:
+ ret = mpt_ioctl_rwperf_reset(arg);
+ break;
+ case MPTFWDOWNLOAD:
+ ret = mpt_ioctl_fw_download(arg);
+ break;
+ case MPTSCSICMD:
+ ret = mpt_ioctl_scsi_cmd(arg);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ up(&mptctl_syscall_sem_ioc[iocp->id]);
+
+ return ret;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int mptctl_open(struct inode *inode, struct file *file)
+{
+ /*
+ * Should support multiple management users
+ */
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int mptctl_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_ioctl_fw_download(unsigned long arg)
+{
+ struct mpt_fw_xfer *ufwdl = (struct mpt_fw_xfer *) arg;
+ struct mpt_fw_xfer kfwdl;
+
+ dprintk((KERN_INFO "mpt_ioctl_fwdl called. mptctl_id = %xh\n", mptctl_id)); //tc
+ if (copy_from_user(&kfwdl, ufwdl, sizeof(struct mpt_fw_xfer))) {
+ printk(KERN_ERR "%s@%d::_ioctl_fwdl - "
+ "Unable to copy mpt_fw_xfer struct @ %p\n",
+ __FILE__, __LINE__, (void*)ufwdl);
+ return -EFAULT;
+ }
+
+ return mpt_ioctl_do_fw_download(kfwdl.iocnum, kfwdl.bufp, kfwdl.fwlen);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * MPT FW Download
+ */
+static int
+mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen)
+{
+ FWDownload_t *dlmsg;
+ MPT_FRAME_HDR *mf;
+ MPT_ADAPTER *iocp;
+// char *fwbuf;
+// dma_addr_t fwbuf_dma;
+ FWDownloadTCSGE_t *fwVoodoo;
+// SGEAllUnion_t *fwSgl;
+ int ret;
+
+ SGESimple32_t *sgl;
+ SGESimple32_t *sgOut, *sgIn;
+ dma_addr_t sgl_dma;
+ struct buflist *buflist;
+ struct buflist *bl;
+ int numfrags = 0;
+ int maxfrags;
+ int n = 0;
+ u32 sgdir;
+ u32 nib;
+ int fw_bytes_copied = 0;
+ u16 iocstat;
+ int i;
+
+ dprintk((KERN_INFO "mpt_ioctl_do_fwdl called. mptctl_id = %xh.\n", mptctl_id));
+
+ dprintk((KERN_INFO "DbG: kfwdl.bufp = %p\n", ufwbuf));
+ dprintk((KERN_INFO "DbG: kfwdl.fwlen = %d\n", (int)fwlen));
+ dprintk((KERN_INFO "DbG: kfwdl.ioc = %04xh\n", ioc));
+
+ if ((ioc = mpt_verify_adapter(ioc, &iocp)) < 0) {
+ printk("%s@%d::_ioctl_fwdl - ioc%d not found!\n",
+ __FILE__, __LINE__, ioc);
+ return -ENXIO; /* (-6) No such device or address */
+ }
+
+ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL)
+ return -EAGAIN;
+ dlmsg = (FWDownload_t*) mf;
+ fwVoodoo = (FWDownloadTCSGE_t *) &dlmsg->SGL;
+ sgOut = (SGESimple32_t *) (fwVoodoo + 1);
+
+ /*
+ * Construct f/w download request
+ */
+ dlmsg->ImageType = MPI_FW_DOWNLOAD_ITYPE_FW;
+ dlmsg->Reserved = 0;
+ dlmsg->ChainOffset = 0;
+ dlmsg->Function = MPI_FUNCTION_FW_DOWNLOAD;
+ dlmsg->Reserved1[0] = dlmsg->Reserved1[1] = dlmsg->Reserved1[2] = 0;
+ dlmsg->MsgFlags = 0;
+
+ fwVoodoo->Reserved = 0;
+ fwVoodoo->ContextSize = 0;
+ fwVoodoo->DetailsLength = 12;
+ fwVoodoo->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
+ fwVoodoo->Reserved1 = 0;
+ fwVoodoo->ImageOffset = 0;
+ fwVoodoo->ImageSize = cpu_to_le32(fwlen);
+
+ /*
+ * Need to kmalloc area(s) for holding firmware image bytes.
+ * But we need to do it piece meal, using a proper
+ * scatter gather list (with 128kB MAX hunks).
+ *
+ * A practical limit here might be # of sg hunks that fit into
+ * a single IOC request frame; 12 or 8 (see below), so:
+ * For FC9xx: 12 x 128kB == 1.5 mB (max)
+ * For C1030: 8 x 128kB == 1 mB (max)
+ * We could support chaining, but things get ugly(ier:)
+ */
+ sgdir = 0x04000000; /* IOC will READ from sys mem */
+ if ((sgl = kbuf_alloc_2_sgl(fwlen, sgdir, &numfrags, &buflist, &sgl_dma, iocp)) == NULL)
+ return -ENOMEM;
+
+ /*
+ * We should only need SGL with 2 simple_32bit entries (up to 256 kB)
+ * for FC9xx f/w image, but calculate max number of sge hunks
+ * we can fit into a request frame, and limit ourselves to that.
+ * (currently no chain support)
+ * For FC9xx: (128-12-16)/8 = 12.5 = 12
+ * For C1030: (96-12-16)/8 = 8.5 = 8
+ */
+ maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t)) / sizeof(SGESimple32_t);
+ if (numfrags > maxfrags) {
+ ret = -EMLINK;
+ goto fwdl_out;
+ }
+
+ dprintk((KERN_INFO "DbG: sgl buffer = %p, sgfrags = %d\n", sgl, numfrags));
+
+ /*
+ * Parse SG list, copying sgl itself,
+ * plus f/w image hunks from user space as we go...
+ */
+ ret = -EFAULT;
+ sgIn = sgl;
+ bl = buflist;
+ for (i=0; i < numfrags; i++) {
+ nib = (sgIn->FlagsLength & 0xF0000000) >> 28;
+ /* skip ignore/chain. */
+ if (nib == 0 || nib == 3) {
+ ;
+ } else if (sgIn->Address) {
+ *sgOut = *sgIn;
+ n++;
+ if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) {
+ printk(KERN_ERR "%s@%d::_ioctl_fwdl - "
+ "Unable to copy f/w buffer hunk#%d @ %p\n",
+ __FILE__, __LINE__, n, (void*)ufwbuf);
+ goto fwdl_out;
+ }
+ fw_bytes_copied += bl->len;
+ }
+ sgIn++;
+ bl++;
+ sgOut++;
+ }
+
+#ifdef MPT_DEBUG
+ {
+ u32 *m = (u32 *)mf;
+ printk(KERN_INFO MYNAM ": F/W download request:\n" KERN_INFO " ");
+ for (i=0; i < 7+numfrags*2; i++)
+ printk(" %08x", le32_to_cpu(m[i]));
+ printk("\n");
+ }
+#endif
+
+ /*
+ * Finally, perform firmware download.
+ */
+ ReplyMsg = NULL;
+ mpt_put_msg_frame(mptctl_id, ioc, mf);
+
+ /*
+ * Wait until the reply has been received
+ */
+ {
+ int foo = 0;
+
+ while (ReplyMsg == NULL) {
+ if (!(foo%1000000)) {
+ dprintk((KERN_INFO "DbG::_do_fwdl: "
+ "In ReplyMsg loop - iteration %d\n",
+ foo)); //tc
+ }
+ ret = -ETIME;
+ if (++foo > 60000000)
+ goto fwdl_out;
+ mb();
+ schedule();
+ barrier();
+ }
+ }
+
+ if (sgl)
+ kfree_sgl(sgl, sgl_dma, buflist, iocp);
+
+ iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK;
+ if (iocstat == MPI_IOCSTATUS_SUCCESS) {
+ printk(KERN_INFO MYNAM ": F/W update successfully sent to %s!\n", iocp->name);
+ return 0;
+ } else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) {
+ printk(KERN_WARNING MYNAM ": ?Hmmm... %s says it doesn't support F/W download!?!\n",
+ iocp->name);
+ printk(KERN_WARNING MYNAM ": (time to go bang on somebodies door)\n");
+ return -EBADRQC;
+ } else if (iocstat == MPI_IOCSTATUS_BUSY) {
+ printk(KERN_WARNING MYNAM ": Warning! %s says: IOC_BUSY!\n", iocp->name);
+ printk(KERN_WARNING MYNAM ": (try again later?)\n");
+ return -EBUSY;
+ } else {
+ printk(KERN_WARNING MYNAM "::ioctl_fwdl() ERROR! %s returned [bad] status = %04xh\n",
+ iocp->name, iocstat);
+ printk(KERN_WARNING MYNAM ": (bad VooDoo)\n");
+ return -ENOMSG;
+ }
+ return 0;
+
+fwdl_out:
+ kfree_sgl(sgl, sgl_dma, buflist, iocp);
+ return ret;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * NEW rwperf (read/write performance) stuff starts here...
+ */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static SGESimple32_t *
+kbuf_alloc_2_sgl(int bytes, u32 sgdir, int *frags,
+ struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc)
+{
+ SGESimple32_t *sglbuf = NULL;
+ struct buflist *buflist = NULL;
+ int numfrags = 0;
+ int fragcnt = 0;
+ int alloc_sz = MIN(bytes,MAX_KMALLOC_SZ); // avoid kernel warning msg!
+ int bytes_allocd = 0;
+ int this_alloc;
+ SGESimple32_t *sgl;
+ u32 pa; // phys addr
+ SGEChain32_t *last_chain = NULL;
+ SGEChain32_t *old_chain = NULL;
+ int chaincnt = 0;
+ int i, buflist_ent;
+ int sg_spill = MAX_FRAGS_SPILL1;
+ int dir;
+
+ *frags = 0;
+ *blp = NULL;
+ i = MAX_SGL_BYTES / 8;
+ buflist = kmalloc(i, GFP_USER);
+ if (buflist == NULL)
+ return NULL;
+ memset(buflist, 0, i);
+ buflist_ent = 0;
+
+ sglbuf = pci_alloc_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf_dma);
+ if (sglbuf == NULL)
+ goto free_and_fail;
+
+ if (sgdir & 0x04000000)
+ dir = PCI_DMA_TODEVICE;
+ else
+ dir = PCI_DMA_FROMDEVICE;
+
+ sgl = sglbuf;
+ while (bytes_allocd < bytes) {
+ this_alloc = MIN(alloc_sz, bytes-bytes_allocd);
+ buflist[buflist_ent].len = this_alloc;
+ buflist[buflist_ent].kptr = pci_alloc_consistent(ioc->pcidev,
+ this_alloc,
+ &pa);
+ if (buflist[buflist_ent].kptr == NULL) {
+ alloc_sz = alloc_sz / 2;
+ if (alloc_sz == 0) {
+ printk(KERN_WARNING MYNAM "-SG: No can do - "
+ "not enough memory! :-(\n");
+ printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n",
+ numfrags);
+ goto free_and_fail;
+ }
+ continue;
+ } else {
+ dma_addr_t dma_addr;
+
+ bytes_allocd += this_alloc;
+
+ /* Write one SIMPLE sge */
+ sgl->FlagsLength = cpu_to_le32(0x10000000|sgdir|this_alloc);
+ dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir);
+ sgl->Address = cpu_to_le32(dma_addr);
+
+ fragcnt++;
+ numfrags++;
+ sgl++;
+ buflist_ent++;
+ }
+
+ if (bytes_allocd >= bytes)
+ break;
+
+ /* Need to chain? */
+ if (fragcnt == sg_spill) {
+ dma_addr_t chain_link;
+
+ if (last_chain != NULL)
+ last_chain->NextChainOffset = 0x1E;
+
+ fragcnt = 0;
+ sg_spill = MAX_FRAGS_SPILL2;
+
+ /* fixup previous SIMPLE sge */
+ sgl[-1].FlagsLength |= cpu_to_le32(0x80000000);
+
+ chain_link = (*sglbuf_dma) +
+ ((u8 *)(sgl+1) - (u8 *)sglbuf);
+
+ /* Write one CHAIN sge */
+ sgl->FlagsLength = cpu_to_le32(0x30000080);
+ sgl->Address = cpu_to_le32(chain_link);
+
+ old_chain = last_chain;
+ last_chain = (SGEChain32_t*)sgl;
+ chaincnt++;
+ numfrags++;
+ sgl++;
+ }
+
+ /* overflow check... */
+ if (numfrags*8 > MAX_SGL_BYTES) {
+ /* GRRRRR... */
+ printk(KERN_WARNING MYNAM "-SG: No can do - "
+ "too many SG frags! :-(\n");
+ printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n",
+ numfrags);
+ goto free_and_fail;
+ }
+ }
+
+ /* Last sge fixup: set LE+eol+eob bits */
+ sgl[-1].FlagsLength |= cpu_to_le32(0xC1000000);
+
+ /* Chain fixup needed? */
+ if (last_chain != NULL && fragcnt < 16)
+ last_chain->Length = cpu_to_le16(fragcnt * 8);
+
+ *frags = numfrags;
+ *blp = buflist;
+
+ dprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
+ "%d SG frags generated! (%d CHAIN%s)\n",
+ numfrags, chaincnt, chaincnt>1?"s":""));
+
+ dprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
+ "last (big) alloc_sz=%d\n",
+ alloc_sz));
+
+ return sglbuf;
+
+free_and_fail:
+ if (sglbuf != NULL) {
+ int i;
+
+ for (i = 0; i < numfrags; i++) {
+ dma_addr_t dma_addr;
+ u8 *kptr;
+ int len;
+
+ if ((sglbuf[i].FlagsLength >> 24) == 0x30)
+ continue;
+
+ dma_addr = le32_to_cpu(sglbuf[i].Address);
+ kptr = buflist[i].kptr;
+ len = buflist[i].len;
+
+ pci_free_consistent(ioc->pcidev, len, kptr, dma_addr);
+ }
+ pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf, *sglbuf_dma);
+ }
+ kfree(buflist);
+ return NULL;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+kfree_sgl(SGESimple32_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTER *ioc)
+{
+ SGESimple32_t *sg = sgl;
+ struct buflist *bl = buflist;
+ u32 nib;
+ int dir;
+ int n = 0;
+
+ if (sg->FlagsLength & 0x04000000)
+ dir = PCI_DMA_TODEVICE;
+ else
+ dir = PCI_DMA_FROMDEVICE;
+
+ nib = (sg->FlagsLength & 0xF0000000) >> 28;
+ while (! (nib & 0x4)) { /* eob */
+ /* skip ignore/chain. */
+ if (nib == 0 || nib == 3) {
+ ;
+ } else if (sg->Address) {
+ dma_addr_t dma_addr;
+ void *kptr;
+ int len;
+
+ dma_addr = le32_to_cpu(sg->Address);
+ kptr = bl->kptr;
+ len = bl->len;
+ pci_unmap_single(ioc->pcidev, dma_addr, len, dir);
+ pci_free_consistent(ioc->pcidev, len, kptr, dma_addr);
+ n++;
+ }
+ sg++;
+ bl++;
+ nib = (sg->FlagsLength & 0xF0000000) >> 28;
+ }
+
+ /* we're at eob! */
+ if (sg->Address) {
+ dma_addr_t dma_addr;
+ void *kptr;
+ int len;
+
+ dma_addr = le32_to_cpu(sg->Address);
+ kptr = bl->kptr;
+ len = bl->len;
+ pci_unmap_single(ioc->pcidev, dma_addr, len, dir);
+ pci_free_consistent(ioc->pcidev, len, kptr, dma_addr);
+ n++;
+ }
+
+ pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sgl, sgl_dma);
+ kfree(buflist);
+ dprintk((KERN_INFO MYNAM "-SG: Free'd 1 SGL buf + %d kbufs!\n", n));
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_ioctl_rwperf_init(struct mpt_raw_r_w *dest, unsigned long src,
+ char *caller, MPT_ADAPTER **iocpp)
+{
+ char *myname = "_rwperf_init()";
+ int ioc;
+
+ /* get copy of structure passed from user space */
+ if (copy_from_user(dest, (void*)src, sizeof(*dest))) {
+ printk(KERN_ERR MYNAM "::%s() @%d - Can't copy mpt_raw_r_w data @ %p\n",
+ myname, __LINE__, (void*)src);
+ return -EFAULT; /* (-14) Bad address */
+ } else {
+ dprintk((KERN_INFO MYNAM "-perf: PerfInfo.{ioc,targ,qd,iters,nblks}"
+ ": %d %d %d %d %d\n",
+ dest->iocnum, dest->target,
+ (int)dest->qdepth, dest->iters, dest->nblks ));
+ dprintk((KERN_INFO MYNAM "-perf: PerfInfo.{cache,skip,range,rdwr,seqran}"
+ ": %d %d %d %d %d\n",
+ dest->cache_sz, dest->skip, dest->range,
+ dest->rdwr, dest->seqran ));
+
+ /* Get the MPT adapter id. */
+ if ((ioc = mpt_verify_adapter(dest->iocnum, iocpp)) < 0) {
+ printk(KERN_ERR MYNAM "::%s() @%d - ioc%d not found!\n",
+ myname, __LINE__, dest->iocnum);
+ return -ENXIO; /* (-6) No such device or address */
+ } else {
+ dprintk((MYNAM "-perf: %s using mpt/ioc%x, target %02xh\n",
+ caller, dest->iocnum, dest->target));
+ }
+ }
+
+ return ioc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/* Treat first N blocks of disk as sacred! */
+#define SACRED_BLOCKS 100
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_ioctl_rwperf(unsigned long arg)
+{
+ struct mpt_raw_r_w kPerfInfo;
+ /* NOTE: local copy, on stack==KERNEL_SPACE! */
+ u8 target, targetM;
+ u8 lun, lunM;
+ u8 scsiop;
+ int qdepth;
+ int iters;
+ int cache_sz;
+ u32 xferbytes;
+ u32 scsidir;
+ u32 qtag;
+ u32 scsictl;
+ u32 sgdir;
+ u32 blkno;
+ u32 sbphys;
+ SGESimple32_t *sgl;
+ dma_addr_t sgl_dma;
+ struct buflist *buflist;
+ SGESimple32_t *sgOut, *sgIn;
+ int numfrags;
+ u32 *msg;
+ int i;
+ int ioc;
+ MPT_FRAME_HDR *mf;
+ MPT_ADAPTER *iocp;
+ int sgfragcpycnt;
+ int blklo, blkhi;
+ u8 nextchainoffset;
+ u8 *SenseBuf;
+ dma_addr_t SenseBufDMA;
+ char *myname = "_rwperf()";
+
+ dprintk((KERN_INFO "%s - starting...\n", myname));
+
+ /* Validate target device */
+ if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0)
+ return ioc;
+
+ /* Allocate DMA'able memory for the sense buffer. */
+ SenseBuf = pci_alloc_consistent(iocp->pcidev, 256, &SenseBufDMA);
+
+ /* set perf parameters from input */
+ target = kPerfInfo.target & 0x0FF;
+ targetM = target & myMAX_T_MASK;
+ lun = kPerfInfo.lun & 0x1F; // LUN=31 max
+ lunM = lun & myMAX_L_MASK;
+ qdepth = kPerfInfo.qdepth;
+ iters = kPerfInfo.iters;
+ xferbytes = ((u32)kPerfInfo.nblks)<<9;
+
+ DevInUse[targetM][lunM] = 1;
+ DevIosCount[targetM][lunM] = 0;
+
+ cache_sz = kPerfInfo.cache_sz * 1024; // CacheSz in kB!
+
+ /* ToDo: */
+ /* get capacity (?) */
+
+
+ // pre-build, one time, everything we can for speed in the loops below...
+
+ scsiop = 0x28; // default to SCSI READ!
+ scsidir = MPI_SCSIIO_CONTROL_READ; // DATA IN (host<--ioc<--dev)
+ // 02000000
+ qtag = MPI_SCSIIO_CONTROL_SIMPLEQ; // 00000000
+
+ if (xferbytes == 0) {
+ // Do 0-byte READ!!!
+ // IMPORTANT! Need to set no SCSI DIR for this!
+ scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
+ }
+
+ scsictl = scsidir | qtag;
+
+ /*
+ * Set sgdir for DMA transfer.
+ */
+// sgdir = 0x04000000; // SCSI WRITE
+ sgdir = 0x00000000; // SCSI READ
+
+ if ((sgl = kbuf_alloc_2_sgl(MAX(512,xferbytes), sgdir, &numfrags, &buflist, &sgl_dma, iocp)) == NULL)
+ return -ENOMEM;
+
+ sgfragcpycnt = MIN(10,numfrags);
+ nextchainoffset = 0;
+ if (numfrags > 10)
+ nextchainoffset = 0x1E;
+
+ sbphys = SenseBufDMA;
+
+ rwperf_reset = 0;
+
+// do { // target-loop
+
+ blkno = SACRED_BLOCKS; // Treat first N blocks as sacred!
+ // FIXME! Skip option
+ blklo = blkno;
+ blkhi = blkno;
+
+ do { // inner-loop
+
+ while ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
+ mb();
+ schedule();
+ barrier();
+ }
+ msg = (u32*)mf;
+
+ /* Start piecing the SCSIIORequest together */
+ msg[0] = 0x00000000 | nextchainoffset<<16 | target;
+ msg[1] = 0x0000FF0A; // 255 sense bytes, 10-byte CDB!
+ msg[3] = lun << 8;
+ msg[4] = 0;
+ msg[5] = scsictl;
+
+ // 16 bytes of CDB @ msg[6,7,8,9] are below...
+
+ msg[6] = ( ((blkno & 0xFF000000) >> 8)
+ | ((blkno & 0x00FF0000) << 8)
+ | scsiop );
+ msg[7] = ( (((u32)kPerfInfo.nblks & 0x0000FF00) << 16)
+ | ((blkno & 0x000000FF) << 8)
+ | ((blkno & 0x0000FF00) >> 8) );
+ msg[8] = (kPerfInfo.nblks & 0x00FF);
+ msg[9] = 0;
+
+ msg[10] = xferbytes;
+
+// msg[11] = 0xD0000100;
+// msg[12] = sbphys;
+// msg[13] = 0;
+ msg[11] = sbphys;
+
+ // Copy the SGL...
+ if (xferbytes) {
+ sgOut = (SGESimple32_t*)&msg[12];
+ sgIn = sgl;
+ for (i=0; i < sgfragcpycnt; i++)
+ *sgOut++ = *sgIn++;
+ }
+
+ // fubar! QueueDepth issue!!!
+ while ( !rwperf_reset
+ && (DevIosCount[targetM][lunM] >= MIN(qdepth,64)) )
+ {
+ mb();
+ schedule();
+ barrier();
+ }
+
+// blkno += kPerfInfo.nblks;
+// EXP Stuff!
+// Try optimizing to certain cache size for the target!
+// by keeping blkno within cache range if at all possible
+#if 0
+ if ( cache_sz
+ && ((2 * kPerfInfo.nblks) <= (cache_sz>>9))
+ && ((blkno + kPerfInfo.nblks) > ((cache_sz>>9) + SACRED_BLOCKS)) )
+ blkno = SACRED_BLOCKS;
+ else
+ blkno += kPerfInfo.nblks;
+#endif
+// Ok, cheat!
+ if (cache_sz && ((blkno + kPerfInfo.nblks) > ((cache_sz>>9) + SACRED_BLOCKS)) )
+ blkno = SACRED_BLOCKS;
+ else
+ blkno += kPerfInfo.nblks;
+
+ if (blkno > blkhi)
+ blkhi = blkno;
+
+ DevIosCount[targetM][lunM]++;
+
+ /*
+ * Finally, post the request
+ */
+ mpt_put_msg_frame(mptctl_id, ioc, mf);
+
+
+ /* let linux breath! */
+ mb();
+ schedule();
+ barrier();
+
+ //dprintk((KERN_DEBUG MYNAM "-perf: inner-loop, cnt=%d\n", iters));
+
+ } while ((--iters > 0) && !rwperf_reset);
+
+ dprintk((KERN_INFO MYNAM "-perf: DbG: blklo=%d, blkhi=%d\n", blklo, blkhi));
+ dprintk((KERN_INFO MYNAM "-perf: target-loop, thisTarget=%d\n", target));
+
+// // TEMPORARY!
+// target = 0;
+
+// } while (target);
+
+
+ if (DevIosCount[targetM][lunM]) {
+ dprintk((KERN_INFO " DbG: DevIosCount[%d][%d]=%d\n",
+ targetM, lunM, DevIosCount[targetM][lunM]));
+ }
+
+ while (DevIosCount[targetM][lunM]) {
+ //dprintk((KERN_DEBUG " DbG: Waiting... DevIosCount[%d][%d]=%d\n",
+ // targetM, lunM, DevIosCount[targetM][lunM]));
+ mb();
+ schedule();
+ barrier();
+ }
+ DevInUse[targetM][lunM] = 0;
+
+ pci_free_consistent(iocp->pcidev, 256, SenseBuf, SenseBufDMA);
+
+ if (sgl)
+ kfree_sgl(sgl, sgl_dma, buflist, iocp);
+
+ dprintk((KERN_INFO " *** done ***\n"));
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_ioctl_rwperf_status(unsigned long arg)
+{
+ struct mpt_raw_r_w kPerfInfo;
+ /* NOTE: local copy, on stack==KERNEL_SPACE! */
+ MPT_ADAPTER *iocp;
+ int ioc;
+// u8 targ;
+// u8 lun;
+ int T, L;
+ char *myname = "_rwperf_status()";
+
+
+ dprintk((KERN_INFO "%s - starting...\n", myname));
+
+ /* Get a pointer to the MPT adapter. */
+ if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0)
+ return ioc;
+
+ /* set perf parameters from input */
+// targ = kPerfInfo.target & 0xFF;
+// lun = kPerfInfo.lun & 0x1F;
+
+ for (T=0; T < myMAX_TARGETS; T++)
+ for (L=0; L < myMAX_LUNS; L++)
+ if (DevIosCount[T][L]) {
+ printk(KERN_INFO "%s: ioc%d->00:%02x:%02x"
+ ", IosCnt=%d\n",
+ myname, ioc, T, L, DevIosCount[T][L] );
+ }
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_ioctl_rwperf_reset(unsigned long arg)
+{
+ struct mpt_raw_r_w kPerfInfo;
+ /* NOTE: local copy, on stack==KERNEL_SPACE! */
+ MPT_ADAPTER *iocp;
+ int ioc;
+// u8 targ;
+// u8 lun;
+ int T, L;
+ int i;
+ char *myname = "_rwperf_reset()";
+
+ dprintk((KERN_INFO "%s - starting...\n", myname));
+
+ /* Get MPT adapter id. */
+ if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0)
+ return ioc;
+
+ /* set perf parameters from input */
+// targ = kPerfInfo.target & 0xFF;
+// lun = kPerfInfo.lun & 0x1F;
+
+ rwperf_reset = 1;
+ for (i=0; i < 1000000; i++) {
+ mb();
+ schedule();
+ barrier();
+ }
+ rwperf_reset = 0;
+
+ for (T=0; T < myMAX_TARGETS; T++)
+ for (L=0; L < myMAX_LUNS; L++)
+ if (DevIosCount[T][L]) {
+ printk(KERN_INFO "%s: ioc%d->00:%02x:%02x, "
+ "IosCnt RESET! (from %d to 0)\n",
+ myname, ioc, T, L, DevIosCount[T][L] );
+ DevIosCount[T][L] = 0;
+ DevInUse[T][L] = 0;
+ }
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_ioctl_scsi_cmd(unsigned long arg)
+{
+ return -ENOSYS;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+static struct file_operations mptctl_fops = {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,51)
+ owner: THIS_MODULE,
+#endif
+ llseek: mptctl_llseek,
+ read: mptctl_read,
+ write: mptctl_write,
+ ioctl: mpt_ioctl,
+ open: mptctl_open,
+ release: mptctl_release,
+};
+
+static struct miscdevice mptctl_miscdev = {
+ MPT_MINOR,
+ MYNAM,
+ &mptctl_fops
+};
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#if defined(__sparc__) && defined(__sparc_v9__) /*{*/
+
+/* The dynamic ioctl32 compat. registry only exists in >2.3.x sparc64 kernels */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) /*{*/
+extern int register_ioctl32_conversion(unsigned int cmd,
+ int (*handler)(unsigned int,
+ unsigned int,
+ unsigned long,
+ struct file *));
+int unregister_ioctl32_conversion(unsigned int cmd);
+
+struct mpt_fw_xfer32 {
+ unsigned int iocnum;
+ unsigned int fwlen;
+ u32 bufp;
+};
+
+#define MPTFWDOWNLOAD32 _IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer32)
+
+extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+sparc32_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd,
+ unsigned long arg, struct file *filp)
+{
+ struct mpt_fw_xfer32 kfw32;
+ struct mpt_fw_xfer kfw;
+ MPT_ADAPTER *iocp = NULL;
+ int iocnum, iocnumX;
+ int nonblock = (filp->f_flags & O_NONBLOCK);
+ int ret;
+
+ dprintk((KERN_INFO MYNAM "::sparc32_mptfwxfer_ioctl() called\n"));
+
+ if (copy_from_user(&kfw32, (char *)arg, sizeof(kfw32)))
+ return -EFAULT;
+
+ /* Verify intended MPT adapter */
+ iocnumX = kfw32.iocnum & 0xFF;
+ if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
+ (iocp == NULL)) {
+ printk(KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n",
+ __LINE__, iocnumX);
+ return -ENODEV;
+ }
+
+ if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
+ return ret;
+
+ kfw.iocnum = iocnum;
+ kfw.fwlen = kfw32.fwlen;
+ kfw.bufp = (void *)(unsigned long)kfw32.bufp;
+
+ ret = mpt_ioctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen);
+
+ up(&mptctl_syscall_sem_ioc[iocp->id]);
+
+ return ret;
+}
+
+#if 0 /* { */
+static int
+sparc32_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd,
+ unsigned long arg, struct file *filp)
+{
+ struct mpt_fw_xfer32 kfw32;
+ struct mpt_fw_xfer kfw;
+ mm_segment_t old_fs;
+ int ret;
+
+ dprintk((KERN_INFO MYNAM "::sparc32_mptfwxfer_ioctl() called\n"));
+
+ if (copy_from_user(&kfw32, (char *)arg, sizeof(kfw32)))
+ return -EFAULT;
+
+ /* Verify intended MPT adapter */
+ iocnumX = kfw32.iocnum & 0xFF;
+ if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
+ (iocp == NULL)) {
+ printk(KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n",
+ __LINE__, iocnumX);
+ return -ENODEV;
+ }
+
+ if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
+ return ret;
+
+ kfw.iocnum = iocnum;
+ kfw.fwlen = kfw32.fwlen;
+ kfw.bufp = (void *)(unsigned long)kfw32.bufp;
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_ioctl(fd, MPTFWDOWNLOAD, (unsigned long)&kfw);
+ set_fs(old_fs);
+
+ up(&mptctl_syscall_sem_ioc[iocp->id]);
+
+ return ret;
+}
+#endif /* #if 0 } */
+
+#endif /*} linux >= 2.3.x */
+#endif /*} sparc */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+int __init mptctl_init(void)
+{
+ int err;
+ int i;
+ int where = 1;
+
+ show_mptmod_ver(my_NAME, my_VERSION);
+
+ for (i=0; i<MPT_MAX_ADAPTERS; i++) {
+ sema_init(&mptctl_syscall_sem_ioc[i], 1);
+ }
+
+#if defined(__sparc__) && defined(__sparc_v9__) /*{*/
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) /*{*/
+ err = register_ioctl32_conversion(MPTRWPERF, NULL);
+ if (++where && err) goto out_fail;
+ err = register_ioctl32_conversion(MPTRWPERF_CHK, NULL);
+ if (++where && err) goto out_fail;
+ err = register_ioctl32_conversion(MPTRWPERF_RESET, NULL);
+ if (++where && err) goto out_fail;
+ err = register_ioctl32_conversion(MPTFWDOWNLOAD32,
+ sparc32_mptfwxfer_ioctl);
+ if (++where && err) goto out_fail;
+#endif /*} linux >= 2.3.x */
+#endif /*} sparc */
+
+ if (misc_register(&mptctl_miscdev) == -1) {
+ printk(KERN_ERR MYNAM ": Can't register misc device [minor=%d].\n", MPT_MINOR);
+ err = -EBUSY;
+ goto out_fail;
+ }
+ printk(KERN_INFO MYNAM ": Registered with Fusion MPT base driver\n");
+ printk(KERN_INFO MYNAM ": /dev/%s @ (major,minor=%d,%d)\n",
+ mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
+
+ /*
+ * Install our handler
+ */
+ ++where;
+ if ((mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER)) < 0) {
+ printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
+ misc_deregister(&mptctl_miscdev);
+ err = -EBUSY;
+ goto out_fail;
+ }
+
+ return 0;
+
+out_fail:
+
+#if defined(__sparc__) && defined(__sparc_v9__) /*{*/
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) /*{*/
+ printk(KERN_ERR MYNAM ": ERROR: Failed to register ioctl32_conversion!"
+ " (%d:err=%d)\n", where, err);
+ unregister_ioctl32_conversion(MPTRWPERF);
+ unregister_ioctl32_conversion(MPTRWPERF_CHK);
+ unregister_ioctl32_conversion(MPTRWPERF_RESET);
+ unregister_ioctl32_conversion(MPTFWDOWNLOAD32);
+#endif /*} linux >= 2.3.x */
+#endif /*} sparc */
+
+ return err;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+void mptctl_exit(void)
+{
+ misc_deregister(&mptctl_miscdev);
+ printk(KERN_INFO MYNAM ": /dev/%s @ (major,minor=%d,%d)\n",
+ mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
+ printk(KERN_INFO MYNAM ": Deregistered from Fusion MPT base driver\n");
+
+ mpt_deregister(mptctl_id);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+module_init(mptctl_init);
+module_exit(mptctl_exit);
--- /dev/null
+/*
+ * linux/drivers/message/fusion/mptlan.c
+ * IP Over Fibre Channel device driver.
+ * For use with PCI chip/adapter(s):
+ * LSIFC9xx/LSI409xx Fibre Channel
+ * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ * Credits:
+ * This driver would not exist if not for Alan Cox's development
+ * of the linux i2o driver.
+ *
+ * Special thanks goes to the I2O LAN driver people at the
+ * University of Helsinki, who, unbeknownst to them, provided
+ * the inspiration and initial structure for this driver.
+ *
+ * A huge debt of gratitude is owed to David S. Miller (DaveM)
+ * for fixing much of the stupid and broken stuff in the early
+ * driver while porting to sparc64 platform. THANK YOU!
+ *
+ * A really huge debt of gratitude is owed to Eddie C. Dost
+ * for gobs of hard work fixing and optimizing LAN code.
+ * THANK YOU!
+ *
+ * (see also mptbase.c)
+ *
+ * Copyright (c) 2000-2001 LSI Logic Corporation
+ * Originally By: Noah Romer
+ *
+ * $Id: mptlan.c,v 1.25 2001/03/02 22:12:04 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ 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; version 2 of the License.
+
+ 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.
+
+ NO WARRANTY
+ THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ solely responsible for determining the appropriateness of using and
+ distributing the Program and assumes all risks associated with its
+ exercise of rights under this Agreement, including but not limited to
+ the risks and costs of program errors, damage to or loss of data,
+ programs or equipment, and unavailability or interruption of operations.
+
+ DISCLAIMER OF LIABILITY
+ NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Define statements used for debugging
+ */
+//#define MPT_LAN_IO_DEBUG
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include "mptlan.h"
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+
+#define MYNAM "mptlan"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * MPT LAN message sizes without variable part.
+ */
+#define MPT_LAN_RECEIVE_POST_REQUEST_SIZE \
+ (sizeof(LANReceivePostRequest_t) - sizeof(SGE_MPI_UNION))
+
+#define MPT_LAN_TRANSACTION32_SIZE \
+ (sizeof(SGETransaction32_t) - sizeof(u32))
+
+/*
+ * Fusion MPT LAN private structures
+ */
+
+struct BufferControl {
+ struct sk_buff *skb;
+ dma_addr_t dma;
+ unsigned int len;
+};
+
+struct mpt_lan_priv {
+ MPT_ADAPTER *mpt_dev;
+ u8 pnum; /* Port number in the IOC. This is not a Unix network port! */
+
+ atomic_t buckets_out; /* number of unused buckets on IOC */
+ int bucketthresh; /* Send more when this many used */
+
+ int *mpt_txfidx; /* Free Tx Context list */
+ int mpt_txfidx_tail;
+ spinlock_t txfidx_lock;
+
+ int *mpt_rxfidx; /* Free Rx Context list */
+ int mpt_rxfidx_tail;
+ spinlock_t rxfidx_lock;
+
+ struct BufferControl *RcvCtl; /* Receive BufferControl structs */
+ struct BufferControl *SendCtl; /* Send BufferControl structs */
+
+ int max_buckets_out; /* Max buckets to send to IOC */
+ int tx_max_out; /* IOC's Tx queue len */
+
+ u32 total_posted;
+ u32 total_received;
+ struct net_device_stats stats; /* Per device statistics */
+
+ struct tq_struct post_buckets_task;
+ unsigned long post_buckets_active;
+};
+
+struct mpt_lan_ohdr {
+ u16 dtype;
+ u8 daddr[FC_ALEN];
+ u16 stype;
+ u8 saddr[FC_ALEN];
+};
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*
+ * Forward protos...
+ */
+static int lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
+ MPT_FRAME_HDR *reply);
+static int mpt_lan_open(struct net_device *dev);
+static int mpt_lan_reset(struct net_device *dev);
+static int mpt_lan_close(struct net_device *dev);
+static void mpt_lan_post_receive_buckets(void *dev_id);
+static void mpt_lan_wake_post_buckets_task(struct net_device *dev);
+static int mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg);
+static int mpt_lan_receive_post_reply(struct net_device *dev,
+ LANReceivePostReply_t *pRecvRep);
+static int mpt_lan_send_turbo(struct net_device *dev, u32 tmsg);
+static int mpt_lan_send_reply(struct net_device *dev,
+ LANSendReply_t *pSendRep);
+static int mpt_lan_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
+static unsigned short mpt_lan_type_trans(struct sk_buff *skb,
+ struct net_device *dev);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Fusion MPT LAN private data
+ */
+static int LanCtx = -1;
+
+static u32 max_buckets_out = 127;
+static u32 tx_max_out_p = 127 - 16;
+
+static struct net_device *mpt_landev[MPT_MAX_ADAPTERS+1];
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Fusion MPT LAN external data
+ */
+extern int mpt_lan_index;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * lan_reply - Handle all data sent from the hardware.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @mf: Pointer to original MPT request frame (NULL if TurboReply)
+ * @reply: Pointer to MPT reply frame
+ *
+ * Returns 1 indicating original alloc'd request frame ptr
+ * should be freed, or 0 if it shouldn't.
+ */
+static int
+lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
+{
+ struct net_device *dev = mpt_landev[ioc->id];
+ int FreeReqFrame = 0;
+
+ dioprintk((KERN_INFO MYNAM ": %s/%s: Got reply.\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev)));
+
+// dioprintk((KERN_INFO MYNAM "@lan_reply: mf = %p, reply = %p\n",
+// mf, reply));
+
+ if (mf == NULL) {
+ u32 tmsg = CAST_PTR_TO_U32(reply);
+
+ dioprintk((KERN_INFO MYNAM ": %s/%s: @lan_reply, tmsg %08x\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ tmsg));
+
+ switch (GET_LAN_FORM(tmsg)) {
+
+ // NOTE! (Optimization) First case here is now caught in
+ // mptbase.c::mpt_interrupt() routine and callcack here
+ // is now skipped for this case! 20001218 -sralston
+#if 0
+ case LAN_REPLY_FORM_MESSAGE_CONTEXT:
+// dioprintk((KERN_INFO MYNAM "/lan_reply: "
+// "MessageContext turbo reply received\n"));
+ FreeReqFrame = 1;
+ break;
+#endif
+
+ case LAN_REPLY_FORM_SEND_SINGLE:
+// dioprintk((MYNAM "/lan_reply: "
+// "calling mpt_lan_send_reply (turbo)\n"));
+
+ // Potential BUG here? -sralston
+ // FreeReqFrame = mpt_lan_send_turbo(dev, tmsg);
+ // If/when mpt_lan_send_turbo would return 1 here,
+ // calling routine (mptbase.c|mpt_interrupt)
+ // would Oops because mf has already been set
+ // to NULL. So after return from this func,
+ // mpt_interrupt() will attempt to put (NULL) mf ptr
+ // item back onto it's adapter FreeQ - Oops!:-(
+ // It's Ok, since mpt_lan_send_turbo() *currently*
+ // always returns 0, but..., just in case:
+
+ (void) mpt_lan_send_turbo(dev, tmsg);
+ FreeReqFrame = 0;
+
+ break;
+
+ case LAN_REPLY_FORM_RECEIVE_SINGLE:
+// dioprintk((KERN_INFO MYNAM "@lan_reply: "
+// "rcv-Turbo = %08x\n", tmsg));
+ mpt_lan_receive_post_turbo(dev, tmsg);
+ break;
+
+ default:
+ printk (KERN_ERR MYNAM "/lan_reply: Got a turbo reply "
+ "that I don't know what to do with\n");
+
+ /* CHECKME! Hmmm... FreeReqFrame is 0 here; is that right? */
+
+ break;
+ }
+
+ return FreeReqFrame;
+ }
+
+// msg = (u32 *) reply;
+// dioprintk((KERN_INFO MYNAM "@lan_reply: msg = %08x %08x %08x %08x\n",
+// le32_to_cpu(msg[0]), le32_to_cpu(msg[1]),
+// le32_to_cpu(msg[2]), le32_to_cpu(msg[3])));
+// dioprintk((KERN_INFO MYNAM "@lan_reply: Function = %02xh\n",
+// reply->u.hdr.Function));
+
+ switch (reply->u.hdr.Function) {
+
+ case MPI_FUNCTION_LAN_SEND:
+ {
+ LANSendReply_t *pSendRep;
+
+ pSendRep = (LANSendReply_t *) reply;
+ FreeReqFrame = mpt_lan_send_reply(dev, pSendRep);
+ break;
+ }
+
+ case MPI_FUNCTION_LAN_RECEIVE:
+ {
+ LANReceivePostReply_t *pRecvRep;
+
+ pRecvRep = (LANReceivePostReply_t *) reply;
+ if (pRecvRep->NumberOfContexts) {
+ mpt_lan_receive_post_reply(dev, pRecvRep);
+ if (!(pRecvRep->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY))
+ FreeReqFrame = 1;
+ } else
+ dioprintk((KERN_INFO MYNAM "@lan_reply: zero context "
+ "ReceivePostReply received.\n"));
+ break;
+ }
+
+ case MPI_FUNCTION_LAN_RESET:
+ /* Just a default reply. Might want to check it to
+ * make sure that everything went ok.
+ */
+ FreeReqFrame = 1;
+ break;
+
+ case MPI_FUNCTION_EVENT_NOTIFICATION:
+ case MPI_FUNCTION_EVENT_ACK:
+ /* UPDATE! 20010120 -sralston
+ * _EVENT_NOTIFICATION should NOT come down this path any more.
+ * Should be routed to mpt_lan_event_process(), but just in case...
+ */
+ FreeReqFrame = 1;
+ break;
+
+ default:
+ printk (KERN_ERR MYNAM "/lan_reply: Got a non-turbo "
+ "reply that I don't know what to do with\n");
+
+ /* CHECKME! Hmmm... FreeReqFrame is 0 here; is that right? */
+ FreeReqFrame = 1;
+
+ break;
+ }
+
+ return FreeReqFrame;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
+{
+ dprintk((KERN_INFO MYNAM ": MPT event routed to LAN driver!\n"));
+
+ switch (le32_to_cpu(pEvReply->Event)) {
+ case MPI_EVENT_NONE: /* 00 */
+ case MPI_EVENT_LOG_DATA: /* 01 */
+ case MPI_EVENT_STATE_CHANGE: /* 02 */
+ case MPI_EVENT_UNIT_ATTENTION: /* 03 */
+ case MPI_EVENT_IOC_BUS_RESET: /* 04 */
+ case MPI_EVENT_EXT_BUS_RESET: /* 05 */
+ case MPI_EVENT_RESCAN: /* 06 */
+ /* Ok, do we need to do anything here? As far as
+ I can tell, this is when a new device gets added
+ to the loop. */
+ case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
+ case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
+ case MPI_EVENT_LOGOUT: /* 09 */
+ case MPI_EVENT_EVENT_CHANGE: /* 0A */
+ default:
+ break;
+ }
+
+ /*
+ * NOTE: pEvent->AckRequired handling now done in mptbase.c;
+ * Do NOT do it here now!
+ */
+
+ return 1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_open(struct net_device *dev)
+{
+ struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+ int i;
+
+ mpt_lan_reset(dev);
+
+ priv->mpt_txfidx = kmalloc(priv->tx_max_out * sizeof(int), GFP_KERNEL);
+ if (priv->mpt_txfidx == NULL)
+ goto out;
+ priv->mpt_txfidx_tail = -1;
+
+ priv->SendCtl = kmalloc(priv->tx_max_out * sizeof(struct BufferControl),
+ GFP_KERNEL);
+ if (priv->SendCtl == NULL)
+ goto out_mpt_txfidx;
+ for (i = 0; i < priv->tx_max_out; i++) {
+ memset(&priv->SendCtl[i], 0, sizeof(struct BufferControl));
+ priv->mpt_txfidx[++priv->mpt_txfidx_tail] = i;
+ }
+
+ dprintk((KERN_INFO MYNAM "@lo: Finished initializing SendCtl\n"));
+
+ priv->mpt_rxfidx = kmalloc(priv->max_buckets_out * sizeof(int),
+ GFP_KERNEL);
+ if (priv->mpt_rxfidx == NULL)
+ goto out_SendCtl;
+ priv->mpt_rxfidx_tail = -1;
+
+ priv->RcvCtl = kmalloc(priv->max_buckets_out *
+ sizeof(struct BufferControl),
+ GFP_KERNEL);
+ if (priv->RcvCtl == NULL)
+ goto out_mpt_rxfidx;
+ for (i = 0; i < priv->max_buckets_out; i++) {
+ memset(&priv->RcvCtl[i], 0, sizeof(struct BufferControl));
+ priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = i;
+ }
+
+/**/ dprintk((KERN_INFO MYNAM "/lo: txfidx contains - "));
+/**/ for (i = 0; i < priv->tx_max_out; i++)
+/**/ dprintk((" %xh", priv->mpt_txfidx[i]));
+/**/ dprintk(("\n"));
+
+ dprintk((KERN_INFO MYNAM "/lo: Finished initializing RcvCtl\n"));
+
+ mpt_lan_post_receive_buckets(dev);
+ printk(KERN_INFO MYNAM ": %s/%s: interface up & active\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev));
+
+ if (mpt_event_register(LanCtx, mpt_lan_event_process) != 0) {
+ /* FIXME! */
+ }
+
+ netif_start_queue(dev);
+ dprintk((KERN_INFO MYNAM "/lo: Done.\n"));
+
+ return 0;
+out_mpt_rxfidx:
+ kfree(priv->mpt_rxfidx);
+ priv->mpt_rxfidx = NULL;
+out_SendCtl:
+ kfree(priv->SendCtl);
+ priv->SendCtl = NULL;
+out_mpt_txfidx:
+ kfree(priv->mpt_txfidx);
+ priv->mpt_txfidx = NULL;
+out: return -ENOMEM;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_reset(struct net_device *dev)
+{
+ MPT_FRAME_HDR *mf;
+ LANResetRequest_t *pResetReq;
+ struct mpt_lan_priv *priv = (struct mpt_lan_priv *)dev->priv;
+
+ mf = mpt_get_msg_frame(LanCtx, priv->mpt_dev->id);
+
+ if (mf == NULL) {
+/* dprintk((KERN_ERR MYNAM "/reset: Evil funkiness abounds! "
+ "Unable to allocate a request frame.\n"));
+*/
+ return -1;
+ }
+
+ pResetReq = (LANResetRequest_t *) mf;
+
+ pResetReq->Function = MPI_FUNCTION_LAN_RESET;
+ pResetReq->ChainOffset = 0;
+ pResetReq->Reserved = 0;
+ pResetReq->PortNumber = priv->pnum;
+ pResetReq->MsgFlags = 0;
+ pResetReq->Reserved2 = 0;
+
+ mpt_put_msg_frame(LanCtx, priv->mpt_dev->id, mf);
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_close(struct net_device *dev)
+{
+ struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+ MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+ unsigned int timeout;
+ int i;
+
+ dprintk((KERN_INFO MYNAM ": mpt_lan_close called\n"));
+
+ mpt_event_deregister(LanCtx);
+
+ dprintk((KERN_INFO MYNAM ":lan_close: Posted %d buckets "
+ "since driver was loaded, %d still out\n",
+ priv->total_posted,atomic_read(&priv->buckets_out)));
+
+ netif_stop_queue(dev);
+
+ mpt_lan_reset(dev);
+
+ timeout = 2 * HZ;
+ while (atomic_read(&priv->buckets_out) && --timeout) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ }
+
+ for (i = 0; i < priv->max_buckets_out; i++) {
+ if (priv->RcvCtl[i].skb != NULL) {
+/**/ dprintk((KERN_INFO MYNAM "/lan_close: bucket %05x "
+/**/ "is still out\n", i));
+ pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[i].dma,
+ priv->RcvCtl[i].len,
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(priv->RcvCtl[i].skb);
+ }
+ }
+
+ kfree (priv->RcvCtl);
+ kfree (priv->mpt_rxfidx);
+
+ for (i = 0; i < priv->tx_max_out; i++) {
+ if (priv->SendCtl[i].skb != NULL) {
+ pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[i].dma,
+ priv->SendCtl[i].len,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb(priv->SendCtl[i].skb);
+ }
+ }
+
+ kfree(priv->SendCtl);
+ kfree(priv->mpt_txfidx);
+
+ atomic_set(&priv->buckets_out, 0);
+
+ printk(KERN_INFO MYNAM ": %s/%s: interface down & inactive\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev));
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static struct net_device_stats *
+mpt_lan_get_stats(struct net_device *dev)
+{
+ struct mpt_lan_priv *priv = (struct mpt_lan_priv *)dev->priv;
+
+ return (struct net_device_stats *) &priv->stats;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if ((new_mtu < MPT_LAN_MIN_MTU) || (new_mtu > MPT_LAN_MAX_MTU))
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Tx timeout handler. */
+static void
+mpt_lan_tx_timeout(struct net_device *dev)
+{
+ netif_wake_queue(dev);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+//static inline int
+static int
+mpt_lan_send_turbo(struct net_device *dev, u32 tmsg)
+{
+ struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+ MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+ struct sk_buff *sent;
+ unsigned long flags;
+ u32 ctx;
+
+ ctx = GET_LAN_BUFFER_CONTEXT(tmsg);
+ sent = priv->SendCtl[ctx].skb;
+
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += sent->len;
+
+ dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ __FUNCTION__, sent));
+
+ priv->SendCtl[ctx].skb = NULL;
+ pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
+ priv->SendCtl[ctx].len, PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(sent);
+
+ spin_lock_irqsave(&priv->txfidx_lock, flags);
+ priv->mpt_txfidx[++priv->mpt_txfidx_tail] = ctx;
+ spin_unlock_irqrestore(&priv->txfidx_lock, flags);
+
+ netif_wake_queue(dev);
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep)
+{
+ struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+ MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+ struct sk_buff *sent;
+ unsigned long flags;
+ int FreeReqFrame = 0;
+ u32 *pContext;
+ u32 ctx;
+ u8 count;
+
+ count = pSendRep->NumberOfContexts;
+
+ dioprintk((KERN_INFO MYNAM ": send_reply: IOCStatus: %04x\n",
+ le16_to_cpu(pSendRep->IOCStatus)));
+
+ /* Add check for Loginfo Flag in IOCStatus */
+
+ switch (le16_to_cpu(pSendRep->IOCStatus)) {
+ case MPI_IOCSTATUS_SUCCESS:
+ priv->stats.tx_packets += count;
+ break;
+
+ case MPI_IOCSTATUS_LAN_CANCELED:
+ case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED:
+ break;
+
+ case MPI_IOCSTATUS_INVALID_SGL:
+ priv->stats.tx_errors += count;
+ printk (KERN_ERR MYNAM ": %s/%s: ERROR - Invalid SGL sent to IOC!\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev));
+ goto out;
+
+ default:
+ priv->stats.tx_errors += count;
+ break;
+ }
+
+ pContext = &pSendRep->BufferContext;
+
+ spin_lock_irqsave(&priv->txfidx_lock, flags);
+ while (count > 0) {
+ ctx = GET_LAN_BUFFER_CONTEXT(le32_to_cpu(*pContext));
+
+ sent = priv->SendCtl[ctx].skb;
+ priv->stats.tx_bytes += sent->len;
+
+ dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ __FUNCTION__, sent));
+
+ priv->SendCtl[ctx].skb = NULL;
+ pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
+ priv->SendCtl[ctx].len, PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(sent);
+
+ priv->mpt_txfidx[++priv->mpt_txfidx_tail] = ctx;
+
+ pContext++;
+ count--;
+ }
+ spin_unlock_irqrestore(&priv->txfidx_lock, flags);
+
+out:
+ if (!(pSendRep->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY))
+ FreeReqFrame = 1;
+
+ netif_wake_queue(dev);
+ return FreeReqFrame;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
+{
+ struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+ MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+ MPT_FRAME_HDR *mf;
+ LANSendRequest_t *pSendReq;
+ SGETransaction32_t *pTrans;
+ SGESimple64_t *pSimple;
+ dma_addr_t dma;
+ unsigned long flags;
+ int ctx;
+
+ dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n",
+ __FUNCTION__, skb));
+
+ spin_lock_irqsave(&priv->txfidx_lock, flags);
+ if (priv->mpt_txfidx_tail < 0) {
+ netif_stop_queue(dev);
+ spin_unlock_irqrestore(&priv->txfidx_lock, flags);
+
+ printk (KERN_ERR "%s: no tx context available: %u\n",
+ __FUNCTION__, priv->mpt_txfidx_tail);
+ return 1;
+ }
+
+ mf = mpt_get_msg_frame(LanCtx, mpt_dev->id);
+ if (mf == NULL) {
+ netif_stop_queue(dev);
+ dev_kfree_skb(skb);
+ spin_unlock_irqrestore(&priv->txfidx_lock, flags);
+
+ printk (KERN_ERR "%s: Unable to alloc request frame\n",
+ __FUNCTION__);
+ return 1;
+ }
+
+ ctx = priv->mpt_txfidx[priv->mpt_txfidx_tail--];
+ spin_unlock_irqrestore(&priv->txfidx_lock, flags);
+
+// dioprintk((KERN_INFO MYNAM ": %s/%s: Creating new msg frame (send).\n",
+// IOC_AND_NETDEV_NAMES_s_s(dev)));
+
+ pSendReq = (LANSendRequest_t *) mf;
+
+ /* Set the mac.raw pointer, since this apparently isn't getting
+ * done before we get the skb. Pull the data pointer past the mac data.
+ */
+ skb->mac.raw = skb->data;
+ skb_pull(skb, 12);
+
+ dma = pci_map_single(mpt_dev->pcidev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+
+ priv->SendCtl[ctx].skb = skb;
+ priv->SendCtl[ctx].dma = dma;
+ priv->SendCtl[ctx].len = skb->len;
+
+ /* Message Header */
+ pSendReq->Function = MPI_FUNCTION_LAN_SEND;
+ pSendReq->ChainOffset = 0;
+ pSendReq->MsgFlags = 0;
+ pSendReq->PortNumber = priv->pnum;
+
+ /* Transaction Context Element */
+ pTrans = (SGETransaction32_t *) pSendReq->SG_List;
+
+ /* No Flags, 8 bytes of Details, 32bit Context (bloody turbo replies) */
+ pTrans->ContextSize = sizeof(u32);
+ pTrans->DetailsLength = 2 * sizeof(u32);
+ pTrans->Flags = 0;
+ pTrans->TransactionContext[0] = cpu_to_le32(ctx);
+
+// dioprintk((KERN_INFO MYNAM ": %s/%s: BC = %08x, skb = %p, buff = %p\n",
+// IOC_AND_NETDEV_NAMES_s_s(dev),
+// ctx, skb, skb->data));
+
+ pTrans->TransactionDetails[0] = cpu_to_le32((0x1000 << 16) |
+ (skb->mac.raw[0] << 8) |
+ (skb->mac.raw[1] << 0));
+ pTrans->TransactionDetails[1] = cpu_to_le32((skb->mac.raw[2] << 24) |
+ (skb->mac.raw[3] << 16) |
+ (skb->mac.raw[4] << 8) |
+ (skb->mac.raw[5] << 0));
+
+ pSimple = (SGESimple64_t *) &pTrans->TransactionDetails[2];
+
+ pSimple->FlagsLength = cpu_to_le32(
+ ((MPI_SGE_FLAGS_END_OF_BUFFER |
+ MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI_SGE_FLAGS_64_BIT_ADDRESSING |
+ MPI_SGE_FLAGS_END_OF_LIST) << MPI_SGE_FLAGS_SHIFT) |
+ skb->len);
+ pSimple->Address.Low = cpu_to_le32((u32) dma);
+ if (sizeof(dma_addr_t) > sizeof(u32))
+ pSimple->Address.High = cpu_to_le32((u32) ((u64) dma >> 32));
+ else
+ pSimple->Address.High = 0;
+
+ mpt_put_msg_frame (LanCtx, mpt_dev->id, mf);
+ dev->trans_start = jiffies;
+
+ dioprintk((KERN_INFO MYNAM ": %s/%s: Sending packet. FlagsLength = %08x.\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ le32_to_cpu(pSimple->FlagsLength)));
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static inline void
+mpt_lan_wake_post_buckets_task(struct net_device *dev)
+{
+ struct mpt_lan_priv *priv = dev->priv;
+
+ if (test_and_set_bit(0, &priv->post_buckets_active) == 0) {
+ queue_task(&priv->post_buckets_task, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ dioprintk((KERN_INFO MYNAM ": %s/%s: Queued post_buckets task.\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev) ));
+ }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static inline int
+mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb)
+{
+ struct mpt_lan_priv *priv = dev->priv;
+
+ skb->protocol = mpt_lan_type_trans(skb, dev);
+
+ dioprintk((KERN_INFO MYNAM ": %s/%s: Incoming packet (%d bytes) "
+ "delivered to upper level.\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev), skb->len));
+
+ priv->stats.rx_bytes += skb->len;
+ priv->stats.rx_packets++;
+
+ skb->dev = dev;
+ netif_rx(skb);
+
+ dioprintk((MYNAM "/receive_skb: %d buckets remaining\n",
+ atomic_read(&priv->buckets_out)));
+
+ if (atomic_read(&priv->buckets_out) < priv->bucketthresh)
+ mpt_lan_wake_post_buckets_task(dev);
+
+ dioprintk((KERN_INFO MYNAM "/receive_post_reply: %d buckets "
+ "remaining, %d received back since sod\n",
+ atomic_read(&priv->buckets_out), priv->total_received));
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+//static inline int
+static int
+mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg)
+{
+ struct mpt_lan_priv *priv = dev->priv;
+ MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+ struct sk_buff *skb, *old_skb;
+ unsigned long flags;
+ u32 ctx, len;
+
+ ctx = GET_LAN_BUCKET_CONTEXT(tmsg);
+ skb = priv->RcvCtl[ctx].skb;
+
+ len = GET_LAN_PACKET_LENGTH(tmsg);
+
+ if (len < MPT_LAN_RX_COPYBREAK) {
+ old_skb = skb;
+
+ skb = (struct sk_buff *)dev_alloc_skb(len);
+ if (!skb) {
+ printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ __FILE__, __LINE__);
+ return -ENOMEM;
+ }
+
+ pci_dma_sync_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
+ priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
+
+ memcpy(skb_put(skb, len), old_skb->data, len);
+
+ goto out;
+ }
+
+ skb_put(skb, len);
+
+ priv->RcvCtl[ctx].skb = NULL;
+
+ pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
+ priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
+
+out:
+ spin_lock_irqsave(&priv->rxfidx_lock, flags);
+ priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+ spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+ atomic_dec(&priv->buckets_out);
+ priv->total_received++;
+
+ return mpt_lan_receive_skb(dev, skb);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_receive_post_free(struct net_device *dev,
+ LANReceivePostReply_t *pRecvRep)
+{
+ struct mpt_lan_priv *priv = dev->priv;
+ MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+ unsigned long flags;
+ struct sk_buff *skb;
+ u32 ctx;
+ u8 count;
+ int i;
+
+ count = pRecvRep->NumberOfContexts;
+
+/**/ dprintk((KERN_INFO MYNAM "/receive_post_reply: "
+ "IOC returned %d buckets, freeing them...\n", count));
+
+ spin_lock_irqsave(&priv->rxfidx_lock, flags);
+ for (i = 0; i < count; i++) {
+ ctx = le32_to_cpu(pRecvRep->BucketContext[i]);
+
+ skb = priv->RcvCtl[ctx].skb;
+
+// dprintk((KERN_INFO MYNAM ": %s: dev_name = %s\n",
+// IOC_AND_NETDEV_NAMES_s_s(dev)));
+// dprintk((KERN_INFO MYNAM "@rpr[2], priv = %p, buckets_out addr = %p",
+// priv, &(priv->buckets_out)));
+// dprintk((KERN_INFO MYNAM "@rpr[2] TC + 3\n"));
+
+ priv->RcvCtl[ctx].skb = NULL;
+ pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
+ priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb_any(skb);
+
+ priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+ }
+ spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+ atomic_sub(count, &priv->buckets_out);
+
+// for (i = 0; i < priv->max_buckets_out; i++)
+// if (priv->RcvCtl[i].skb != NULL)
+// dprintk((KERN_INFO MYNAM "@rpr: bucket %03x "
+// "is still out\n", i));
+
+/* dprintk((KERN_INFO MYNAM "/receive_post_reply: freed %d buckets\n",
+ count));
+*/
+/**/ dprintk((KERN_INFO MYNAM "@receive_post_reply: %d buckets "
+/**/ "remaining, %d received back since sod.\n",
+/**/ atomic_read(&priv->buckets_out), priv->total_received));
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_receive_post_reply(struct net_device *dev,
+ LANReceivePostReply_t *pRecvRep)
+{
+ struct mpt_lan_priv *priv = dev->priv;
+ MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+ struct sk_buff *skb, *old_skb;
+ unsigned long flags;
+ u32 len, ctx;
+ u32 offset;
+ u8 count;
+ int i, l;
+
+ dioprintk((KERN_INFO MYNAM ": mpt_lan_receive_post_reply called\n"));
+ dioprintk((KERN_INFO MYNAM ": receive_post_reply: IOCStatus: %04x\n",
+ le16_to_cpu(pRecvRep->IOCStatus)));
+
+ if (le16_to_cpu(pRecvRep->IOCStatus) & MPI_IOCSTATUS_LAN_CANCELED)
+ return mpt_lan_receive_post_free(dev, pRecvRep);
+
+ len = le32_to_cpu(pRecvRep->PacketLength);
+ if (len == 0) {
+ printk (KERN_ERR MYNAM ": %s/%s: ERROR - Got a non-TURBO "
+ "ReceivePostReply w/ PacketLength zero!\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev));
+ printk (KERN_ERR MYNAM ": MsgFlags = %02x, IOCStatus = %04x\n",
+ pRecvRep->MsgFlags, le16_to_cpu(pRecvRep->IOCStatus));
+ return -1;
+ }
+
+ ctx = le32_to_cpu(pRecvRep->BucketContext[0]);
+ count = pRecvRep->NumberOfContexts;
+ skb = priv->RcvCtl[ctx].skb;
+
+ offset = le32_to_cpu(pRecvRep->PacketOffset);
+// if (offset != 0) {
+// printk (KERN_INFO MYNAM ": %s/%s: Got a ReceivePostReply "
+// "w/ PacketOffset %u\n",
+// IOC_AND_NETDEV_NAMES_s_s(dev),
+// offset);
+// }
+
+ dioprintk((KERN_INFO MYNAM ": %s/%s: @rpr, offset = %d, len = %d\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ offset, len));
+
+ if (count > 1) {
+ int szrem = len;
+
+// dioprintk((KERN_INFO MYNAM ": %s/%s: Multiple buckets returned "
+// "for single packet, concatenating...\n",
+// IOC_AND_NETDEV_NAMES_s_s(dev)));
+
+ skb = (struct sk_buff *)dev_alloc_skb(len);
+ if (!skb) {
+ printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ __FILE__, __LINE__);
+ return -ENOMEM;
+ }
+
+ spin_lock_irqsave(&priv->rxfidx_lock, flags);
+ for (i = 0; i < count; i++) {
+
+ ctx = le32_to_cpu(pRecvRep->BucketContext[i]);
+ old_skb = priv->RcvCtl[ctx].skb;
+
+ l = priv->RcvCtl[ctx].len;
+ if (szrem < l)
+ l = szrem;
+
+// dioprintk((KERN_INFO MYNAM ": %s/%s: Buckets = %d, len = %u\n",
+// IOC_AND_NETDEV_NAMES_s_s(dev),
+// i, l));
+
+ pci_dma_sync_single(mpt_dev->pcidev,
+ priv->RcvCtl[ctx].dma,
+ priv->RcvCtl[ctx].len,
+ PCI_DMA_FROMDEVICE);
+ memcpy(skb_put(skb, l), old_skb->data, l);
+
+ priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+ szrem -= l;
+ }
+ spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+ } else if (len < MPT_LAN_RX_COPYBREAK) {
+
+ old_skb = skb;
+
+ skb = (struct sk_buff *)dev_alloc_skb(len);
+ if (!skb) {
+ printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ __FILE__, __LINE__);
+ return -ENOMEM;
+ }
+
+ pci_dma_sync_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
+ priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
+
+ memcpy(skb_put(skb, len), old_skb->data, len);
+
+ spin_lock_irqsave(&priv->rxfidx_lock, flags);
+ priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+ spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+ } else {
+ spin_lock_irqsave(&priv->rxfidx_lock, flags);
+
+ priv->RcvCtl[ctx].skb = NULL;
+
+ pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
+ priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
+ priv->RcvCtl[ctx].dma = 0;
+
+ priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+ spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+ skb_put(skb,len);
+ }
+
+ atomic_sub(count, &priv->buckets_out);
+ priv->total_received += count;
+
+ if (priv->mpt_rxfidx_tail >= MPT_LAN_MAX_BUCKETS_OUT) {
+ printk (KERN_ERR MYNAM ": %s/%s: Yoohoo! mpt_rxfidx_tail = %d, "
+ "MPT_LAN_MAX_BUCKETS_OUT = %d\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ priv->mpt_rxfidx_tail,
+ MPT_LAN_MAX_BUCKETS_OUT);
+
+ panic("Damn it Jim! I'm a doctor, not a programmer! "
+ "Oh, wait a sec, I am a programmer. "
+ "And, who's Jim?!?!\n"
+ "Arrgghh! We've done it again!\n");
+ }
+
+#if 0
+ {
+ u32 remaining = le32_to_cpu(pRecvRep->BucketsRemaining);
+ if (remaining < priv->bucketthresh)
+ mpt_lan_wake_post_buckets_task(dev);
+
+ if (remaining == 0)
+ printk (KERN_WARNING MYNAM ": %s/%s: WARNING - IOC out of buckets! "
+ "(priv->buckets_out = %d)\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ atomic_read(&priv->buckets_out));
+ else
+ printk (KERN_INFO MYNAM ": %s/%s: IOC says %d buckets left. "
+ "(priv->buckets_out = %d)\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ remaining, atomic_read(&priv->buckets_out));
+ }
+#endif
+
+ return mpt_lan_receive_skb(dev, skb);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Simple SGE's only at the moment */
+
+static void
+mpt_lan_post_receive_buckets(void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct mpt_lan_priv *priv = dev->priv;
+ MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+ MPT_FRAME_HDR *mf;
+ LANReceivePostRequest_t *pRecvReq;
+ SGETransaction32_t *pTrans;
+ SGESimple64_t *pSimple;
+ struct sk_buff *skb;
+ dma_addr_t dma;
+ u32 curr, buckets, count, max;
+ u32 len = (dev->mtu + dev->hard_header_len + 4);
+ unsigned long flags;
+ int i;
+
+ curr = atomic_read(&priv->buckets_out);
+ buckets = (priv->max_buckets_out - curr);
+
+ dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, Start_buckets = %u, buckets_out = %u\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ __FUNCTION__, buckets, curr));
+
+ max = (mpt_dev->req_sz - MPT_LAN_RECEIVE_POST_REQUEST_SIZE) /
+ (MPT_LAN_TRANSACTION32_SIZE + sizeof(SGESimple64_t));
+
+ while (buckets) {
+ mf = mpt_get_msg_frame(LanCtx, mpt_dev->id);
+ if (mf == NULL) {
+ printk (KERN_ERR "%s: Unable to alloc request frame\n",
+ __FUNCTION__);
+ dioprintk((KERN_ERR "%s: %u buckets remaining\n",
+ __FUNCTION__, buckets));
+ goto out;
+ }
+ pRecvReq = (LANReceivePostRequest_t *) mf;
+
+ count = buckets;
+ if (count > max)
+ count = max;
+
+ pRecvReq->Function = MPI_FUNCTION_LAN_RECEIVE;
+ pRecvReq->ChainOffset = 0;
+ pRecvReq->MsgFlags = 0;
+ pRecvReq->PortNumber = priv->pnum;
+
+ pTrans = (SGETransaction32_t *) pRecvReq->SG_List;
+ pSimple = NULL;
+
+ for (i = 0; i < count; i++) {
+ int ctx;
+
+ spin_lock_irqsave(&priv->rxfidx_lock, flags);
+ if (priv->mpt_rxfidx_tail < 0) {
+ printk (KERN_ERR "%s: Can't alloc context\n",
+ __FUNCTION__);
+ spin_unlock_irqrestore(&priv->rxfidx_lock,
+ flags);
+ break;
+ }
+
+ ctx = priv->mpt_rxfidx[priv->mpt_rxfidx_tail--];
+
+ skb = priv->RcvCtl[ctx].skb;
+ if (skb && (priv->RcvCtl[ctx].len != len)) {
+ pci_unmap_single(mpt_dev->pcidev,
+ priv->RcvCtl[ctx].dma,
+ priv->RcvCtl[ctx].len,
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(priv->RcvCtl[ctx].skb);
+ skb = priv->RcvCtl[ctx].skb = NULL;
+ }
+
+ if (skb == NULL) {
+ skb = dev_alloc_skb(len);
+ if (skb == NULL) {
+/**/ printk (KERN_WARNING
+/**/ MYNAM "/%s: Can't alloc skb\n",
+/**/ __FUNCTION__);
+ priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+ spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+ break;
+ }
+
+ dma = pci_map_single(mpt_dev->pcidev, skb->data,
+ len, PCI_DMA_FROMDEVICE);
+
+ priv->RcvCtl[ctx].skb = skb;
+ priv->RcvCtl[ctx].dma = dma;
+ priv->RcvCtl[ctx].len = len;
+ }
+
+ spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+ pTrans->ContextSize = sizeof(u32);
+ pTrans->DetailsLength = 0;
+ pTrans->Flags = 0;
+ pTrans->TransactionContext[0] = cpu_to_le32(ctx);
+
+ pSimple = (SGESimple64_t *) pTrans->TransactionDetails;
+
+ pSimple->FlagsLength = cpu_to_le32(
+ ((MPI_SGE_FLAGS_END_OF_BUFFER |
+ MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI_SGE_FLAGS_64_BIT_ADDRESSING) << MPI_SGE_FLAGS_SHIFT) | len);
+ pSimple->Address.Low = cpu_to_le32((u32) priv->RcvCtl[ctx].dma);
+ if (sizeof(dma_addr_t) > sizeof(u32))
+ pSimple->Address.High = cpu_to_le32((u32) ((u64) priv->RcvCtl[ctx].dma >> 32));
+ else
+ pSimple->Address.High = 0;
+
+ pTrans = (SGETransaction32_t *) (pSimple + 1);
+ }
+
+ if (pSimple == NULL) {
+/**/ printk (KERN_WARNING MYNAM "/%s: No buckets posted\n",
+/**/ __FUNCTION__);
+ mpt_free_msg_frame(LanCtx, mpt_dev->id, mf);
+ goto out;
+ }
+
+ pSimple->FlagsLength |= cpu_to_le32(MPI_SGE_FLAGS_END_OF_LIST << MPI_SGE_FLAGS_SHIFT);
+
+ pRecvReq->BucketCount = cpu_to_le32(i);
+
+/* printk(KERN_INFO MYNAM ": posting buckets\n ");
+ * for (i = 0; i < j + 2; i ++)
+ * printk (" %08x", le32_to_cpu(msg[i]));
+ * printk ("\n");
+ */
+
+ mpt_put_msg_frame(LanCtx, mpt_dev->id, mf);
+
+ priv->total_posted += i;
+ buckets -= i;
+ atomic_add(i, &priv->buckets_out);
+ }
+
+out:
+ dioprintk((KERN_INFO MYNAM "/%s: End_buckets = %u, priv->buckets_out = %u\n",
+ __FUNCTION__, buckets, atomic_read(&priv->buckets_out)));
+ dioprintk((KERN_INFO MYNAM "/%s: Posted %u buckets and received %u back\n",
+ __FUNCTION__, priv->total_posted, priv->total_received));
+
+ clear_bit(0, &priv->post_buckets_active);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+struct net_device *
+mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
+{
+ struct net_device *dev = NULL;
+ struct mpt_lan_priv *priv = NULL;
+ u8 HWaddr[FC_ALEN], *a;
+
+ dev = init_fcdev(NULL, sizeof(struct mpt_lan_priv));
+ if (!dev)
+ return (NULL);
+ dev->mtu = MPT_LAN_MTU;
+
+ priv = (struct mpt_lan_priv *) dev->priv;
+
+ priv->mpt_dev = mpt_dev;
+ priv->pnum = pnum;
+
+ memset(&priv->post_buckets_task, 0, sizeof(struct tq_struct));
+ priv->post_buckets_task.routine = mpt_lan_post_receive_buckets;
+ priv->post_buckets_task.data = dev;
+ priv->post_buckets_active = 0;
+
+ dprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n",
+ __LINE__, dev->mtu + dev->hard_header_len + 4));
+
+ atomic_set(&priv->buckets_out, 0);
+ priv->total_posted = 0;
+ priv->total_received = 0;
+ priv->max_buckets_out = max_buckets_out;
+ if (mpt_dev->pfacts0.MaxLanBuckets < max_buckets_out)
+ priv->max_buckets_out = mpt_dev->pfacts0.MaxLanBuckets;
+
+ dprintk((KERN_INFO MYNAM "@%d: MaxLanBuckets=%d, max_buckets_out/priv=%d/%d\n",
+ __LINE__,
+ mpt_dev->pfacts0.MaxLanBuckets,
+ max_buckets_out,
+ priv->max_buckets_out));
+
+ priv->bucketthresh = priv->max_buckets_out * 2 / 3;
+ priv->txfidx_lock = SPIN_LOCK_UNLOCKED;
+ priv->rxfidx_lock = SPIN_LOCK_UNLOCKED;
+
+ memset(&priv->stats, 0, sizeof(priv->stats));
+
+ /* Grab pre-fetched LANPage1 stuff. :-) */
+ a = (u8 *) &mpt_dev->lan_cnfg_page1.HardwareAddressLow;
+
+ HWaddr[0] = a[5];
+ HWaddr[1] = a[4];
+ HWaddr[2] = a[3];
+ HWaddr[3] = a[2];
+ HWaddr[4] = a[1];
+ HWaddr[5] = a[0];
+
+ dev->addr_len = FC_ALEN;
+ memcpy(dev->dev_addr, HWaddr, FC_ALEN);
+ memset(dev->broadcast, 0xff, FC_ALEN);
+
+ /* The Tx queue is 127 deep on the 909.
+ * Give ourselves some breathing room.
+ */
+ priv->tx_max_out = (tx_max_out_p <= MPT_TX_MAX_OUT_LIM) ?
+ tx_max_out_p : MPT_TX_MAX_OUT_LIM;
+
+ dev->open = mpt_lan_open;
+ dev->stop = mpt_lan_close;
+ dev->get_stats = mpt_lan_get_stats;
+ dev->set_multicast_list = NULL;
+ dev->change_mtu = mpt_lan_change_mtu;
+ dev->hard_start_xmit = mpt_lan_sdu_send;
+
+/* Not in 2.3.42. Need 2.3.45+ */
+ dev->tx_timeout = mpt_lan_tx_timeout;
+ dev->watchdog_timeo = MPT_LAN_TX_TIMEOUT;
+
+ dprintk((KERN_INFO MYNAM ": Finished registering dev "
+ "and setting initial values\n"));
+
+ SET_MODULE_OWNER(dev);
+
+ return dev;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+int __init
+mpt_lan_init (void)
+{
+ struct net_device *dev;
+ MPT_ADAPTER *curadapter;
+ int i = 0, j;
+
+ show_mptmod_ver(LANAME, LANVER);
+
+ if ((LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER)) < 0) {
+ printk (KERN_ERR MYNAM ": Failed to register with MPT base driver\n");
+ return -EBUSY;
+ }
+
+ /* Set the callback index to be used by driver core for turbo replies */
+ mpt_lan_index = LanCtx;
+
+ dprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx));
+
+ for (j = 0; j < MPT_MAX_ADAPTERS; j++) {
+ mpt_landev[j] = NULL;
+ }
+ j = 0;
+
+ curadapter = mpt_adapter_find_first();
+ while (curadapter != NULL) {
+ for (i = 0; i < curadapter->facts0.NumberOfPorts; i++) {
+ printk (KERN_INFO MYNAM ": %s: PortNum=%x, ProtocolFlags=%02Xh (%c%c%c%c)\n",
+ curadapter->name,
+ curadapter->pfacts0.PortNumber,
+ curadapter->pfacts0.ProtocolFlags,
+ MPT_PROTOCOL_FLAGS_c_c_c_c(curadapter->pfacts0.ProtocolFlags));
+
+ if (curadapter->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+ dev = mpt_register_lan_device (curadapter, i);
+ if (dev != NULL) {
+ printk (KERN_INFO MYNAM ": %s: Fusion MPT LAN device registered as '%s'\n",
+ curadapter->name, dev->name);
+ printk (KERN_INFO MYNAM ": %s/%s: LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ dev->dev_addr[0], dev->dev_addr[1],
+ dev->dev_addr[2], dev->dev_addr[3],
+ dev->dev_addr[4], dev->dev_addr[5]);
+// printk (KERN_INFO MYNAM ": %s/%s: Max_TX_outstanding = %d\n",
+// IOC_AND_NETDEV_NAMES_s_s(dev),
+// NETDEV_TO_LANPRIV_PTR(dev)->tx_max_out);
+ mpt_landev[j] = dev;
+ dprintk((KERN_INFO MYNAM "/init: dev_addr=%p, mpt_landev[%d]=%p\n",
+ dev, j, mpt_landev[j]));
+
+ j++;
+ } else {
+ printk (KERN_ERR MYNAM ": %s: Unable to register port%d as a LAN device\n",
+ curadapter->name,
+ curadapter->pfacts0.PortNumber);
+ }
+ } else {
+ printk (KERN_INFO MYNAM ": %s: Hmmm... LAN protocol seems to be disabled on this adapter port!\n",
+ curadapter->name);
+ }
+ }
+ curadapter = mpt_adapter_find_next(curadapter);
+ }
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+void __init mpt_lan_exit(void)
+{
+ int i;
+
+ for (i = 0; mpt_landev[i] != NULL; i++) {
+ struct net_device *dev = mpt_landev[i];
+
+ printk (KERN_INFO MYNAM ": %s/%s: Fusion MPT LAN device unregistered\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev));
+ unregister_fcdev(dev);
+ mpt_landev[i] = (struct net_device *) 0xdeadbeef; /* Debug */
+ }
+
+ if (LanCtx >= 0) {
+ mpt_deregister(LanCtx);
+ LanCtx = -1;
+ mpt_lan_index = 0;
+ }
+
+ /* deregister any send/receive handler structs. I2Oism? */
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+MODULE_PARM(tx_max_out_p, "i");
+MODULE_PARM(max_buckets_out, "i"); // Debug stuff. FIXME!
+
+module_init(mpt_lan_init);
+module_exit(mpt_lan_exit);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static unsigned short
+mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev)
+{
+ struct mpt_lan_ohdr *fch = (struct mpt_lan_ohdr *)skb->data;
+ struct fcllc *fcllc;
+
+ skb->mac.raw = skb->data;
+ skb_pull(skb, sizeof(struct mpt_lan_ohdr));
+
+ if (fch->dtype == htons(0xffff)) {
+ u32 *p = (u32 *) fch;
+
+ swab32s(p + 0);
+ swab32s(p + 1);
+ swab32s(p + 2);
+ swab32s(p + 3);
+
+ printk (KERN_WARNING MYNAM ": %s: WARNING - Broadcast swap F/W bug detected!\n",
+ NETDEV_PTR_TO_IOC_NAME_s(dev));
+ printk (KERN_WARNING MYNAM ": Please update sender @ MAC_addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ fch->saddr[0], fch->saddr[1], fch->saddr[2],
+ fch->saddr[3], fch->saddr[4], fch->saddr[5]);
+ }
+
+ if (*fch->daddr & 1) {
+ if (!memcmp(fch->daddr, dev->broadcast, FC_ALEN)) {
+ skb->pkt_type = PACKET_BROADCAST;
+ } else {
+ skb->pkt_type = PACKET_MULTICAST;
+ }
+ } else {
+ if (memcmp(fch->daddr, dev->dev_addr, FC_ALEN)) {
+ skb->pkt_type = PACKET_OTHERHOST;
+ } else {
+ skb->pkt_type = PACKET_HOST;
+ }
+ }
+
+ /* Strip the SNAP header from ARP packets since we don't
+ * pass them through to the 802.2/SNAP layers.
+ */
+ fcllc = (struct fcllc *)skb->data;
+
+ if (fcllc->dsap == EXTENDED_SAP &&
+ (fcllc->ethertype == htons(ETH_P_IP) ||
+ fcllc->ethertype == htons(ETH_P_ARP))) {
+ skb_pull(skb, sizeof(struct fcllc));
+ return fcllc->ethertype;
+ }
+
+ return htons(ETH_P_802_2);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
--- /dev/null
+/* mptlan.h */
+
+#ifndef LINUX_MPTLAN_H_INCLUDED
+#define LINUX_MPTLAN_H_INCLUDED
+/*****************************************************************************/
+
+#if !defined(__GENKSYMS__)
+#include <linux/module.h>
+#endif
+
+#include <linux/netdevice.h>
+#include <linux/errno.h>
+// #include <linux/etherdevice.h>
+#include <linux/fcdevice.h>
+// #include <linux/fddidevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/tqueue.h>
+// #include <linux/trdevice.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+ /* Override mptbase.h by pre-defining these! */
+ #define MODULEAUTHOR "Noah Romer, Eddie C. Dost"
+
+#include "mptbase.h"
+
+/*****************************************************************************/
+#define LANAME "Fusion MPT LAN driver"
+#define LANVER MPT_LINUX_VERSION_COMMON
+
+#ifdef MODULE
+MODULE_AUTHOR(MODULEAUTHOR);
+MODULE_DESCRIPTION(LANAME);
+#endif
+/*****************************************************************************/
+
+#define MPT_LAN_MAX_BUCKETS_OUT 256
+#define MPT_LAN_BUCKET_THRESH 18 /* 9 buckets in one message */
+#define MPT_LAN_RX_COPYBREAK 200
+#define MPT_LAN_TX_TIMEOUT (1*HZ)
+#define MPT_TX_MAX_OUT_LIM 127
+
+#define MPT_LAN_MIN_MTU 96 /* RFC2625 */
+#define MPT_LAN_MAX_MTU 65280 /* RFC2625 */
+#define MPT_LAN_MTU 16128 /* be nice to slab allocator */
+
+/* MPT LAN Reset and Suspend Resource Flags Defines */
+
+#define MPT_LAN_RESOURCE_FLAG_RETURN_POSTED_BUCKETS 0x01
+#define MPT_LAN_RESOURCE_FLAG_RETURN_PEND_TRANSMITS 0x02
+
+/*****************************************************************************/
+#ifdef MPT_LAN_IO_DEBUG
+#define dioprintk(x) printk x
+#else
+#define dioprintk(x)
+#endif
+
+#define NETDEV_TO_LANPRIV_PTR(d) ((struct mpt_lan_priv *)(d)->priv)
+#define NETDEV_PTR_TO_IOC_NAME_s(d) (NETDEV_TO_LANPRIV_PTR(d)->mpt_dev->name)
+#define IOC_AND_NETDEV_NAMES_s_s(d) NETDEV_PTR_TO_IOC_NAME_s(d), (d)->name
+
+/*****************************************************************************/
+#endif
+
--- /dev/null
+/*
+ * linux/drivers/message/fusion/mptscsih.c
+ * High performance SCSI / Fibre Channel SCSI Host device driver.
+ * For use with PCI chip/adapter(s):
+ * LSIFC9xx/LSI409xx Fibre Channel
+ * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ * Credits:
+ * This driver would not exist if not for Alan Cox's development
+ * of the linux i2o driver.
+ *
+ * A huge debt of gratitude is owed to David S. Miller (DaveM)
+ * for fixing much of the stupid and broken stuff in the early
+ * driver while porting to sparc64 platform. THANK YOU!
+ *
+ * (see mptbase.c)
+ *
+ * Copyright (c) 1999-2001 LSI Logic Corporation
+ * Original author: Steven J. Ralston
+ * (mailto:Steve.Ralston@lsil.com)
+ *
+ * $Id: mptscsih.c,v 1.24 2001/03/22 08:45:08 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ 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; version 2 of the License.
+
+ 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.
+
+ NO WARRANTY
+ THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ solely responsible for determining the appropriateness of using and
+ distributing the Program and assumes all risks associated with its
+ exercise of rights under this Agreement, including but not limited to
+ the risks and costs of program errors, damage to or loss of data,
+ programs or equipment, and unavailability or interruption of operations.
+
+ DISCLAIMER OF LIABILITY
+ NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kdev_t.h>
+#include <linux/blkdev.h>
+#include <linux/blk.h> /* for io_request_lock (spinlock) decl */
+#include "../../scsi/scsi.h"
+#include "../../scsi/hosts.h"
+#include "../../scsi/sd.h"
+
+#include "mptbase.h"
+#include "mptscsih.h"
+#include "isense.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#define my_NAME "Fusion MPT SCSI Host driver"
+#define my_VERSION MPT_LINUX_VERSION_COMMON
+#define MYNAM "mptscsih"
+
+MODULE_AUTHOR(MODULEAUTHOR);
+MODULE_DESCRIPTION(my_NAME);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+typedef struct _BIG_SENSE_BUF {
+ u8 data[256];
+} BIG_SENSE_BUF;
+
+typedef struct _MPT_SCSI_HOST {
+ MPT_ADAPTER *ioc;
+ int port;
+ struct scsi_cmnd **ScsiLookup;
+ u8 *SgHunks;
+ dma_addr_t SgHunksDMA;
+ u32 qtag_tick;
+ FCDEV_TRACKER TargetsQ;
+} MPT_SCSI_HOST;
+
+typedef struct _MPT_SCSI_DEV {
+ struct _MPT_SCSI_DEV *forw;
+ struct _MPT_SCSI_DEV *back;
+ MPT_ADAPTER *ioc;
+ int sense_sz;
+ BIG_SENSE_BUF CachedSense;
+ unsigned long io_cnt;
+ unsigned long read_cnt;
+} MPT_SCSI_DEV;
+
+/*
+ * Other private/forward protos...
+ */
+
+static int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
+static void mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
+static int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
+static int mptscsih_io_direction(Scsi_Cmnd *cmd);
+static void copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
+static u32 SCPNT_TO_MSGCTX(Scsi_Cmnd *sc);
+
+static int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
+
+
+static int mpt_scsi_hosts = 0;
+static atomic_t queue_depth;
+
+static int ScsiDoneCtx = -1;
+static int ScsiTaskCtx = -1;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,28)
+static struct proc_dir_entry proc_mpt_scsihost =
+{
+ low_ino: PROC_SCSI_MPT,
+ namelen: 8,
+ name: "mptscsih",
+ mode: S_IFDIR | S_IRUGO | S_IXUGO,
+ nlink: 2,
+};
+#endif
+
+#define SNS_LEN(scp) sizeof((scp)->sense_buffer)
+
+#ifndef MPT_SCSI_USE_NEW_EH
+/*
+ * Stuff to handle single-threading SCSI TaskMgmt
+ * (abort/reset) requests...
+ */
+static spinlock_t mpt_scsih_taskQ_lock = SPIN_LOCK_UNLOCKED;
+static MPT_Q_TRACKER mpt_scsih_taskQ = {
+ (MPT_FRAME_HDR*) &mpt_scsih_taskQ,
+ (MPT_FRAME_HDR*) &mpt_scsih_taskQ
+};
+static int mpt_scsih_taskQ_cnt = 0;
+static int mpt_scsih_taskQ_bh_active = 0;
+static MPT_FRAME_HDR *mpt_scsih_active_taskmgmt_mf = NULL;
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * mptscsih_io_done - Main SCSI IO callback routine registered to
+ * Fusion MPT (base) driver
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @mf: Pointer to original MPT request frame
+ * @r: Pointer to MPT reply frame (NULL if TurboReply)
+ *
+ * This routine is called from mpt.c::mpt_interrupt() at the completion
+ * of any SCSI IO request.
+ * This routine is registered with the Fusion MPT (base) driver at driver
+ * load/init time via the mpt_register() API call.
+ *
+ * Returns 1 indicating alloc'd request frame ptr should be freed.
+ */
+static int
+mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r)
+{
+ Scsi_Cmnd *sc;
+ MPT_SCSI_HOST *hd;
+ MPT_SCSI_DEV *mpt_sdev = NULL;
+ u16 req_idx;
+
+ if ((mf == NULL) ||
+ (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
+ printk(KERN_ERR MYNAM ": ERROR! NULL or BAD req frame ptr (=%p)!\n", mf);
+ return 1;
+ }
+
+ hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+ req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+ sc = hd->ScsiLookup[req_idx];
+ hd->ScsiLookup[req_idx] = NULL;
+
+ dmfprintk((KERN_INFO MYNAM ": ScsiDone (req:sc:reply=%p:%p:%p)\n", mf, sc, r));
+
+ atomic_dec(&queue_depth);
+
+ /*
+ * Check for {1st} {IO} completion to "new" device.
+ * How do we know it's a new device?
+ * If we haven't set SDpnt->hostdata I guess...
+ */
+ if (sc && sc->device) {
+ mpt_sdev = (MPT_SCSI_DEV*)sc->device->hostdata;
+ if (!mpt_sdev) {
+ dprintk((KERN_INFO MYNAM ": *NEW* SCSI device (%d:%d:%d)!\n",
+ sc->device->id, sc->device->lun, sc->device->channel));
+ if ((sc->device->hostdata = kmalloc(sizeof(MPT_SCSI_DEV), GFP_ATOMIC)) == NULL) {
+ printk(KERN_ERR MYNAM ": ERROR: kmalloc(%d) FAILED!\n", (int)sizeof(MPT_SCSI_DEV));
+ } else {
+ memset(sc->device->hostdata, 0, sizeof(MPT_SCSI_DEV));
+ mpt_sdev = (MPT_SCSI_DEV *) sc->device->hostdata;
+ mpt_sdev->ioc = ioc;
+ }
+ } else {
+ if (++mpt_sdev->io_cnt && mptscsih_io_direction(sc) < 0) {
+ if (++mpt_sdev->read_cnt == 3) {
+ dprintk((KERN_INFO MYNAM ": 3rd DATA_IN, CDB[0]=%02x\n",
+ sc->cmnd[0]));
+ }
+ }
+#if 0
+ if (mpt_sdev->sense_sz) {
+ /*
+ * Completion of first IO down this path
+ * *should* invalidate device SenseData...
+ */
+ mpt_sdev->sense_sz = 0;
+ }
+#endif
+ }
+ }
+
+#if 0
+{
+ MPT_FRAME_HDR *mf_chk;
+
+ /* This, I imagine, is a costly check, but...
+ * If abort/reset active, check to see if this is a IO
+ * that completed while ABORT/RESET for it is waiting
+ * on our taskQ!
+ */
+ if (! Q_IS_EMPTY(&mpt_scsih_taskQ)) {
+ /* If ABORT for this IO is queued, zap it! */
+ mf_chk = search_taskQ(1,sc,MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
+ if (mf_chk != NULL) {
+ sc->result = DID_ABORT << 16;
+ spin_lock_irqsave(&io_request_lock, flags);
+ sc->scsi_done(sc);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ return 1;
+ }
+ }
+}
+#endif
+
+ if (r != NULL && sc != NULL) {
+ SCSIIOReply_t *pScsiReply;
+ SCSIIORequest_t *pScsiReq;
+ u16 status;
+
+ pScsiReply = (SCSIIOReply_t *) r;
+ pScsiReq = (SCSIIORequest_t *) mf;
+
+ status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+
+ dprintk((KERN_NOTICE MYNAM ": Uh-Oh! (req:sc:reply=%p:%p:%p)\n", mf, sc, r));
+ dprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh"
+ ", SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
+ status, pScsiReply->SCSIState, pScsiReply->SCSIStatus,
+ le32_to_cpu(pScsiReply->IOCLogInfo)));
+
+ /*
+ * Look for + dump FCP ResponseInfo[]!
+ */
+ if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID) {
+ dprintk((KERN_NOTICE " FCP_ResponseInfo=%08xh\n",
+ le32_to_cpu(pScsiReply->ResponseInfo)));
+ }
+
+ switch(status) {
+ case MPI_IOCSTATUS_BUSY: /* 0x0002 */
+ /*sc->result = DID_BUS_BUSY << 16;*/ /* YIKES! - Seems to
+ * kill linux interrupt
+ * handler
+ */
+ sc->result = STS_BUSY; /* Try SCSI BUSY! */
+ break;
+
+ case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
+ /* Not real sure here... */
+ sc->result = DID_OK << 16;
+ break;
+
+ case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
+ case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
+ sc->result = DID_BAD_TARGET << 16;
+ break;
+
+ case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
+ /* Spoof to SCSI Selection Timeout! */
+ sc->result = DID_NO_CONNECT << 16;
+ break;
+
+ case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
+ /*
+ * YIKES! I just discovered that SCSI IO which
+ * returns check condition, SenseKey=05 (ILLEGAL REQUEST)
+ * and ASC/ASCQ=94/01 (LSI Logic RAID vendor specific),
+ * comes down this path!
+ * Do upfront check for valid SenseData and give it
+ * precedence!
+ */
+ if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+ copy_sense_data(sc, hd, mf, pScsiReply);
+ sc->result = pScsiReply->SCSIStatus;
+ break;
+ }
+
+ dprintk((KERN_NOTICE MYNAM ": sc->underflow={report ERR if < %02xh bytes xfer'd}\n", sc->underflow));
+ dprintk((KERN_NOTICE MYNAM ": ActBytesXferd=%02xh\n", le32_to_cpu(pScsiReply->TransferCount)));
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+ sc->resid = sc->request_bufflen - le32_to_cpu(pScsiReply->TransferCount);
+ dprintk((KERN_NOTICE MYNAM ": SET sc->resid=%02xh\n", sc->resid));
+#endif
+
+#if 0
+ if (sc->underflow && (le32_to_cpu(pScsiReply->TransferCount) < sc->underflow)) {
+ sc->result = DID_ERROR << 16;
+ sc->resid = sc->request_bufflen - le32_to_cpu(pScsiReply->TransferCount);
+ } else {
+ sc->result = 0;
+ }
+#endif
+
+ /* workaround attempts... */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+ if (sc->resid >= 0x200) {
+ /* GRRRRR...
+ * //sc->result = DID_SOFT_ERROR << 16;
+ * Try spoofing to BUSY
+ */
+ sc->result = STS_BUSY;
+ } else {
+ sc->result = 0;
+ }
+#else
+ sc->result = 0;
+#endif
+ break;
+
+ case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
+ sc->result = DID_ABORT << 16;
+ break;
+
+ case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
+ case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
+ sc->result = DID_RESET << 16;
+ break;
+
+ case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
+ sc->result = pScsiReply->SCSIStatus;
+
+ if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+ copy_sense_data(sc, hd, mf, pScsiReply);
+
+ /* If running agains circa 200003dd 909 MPT f/w,
+ * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
+ * (QUEUE_FULL) returned from device! --> get 0x0000?128
+ * and with SenseBytes set to 0.
+ */
+ if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
+ mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
+ }
+ else if (pScsiReply->SCSIState & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
+ /*
+ * What to do?
+ */
+ sc->result = DID_SOFT_ERROR << 16;
+ }
+ else if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) {
+ /* Not real sure here either... */
+ sc->result = DID_ABORT << 16;
+ }
+
+ if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
+ mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
+
+ break;
+
+ case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
+ case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
+ case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
+ case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
+ case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
+ case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
+ case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
+ case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
+ case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
+ case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
+ case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
+ case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
+ default:
+ /*
+ * What to do?
+ */
+ sc->result = DID_SOFT_ERROR << 16;
+ break;
+
+ } /* switch(status) */
+
+ dprintk((KERN_NOTICE MYNAM ": sc->result set to %08xh\n", sc->result));
+ }
+
+ if (sc != NULL) {
+ unsigned long flags;
+
+ /* Unmap the DMA buffers, if any. */
+ if (sc->use_sg) {
+ pci_unmap_sg(ioc->pcidev,
+ (struct scatterlist *) sc->request_buffer,
+ sc->use_sg,
+ scsi_to_pci_dma_dir(sc->sc_data_direction));
+ } else if (sc->request_bufflen) {
+ pci_unmap_single(ioc->pcidev,
+ (dma_addr_t)((long)sc->SCp.ptr),
+ sc->request_bufflen,
+ scsi_to_pci_dma_dir(sc->sc_data_direction));
+ }
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ sc->scsi_done(sc);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ }
+
+ return 1;
+}
+
+#ifndef MPT_SCSI_USE_NEW_EH
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * search_taskQ - Search SCSI task mgmt request queue for specific
+ * request type
+ * @remove: (Boolean) Should request be removed if found?
+ * @sc: Pointer to Scsi_Cmnd structure
+ * @task_type: Task type to search for
+ *
+ * Returns pointer to MPT request frame if found, or %NULL if request
+ * was not found.
+ */
+static MPT_FRAME_HDR *
+search_taskQ(int remove, Scsi_Cmnd *sc, u8 task_type)
+{
+ MPT_FRAME_HDR *mf = NULL;
+ unsigned long flags;
+ int count = 0;
+ int list_sz;
+
+ dslprintk((KERN_INFO MYNAM ": spinlock#1\n"));
+ spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+ list_sz = mpt_scsih_taskQ_cnt;
+ if (! Q_IS_EMPTY(&mpt_scsih_taskQ)) {
+ mf = mpt_scsih_taskQ.head;
+ do {
+ count++;
+ if (mf->u.frame.linkage.argp1 == sc &&
+ mf->u.frame.linkage.arg1 == task_type) {
+ if (remove) {
+ Q_DEL_ITEM(&mf->u.frame.linkage);
+ mpt_scsih_taskQ_cnt--;
+ }
+ break;
+ }
+ } while ((mf = mf->u.frame.linkage.forw) != (MPT_FRAME_HDR*)&mpt_scsih_taskQ);
+ if (mf == (MPT_FRAME_HDR*)&mpt_scsih_taskQ) {
+ mf = NULL;
+ }
+ }
+ spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+
+ if (list_sz) {
+ dprintk((KERN_INFO MYNAM ": search_taskQ(%d,%p,%d) results=%p (%sFOUND%s)!\n",
+ remove, sc, task_type,
+ mf,
+ mf ? "" : "NOT_",
+ (mf && remove) ? "+REMOVED" : "" ));
+ dprintk((KERN_INFO MYNAM ": (searched thru %d of %d items on taskQ)\n",
+ count,
+ list_sz ));
+ }
+
+ return mf;
+}
+
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*
+ * Hack! I'd like to report if a device is returning QUEUE_FULL
+ * but maybe not each and every time...
+ */
+static long last_queue_full = 0;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * mptscsih_report_queue_full - Report QUEUE_FULL status returned
+ * from a SCSI target device.
+ * @sc: Pointer to Scsi_Cmnd structure
+ * @pScsiReply: Pointer to SCSIIOReply_t
+ * @pScsiReq: Pointer to original SCSI request
+ *
+ * This routine periodically reports QUEUE_FULL status returned from a
+ * SCSI target device. It reports this to the console via kernel
+ * printk() API call, not more than once every 10 seconds.
+ */
+static void
+mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
+{
+ long time = jiffies;
+
+ if (time - last_queue_full > 10 * HZ) {
+ printk(KERN_WARNING MYNAM ": Device reported QUEUE_FULL! SCSI bus:target:lun = %d:%d:%d\n",
+ 0, sc->target, sc->lun);
+ last_queue_full = time;
+ }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int BeenHereDoneThat = 0;
+
+/* SCSI fops start here... */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mptscsih_detect - Register MPT adapter(s) as SCSI host(s) with
+ * linux scsi mid-layer.
+ * @tpnt: Pointer to Scsi_Host_Template structure
+ *
+ * (linux Scsi_Host_Template.detect routine)
+ *
+ * Returns number of SCSI host adapters that were successfully
+ * registered with the linux scsi mid-layer via the scsi_register()
+ * API call.
+ */
+int
+mptscsih_detect(Scsi_Host_Template *tpnt)
+{
+ struct Scsi_Host *sh = NULL;
+ MPT_SCSI_HOST *hd = NULL;
+ MPT_ADAPTER *this;
+ unsigned long flags;
+ int sz;
+ u8 *mem;
+
+ if (! BeenHereDoneThat++) {
+ show_mptmod_ver(my_NAME, my_VERSION);
+
+ ScsiDoneCtx = mpt_register(mptscsih_io_done, MPTSCSIH_DRIVER);
+ ScsiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSCSIH_DRIVER);
+
+#ifndef MPT_SCSI_USE_NEW_EH
+ Q_INIT(&mpt_scsih_taskQ, MPT_FRAME_HDR);
+ spin_lock_init(&mpt_scsih_taskQ_lock);
+#endif
+
+ if (mpt_event_register(ScsiDoneCtx, mptscsih_event_process) == 0) {
+ dprintk((KERN_INFO MYNAM ": Registered for IOC event notifications\n"));
+ } else {
+ /* FIXME! */
+ }
+ }
+
+ dprintk((KERN_INFO MYNAM ": mpt_scsih_detect()\n"));
+
+ this = mpt_adapter_find_first();
+ while (this != NULL) {
+ /* FIXME! Multi-port (aka FC929) support...
+ * for (i = 0; i < this->facts.NumberOfPorts; i++)
+ */
+
+ /* 20010215 -sralston
+ * Added sanity check on SCSI Initiator-mode enabled
+ * for this MPT adapter.
+ */
+ if (!(this->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) {
+ printk(KERN_ERR MYNAM ": Skipping %s because SCSI Initiator mode is NOT enabled!\n",
+ this->name);
+ this = mpt_adapter_find_next(this);
+ continue;
+ }
+
+ /* 20010202 -sralston
+ * Added sanity check on readiness of the MPT adapter.
+ */
+ if (this->last_state != MPI_IOC_STATE_OPERATIONAL) {
+ printk(KERN_ERR MYNAM ": ERROR - Skipping %s because it's not operational!\n",
+ this->name);
+ this = mpt_adapter_find_next(this);
+ continue;
+ }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+ tpnt->proc_dir = &proc_mpt_scsihost;
+#endif
+ sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST));
+ if (sh != NULL) {
+ save_flags(flags);
+ cli();
+ sh->io_port = 0;
+ sh->n_io_port = 0;
+ sh->irq = 0;
+
+ /* Yikes! This is important!
+ * Otherwise, by default, linux only scans target IDs 0-7!
+ */
+ sh->max_id = this->pfacts0.MaxDevices - 1;
+
+ sh->this_id = this->pfacts0.PortSCSIID;
+
+ restore_flags(flags);
+
+ hd = (MPT_SCSI_HOST *) sh->hostdata;
+ hd->ioc = this;
+ hd->port = 0; /* FIXME! */
+
+ /* SCSI needs Scsi_Cmnd lookup table!
+ * (with size equal to req_depth*PtrSz!)
+ */
+ sz = hd->ioc->req_depth * sizeof(void *);
+ mem = kmalloc(sz, GFP_KERNEL);
+ if (mem == NULL)
+ return mpt_scsi_hosts;
+
+ memset(mem, 0, sz);
+ hd->ScsiLookup = (struct scsi_cmnd **) mem;
+
+ dprintk((KERN_INFO MYNAM ": ScsiLookup @ %p, sz=%d\n",
+ hd->ScsiLookup, sz));
+
+ /* SCSI also needs SG buckets/hunk management!
+ * (with size equal to N * req_sz * req_depth!)
+ * (where N is number of SG buckets per hunk)
+ */
+ sz = MPT_SG_BUCKETS_PER_HUNK * hd->ioc->req_sz * hd->ioc->req_depth;
+ mem = pci_alloc_consistent(hd->ioc->pcidev, sz,
+ &hd->SgHunksDMA);
+ if (mem == NULL)
+ return mpt_scsi_hosts;
+
+ memset(mem, 0, sz);
+ hd->SgHunks = (u8*)mem;
+
+ dprintk((KERN_INFO MYNAM ": SgHunks @ %p(%08x), sz=%d\n",
+ hd->SgHunks, hd->SgHunksDMA, sz));
+
+ hd->qtag_tick = jiffies;
+
+ this->sh = sh;
+ mpt_scsi_hosts++;
+ }
+ this = mpt_adapter_find_next(this);
+ }
+
+ return mpt_scsi_hosts;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ static char *info_kbuf = NULL;
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mptscsih_release - Unregister SCSI host from linux scsi mid-layer
+ * @host: Pointer to Scsi_Host structure
+ *
+ * (linux Scsi_Host_Template.release routine)
+ * This routine releases all resources associated with the SCSI host
+ * adapter.
+ *
+ * Returns 0 for success.
+ */
+int
+mptscsih_release(struct Scsi_Host *host)
+{
+ MPT_SCSI_HOST *hd;
+#ifndef MPT_SCSI_USE_NEW_EH
+ unsigned long flags;
+
+ spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+ if (mpt_scsih_taskQ_bh_active) {
+ int count = 10 * HZ;
+
+ dprintk((KERN_INFO MYNAM ": Info: Zapping TaskMgmt thread!\n"));
+
+ /* Zap the taskQ! */
+ Q_INIT(&mpt_scsih_taskQ, MPT_FRAME_HDR);
+ spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+
+ while(mpt_scsih_taskQ_bh_active && --count) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ }
+ if (!count)
+ printk(KERN_ERR MYNAM ": ERROR! TaskMgmt thread still active!\n");
+ }
+ spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+#endif
+
+ hd = (MPT_SCSI_HOST *) host->hostdata;
+ if (hd != NULL) {
+ int sz1, sz2;
+
+ sz1 = sz2 = 0;
+ if (hd->ScsiLookup != NULL) {
+ sz1 = hd->ioc->req_depth * sizeof(void *);
+ kfree(hd->ScsiLookup);
+ hd->ScsiLookup = NULL;
+ }
+
+ if (hd->SgHunks != NULL) {
+
+ sz2 = MPT_SG_BUCKETS_PER_HUNK * hd->ioc->req_sz * hd->ioc->req_depth;
+ pci_free_consistent(hd->ioc->pcidev, sz2,
+ hd->SgHunks, hd->SgHunksDMA);
+ hd->SgHunks = NULL;
+ }
+ dprintk((KERN_INFO MYNAM ": Free'd ScsiLookup (%d) and SgHunks (%d) memory\n", sz1, sz2));
+ }
+
+ if (mpt_scsi_hosts) {
+ if (--mpt_scsi_hosts == 0) {
+#if 0
+ mptscsih_flush_pending();
+#endif
+ mpt_event_deregister(ScsiDoneCtx);
+ dprintk((KERN_INFO MYNAM ": Deregistered for IOC event notifications\n"));
+
+ mpt_deregister(ScsiDoneCtx);
+ mpt_deregister(ScsiTaskCtx);
+
+ if (info_kbuf != NULL)
+ kfree(info_kbuf);
+ }
+ }
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mptscsih_info - Return information about MPT adapter
+ * @SChost: Pointer to Scsi_Host structure
+ *
+ * (linux Scsi_Host_Template.info routine)
+ *
+ * Returns pointer to buffer where information was written.
+ */
+const char *
+mptscsih_info(struct Scsi_Host *SChost)
+{
+ MPT_SCSI_HOST *h;
+ int size = 0;
+
+ if (info_kbuf == NULL)
+ if ((info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
+ return info_kbuf;
+
+ h = (MPT_SCSI_HOST *)SChost->hostdata;
+ info_kbuf[0] = '\0';
+ mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0);
+ info_kbuf[size-1] = '\0';
+
+ return info_kbuf;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ static int max_qd = 1;
+#ifdef MPT_DEBUG
+ static int max_sges = 0;
+ static int max_xfer = 0;
+#endif
+#if 0
+ static int max_num_sges = 0;
+ static int max_sgent_len = 0;
+#endif
+#if 0
+static int index_log[128];
+static int index_ent = 0;
+static __inline__ void ADD_INDEX_LOG(int req_ent)
+{
+ int i = index_ent++;
+
+ index_log[i & (128 - 1)] = req_ent;
+}
+#else
+#define ADD_INDEX_LOG(req_ent) do { } while(0)
+#endif
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
+ * @SCpnt: Pointer to Scsi_Cmnd structure
+ * @done: Pointer SCSI mid-layer IO completion function
+ *
+ * (linux Scsi_Host_Template.queuecommand routine)
+ * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
+ * from a linux Scsi_Cmnd request and send it to the IOC.
+ *
+ * Returns 0. (rtn value discarded by linux scsi mid-layer)
+ */
+int
+mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+ struct Scsi_Host *host;
+ MPT_SCSI_HOST *hd;
+ MPT_FRAME_HDR *mf;
+ SCSIIORequest_t *pScsiReq;
+ int datadir;
+ u32 len;
+ u32 sgdir;
+ u32 scsictl;
+ u32 scsidir;
+ u32 qtag;
+ u32 *mptr;
+ int sge_spill1;
+ int frm_sz;
+ int sges_left;
+ u32 chain_offset;
+ int my_idx;
+ int i;
+
+ dmfprintk((KERN_INFO MYNAM "_qcmd: SCpnt=%p, done()=%p\n",
+ SCpnt, done));
+
+ host = SCpnt->host;
+ hd = (MPT_SCSI_HOST *) host->hostdata;
+
+#if 0
+ if (host->host_busy >= 60) {
+ MPT_ADAPTER *ioc = hd->ioc;
+ u16 pci_command, pci_status;
+
+ /* The IOC is probably hung, investigate status. */
+ printk("MPI: IOC probably hung IOCSTAT[%08x] INTSTAT[%08x] REPLYFIFO[%08x]\n",
+ readl(&ioc->chip.fc9xx->DoorbellValue),
+ readl(&ioc->chip.fc9xx->IntStatus),
+ readl(&ioc->chip.fc9xx->ReplyFifo));
+ pci_read_config_word(ioc->pcidev, PCI_COMMAND, &pci_command);
+ pci_read_config_word(ioc->pcidev, PCI_STATUS, &pci_status);
+ printk("MPI: PCI command[%04x] status[%04x]\n", pci_command, pci_status);
+ {
+ /* DUMP req index logger. */
+ int begin, end;
+
+ begin = (index_ent - 65) & (128 - 1);
+ end = index_ent & (128 - 1);
+ printk("MPI: REQ_INDEX_HIST[");
+ while (begin != end) {
+ printk("(%04x)", index_log[begin]);
+ begin = (begin + 1) & (128 - 1);
+ }
+ printk("\n");
+ }
+ sti();
+ while(1)
+ barrier();
+ }
+#endif
+
+ SCpnt->scsi_done = done;
+
+ /* 20000617 -sralston
+ * GRRRRR... Shouldn't have to do this but...
+ * Do explicit check for REQUEST_SENSE and cached SenseData.
+ * If yes, return cached SenseData.
+ */
+#ifdef MPT_SCSI_CACHE_AUTOSENSE
+ {
+ MPT_SCSI_DEV *mpt_sdev;
+
+ mpt_sdev = (MPT_SCSI_DEV *) SCpnt->device->hostdata;
+ if (mpt_sdev && SCpnt->cmnd[0] == REQUEST_SENSE) {
+ u8 *dest = NULL;
+
+ if (!SCpnt->use_sg)
+ dest = SCpnt->request_buffer;
+ else {
+ struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
+ if (sg)
+ dest = (u8 *) (unsigned long)sg_dma_address(sg);
+ }
+
+ if (dest && mpt_sdev->sense_sz) {
+ memcpy(dest, mpt_sdev->CachedSense.data, mpt_sdev->sense_sz);
+#ifdef MPT_DEBUG
+ {
+ int i;
+ u8 *sb;
+
+ sb = mpt_sdev->CachedSense.data;
+ if (sb && ((sb[0] & 0x70) == 0x70)) {
+ printk(KERN_WARNING MYNAM ": Returning last cached SCSI (hex) SenseData:\n");
+ printk(KERN_WARNING " ");
+ for (i = 0; i < (8 + sb[7]); i++)
+ printk("%s%02x", i == 13 ? "-" : " ", sb[i]);
+ printk("\n");
+ }
+ }
+#endif
+ }
+ SCpnt->resid = SCpnt->request_bufflen - mpt_sdev->sense_sz;
+ SCpnt->result = 0;
+/* spin_lock(&io_request_lock); */
+ SCpnt->scsi_done(SCpnt);
+/* spin_unlock(&io_request_lock); */
+ return 0;
+ }
+ }
+#endif
+
+ if ((mf = mpt_get_msg_frame(ScsiDoneCtx, hd->ioc->id)) == NULL) {
+/* SCpnt->result = DID_SOFT_ERROR << 16; */
+ SCpnt->result = STS_BUSY;
+ SCpnt->scsi_done(SCpnt);
+/* return 1; */
+ return 0;
+ }
+ pScsiReq = (SCSIIORequest_t *) mf;
+
+ my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+
+ ADD_INDEX_LOG(my_idx);
+
+ /* Map the data portion, if any. */
+ sges_left = SCpnt->use_sg;
+ if (sges_left) {
+ sges_left = pci_map_sg(hd->ioc->pcidev,
+ (struct scatterlist *) SCpnt->request_buffer,
+ sges_left,
+ scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+ } else if (SCpnt->request_bufflen) {
+ dma_addr_t buf_dma_addr;
+
+ buf_dma_addr = pci_map_single(hd->ioc->pcidev,
+ SCpnt->request_buffer,
+ SCpnt->request_bufflen,
+ scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+
+ /* We hide it here for later unmap. */
+ SCpnt->SCp.ptr = (char *)(unsigned long) buf_dma_addr;
+ }
+
+ /*
+ * Put together a MPT SCSI request...
+ */
+
+ /* Assume SimpleQ, NO DATA XFER for now */
+
+ len = SCpnt->request_bufflen;
+ sgdir = 0x00000000; /* SGL IN (host<--ioc) */
+ scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
+
+ /*
+ * The scsi layer should be handling this stuff
+ * (In 2.3.x it does -DaveM)
+ */
+
+ /* BUG FIX! 19991030 -sralston
+ * TUR's being issued with scsictl=0x02000000 (DATA_IN)!
+ * Seems we may receive a buffer (len>0) even when there
+ * will be no data transfer! GRRRRR...
+ */
+ datadir = mptscsih_io_direction(SCpnt);
+ if (datadir < 0) {
+ scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
+ } else if (datadir > 0) {
+ sgdir = 0x04000000; /* SGL OUT (host-->ioc) */
+ scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
+ } else {
+ len = 0;
+ }
+
+ qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
+
+ /*
+ * Attach tags to the devices
+ */
+ if (SCpnt->device->tagged_supported) {
+ /*
+ * Some drives are too stupid to handle fairness issues
+ * with tagged queueing. We throw in the odd ordered
+ * tag to stop them starving themselves.
+ */
+ if ((jiffies - hd->qtag_tick) > (5*HZ)) {
+ qtag = MPI_SCSIIO_CONTROL_ORDEREDQ;
+ hd->qtag_tick = jiffies;
+
+#if 0
+ /* These are ALWAYS zero!
+ * (Because this is a place for the device driver to dynamically
+ * assign tag numbers any way it sees fit. That's why -DaveM)
+ */
+ dprintk((KERN_DEBUG MYNAM ": sc->device->current_tag = %08x\n",
+ SCpnt->device->current_tag));
+ dprintk((KERN_DEBUG MYNAM ": sc->tag = %08x\n",
+ SCpnt->tag));
+#endif
+ }
+#if 0
+ else {
+ /* Hmmm... I always see value of 0 here,
+ * of which {HEAD_OF, ORDERED, SIMPLE} are NOT! -sralston
+ * (Because this is a place for the device driver to dynamically
+ * assign tag numbers any way it sees fit. That's why -DaveM)
+ *
+ * if (SCpnt->tag == HEAD_OF_QUEUE_TAG)
+ */
+ if (SCpnt->device->current_tag == HEAD_OF_QUEUE_TAG)
+ qtag = MPI_SCSIIO_CONTROL_HEADOFQ;
+ else if (SCpnt->tag == ORDERED_QUEUE_TAG)
+ qtag = MPI_SCSIIO_CONTROL_ORDEREDQ;
+ }
+#endif
+ }
+
+ scsictl = scsidir | qtag;
+
+ frm_sz = hd->ioc->req_sz;
+
+ /* Ack!
+ * sge_spill1 = 9;
+ */
+ sge_spill1 = (frm_sz - (sizeof(SCSIIORequest_t) - sizeof(SGEIOUnion_t) + sizeof(SGEChain32_t))) / 8;
+ /* spill1: for req_sz == 128 (128-48==80, 80/8==10 SGEs max, first time!), --> use 9
+ * spill1: for req_sz == 96 ( 96-48==48, 48/8== 6 SGEs max, first time!), --> use 5
+ */
+ dsgprintk((KERN_INFO MYNAM ": SG: %x spill1 = %d\n",
+ my_idx, sge_spill1));
+
+#ifdef MPT_DEBUG
+ if (sges_left > max_sges) {
+ max_sges = sges_left;
+ dprintk((KERN_INFO MYNAM ": MPT_MaxSges = %d\n", max_sges));
+ }
+#endif
+#if 0
+ if (sges_left > max_num_sges) {
+ max_num_sges = sges_left;
+ printk(KERN_INFO MYNAM ": MPT_MaxNumSges = %d\n", max_num_sges);
+ }
+#endif
+
+ dsgprintk((KERN_INFO MYNAM ": SG: %x sges_left = %d (initially)\n",
+ my_idx, sges_left));
+
+ chain_offset = 0;
+ if (sges_left > (sge_spill1+1)) {
+#if 0
+ chain_offset = 0x1E;
+#endif
+ chain_offset = (frm_sz - 8) / 4;
+ }
+
+ pScsiReq->TargetID = SCpnt->target;
+ pScsiReq->Bus = hd->port;
+ pScsiReq->ChainOffset = chain_offset;
+ pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
+ pScsiReq->CDBLength = SCpnt->cmd_len;
+
+/* We have 256 bytes alloc'd per IO; let's use it. */
+/* pScsiReq->SenseBufferLength = SNS_LEN(SCpnt); */
+ pScsiReq->SenseBufferLength = 255;
+
+ pScsiReq->Reserved = 0;
+ pScsiReq->MsgFlags = 0;
+ pScsiReq->LUN[0] = 0;
+ pScsiReq->LUN[1] = SCpnt->lun;
+ pScsiReq->LUN[2] = 0;
+ pScsiReq->LUN[3] = 0;
+ pScsiReq->LUN[4] = 0;
+ pScsiReq->LUN[5] = 0;
+ pScsiReq->LUN[6] = 0;
+ pScsiReq->LUN[7] = 0;
+ pScsiReq->Control = cpu_to_le32(scsictl);
+
+ /*
+ * Write SCSI CDB into the message
+ */
+ for (i = 0; i < 12; i++)
+ pScsiReq->CDB[i] = SCpnt->cmnd[i];
+ for (i = 12; i < 16; i++)
+ pScsiReq->CDB[i] = 0;
+
+ /* DataLength */
+ pScsiReq->DataLength = cpu_to_le32(len);
+
+ /* SenseBuffer low address */
+ pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_pool_dma + (my_idx * 256));
+
+ mptr = (u32 *) &pScsiReq->SGL;
+
+ /*
+ * Now fill in the SGList...
+ * NOTES: For 128 byte req_sz, we can hold up to 10 simple SGE's
+ * in the remaining request frame. We -could- do unlimited chains
+ * but each chain buffer can only be req_sz bytes in size, and
+ * we lose one SGE whenever we chain.
+ * For 128 req_sz, we can hold up to 16 SGE's per chain buffer.
+ * For practical reasons, limit ourselves to 1 overflow chain buffer;
+ * giving us 9 + 16 == 25 SGE's max.
+ * At 4 Kb per SGE, that yields 100 Kb max transfer.
+ *
+ * (This code needs to be completely changed when/if 64-bit DMA
+ * addressing is used, since we will be able to fit much less than
+ * 10 embedded SG entries. -DaveM)
+ */
+ if (sges_left) {
+ struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
+ u32 v1, v2;
+ int sge_spill2;
+ int sge_cur_spill;
+ int sgCnt;
+ u8 *pSgBucket;
+ int chain_sz;
+
+ len = 0;
+
+ /* sge_spill2 = 15;
+ * spill2: for req_sz == 128 (128/8==16 SGEs max, first time!), --> use 15
+ * spill2: for req_sz == 96 ( 96/8==12 SGEs max, first time!), --> use 11
+ */
+ sge_spill2 = frm_sz / 8 - 1;
+ dsgprintk((KERN_INFO MYNAM ": SG: %x spill2 = %d\n",
+ my_idx, sge_spill2));
+
+ pSgBucket = NULL;
+ sgCnt = 0;
+ sge_cur_spill = sge_spill1;
+ while (sges_left) {
+#if 0
+ if (sg_dma_len(sg) > max_sgent_len) {
+ max_sgent_len = sg_dma_len(sg);
+ printk(KERN_INFO MYNAM ": MPT_MaxSgentLen = %d\n", max_sgent_len);
+ }
+#endif
+ /* Write one simple SGE */
+ v1 = sgdir | 0x10000000 | sg_dma_len(sg);
+ len += sg_dma_len(sg);
+ v2 = sg_dma_address(sg);
+ dsgprintk((KERN_INFO MYNAM ": SG: %x Writing SGE @%p: %08x %08x, sges_left=%d\n",
+ my_idx, mptr, v1, v2, sges_left));
+ *mptr++ = cpu_to_le32(v1);
+ *mptr++ = cpu_to_le32(v2);
+ sg++;
+ sgCnt++;
+
+ if (--sges_left == 0) {
+ /* re-write 1st word of previous SGE with SIMPLE,
+ * LE, EOB, and EOL bits!
+ */
+ v1 = 0xD1000000 | sgdir | sg_dma_len(sg-1);
+ dsgprintk((KERN_INFO MYNAM ": SG: %x (re)Writing SGE @%p: %08x (VERY LAST SGE!)\n",
+ my_idx, mptr-2, v1));
+ *(mptr - 2) = cpu_to_le32(v1);
+ } else {
+ if ((sges_left > 1) && ((sgCnt % sge_cur_spill) == 0)) {
+ dsgprintk((KERN_INFO MYNAM ": SG: %x SG spill at modulo 0!\n",
+ my_idx));
+
+ /* Fixup previous SGE with LE bit! */
+ v1 = sgdir | 0x90000000 | sg_dma_len(sg-1);
+ dsgprintk((KERN_INFO MYNAM ": SG: %x (re)Writing SGE @%p: %08x (LAST BUCKET SGE!)\n",
+ my_idx, mptr-2, v1));
+ *(mptr - 2) = cpu_to_le32(v1);
+
+ chain_offset = 0;
+ /* Going to need another chain? */
+ if (sges_left > (sge_spill2+1)) {
+#if 0
+ chain_offset = 0x1E;
+#endif
+ chain_offset = (frm_sz - 8) / 4;
+ chain_sz = frm_sz;
+ } else {
+ chain_sz = sges_left * 8;
+ }
+
+ /* write chain SGE at mptr. */
+ v1 = 0x30000000 | chain_offset<<16 | chain_sz;
+ if (pSgBucket == NULL) {
+ pSgBucket = hd->SgHunks
+ + (my_idx * frm_sz * MPT_SG_BUCKETS_PER_HUNK);
+ } else {
+ pSgBucket += frm_sz;
+ }
+ v2 = (hd->SgHunksDMA +
+ ((u8 *)pSgBucket - (u8 *)hd->SgHunks));
+ dsgprintk((KERN_INFO MYNAM ": SG: %x Writing SGE @%p: %08x %08x (CHAIN!)\n",
+ my_idx, mptr, v1, v2));
+ *(mptr++) = cpu_to_le32(v1);
+ *(mptr) = cpu_to_le32(v2);
+
+ mptr = (u32 *) pSgBucket;
+ sgCnt = 0;
+ sge_cur_spill = sge_spill2;
+ }
+ }
+ }
+ } else {
+ dsgprintk((KERN_INFO MYNAM ": SG: non-SG for %p, len=%d\n",
+ SCpnt, SCpnt->request_bufflen));
+
+ if (len > 0) {
+ dma_addr_t buf_dma_addr;
+
+ buf_dma_addr = (dma_addr_t) (unsigned long)SCpnt->SCp.ptr;
+ *(mptr++) = cpu_to_le32(0xD1000000|sgdir|SCpnt->request_bufflen);
+ *(mptr++) = cpu_to_le32(buf_dma_addr);
+ }
+ }
+
+#ifdef MPT_DEBUG
+ /* if (SCpnt->request_bufflen > max_xfer) */
+ if (len > max_xfer) {
+ max_xfer = len;
+ dprintk((KERN_INFO MYNAM ": MPT_MaxXfer = %d\n", max_xfer));
+ }
+#endif
+
+ hd->ScsiLookup[my_idx] = SCpnt;
+
+ /* Main banana... */
+ mpt_put_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
+
+ atomic_inc(&queue_depth);
+ if (atomic_read(&queue_depth) > max_qd) {
+ max_qd = atomic_read(&queue_depth);
+ dprintk((KERN_INFO MYNAM ": Queue depth now %d.\n", max_qd));
+ }
+
+ mb();
+ dmfprintk((KERN_INFO MYNAM ": Issued SCSI cmd (%p)\n", SCpnt));
+
+ return 0;
+}
+
+#ifdef MPT_SCSI_USE_NEW_EH /* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ mptscsih_abort
+ Returns: 0=SUCCESS, else FAILED
+*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mptscsih_abort - Abort linux Scsi_Cmnd routine, new_eh variant
+ * @SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted
+ *
+ * (linux Scsi_Host_Template.eh_abort_handler routine)
+ *
+ * Returns SUCCESS or FAILED.
+ */
+int
+mptscsih_abort(Scsi_Cmnd * SCpnt)
+{
+ MPT_FRAME_HDR *mf;
+ SCSITaskMgmt_t *pScsiTm;
+ MPT_SCSI_HOST *hd;
+ u32 *msg;
+ u32 ctx2abort;
+ int i;
+
+ printk(KERN_WARNING MYNAM ": Attempting _ABORT SCSI IO (=%p)\n", SCpnt);
+ printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+ hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
+
+ if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+/* SCpnt->result = DID_SOFT_ERROR << 16; */
+ SCpnt->result = STS_BUSY;
+ SCpnt->scsi_done(SCpnt);
+ return FAILED;
+ }
+
+ pScsiTm = (SCSITaskMgmt_t *) mf;
+ msg = (u32 *) mf;
+
+ pScsiTm->TargetID = SCpnt->target;
+ pScsiTm->Bus = hd->port;
+ pScsiTm->ChainOffset = 0;
+ pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+
+ pScsiTm->Reserved = 0;
+ pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
+ pScsiTm->Reserved1 = 0;
+ pScsiTm->MsgFlags = 0;
+
+ for (i = 0; i < 8; i++) {
+ u8 val = 0;
+ if (i == 1)
+ val = SCpnt->lun;
+ pScsiTm->LUN[i] = val;
+ }
+
+ for (i = 0; i < 7; i++)
+ pScsiTm->Reserved2[i] = 0;
+
+ /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
+ * (the IO to be ABORT'd)
+ *
+ * NOTE: Since we do not byteswap MsgContext, we do not
+ * swap it here either. It is an opaque cookie to
+ * the controller, so it does not matter. -DaveM
+ */
+ ctx2abort = SCPNT_TO_MSGCTX(SCpnt);
+ dprintk((KERN_INFO MYNAM ":DbG: ctx2abort = %08x\n", ctx2abort));
+ pScsiTm->TaskMsgContext = ctx2abort;
+
+ wmb();
+
+/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake
+ mpt_put_msg_frame(hd->ioc->id, mf);
+*/
+/* FIXME! Check return status! */
+ (void) mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, sizeof(SCSITaskMgmt_t), msg);
+
+ wmb();
+
+ return SUCCESS;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
+ * @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
+ *
+ * (linux Scsi_Host_Template.eh_bus_reset_handler routine)
+ *
+ * Returns SUCCESS or FAILED.
+ */
+int
+mptscsih_bus_reset(Scsi_Cmnd * SCpnt)
+{
+ MPT_FRAME_HDR *mf;
+ SCSITaskMgmt_t *pScsiTm;
+ MPT_SCSI_HOST *hd;
+ u32 *msg;
+ int i;
+
+ printk(KERN_WARNING MYNAM ": Attempting _BUS_RESET (%p)\n", SCpnt);
+ printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+ hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
+
+ if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+/* SCpnt->result = DID_SOFT_ERROR << 16; */
+ SCpnt->result = STS_BUSY;
+ SCpnt->scsi_done(SCpnt);
+ return FAILED;
+ }
+
+ pScsiTm = (SCSITaskMgmt_t *) mf;
+ msg = (u32 *) mf;
+
+ pScsiTm->TargetID = SCpnt->target;
+ pScsiTm->Bus = hd->port;
+ pScsiTm->ChainOffset = 0;
+ pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+
+ pScsiTm->Reserved = 0;
+ pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
+ pScsiTm->Reserved1 = 0;
+ pScsiTm->MsgFlags = 0;
+
+ for (i = 0; i < 8; i++)
+ pScsiTm->LUN[i] = 0;
+
+ /* Control: No data direction, set task mgmt bit? */
+ for (i = 0; i < 7; i++)
+ pScsiTm->Reserved2[i] = 0;
+
+ pScsiTm->TaskMsgContext = cpu_to_le32(0);
+
+ wmb();
+
+/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake
+ mpt_put_msg_frame(hd->ioc->id, mf);
+*/
+/* FIXME! Check return status! */
+ (void) mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, sizeof(SCSITaskMgmt_t), msg);
+
+ wmb();
+
+ return SUCCESS;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
+ * @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
+ *
+ * (linux Scsi_Host_Template.eh_dev_reset_handler routine)
+ *
+ * Returns SUCCESS or FAILED.
+ */
+int
+mptscsih_dev_reset(Scsi_Cmnd * SCpnt)
+{
+ MPT_FRAME_HDR *mf;
+ SCSITaskMgmt_t *pScsiTm;
+ MPT_SCSI_HOST *hd;
+ u32 *msg;
+ int i;
+
+ printk(KERN_WARNING MYNAM ": Attempting _TARGET_RESET (%p)\n", SCpnt);
+ printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+ hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
+
+ if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+/* SCpnt->result = DID_SOFT_ERROR << 16; */
+ SCpnt->result = STS_BUSY;
+ SCpnt->scsi_done(SCpnt);
+ return FAILED;
+ }
+
+ pScsiTm = (SCSITaskMgmt_t *) mf;
+ msg = (u32*)mf;
+
+ pScsiTm->TargetID = SCpnt->target;
+ pScsiTm->Bus = hd->port;
+ pScsiTm->ChainOffset = 0;
+ pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+
+ pScsiTm->Reserved = 0;
+ pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
+ pScsiTm->Reserved1 = 0;
+ pScsiTm->MsgFlags = 0;
+
+ /* _TARGET_RESET goes to LUN 0 always! */
+ for (i = 0; i < 8; i++)
+ pScsiTm->LUN[i] = 0;
+
+ /* Control: No data direction, set task mgmt bit? */
+ for (i = 0; i < 7; i++)
+ pScsiTm->Reserved2[i] = 0;
+
+ pScsiTm->TaskMsgContext = cpu_to_le32(0);
+
+ wmb();
+
+/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake
+ mpt_put_msg_frame(hd->ioc->id, mf);
+*/
+/* FIXME! Check return status! */
+ (void) mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, sizeof(SCSITaskMgmt_t), msg);
+
+ wmb();
+
+ return SUCCESS;
+}
+
+#if 0 /* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mptscsih_host_reset - Perform a SCSI host adapter RESET!
+ * new_eh variant
+ * @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
+ *
+ * (linux Scsi_Host_Template.eh_host_reset_handler routine)
+ *
+ * Returns SUCCESS or FAILED.
+ */
+int
+mptscsih_host_reset(Scsi_Cmnd * SCpnt)
+{
+ return FAILED;
+}
+#endif /* } */
+
+#else /* MPT_SCSI old EH stuff... */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mptscsih_old_abort - Abort linux Scsi_Cmnd routine
+ * @SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted
+ *
+ * (linux Scsi_Host_Template.abort routine)
+ *
+ * Returns SCSI_ABORT_{SUCCESS,BUSY,PENDING}.
+ */
+int
+mptscsih_old_abort(Scsi_Cmnd *SCpnt)
+{
+ MPT_SCSI_HOST *hd;
+ MPT_FRAME_HDR *mf;
+ struct tq_struct *ptaskfoo;
+ unsigned long flags;
+
+ printk(KERN_WARNING MYNAM ": Scheduling _ABORT SCSI IO (=%p)\n", SCpnt);
+ printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+ if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
+ SCpnt->result = DID_ABORT << 16;
+ SCpnt->scsi_done(SCpnt);
+ return SCSI_ABORT_SUCCESS;
+ }
+
+ /*
+ * Check to see if there's already an ABORT queued for this guy.
+ */
+ mf = search_taskQ(0,SCpnt,MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
+ if (mf != NULL) {
+ return SCSI_ABORT_PENDING;
+ }
+
+ if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+/* SCpnt->result = DID_SOFT_ERROR << 16; */
+ SCpnt->result = STS_BUSY;
+ SCpnt->scsi_done(SCpnt);
+ return SCSI_ABORT_BUSY;
+ }
+
+ /*
+ * Add ourselves to (end of) mpt_scsih_taskQ.
+ * Check to see if our _bh is running. If NOT, schedule it.
+ */
+ dslprintk((KERN_INFO MYNAM ": spinlock#2\n"));
+ spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+ Q_ADD_TAIL(&mpt_scsih_taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+ mpt_scsih_taskQ_cnt++;
+ /* Yikes - linkage! */
+/* SCpnt->host_scribble = (unsigned char *)mf; */
+ mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
+ mf->u.frame.linkage.argp1 = SCpnt;
+ if (! mpt_scsih_taskQ_bh_active) {
+ mpt_scsih_taskQ_bh_active = 1;
+ /*
+ * Oh how cute, no alloc/free/mgmt needed if we use
+ * (bottom/unused portion of) MPT request frame.
+ */
+ ptaskfoo = (struct tq_struct *) ((u8*)mf + hd->ioc->req_sz - sizeof(*ptaskfoo));
+ ptaskfoo->sync = 0;
+ ptaskfoo->routine = mptscsih_taskmgmt_bh;
+ ptaskfoo->data = SCpnt;
+
+ SCHEDULE_TASK(ptaskfoo);
+ }
+ spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+
+ return SCSI_ABORT_PENDING;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mptscsih_old_reset - Perform a SCSI BUS_RESET!
+ * @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
+ * @reset_flags: (not used?)
+ *
+ * (linux Scsi_Host_Template.reset routine)
+ *
+ * Returns SCSI_RESET_{SUCCESS,PUNT,PENDING}.
+ */
+int
+mptscsih_old_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+{
+ MPT_SCSI_HOST *hd;
+ MPT_FRAME_HDR *mf;
+ struct tq_struct *ptaskfoo;
+ unsigned long flags;
+
+ printk(KERN_WARNING MYNAM ": Scheduling _BUS_RESET (=%p)\n", SCpnt);
+ printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+ if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
+ SCpnt->result = DID_RESET << 16;
+ SCpnt->scsi_done(SCpnt);
+ return SCSI_RESET_SUCCESS;
+ }
+
+ /*
+ * Check to see if there's already a BUS_RESET queued for this guy.
+ */
+ mf = search_taskQ(0,SCpnt,MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS);
+ if (mf != NULL) {
+ return SCSI_RESET_PENDING;
+ }
+
+ if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+/* SCpnt->result = DID_SOFT_ERROR << 16; */
+ SCpnt->result = STS_BUSY;
+ SCpnt->scsi_done(SCpnt);
+ return SCSI_RESET_PUNT;
+ }
+
+ /*
+ * Add ourselves to (end of) mpt_scsih_taskQ.
+ * Check to see if our _bh is running. If NOT, schedule it.
+ */
+ dslprintk((KERN_INFO MYNAM ": spinlock#3\n"));
+ spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+ Q_ADD_TAIL(&mpt_scsih_taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+ mpt_scsih_taskQ_cnt++;
+ /* Yikes - linkage! */
+/* SCpnt->host_scribble = (unsigned char *)mf; */
+ mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
+ mf->u.frame.linkage.argp1 = SCpnt;
+ if (! mpt_scsih_taskQ_bh_active) {
+ mpt_scsih_taskQ_bh_active = 1;
+ /*
+ * Oh how cute, no alloc/free/mgmt needed if we use
+ * (bottom/unused portion of) MPT request frame.
+ */
+ ptaskfoo = (struct tq_struct *) ((u8*)mf + hd->ioc->req_sz - sizeof(*ptaskfoo));
+ ptaskfoo->sync = 0;
+ ptaskfoo->routine = mptscsih_taskmgmt_bh;
+ ptaskfoo->data = SCpnt;
+
+ SCHEDULE_TASK(ptaskfoo);
+ }
+ spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+
+ return SCSI_RESET_PENDING;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * mptscsih_taskmgmt_bh - SCSI task mgmt bottom half handler
+ * @sc: (unused)
+ *
+ * This routine (thread) is active whenever there are any outstanding
+ * SCSI task management requests for a SCSI host adapter.
+ * IMPORTANT! This routine is scheduled therefore should never be
+ * running in ISR context. i.e., it's safe to sleep here.
+ */
+void
+mptscsih_taskmgmt_bh(void *sc)
+{
+ Scsi_Cmnd *SCpnt;
+ MPT_FRAME_HDR *mf;
+ SCSITaskMgmt_t *pScsiTm;
+ MPT_SCSI_HOST *hd;
+ u32 ctx2abort = 0;
+ int i;
+ unsigned long flags;
+ u8 task_type;
+
+ dslprintk((KERN_INFO MYNAM ": spinlock#4\n"));
+ spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+ mpt_scsih_taskQ_bh_active = 1;
+ spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+
+ while (1) {
+ /*
+ * We MUST remove item from taskQ *before* we format the
+ * frame as a SCSITaskMgmt request and send it down to the IOC.
+ */
+ dslprintk((KERN_INFO MYNAM ": spinlock#5\n"));
+ spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+ if (Q_IS_EMPTY(&mpt_scsih_taskQ)) {
+ spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+ break;
+ }
+ mf = mpt_scsih_taskQ.head;
+ Q_DEL_ITEM(&mf->u.frame.linkage);
+ mpt_scsih_taskQ_cnt--;
+ mpt_scsih_active_taskmgmt_mf = mf;
+ spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+
+ SCpnt = (Scsi_Cmnd*)mf->u.frame.linkage.argp1;
+ if (SCpnt == NULL) {
+ printk(KERN_ERR MYNAM ": ERROR: TaskMgmt has NULL SCpnt! (%p:%p)\n", mf, SCpnt);
+ continue;
+ }
+ pScsiTm = (SCSITaskMgmt_t *) mf;
+
+ for (i = 0; i < 8; i++) {
+ pScsiTm->LUN[i] = 0;
+ }
+
+ task_type = mf->u.frame.linkage.arg1;
+ if (task_type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
+ {
+ printk(KERN_WARNING MYNAM ": Attempting _ABORT SCSI IO! (mf:sc=%p:%p)\n", mf, SCpnt);
+
+ /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
+ * (the IO to be ABORT'd)
+ *
+ * NOTE: Since we do not byteswap MsgContext, we do not
+ * swap it here either. It is an opaque cookie to
+ * the controller, so it does not matter. -DaveM
+ */
+ ctx2abort = SCPNT_TO_MSGCTX(SCpnt);
+ pScsiTm->LUN[1] = SCpnt->lun;
+ }
+ else if (task_type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
+ {
+ printk(KERN_WARNING MYNAM ": Attempting _BUS_RESET! (against SCSI IO mf:sc=%p:%p)\n", mf, SCpnt);
+ }
+#if 0
+ else if (task_type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {}
+ else if (task_type == MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET) {}
+#endif
+
+ printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+ hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
+
+ pScsiTm->TargetID = SCpnt->target;
+ pScsiTm->Bus = hd->port;
+ pScsiTm->ChainOffset = 0;
+ pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+
+ pScsiTm->Reserved = 0;
+ pScsiTm->TaskType = task_type;
+ pScsiTm->Reserved1 = 0;
+ pScsiTm->MsgFlags = 0;
+
+ for (i = 0; i < 7; i++)
+ pScsiTm->Reserved2[i] = 0;
+
+ dprintk((KERN_INFO MYNAM ":DbG: ctx2abort = %08x\n", ctx2abort));
+ pScsiTm->TaskMsgContext = ctx2abort;
+
+ /* Control: No data direction, set task mgmt bit? */
+
+ /*
+ * As of MPI v0.10 this request can NOT be sent (normally)
+ * via FIFOs. So we can't:
+ * mpt_put_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+ * SCSITaskMgmt requests MUST be sent ONLY via
+ * Doorbell/handshake now. :-(
+ *
+ * FIXME! Check return status!
+ */
+ (void) mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, sizeof(SCSITaskMgmt_t), (u32*)mf);
+
+ /* Spin-Wait for TaskMgmt complete!!! */
+ while (mpt_scsih_active_taskmgmt_mf != NULL) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(HZ/2);
+ }
+ }
+
+ dslprintk((KERN_INFO MYNAM ": spinlock#6\n"));
+ spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+ mpt_scsih_taskQ_bh_active = 0;
+ spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+
+ return;
+}
+
+#endif /* } */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mptscsih_taskmgmt_complete - Callback routine, gets registered to
+ * Fusion MPT base driver
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @mf: Pointer to SCSI task mgmt request frame
+ * @r: Pointer to SCSI task mgmt reply frame
+ *
+ * This routine is called from mptbase.c::mpt_interrupt() at the completion
+ * of any SCSI task management request.
+ * This routine is registered with the MPT (base) driver at driver
+ * load/init time via the mpt_register() API call.
+ *
+ * Returns 1 indicating alloc'd request frame ptr should be freed.
+ */
+static int
+mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r)
+{
+ SCSITaskMgmtReply_t *pScsiTmReply;
+ SCSITaskMgmt_t *pScsiTmReq;
+ u8 tmType;
+#ifndef MPT_SCSI_USE_NEW_EH
+ unsigned long flags;
+#endif
+
+ dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt completed mf=%p, r=%p\n",
+ mf, r));
+
+#ifndef MPT_SCSI_USE_NEW_EH
+ dslprintk((KERN_INFO MYNAM ": spinlock#7\n"));
+ spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+ /* It better be the active one! */
+ if (mf != mpt_scsih_active_taskmgmt_mf) {
+ printk(KERN_ERR MYNAM ": ERROR! Non-active TaskMgmt (=%p) completed!\n", mf);
+ mpt_scsih_active_taskmgmt_mf = NULL;
+ spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+ return 1;
+ }
+
+#ifdef MPT_DEBUG
+ if ((mf == NULL) ||
+ (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
+ printk(KERN_ERR MYNAM ": ERROR! NULL or BAD TaskMgmt ptr (=%p)!\n", mf);
+ mpt_scsih_active_taskmgmt_mf = NULL;
+ spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+ return 1;
+ }
+#endif
+ spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+#endif
+
+ if (r != NULL) {
+ pScsiTmReply = (SCSITaskMgmtReply_t*)r;
+ pScsiTmReq = (SCSITaskMgmt_t*)mf;
+
+ /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
+ tmType = pScsiTmReq->TaskType;
+
+ dprintk((KERN_INFO MYNAM ": TaskType = %d\n", tmType));
+ dprintk((KERN_INFO MYNAM ": TerminationCount = %d\n",
+ le32_to_cpu(pScsiTmReply->TerminationCount)));
+
+ /* Error? (anything non-zero?) */
+ if (*(u32 *)&pScsiTmReply->Reserved2[0]) {
+ dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt (%d) - Oops!\n", tmType));
+ dprintk((KERN_INFO MYNAM ": IOCStatus = %04xh\n",
+ le16_to_cpu(pScsiTmReply->IOCStatus)));
+ dprintk((KERN_INFO MYNAM ": IOCLogInfo = %08xh\n",
+ le32_to_cpu(pScsiTmReply->IOCLogInfo)));
+ } else {
+ dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt (%d) SUCCESS!\n", tmType));
+ }
+ }
+
+#ifndef MPT_SCSI_USE_NEW_EH
+ /*
+ * Signal to _bh thread that we finished.
+ */
+ dslprintk((KERN_INFO MYNAM ": spinlock#8\n"));
+ spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+ mpt_scsih_active_taskmgmt_mf = NULL;
+ spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+#endif
+
+ return 1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * This is anyones guess quite frankly.
+ */
+
+int
+mptscsih_bios_param(Disk * disk, kdev_t dev, int *ip)
+{
+ int size;
+
+ size = disk->capacity;
+ ip[0] = 64; /* heads */
+ ip[1] = 32; /* sectors */
+ if ((ip[2] = size >> 11) > 1024) { /* cylinders, test for big disk */
+ ip[0] = 255; /* heads */
+ ip[1] = 63; /* sectors */
+ ip[2] = size / (255 * 63); /* cylinders */
+ }
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Private routines...
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* 19991030 -sralston
+ * Return absolute SCSI data direction:
+ * 1 = _DATA_OUT
+ * 0 = _DIR_NONE
+ * -1 = _DATA_IN
+ */
+static int
+mptscsih_io_direction(Scsi_Cmnd *cmd)
+{
+ switch (cmd->cmnd[0]) {
+ /* _DATA_OUT commands */
+ case WRITE_6: case WRITE_10: case WRITE_12:
+ case WRITE_LONG: case WRITE_SAME: case WRITE_BUFFER:
+ case WRITE_VERIFY: case WRITE_VERIFY_12:
+ case COMPARE: case COPY: case COPY_VERIFY:
+ case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW:
+ case SEARCH_EQUAL_12: case SEARCH_HIGH_12: case SEARCH_LOW_12:
+ case MODE_SELECT: case MODE_SELECT_10: case LOG_SELECT:
+ case SEND_DIAGNOSTIC: case CHANGE_DEFINITION: case UPDATE_BLOCK:
+ case SET_WINDOW: case MEDIUM_SCAN: case SEND_VOLUME_TAG:
+ case REASSIGN_BLOCKS:
+ case PERSISTENT_RESERVE_OUT:
+ case 0xea:
+ return 1;
+
+ /* No data transfer commands */
+ case SEEK_6: case SEEK_10:
+ case RESERVE: case RELEASE:
+ case TEST_UNIT_READY:
+ case START_STOP:
+ case ALLOW_MEDIUM_REMOVAL:
+ return 0;
+
+ /* Conditional data transfer commands */
+ case FORMAT_UNIT:
+ if (cmd->cmnd[1] & 0x10) /* FmtData (data out phase)? */
+ return 1;
+ else
+ return 0;
+
+ case VERIFY:
+ if (cmd->cmnd[1] & 0x02) /* VERIFY:BYTCHK (data out phase)? */
+ return 1;
+ else
+ return 0;
+
+ case RESERVE_10:
+ if (cmd->cmnd[1] & 0x03) /* RESERSE:{LongID|Extent} (data out phase)? */
+ return 1;
+ else
+ return 0;
+
+#if 0
+ case REZERO_UNIT: /* (or REWIND) */
+ case SPACE:
+ case ERASE: case ERASE_10:
+ case SYNCHRONIZE_CACHE:
+ case LOCK_UNLOCK_CACHE:
+#endif
+
+ /* Must be data _IN! */
+ default:
+ return -1;
+ }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
+{
+ MPT_SCSI_DEV *mpt_sdev = NULL;
+ u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
+ char devFoo[32];
+ IO_Info_t thisIo;
+
+ if (sc && sc->device)
+ mpt_sdev = (MPT_SCSI_DEV*) sc->device->hostdata;
+
+ if (sense_count) {
+ u8 *sense_data;
+ int req_index;
+
+ /* Copy the sense received into the scsi command block. */
+ req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+ sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * 256));
+ memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
+ /* Cache SenseData for this SCSI device! */
+ if (mpt_sdev) {
+ memcpy(mpt_sdev->CachedSense.data, sense_data, sense_count);
+ mpt_sdev->sense_sz = sense_count;
+ }
+ } else {
+ dprintk((KERN_INFO MYNAM ": Hmmm... SenseData len=0! (?)\n"));
+ }
+
+
+ thisIo.cdbPtr = sc->cmnd;
+ thisIo.sensePtr = sc->sense_buffer;
+ thisIo.SCSIStatus = pScsiReply->SCSIStatus;
+ thisIo.DoDisplay = 1;
+ sprintf(devFoo, "ioc%d,scsi%d:%d", hd->ioc->id, sc->target, sc->lun);
+ thisIo.DevIDStr = devFoo;
+/* fubar */
+ thisIo.dataPtr = NULL;
+ thisIo.inqPtr = NULL;
+ if (sc->device) {
+ thisIo.inqPtr = sc->device->vendor-8; /* FIXME!!! */
+ }
+ (void) mpt_ScsiHost_ErrorReport(&thisIo);
+
+ return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static u32
+SCPNT_TO_MSGCTX(Scsi_Cmnd *sc)
+{
+ MPT_SCSI_HOST *hd;
+ MPT_FRAME_HDR *mf;
+ int i;
+
+ hd = (MPT_SCSI_HOST *) sc->host->hostdata;
+
+ for (i = 0; i < hd->ioc->req_depth; i++) {
+ if (hd->ScsiLookup[i] == sc) {
+ mf = MPT_INDEX_2_MFPTR(hd->ioc, i);
+ return mf->u.frame.hwhdr.msgctxu.MsgContext;
+ }
+ }
+
+ return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/* see mptscsih.h */
+
+#ifdef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS
+ static Scsi_Host_Template driver_template = MPT_SCSIHOST;
+# include "../../scsi/scsi_module.c"
+#endif
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
+{
+ u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
+
+ dprintk((KERN_INFO MYNAM ": MPT event (=%02Xh) routed to SCSI host driver!\n", event));
+
+ switch (event) {
+ case MPI_EVENT_UNIT_ATTENTION: /* 03 */
+ /* FIXME! */
+ break;
+ case MPI_EVENT_IOC_BUS_RESET: /* 04 */
+ /* FIXME! */
+ break;
+ case MPI_EVENT_EXT_BUS_RESET: /* 05 */
+ /* FIXME! */
+ break;
+ case MPI_EVENT_LOGOUT: /* 09 */
+ /* FIXME! */
+ break;
+
+ /*
+ * CHECKME! Don't think we need to do
+ * anything for these, but...
+ */
+ case MPI_EVENT_RESCAN: /* 06 */
+ case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
+ case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
+ /*
+ * CHECKME! Falling thru...
+ */
+
+ case MPI_EVENT_NONE: /* 00 */
+ case MPI_EVENT_LOG_DATA: /* 01 */
+ case MPI_EVENT_STATE_CHANGE: /* 02 */
+ case MPI_EVENT_EVENT_CHANGE: /* 0A */
+ default:
+ dprintk((KERN_INFO MYNAM ": Ignoring event (=%02Xh)\n", event));
+ break;
+ }
+
+ return 1; /* currently means nothing really */
+}
+
+#if 0 /* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * scsiherr.c - Fusion MPT SCSI Host driver error handling/reporting.
+ *
+ * drivers/message/fusion/scsiherr.c
+ */
+
+//extern const char **mpt_ScsiOpcodesPtr; /* needed by mptscsih.c */
+//extern ASCQ_Table_t *mpt_ASCQ_TablePtr;
+//extern int mpt_ASCQ_TableSz;
+
+/* Lie! */
+#define MYNAM "mptscsih"
+
+#endif /* } */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Private data...
+ */
+static ASCQ_Table_t *mptscsih_ASCQ_TablePtr;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* old symsense.c stuff... */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Private data...
+ * To protect ourselves against those that would pass us bogus pointers
+ */
+static u8 dummyInqData[SCSI_STD_INQUIRY_BYTES]
+ = { 0x1F, 0x00, 0x00, 0x00,
+ 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static u8 dummySenseData[SCSI_STD_SENSE_BYTES]
+ = { 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00 };
+static u8 dummyCDB[16]
+ = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static u8 dummyScsiData[16]
+ = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+#if 0
+static const char *PeripheralDeviceTypeString[32] = {
+ "Direct-access", /* 00h */
+ "Sequential-access", /* 01h */
+ "Printer", /* 02h */
+ "Processor", /* 03h */
+ /*"Write-Once-Read-Multiple",*/ /* 04h */
+ "WORM", /* 04h */
+ "CD-ROM", /* 05h */
+ "Scanner", /* 06h */
+ "Optical memory", /* 07h */
+ "Media Changer", /* 08h */
+ "Communications", /* 09h */
+ "(Graphics arts pre-press)", /* 0Ah */
+ "(Graphics arts pre-press)", /* 0Bh */
+ "Array controller", /* 0Ch */
+ "Enclosure services", /* 0Dh */
+ "Simplified direct-access", /* 0Eh */
+ "Reserved-0Fh", /* 0Fh */
+ "Reserved-10h", /* 10h */
+ "Reserved-11h", /* 11h */
+ "Reserved-12h", /* 12h */
+ "Reserved-13h", /* 13h */
+ "Reserved-14h", /* 14h */
+ "Reserved-15h", /* 15h */
+ "Reserved-16h", /* 16h */
+ "Reserved-17h", /* 17h */
+ "Reserved-18h", /* 18h */
+ "Reserved-19h", /* 19h */
+ "Reserved-1Ah", /* 1Ah */
+ "Reserved-1Bh", /* 1Bh */
+ "Reserved-1Ch", /* 1Ch */
+ "Reserved-1Dh", /* 1Dh */
+ "Reserved-1Eh", /* 1Eh */
+ "Unknown" /* 1Fh */
+};
+#endif
+
+static char *ScsiStatusString[] = {
+ "GOOD", /* 00h */
+ NULL, /* 01h */
+ "CHECK CONDITION", /* 02h */
+ NULL, /* 03h */
+ "CONDITION MET", /* 04h */
+ NULL, /* 05h */
+ NULL, /* 06h */
+ NULL, /* 07h */
+ "BUSY", /* 08h */
+ NULL, /* 09h */
+ NULL, /* 0Ah */
+ NULL, /* 0Bh */
+ NULL, /* 0Ch */
+ NULL, /* 0Dh */
+ NULL, /* 0Eh */
+ NULL, /* 0Fh */
+ "INTERMEDIATE", /* 10h */
+ NULL, /* 11h */
+ NULL, /* 12h */
+ NULL, /* 13h */
+ "INTERMEDIATE-CONDITION MET", /* 14h */
+ NULL, /* 15h */
+ NULL, /* 16h */
+ NULL, /* 17h */
+ "RESERVATION CONFLICT", /* 18h */
+ NULL, /* 19h */
+ NULL, /* 1Ah */
+ NULL, /* 1Bh */
+ NULL, /* 1Ch */
+ NULL, /* 1Dh */
+ NULL, /* 1Eh */
+ NULL, /* 1Fh */
+ NULL, /* 20h */
+ NULL, /* 21h */
+ "COMMAND TERMINATED", /* 22h */
+ NULL, /* 23h */
+ NULL, /* 24h */
+ NULL, /* 25h */
+ NULL, /* 26h */
+ NULL, /* 27h */
+ "TASK SET FULL", /* 28h */
+ NULL, /* 29h */
+ NULL, /* 2Ah */
+ NULL, /* 2Bh */
+ NULL, /* 2Ch */
+ NULL, /* 2Dh */
+ NULL, /* 2Eh */
+ NULL, /* 2Fh */
+ "ACA ACTIVE", /* 30h */
+ NULL
+};
+
+static const char *ScsiCommonOpString[] = {
+ "TEST UNIT READY", /* 00h */
+ "REZERO UNIT (REWIND)", /* 01h */
+ NULL, /* 02h */
+ "REQUEST_SENSE", /* 03h */
+ "FORMAT UNIT (MEDIUM)", /* 04h */
+ "READ BLOCK LIMITS", /* 05h */
+ NULL, /* 06h */
+ "REASSIGN BLOCKS", /* 07h */
+ "READ(6)", /* 08h */
+ NULL, /* 09h */
+ "WRITE(6)", /* 0Ah */
+ "SEEK(6)", /* 0Bh */
+ NULL, /* 0Ch */
+ NULL, /* 0Dh */
+ NULL, /* 0Eh */
+ "READ REVERSE", /* 0Fh */
+ "WRITE_FILEMARKS", /* 10h */
+ "SPACE(6)", /* 11h */
+ "INQUIRY", /* 12h */
+ NULL
+};
+
+static const char *SenseKeyString[] = {
+ "NO SENSE", /* 0h */
+ "RECOVERED ERROR", /* 1h */
+ "NOT READY", /* 2h */
+ "MEDIUM ERROR", /* 3h */
+ "HARDWARE ERROR", /* 4h */
+ "ILLEGAL REQUEST", /* 5h */
+ "UNIT ATTENTION", /* 6h */
+ "DATA PROTECT", /* 7h */
+ "BLANK CHECK", /* 8h */
+ "VENDOR-SPECIFIC", /* 9h */
+ "ABORTED COPY", /* Ah */
+ "ABORTED COMMAND", /* Bh */
+ "EQUAL (obsolete)", /* Ch */
+ "VOLUME OVERFLOW", /* Dh */
+ "MISCOMPARE", /* Eh */
+ "RESERVED", /* Fh */
+ NULL
+};
+
+#define SPECIAL_ASCQ(c,q) \
+ (((c) == 0x40 && (q) != 0x00) || ((c) == 0x4D) || ((c) == 0x70))
+
+#if 0
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Sense_Key_Specific() - If Sense_Key_Specific_Valid bit is set,
+ * then print additional information via
+ * a call to SDMS_SystemAlert().
+ *
+ * Return: nothing
+ */
+static void Sense_Key_Specific(IO_Info_t *ioop, char *msg1)
+{
+ u8 *sd;
+ u8 BadValue;
+ u8 SenseKey;
+ int Offset;
+ int len = strlen(msg1);
+
+ sd = ioop->sensePtr;
+ if (SD_Additional_Sense_Length(sd) < 8)
+ return;
+
+ SenseKey = SD_Sense_Key(sd);
+
+ if (SD_Sense_Key_Specific_Valid(sd)) {
+ if (SenseKey == SK_ILLEGAL_REQUEST) {
+ Offset = SD_Bad_Byte(sd);
+ if (SD_Was_Illegal_Request(sd)) {
+ BadValue = ioop->cdbPtr[Offset];
+ len += sprintf(msg1+len, "\n Illegal CDB value=%02Xh found at CDB ",
+ BadValue);
+ } else {
+ BadValue = ioop->dataPtr[Offset];
+ len += sprintf(msg1+len, "\n Illegal DATA value=%02Xh found at DATA ",
+ BadValue);
+ }
+ len += sprintf(msg1+len, "byte=%02Xh", Offset);
+ if (SD_SKS_Bit_Pointer_Valid(sd))
+ len += sprintf(msg1+len, "/bit=%1Xh", SD_SKS_Bit_Pointer(sd));
+ } else if ((SenseKey == SK_RECOVERED_ERROR) ||
+ (SenseKey == SK_HARDWARE_ERROR) ||
+ (SenseKey == SK_MEDIUM_ERROR)) {
+ len += sprintf(msg1+len, "\n Recovery algorithm Actual_Retry_Count=%02Xh",
+ SD_Actual_Retry_Count(sd));
+ }
+ }
+}
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int dump_cdb(char *foo, unsigned char *cdb)
+{
+ int i, grpCode, cdbLen;
+ int l = 0;
+
+ grpCode = cdb[0] >> 5;
+ if (grpCode < 1)
+ cdbLen = 6;
+ else if (grpCode < 3)
+ cdbLen = 10;
+ else if (grpCode == 5)
+ cdbLen = 12;
+ else
+ cdbLen = 16;
+
+ for (i=0; i < cdbLen; i++)
+ l += sprintf(foo+l, " %02X", cdb[i]);
+
+ return l;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int dump_sd(char *foo, unsigned char *sd)
+{
+ int snsLen = 8 + SD_Additional_Sense_Length(sd);
+ int l = 0;
+ int i;
+
+ for (i=0; i < MIN(snsLen,18); i++)
+ l += sprintf(foo+l, " %02X", sd[i]);
+ l += sprintf(foo+l, "%s", snsLen>18 ? " ..." : "");
+
+ return l;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Do ASC/ASCQ lookup/grindage to English readable string(s) */
+static const char * ascq_set_strings_4max(
+ u8 ASC, u8 ASCQ,
+ const char **s1, const char **s2, const char **s3, const char **s4)
+{
+ static const char *asc_04_part1_string = "LOGICAL UNIT ";
+ static const char *asc_04_part2a_string = "NOT READY, ";
+ static const char *asc_04_part2b_string = "IS ";
+ static const char *asc_04_ascq_NN_part3_strings[] = { /* ASC ASCQ (hex) */
+ "CAUSE NOT REPORTABLE", /* 04 00 */
+ "IN PROCESS OF BECOMING READY", /* 04 01 */
+ "INITIALIZING CMD. REQUIRED", /* 04 02 */
+ "MANUAL INTERVENTION REQUIRED", /* 04 03 */
+ /* Add " IN PROGRESS" to all the following... */
+ "FORMAT", /* 04 04 */
+ "REBUILD", /* 04 05 */
+ "RECALCULATION", /* 04 06 */
+ "OPERATION", /* 04 07 */
+ "LONG WRITE", /* 04 08 */
+ "SELF-TEST", /* 04 09 */
+ NULL
+ };
+ static char *asc_04_part4_string = " IN PROGRESS";
+
+ static char *asc_29_ascq_NN_strings[] = { /* ASC ASCQ (hex) */
+ "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED", /* 29 00 */
+ "POWER ON OCCURRED", /* 29 01 */
+ "SCSI BUS RESET OCCURRED", /* 29 02 */
+ "BUS DEVICE RESET FUNCTION OCCURRED", /* 29 03 */
+ "DEVICE INTERNAL RESET", /* 29 04 */
+ "TRANSCEIVER MODE CHANGED TO SINGLE-ENDED", /* 29 05 */
+ "TRANSCEIVER MODE CHANGED TO LVD", /* 29 06 */
+ NULL
+ };
+ static char *ascq_vendor_uniq = "(Vendor Unique)";
+ static char *ascq_noone = "(no matching ASC/ASCQ description found)";
+ int idx;
+
+ *s1 = *s2 = *s3 = *s4 = ""; /* set'em all to the empty "" string */
+
+ /* CHECKME! Need lock/sem?
+ * Update and examine for isense module presense.
+ */
+ mptscsih_ASCQ_TablePtr = (ASCQ_Table_t *)mpt_v_ASCQ_TablePtr;
+
+ if (mptscsih_ASCQ_TablePtr == NULL) {
+ /* 2nd chances... */
+ if (ASC == 0x04 && (ASCQ < sizeof(asc_04_ascq_NN_part3_strings)/sizeof(char*)-1)) {
+ *s1 = asc_04_part1_string;
+ *s2 = (ASCQ == 0x01) ? asc_04_part2b_string : asc_04_part2a_string;
+ *s3 = asc_04_ascq_NN_part3_strings[ASCQ];
+ /* check for " IN PROGRESS" ones */
+ if (ASCQ >= 0x04)
+ *s4 = asc_04_part4_string;
+ } else if (ASC == 0x29 && (ASCQ < sizeof(asc_29_ascq_NN_strings)/sizeof(char*)-1))
+ *s1 = asc_29_ascq_NN_strings[ASCQ];
+ /*
+ * else { leave all *s[1-4] values pointing to the empty "" string }
+ */
+ return *s1;
+ }
+
+ /*
+ * Need to check ASC here; if it is "special," then
+ * the ASCQ is variable, and indicates failed component number.
+ * We must treat the ASCQ as a "don't care" while searching the
+ * mptscsih_ASCQ_Table[] by masking it off, and then restoring it later
+ * on when we actually need to identify the failed component.
+ */
+ if (SPECIAL_ASCQ(ASC,ASCQ))
+ ASCQ = 0xFF;
+
+ /* OK, now search mptscsih_ASCQ_Table[] for a matching entry */
+ for (idx = 0; mptscsih_ASCQ_TablePtr && idx < mpt_ASCQ_TableSz; idx++)
+ if ((ASC == mptscsih_ASCQ_TablePtr[idx].ASC) && (ASCQ == mptscsih_ASCQ_TablePtr[idx].ASCQ))
+ return (*s1 = mptscsih_ASCQ_TablePtr[idx].Description);
+
+ if ((ASC >= 0x80) || (ASCQ >= 0x80))
+ *s1 = ascq_vendor_uniq;
+ else
+ *s1 = ascq_noone;
+
+ return *s1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * SCSI Error Report; desired output format...
+ *---
+SCSI Error Report =-=-=-=-=-=-=-=-=-=-=-=-=-= (ioc0,scsi0:0)
+ SCSI_Status=02h (CHECK CONDITION)
+ Original_CDB[]: 00 00 00 00 00 00 - TestUnitReady
+ SenseData[12h]: 70 00 06 00 00 00 00 0A 00 00 00 00 29 00 03 00 00 00
+ SenseKey=6h (UNIT ATTENTION); FRU=03h
+ ASC/ASCQ=29h/00h, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED"
+ *---
+ */
+
+int mpt_ScsiHost_ErrorReport(IO_Info_t *ioop)
+{
+ char foo[512];
+ char buf2[32];
+ char *statstr;
+ const char *opstr;
+ int sk = SD_Sense_Key(ioop->sensePtr);
+ const char *skstr = SenseKeyString[sk];
+ unsigned char asc = SD_ASC(ioop->sensePtr);
+ unsigned char ascq = SD_ASCQ(ioop->sensePtr);
+ int l;
+
+ /*
+ * More quiet mode.
+ * Filter out common, repetitive, warning-type errors... like:
+ * POWER ON (06,29/00 or 06,29/01),
+ * SPINNING UP (02,04/01),
+ * LOGICAL UNIT NOT SUPPORTED (05,25/00), etc.
+ */
+ if ( (sk==SK_UNIT_ATTENTION && asc==0x29 && (ascq==0x00 || ascq==0x01))
+ || (sk==SK_NOT_READY && asc==0x04 && ascq==0x01)
+ || (sk==SK_ILLEGAL_REQUEST && asc==0x25 && ascq==0x00)
+ )
+ {
+ /* Do nothing! */
+ return 0;
+ }
+
+ /*
+ * Protect ourselves...
+ */
+ if (ioop->cdbPtr == NULL)
+ ioop->cdbPtr = dummyCDB;
+ if (ioop->sensePtr == NULL)
+ ioop->sensePtr = dummySenseData;
+ if (ioop->inqPtr == NULL)
+ ioop->inqPtr = dummyInqData;
+ if (ioop->dataPtr == NULL)
+ ioop->dataPtr = dummyScsiData;
+
+ statstr = NULL;
+ if ((ioop->SCSIStatus >= sizeof(ScsiStatusString)/sizeof(char*)-1) ||
+ ((statstr = (char*)ScsiStatusString[ioop->SCSIStatus]) == NULL)) {
+ (void) sprintf(buf2, "Bad-Reserved-%02Xh", ioop->SCSIStatus);
+ statstr = buf2;
+ }
+
+ opstr = NULL;
+ if (1+ioop->cdbPtr[0] <= sizeof(ScsiCommonOpString)/sizeof(char*))
+ opstr = ScsiCommonOpString[ioop->cdbPtr[0]];
+ else if (mpt_ScsiOpcodesPtr)
+ opstr = mpt_ScsiOpcodesPtr[ioop->cdbPtr[0]];
+
+ l = sprintf(foo, "SCSI Error Report =-=-= (%s)\n"
+ " SCSI_Status=%02Xh (%s)\n"
+ " Original_CDB[]:",
+ ioop->DevIDStr,
+ ioop->SCSIStatus,
+ statstr);
+ l += dump_cdb(foo+l, ioop->cdbPtr);
+ if (opstr)
+ l += sprintf(foo+l, " - \"%s\"", opstr);
+ l += sprintf(foo+l, "\n SenseData[%02Xh]:", 8+SD_Additional_Sense_Length(ioop->sensePtr));
+ l += dump_sd(foo+l, ioop->sensePtr);
+ l += sprintf(foo+l, "\n SenseKey=%Xh (%s); FRU=%02Xh\n ASC/ASCQ=%02Xh/%02Xh",
+ sk, skstr, SD_FRU(ioop->sensePtr), asc, ascq );
+
+ {
+ const char *x1, *x2, *x3, *x4;
+ x1 = x2 = x3 = x4 = "";
+ x1 = ascq_set_strings_4max(asc, ascq, &x1, &x2, &x3, &x4);
+ if (x1 != NULL) {
+ if (x1[0] != '(')
+ l += sprintf(foo+l, " \"%s%s%s%s\"", x1,x2,x3,x4);
+ else
+ l += sprintf(foo+l, " %s%s%s%s", x1,x2,x3,x4);
+ }
+ }
+
+#if 0
+ if (SPECIAL_ASCQ(asc,ascq))
+ l += sprintf(foo+l, " (%02Xh)", ascq);
+#endif
+
+ PrintF(("%s\n", foo));
+
+ return l;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
--- /dev/null
+/*
+ * linux/drivers/message/fusion/mptscsih.h
+ * High performance SCSI / Fibre Channel SCSI Host device driver.
+ * For use with PCI chip/adapter(s):
+ * LSIFC9xx/LSI409xx Fibre Channel
+ * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ * Credits:
+ * This driver would not exist if not for Alan Cox's development
+ * of the linux i2o driver.
+ *
+ * A huge debt of gratitude is owed to David S. Miller (DaveM)
+ * for fixing much of the stupid and broken stuff in the early
+ * driver while porting to sparc64 platform. THANK YOU!
+ *
+ * (see also mptbase.c)
+ *
+ * Copyright (c) 1999-2001 LSI Logic Corporation
+ * Originally By: Steven J. Ralston
+ * (mailto:Steve.Ralston@lsil.com)
+ *
+ * $Id: mptscsih.h,v 1.7 2001/01/11 16:56:43 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ 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; version 2 of the License.
+
+ 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.
+
+ NO WARRANTY
+ THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ solely responsible for determining the appropriateness of using and
+ distributing the Program and assumes all risks associated with its
+ exercise of rights under this Agreement, including but not limited to
+ the risks and costs of program errors, damage to or loss of data,
+ programs or equipment, and unavailability or interruption of operations.
+
+ DISCLAIMER OF LIABILITY
+ NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef SCSIHOST_H_INCLUDED
+#define SCSIHOST_H_INCLUDED
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include "linux/version.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * SCSI Public stuff...
+ */
+
+#ifdef __sparc__
+#define MPT_SCSI_CAN_QUEUE 63
+#define MPT_SCSI_CMD_PER_LUN 63
+ /* FIXME! Still investigating qd=64 hang on sparc64... */
+#else
+#define MPT_SCSI_CAN_QUEUE 64
+#define MPT_SCSI_CMD_PER_LUN 64
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Various bits and pieces broke within the lk-2.4.0-testN series:-(
+ * So here are various HACKS to work around them.
+ */
+
+/*
+ * Conditionalizing with "#ifdef MODULE/#endif" around:
+ * static Scsi_Host_Template driver_template = XX;
+ * #include <../../scsi/scsi_module.c>
+ * lines was REMOVED @ lk-2.4.0-test9
+ * Issue discovered 20001213 by: sshirron
+ */
+#define MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS 1
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,0)
+# if LINUX_VERSION_CODE == KERNEL_VERSION(2,4,0)
+ /*
+ * Super HACK! -by sralston:-(
+ * (good grief; heaven help me!)
+ */
+# include <linux/capability.h>
+# if !defined(CAP_LEASE) && !defined(MODULE)
+# undef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS
+# endif
+# else
+# ifndef MODULE
+# undef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS
+# endif
+# endif
+#endif
+
+/*
+ * tq_scheduler disappeared @ lk-2.4.0-test12
+ * (right when <linux/sched.h> newly defined TQ_ACTIVE)
+ */
+#define HAVE_TQ_SCHED 1
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+# include <linux/sched.h>
+# ifdef TQ_ACTIVE
+# undef HAVE_TQ_SCHED
+# endif
+#endif
+#ifdef HAVE_TQ_SCHED
+#define SCHEDULE_TASK(x) \
+ /*MOD_INC_USE_COUNT*/; \
+ (x)->next = NULL; \
+ queue_task(x, &tq_scheduler)
+#else
+#define SCHEDULE_TASK(x) \
+ /*MOD_INC_USE_COUNT*/; \
+ if (schedule_task(x) == 0) { \
+ /*MOD_DEC_USE_COUNT*/; \
+ }
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#define x_scsi_detect mptscsih_detect
+#define x_scsi_release mptscsih_release
+#define x_scsi_info mptscsih_info
+#define x_scsi_queuecommand mptscsih_qcmd
+#define x_scsi_abort mptscsih_abort
+#define x_scsi_bus_reset mptscsih_bus_reset
+#define x_scsi_dev_reset mptscsih_dev_reset
+#define x_scsi_host_reset mptscsih_host_reset
+#define x_scsi_bios_param mptscsih_bios_param
+
+#define x_scsi_taskmgmt_bh mptscsih_taskmgmt_bh
+#define x_scsi_old_abort mptscsih_old_abort
+#define x_scsi_old_reset mptscsih_old_reset
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * MPT SCSI Host / Initiator decls...
+ */
+extern int x_scsi_detect(Scsi_Host_Template *);
+extern int x_scsi_release(struct Scsi_Host *host);
+extern const char *x_scsi_info(struct Scsi_Host *);
+/*extern int x_scsi_command(Scsi_Cmnd *);*/
+extern int x_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+#ifdef MPT_SCSI_USE_NEW_EH
+extern int x_scsi_abort(Scsi_Cmnd *);
+extern int x_scsi_bus_reset(Scsi_Cmnd *);
+extern int x_scsi_dev_reset(Scsi_Cmnd *);
+/*extern int x_scsi_host_reset(Scsi_Cmnd *);*/
+#else
+extern int x_scsi_old_abort(Scsi_Cmnd *);
+extern int x_scsi_old_reset(Scsi_Cmnd *, unsigned int);
+#endif
+extern int x_scsi_bios_param(Disk *, kdev_t, int *);
+extern void x_scsi_taskmgmt_bh(void *);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+#define PROC_SCSI_DECL
+#else
+#define PROC_SCSI_DECL proc_name: "mptscsih",
+#endif
+
+#ifdef MPT_SCSI_USE_NEW_EH
+
+#define MPT_SCSIHOST { \
+ next: NULL, \
+ PROC_SCSI_DECL \
+ name: "MPT SCSI Host", \
+ detect: x_scsi_detect, \
+ release: x_scsi_release, \
+ info: x_scsi_info, \
+ command: NULL, \
+ queuecommand: x_scsi_queuecommand, \
+ eh_strategy_handler: NULL, \
+ eh_abort_handler: x_scsi_abort, \
+ eh_device_reset_handler: x_scsi_dev_reset, \
+ eh_bus_reset_handler: x_scsi_bus_reset, \
+ eh_host_reset_handler: NULL, \
+ bios_param: x_scsi_bios_param, \
+ can_queue: MPT_SCSI_CAN_QUEUE, \
+ this_id: -1, \
+ sg_tablesize: 25, \
+ cmd_per_lun: MPT_SCSI_CMD_PER_LUN, \
+ unchecked_isa_dma: 0, \
+ use_clustering: ENABLE_CLUSTERING, \
+ use_new_eh_code: 1 \
+}
+
+#else
+
+#define MPT_SCSIHOST { \
+ next: NULL, \
+ PROC_SCSI_DECL \
+ name: "MPT SCSI Host", \
+ detect: x_scsi_detect, \
+ release: x_scsi_release, \
+ info: x_scsi_info, \
+ command: NULL, \
+ queuecommand: x_scsi_queuecommand, \
+ abort: x_scsi_old_abort, \
+ reset: x_scsi_old_reset, \
+ bios_param: x_scsi_bios_param, \
+ can_queue: MPT_SCSI_CAN_QUEUE, \
+ this_id: -1, \
+ sg_tablesize: 25, \
+ cmd_per_lun: MPT_SCSI_CMD_PER_LUN, \
+ unchecked_isa_dma: 0, \
+ use_clustering: ENABLE_CLUSTERING \
+}
+#endif
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/* include/scsi/scsi.h may not be quite complete... */
+#ifndef RESERVE_10
+#define RESERVE_10 0x56
+#endif
+#ifndef RELEASE_10
+#define RELEASE_10 0x57
+#endif
+#ifndef PERSISTENT_RESERVE_IN
+#define PERSISTENT_RESERVE_IN 0x5e
+#endif
+#ifndef PERSISTENT_RESERVE_OUT
+#define PERSISTENT_RESERVE_OUT 0x5f
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#endif
+
--- /dev/null
+/*
+ * linux/drivers/message/fusion/scsi3.h
+ * SCSI-3 definitions and macros.
+ * (Ultimately) SCSI-3 definitions; for now, inheriting
+ * SCSI-2 definitions.
+ *
+ * Copyright (c) 1996-2001 Steven J. Ralston
+ * Written By: Steven J. Ralston (19960517)
+ * (mailto:Steve.Ralston@lsil.com)
+ *
+ * $Id: scsi3.h,v 1.4 2001/01/06 15:54:25 sralston Exp $
+ */
+
+#ifndef SCSI3_H_INCLUDED
+#define SCSI3_H_INCLUDED
+/***************************************************************************/
+
+/****************************************************************************
+ *
+ * Includes
+ */
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+ #ifndef U_STUFF_DEFINED
+ #define U_STUFF_DEFINED
+ typedef unsigned char u8;
+ typedef unsigned short u16;
+ typedef unsigned int u32;
+ #endif
+#endif
+
+/****************************************************************************
+ *
+ * Defines
+ */
+
+/*
+ * SCSI Commands
+ */
+#define CMD_TestUnitReady 0x00
+#define CMD_RezeroUnit 0x01 /* direct-access devices */
+#define CMD_Rewind 0x01 /* sequential-access devices */
+#define CMD_RequestSense 0x03
+#define CMD_FormatUnit 0x04
+#define CMD_ReassignBlock 0x07
+#define CMD_Read6 0x08
+#define CMD_Write6 0x0A
+#define CMD_WriteFilemark 0x10
+#define CMD_Space 0x11
+#define CMD_Inquiry 0x12
+#define CMD_ModeSelect6 0x15
+#define CMD_ModeSense6 0x1A
+#define CMD_Reserve6 0x16
+#define CMD_Release6 0x17
+#define CMD_Erase 0x19
+#define CMD_StartStopUnit 0x1b /* direct-access devices */
+#define CMD_LoadUnload 0x1b /* sequential-access devices */
+#define CMD_ReceiveDiagnostic 0x1C
+#define CMD_SendDiagnostic 0x1D
+#define CMD_ReadCapacity 0x25
+#define CMD_Read10 0x28
+#define CMD_Write10 0x2A
+#define CMD_WriteVerify 0x2E
+#define CMD_Verify 0x2F
+#define CMD_ReadDefectData 0x37
+#define CMD_LogSelect 0x4C
+#define CMD_LogSense 0x4D
+#define CMD_ModeSelect10 0x55
+#define CMD_Reserve10 0x56
+#define CMD_Release10 0x57
+#define CMD_ModeSense10 0x5A
+#define CMD_ReportLuns 0xA0
+
+/*
+ * Control byte field
+ */
+#define CONTROL_BYTE_NACA_BIT 0x04
+#define CONTROL_BYTE_Flag_BIT 0x02
+#define CONTROL_BYTE_Link_BIT 0x01
+
+/*
+ * SCSI Messages
+ */
+#define MSG_COMPLETE 0x00
+#define MSG_EXTENDED 0x01
+#define MSG_SAVE_POINTERS 0x02
+#define MSG_RESTORE_POINTERS 0x03
+#define MSG_DISCONNECT 0x04
+#define MSG_IDERROR 0x05
+#define MSG_ABORT 0x06
+#define MSG_REJECT 0x07
+#define MSG_NOP 0x08
+#define MSG_PARITY_ERROR 0x09
+#define MSG_LINKED_CMD_COMPLETE 0x0a
+#define MSG_LCMD_COMPLETE_W_FLG 0x0b
+#define MSG_BUS_DEVICE_RESET 0x0c
+#define MSG_ABORT_TAG 0x0d
+#define MSG_CLEAR_QUEUE 0x0e
+#define MSG_INITIATE_RECOVERY 0x0f
+
+#define MSG_RELEASE_RECOVRY 0x10
+#define MSG_TERMINATE_IO 0x11
+
+#define MSG_SIMPLE_QUEUE 0x20
+#define MSG_HEAD_OF_QUEUE 0x21
+#define MSG_ORDERED_QUEUE 0x22
+#define MSG_IGNORE_WIDE_RESIDUE 0x23
+
+#define MSG_IDENTIFY 0x80
+#define MSG_IDENTIFY_W_DISC 0xc0
+
+/*
+ * SCSI Phases
+ */
+#define PHS_DATA_OUT 0x00
+#define PHS_DATA_IN 0x01
+#define PHS_COMMAND 0x02
+#define PHS_STATUS 0x03
+#define PHS_MSG_OUT 0x06
+#define PHS_MSG_IN 0x07
+
+/*
+ * Statuses
+ */
+#define STS_GOOD 0x00
+#define STS_CHECK_CONDITION 0x02
+#define STS_CONDITION_MET 0x04
+#define STS_BUSY 0x08
+#define STS_INTERMEDIATE 0x10
+#define STS_INTERMEDIATE_CONDITION_MET 0x14
+#define STS_RESERVATION_CONFLICT 0x18
+#define STS_COMMAND_TERMINATED 0x22
+#define STS_TASK_SET_FULL 0x28
+#define STS_QUEUE_FULL 0x28
+#define STS_ACA_ACTIVE 0x30
+
+#define STS_VALID_MASK 0x3e
+
+#define SCSI_STATUS(x) ((x) & STS_VALID_MASK)
+
+/*
+ * SCSI QTag Types
+ */
+#define QTAG_SIMPLE 0x20
+#define QTAG_HEAD_OF_Q 0x21
+#define QTAG_ORDERED 0x22
+
+/*
+ * SCSI Sense Key Definitons
+ */
+#define SK_NO_SENSE 0x00
+#define SK_RECOVERED_ERROR 0x01
+#define SK_NOT_READY 0x02
+#define SK_MEDIUM_ERROR 0x03
+#define SK_HARDWARE_ERROR 0x04
+#define SK_ILLEGAL_REQUEST 0x05
+#define SK_UNIT_ATTENTION 0x06
+#define SK_DATA_PROTECT 0x07
+#define SK_BLANK_CHECK 0x08
+#define SK_VENDOR_SPECIFIC 0x09
+#define SK_COPY_ABORTED 0x0a
+#define SK_ABORTED_COMMAND 0x0b
+#define SK_EQUAL 0x0c
+#define SK_VOLUME_OVERFLOW 0x0d
+#define SK_MISCOMPARE 0x0e
+#define SK_RESERVED 0x0f
+
+
+
+#define SCSI_MAX_INQUIRY_BYTES 96
+#define SCSI_STD_INQUIRY_BYTES 36
+
+#undef USE_SCSI_COMPLETE_INQDATA
+/*
+ * Structure definition for SCSI Inquiry Data
+ *
+ * NOTE: The following structure is 96 bytes in size
+ * iff USE_SCSI_COMPLETE_INQDATA IS defined above (i.e. w/ "#define").
+ * If USE_SCSI_COMPLETE_INQDATA is NOT defined above (i.e. w/ "#undef")
+ * then the following structure is only 36 bytes in size.
+ * THE CHOICE IS YOURS!
+ */
+typedef struct SCSI_Inquiry_Data
+{
+#ifdef USE_SCSI_COMPLETE_INQDATA
+ u8 InqByte[SCSI_MAX_INQUIRY_BYTES];
+#else
+ u8 InqByte[SCSI_STD_INQUIRY_BYTES];
+#endif
+
+/*
+ * the following structure works only for little-endian (Intel,
+ * LSB first (1234) byte order) systems with 4-byte ints.
+ *
+ u32 Periph_Device_Type : 5,
+ Periph_Qualifier : 3,
+ Device_Type_Modifier : 7,
+ Removable_Media : 1,
+ ANSI_Version : 3,
+ ECMA_Version : 3,
+ ISO_Version : 2,
+ Response_Data_Format : 4,
+ reserved_0 : 3,
+ AERC : 1 ;
+ u32 Additional_Length : 8,
+ reserved_1 :16,
+ SftReset : 1,
+ CmdQue : 1,
+ reserved_2 : 1,
+ Linked : 1,
+ Sync : 1,
+ WBus16 : 1,
+ WBus32 : 1,
+ RelAdr : 1 ;
+ u8 Vendor_ID[8];
+ u8 Product_ID[16];
+ u8 Revision_Level [4];
+#ifdef USE_SCSI_COMPLETE_INQDATA
+ u8 Vendor_Specific[20];
+ u8 reserved_3[40];
+#endif
+ *
+ */
+
+} SCSI_Inquiry_Data_t;
+
+#define INQ_PERIPHINFO_BYTE 0
+#define INQ_Periph_Qualifier_MASK 0xe0
+#define INQ_Periph_Device_Type_MASK 0x1f
+
+#define INQ_Peripheral_Qualifier(inqp) \
+ (int)((*((u8*)(inqp)+INQ_PERIPHINFO_BYTE) & INQ_Periph_Qualifier_MASK) >> 5)
+#define INQ_Peripheral_Device_Type(inqp) \
+ (int)(*((u8*)(inqp)+INQ_PERIPHINFO_BYTE) & INQ_Periph_Device_Type_MASK)
+
+
+#define INQ_DEVTYPEMOD_BYTE 1
+#define INQ_RMB_BIT 0x80
+#define INQ_Device_Type_Modifier_MASK 0x7f
+
+#define INQ_Removable_Medium(inqp) \
+ (int)(*((u8*)(inqp)+INQ_DEVTYPEMOD_BYTE) & INQ_RMB_BIT)
+#define INQ_Device_Type_Modifier(inqp) \
+ (int)(*((u8*)(inqp)+INQ_DEVTYPEMOD_BYTE) & INQ_Device_Type_Modifier_MASK)
+
+
+#define INQ_VERSIONINFO_BYTE 2
+#define INQ_ISO_Version_MASK 0xc0
+#define INQ_ECMA_Version_MASK 0x38
+#define INQ_ANSI_Version_MASK 0x07
+
+#define INQ_ISO_Version(inqp) \
+ (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ISO_Version_MASK)
+#define INQ_ECMA_Version(inqp) \
+ (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ECMA_Version_MASK)
+#define INQ_ANSI_Version(inqp) \
+ (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ANSI_Version_MASK)
+
+
+#define INQ_BYTE3 3
+#define INQ_AERC_BIT 0x80
+#define INQ_TrmTsk_BIT 0x40
+#define INQ_NormACA_BIT 0x20
+#define INQ_RDF_MASK 0x0F
+
+#define INQ_AER_Capable(inqp) \
+ (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_AERC_BIT)
+#define INQ_TrmTsk(inqp) \
+ (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_TrmTsk_BIT)
+#define INQ_NormACA(inqp) \
+ (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_NormACA_BIT)
+#define INQ_Response_Data_Format(inqp) \
+ (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_RDF_MASK)
+
+
+#define INQ_CAPABILITY_BYTE 7
+#define INQ_RelAdr_BIT 0x80
+#define INQ_WBus32_BIT 0x40
+#define INQ_WBus16_BIT 0x20
+#define INQ_Sync_BIT 0x10
+#define INQ_Linked_BIT 0x08
+ /* INQ_Reserved BIT 0x40 */
+#define INQ_CmdQue_BIT 0x02
+#define INQ_SftRe_BIT 0x01
+
+#define IS_RelAdr_DEV(inqp) \
+ (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_RelAdr_BIT)
+#define IS_WBus32_DEV(inqp) \
+ (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_WBus32_BIT)
+#define IS_WBus16_DEV(inqp) \
+ (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_WBus16_BIT)
+#define IS_Sync_DEV(inqp) \
+ (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Sync_BIT)
+#define IS_Linked_DEV(inqp) \
+ (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Linked_BIT)
+#define IS_CmdQue_DEV(inqp) \
+ (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_CmdQue_BIT)
+#define IS_SftRe_DEV(inqp) \
+ (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_SftRe_BIT)
+
+#define INQ_Width_BITS \
+ (INQ_WBus32_BIT | INQ_WBus16_BIT)
+#define IS_Wide_DEV(inqp) \
+ (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Width_BITS)
+
+
+/*
+ * SCSI peripheral device types
+ */
+#define SCSI_TYPE_DAD 0x00 /* Direct Access Device */
+#define SCSI_TYPE_SAD 0x01 /* Sequential Access Device */
+#define SCSI_TYPE_TAPE SCSI_TYPE_SAD
+#define SCSI_TYPE_PRT 0x02 /* Printer */
+#define SCSI_TYPE_PROC 0x03 /* Processor */
+#define SCSI_TYPE_WORM 0x04
+#define SCSI_TYPE_CDROM 0x05
+#define SCSI_TYPE_SCAN 0x06 /* Scanner */
+#define SCSI_TYPE_OPTICAL 0x07 /* Magneto/Optical */
+#define SCSI_TYPE_CHANGER 0x08
+#define SCSI_TYPE_COMM 0x09 /* Communications device */
+#define SCSI_TYPE_UNKNOWN 0x1f
+#define SCSI_TYPE_UNCONFIGURED_LUN 0x7f
+
+#define SCSI_TYPE_MAX_KNOWN SCSI_TYPE_COMM
+
+/*
+ * Peripheral Qualifiers
+ */
+#define DEVICE_PRESENT 0x00
+#define LUN_NOT_PRESENT 0x01
+#define LUN_NOT_SUPPORTED 0x03
+
+/*
+ * ANSI Versions
+ */
+#ifndef SCSI_1
+#define SCSI_1 0x01
+#endif
+#ifndef SCSI_2
+#define SCSI_2 0x02
+#endif
+#ifndef SCSI_3
+#define SCSI_3 0x03
+#endif
+
+
+#define SCSI_MAX_SENSE_BYTES 255
+#define SCSI_STD_SENSE_BYTES 18
+#define SCSI_PAD_SENSE_BYTES (SCSI_MAX_SENSE_BYTES - SCSI_STD_SENSE_BYTES)
+
+#undef USE_SCSI_COMPLETE_SENSE
+/*
+ * Structure definition for SCSI Sense Data
+ *
+ * NOTE: The following structure is 255 bytes in size
+ * iiff USE_SCSI_COMPLETE_SENSE IS defined above (i.e. w/ "#define").
+ * If USE_SCSI_COMPLETE_SENSE is NOT defined above (i.e. w/ "#undef")
+ * then the following structure is only 19 bytes in size.
+ * THE CHOICE IS YOURS!
+ *
+ */
+typedef struct SCSI_Sense_Data
+{
+#ifdef USE_SCSI_COMPLETE_SENSE
+ u8 SenseByte[SCSI_MAX_SENSE_BYTES];
+#else
+ u8 SenseByte[SCSI_STD_SENSE_BYTES];
+#endif
+
+/*
+ * the following structure works only for little-endian (Intel,
+ * LSB first (1234) byte order) systems with 4-byte ints.
+ *
+ u8 Error_Code :4, // 0x00
+ Error_Class :3,
+ Valid :1
+ ;
+ u8 Segment_Number // 0x01
+ ;
+ u8 Sense_Key :4, // 0x02
+ Reserved :1,
+ Incorrect_Length_Indicator:1,
+ End_Of_Media :1,
+ Filemark :1
+ ;
+ u8 Information_MSB; // 0x03
+ u8 Information_Byte2; // 0x04
+ u8 Information_Byte1; // 0x05
+ u8 Information_LSB; // 0x06
+ u8 Additional_Length; // 0x07
+
+ u32 Command_Specific_Information; // 0x08 - 0x0b
+
+ u8 Additional_Sense_Code; // 0x0c
+ u8 Additional_Sense_Code_Qualifier; // 0x0d
+ u8 Field_Replaceable_Unit_Code; // 0x0e
+ u8 Illegal_Req_Bit_Pointer :3, // 0x0f
+ Illegal_Req_Bit_Valid :1,
+ Illegal_Req_Reserved :2,
+ Illegal_Req_Cmd_Data :1,
+ Sense_Key_Specific_Valid :1
+ ;
+ u16 Sense_Key_Specific_Data; // 0x10 - 0x11
+
+#ifdef USE_SCSI_COMPLETE_SENSE
+ u8 Additional_Sense_Data[SCSI_PAD_SENSE_BYTES];
+#else
+ u8 Additional_Sense_Data[1];
+#endif
+ *
+ */
+
+} SCSI_Sense_Data_t;
+
+
+#define SD_ERRCODE_BYTE 0
+#define SD_Valid_BIT 0x80
+#define SD_Error_Code_MASK 0x7f
+#define SD_Valid(sdp) \
+ (int)(*((u8*)(sdp)+SD_ERRCODE_BYTE) & SD_Valid_BIT)
+#define SD_Error_Code(sdp) \
+ (int)(*((u8*)(sdp)+SD_ERRCODE_BYTE) & SD_Error_Code_MASK)
+
+
+#define SD_SEGNUM_BYTE 1
+#define SD_Segment_Number(sdp) (int)(*((u8*)(sdp)+SD_SEGNUM_BYTE))
+
+
+#define SD_SENSEKEY_BYTE 2
+#define SD_Filemark_BIT 0x80
+#define SD_EOM_BIT 0x40
+#define SD_ILI_BIT 0x20
+#define SD_Sense_Key_MASK 0x0f
+#define SD_Filemark(sdp) \
+ (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_Filemark_BIT)
+#define SD_EOM(sdp) \
+ (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_EOM_BIT)
+#define SD_ILI(sdp) \
+ (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_ILI_BIT)
+#define SD_Sense_Key(sdp) \
+ (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_Sense_Key_MASK)
+
+
+#define SD_INFO3_BYTE 3
+#define SD_INFO2_BYTE 4
+#define SD_INFO1_BYTE 5
+#define SD_INFO0_BYTE 6
+#define SD_Information3(sdp) (int)(*((u8*)(sdp)+SD_INFO3_BYTE))
+#define SD_Information2(sdp) (int)(*((u8*)(sdp)+SD_INFO2_BYTE))
+#define SD_Information1(sdp) (int)(*((u8*)(sdp)+SD_INFO1_BYTE))
+#define SD_Information0(sdp) (int)(*((u8*)(sdp)+SD_INFO0_BYTE))
+
+
+#define SD_ADDL_LEN_BYTE 7
+#define SD_Additional_Sense_Length(sdp) \
+ (int)(*((u8*)(sdp)+SD_ADDL_LEN_BYTE))
+#define SD_Addl_Sense_Len SD_Additional_Sense_Length
+
+
+#define SD_CMD_SPECIFIC3_BYTE 8
+#define SD_CMD_SPECIFIC2_BYTE 9
+#define SD_CMD_SPECIFIC1_BYTE 10
+#define SD_CMD_SPECIFIC0_BYTE 11
+#define SD_Cmd_Specific_Info3(sdp) (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC3_BYTE))
+#define SD_Cmd_Specific_Info2(sdp) (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC2_BYTE))
+#define SD_Cmd_Specific_Info1(sdp) (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC1_BYTE))
+#define SD_Cmd_Specific_Info0(sdp) (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC0_BYTE))
+
+
+#define SD_ADDL_SENSE_CODE_BYTE 12
+#define SD_Additional_Sense_Code(sdp) \
+ (int)(*((u8*)(sdp)+SD_ADDL_SENSE_CODE_BYTE))
+#define SD_Addl_Sense_Code SD_Additional_Sense_Code
+#define SD_ASC SD_Additional_Sense_Code
+
+
+#define SD_ADDL_SENSE_CODE_QUAL_BYTE 13
+#define SD_Additional_Sense_Code_Qualifier(sdp) \
+ (int)(*((u8*)(sdp)+SD_ADDL_SENSE_CODE_QUAL_BYTE))
+#define SD_Addl_Sense_Code_Qual SD_Additional_Sense_Code_Qualifier
+#define SD_ASCQ SD_Additional_Sense_Code_Qualifier
+
+
+#define SD_FIELD_REPL_UNIT_CODE_BYTE 14
+#define SD_Field_Replaceable_Unit_Code(sdp) \
+ (int)(*((u8*)(sdp)+SD_FIELD_REPL_UNIT_CODE_BYTE))
+#define SD_Field_Repl_Unit_Code SD_Field_Replaceable_Unit_Code
+#define SD_FRUC SD_Field_Replaceable_Unit_Code
+#define SD_FRU SD_Field_Replaceable_Unit_Code
+
+
+/*
+ * Sense-Key Specific offsets and macros.
+ */
+#define SD_SKS2_BYTE 15
+#define SD_SKS_Valid_BIT 0x80
+#define SD_SKS_Cmd_Data_BIT 0x40
+#define SD_SKS_Bit_Ptr_Valid_BIT 0x08
+#define SD_SKS_Bit_Ptr_MASK 0x07
+#define SD_SKS1_BYTE 16
+#define SD_SKS0_BYTE 17
+#define SD_Sense_Key_Specific_Valid(sdp) \
+ (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Valid_BIT)
+#define SD_SKS_Valid SD_Sense_Key_Specific_Valid
+#define SD_SKS_CDB_Error(sdp) \
+ (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Cmd_Data_BIT)
+#define SD_Was_Illegal_Request SD_SKS_CDB_Error
+#define SD_SKS_Bit_Pointer_Valid(sdp) \
+ (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Bit_Ptr_Valid_BIT)
+#define SD_SKS_Bit_Pointer(sdp) \
+ (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Bit_Ptr_MASK)
+#define SD_Field_Pointer(sdp) \
+ (int)( ((u16)(*((u8*)(sdp)+SD_SKS1_BYTE)) << 8) \
+ + *((u8*)(sdp)+SD_SKS0_BYTE) )
+#define SD_Bad_Byte SD_Field_Pointer
+#define SD_Actual_Retry_Count SD_Field_Pointer
+#define SD_Progress_Indication SD_Field_Pointer
+
+/*
+ * Mode Sense Write Protect Mask
+ */
+#define WRITE_PROTECT_MASK 0X80
+
+/*
+ * Medium Type Codes
+ */
+#define OPTICAL_DEFAULT 0x00
+#define OPTICAL_READ_ONLY_MEDIUM 0x01
+#define OPTICAL_WRITE_ONCE_MEDIUM 0x02
+#define OPTICAL_READ_WRITABLE_MEDIUM 0x03
+#define OPTICAL_RO_OR_WO_MEDIUM 0x04
+#define OPTICAL_RO_OR_RW_MEDIUM 0x05
+#define OPTICAL_WO_OR_RW_MEDIUM 0x06
+
+
+
+/*
+ * Structure definition for READ6, WRITE6 (6-byte CDB)
+ */
+typedef struct SCSI_RW6_CDB
+{
+ u32 OpCode :8,
+ LBA_HI :5, /* 5 MSBit's of the LBA */
+ Lun :3,
+ LBA_MID :8, /* NOTE: total of 21 bits in LBA */
+ LBA_LO :8 ; /* Max LBA = 0x001fffff */
+ u8 BlockCount;
+ u8 Control;
+} SCSI_RW6_t;
+
+#define MAX_RW6_LBA ((u32)0x001fffff)
+
+/*
+ * Structure definition for READ10, WRITE10 (10-byte CDB)
+ *
+ * NOTE: ParityCheck bit is applicable only for VERIFY and WRITE VERIFY for
+ * the ADP-92 DAC only. In the SCSI2 spec. this same bit is defined as a
+ * FUA (forced unit access) bit for READs and WRITEs. Since this driver
+ * does not use the FUA, this bit is defined as it is used by the ADP-92.
+ * Also, for READ CAPACITY, only the OpCode field is used.
+ */
+typedef struct SCSI_RW10_CDB
+{
+ u8 OpCode;
+ u8 Reserved1;
+ u32 LBA;
+ u8 Reserved2;
+ u16 BlockCount;
+ u8 Control;
+} SCSI_RW10_t;
+
+#define PARITY_CHECK 0x08 /* parity check bit - byte[1], bit 3 */
+
+ /*
+ * Structure definition for data returned by READ CAPACITY cmd;
+ * READ CAPACITY data
+ */
+ typedef struct READ_CAP_DATA
+ {
+ u32 MaxLBA;
+ u32 BlockBytes;
+ } SCSI_READ_CAP_DATA_t, *pSCSI_READ_CAP_DATA_t;
+
+
+/*
+ * Structure definition for FORMAT UNIT CDB (6-byte CDB)
+ */
+typedef struct _SCSI_FORMAT_UNIT
+{
+ u8 OpCode;
+ u8 Reserved1;
+ u8 VendorSpecific;
+ u16 Interleave;
+ u8 Control;
+} SCSI_FORMAT_UNIT_t;
+
+/*
+ * Structure definition for REQUEST SENSE (6-byte CDB)
+ */
+typedef struct _SCSI_REQUEST_SENSE
+{
+ u8 OpCode;
+ u8 Reserved1;
+ u8 Reserved2;
+ u8 Reserved3;
+ u8 AllocLength;
+ u8 Control;
+} SCSI_REQ_SENSE_t;
+
+/*
+ * Structure definition for REPORT LUNS (12-byte CDB)
+ */
+typedef struct _SCSI_REPORT_LUNS
+{
+ u8 OpCode;
+ u8 Reserved1[5];
+ u32 AllocationLength;
+ u8 Reserved2;
+ u8 Control;
+} SCSI_REPORT_LUNS_t, *pSCSI_REPORT_LUNS_t;
+
+ /*
+ * (per-level) LUN information bytes
+ */
+/*
+ * Following doesn't work on ARMCC compiler
+ * [apparently] because it pads every struct
+ * to be multiple of 4 bytes!
+ * So SCSI_LUN_LEVELS_t winds up being 16
+ * bytes instead of 8!
+ *
+ typedef struct LUN_INFO
+ {
+ u8 AddrMethod_plus_LunOrBusNumber;
+ u8 LunOrTarget;
+ } SCSI_LUN_INFO_t, *pSCSI_LUN_INFO_t;
+
+ typedef struct LUN_LEVELS
+ {
+ SCSI_LUN_INFO_t LUN_0;
+ SCSI_LUN_INFO_t LUN_1;
+ SCSI_LUN_INFO_t LUN_2;
+ SCSI_LUN_INFO_t LUN_3;
+ } SCSI_LUN_LEVELS_t, *pSCSI_LUN_LEVELS_t;
+*/
+ /*
+ * All 4 levels (8 bytes) of LUN information
+ */
+ typedef struct LUN_LEVELS
+ {
+ u8 LVL1_AddrMethod_plus_LunOrBusNumber;
+ u8 LVL1_LunOrTarget;
+ u8 LVL2_AddrMethod_plus_LunOrBusNumber;
+ u8 LVL2_LunOrTarget;
+ u8 LVL3_AddrMethod_plus_LunOrBusNumber;
+ u8 LVL3_LunOrTarget;
+ u8 LVL4_AddrMethod_plus_LunOrBusNumber;
+ u8 LVL4_LunOrTarget;
+ } SCSI_LUN_LEVELS_t, *pSCSI_LUN_LEVELS_t;
+
+ /*
+ * Structure definition for data returned by REPORT LUNS cmd;
+ * LUN reporting parameter list format
+ */
+ typedef struct LUN_REPORT
+ {
+ u32 LunListLength;
+ u32 Reserved;
+ SCSI_LUN_LEVELS_t LunInfo[1];
+ } SCSI_LUN_REPORT_t, *pSCSI_LUN_REPORT_t;
+
+/****************************************************************************
+ *
+ * Externals
+ */
+
+/****************************************************************************
+ *
+ * Public Typedefs & Related Defines
+ */
+
+/****************************************************************************
+ *
+ * Macros (embedded, above)
+ */
+
+/****************************************************************************
+ *
+ * Public Variables
+ */
+
+/****************************************************************************
+ *
+ * Public Prototypes (module entry points)
+ */
+
+
+/***************************************************************************/
+#endif
--- /dev/null
+
+static const char *ScsiOpcodeString[256] = {
+ "TEST UNIT READY\0\01", /* 00h */
+ "REWIND\0\002"
+ "\001REZERO UNIT", /* 01h */
+ "\0\0", /* 02h */
+ "REQUEST SENSE\0\01", /* 03h */
+ "FORMAT UNIT\0\03"
+ "\001FORMAT MEDIUM\0"
+ "\002FORMAT", /* 04h */
+ "READ BLOCK LIMITS\0\1", /* 05h */
+ "\0\0", /* 06h */
+ "REASSIGN BLOCKS\0\02"
+ "\010INITIALIZE ELEMENT STATUS", /* 07h */
+ "READ(06)\0\04"
+ "\001READ\0"
+ "\003RECEIVE\0"
+ "\011GET MESSAGE(06)", /* 08h */
+ "\0\0", /* 09h */
+ "WRITE(06)\0\05"
+ "\001WRITE\0"
+ "\002PRINT\0"
+ "\003SEND(6)\0"
+ "\011SEND MESSAGE(06)", /* 0Ah */
+ "SEEK(06)\0\02"
+ "\003SLEW AND PRINT", /* 0Bh */
+ "\0\0", /* 0Ch */
+ "\0\0", /* 0Dh */
+ "\0\0", /* 0Eh */
+ "READ REVERSE\0\01", /* 0Fh */
+ "WRITE FILEMARKS\0\02"
+ "\003SYNCRONIZE BUFFER", /* 10h */
+ "SPACE(6)\0\01", /* 11h */
+ "INQUIRY\0\01", /* 12h */
+ "VERIFY\0\01", /* 13h */
+ "RECOVER BUFFERED DATA\0\01", /* 14h */
+ "MODE SELECT(06)\0\01", /* 15h */
+ "RESERVE(06)\0\02"
+ "\010RESERVE ELEMENT(06)", /* 16h */
+ "RELEASE(06)\0\02"
+ "\010RELEASE ELEMENT(06)", /* 17h */
+ "COPY\0\01", /* 18h */
+ "ERASE\0\01", /* 19h */
+ "MODE SENSE(06)\0\01", /* 1Ah */
+ "STOP START UNIT\0\04"
+ "\001LOAD UNLOAD\0"
+ "\002STOP PRINT\0"
+ "\006SCAN\0\002", /* 1Bh */
+ "RECEIVE DIAGNOSTIC RESULTS\0\01", /* 1Ch */
+ "SEND DIAGNOSTIC\0\01", /* 1Dh */
+ "PREVENT ALLOW MEDIUM REMOVAL\0\01", /* 1Eh */
+ "\0\0", /* 1Fh */
+ "\0\0", /* 20h */
+ "\0\0", /* 21h */
+ "\0\0", /* 22h */
+ "READ FORMAT CAPACITIES\0\01", /* 23h */
+ "SET WINDOW\0\01", /* 24h */
+ "READ CAPACITY\0\03"
+ "\006GET WINDOW\0"
+ "\037FREAD CARD CAPACITY", /* 25h */
+ "\0\0", /* 26h */
+ "\0\0", /* 27h */
+ "READ(10)\0\02"
+ "\011GET MESSAGE(10)", /* 28h */
+ "READ GENERATION\0\01", /* 29h */
+ "WRITE(10)\0\03"
+ "\011SEND(10)\0"
+ "\011SEND MESSAGE(10)", /* 2Ah */
+ "SEEK(10)\0\03"
+ "LOCATE(10)\0"
+ "POSITION TO ELEMENT", /* 2Bh */
+ "ERASE(10)\0\01", /* 2Ch */
+ "READ UPDATED BLOCK\0\01", /* 2Dh */
+ "WRITE AND VERIFY(10)\0\01", /* 2Eh */
+ "VERIFY(10)\0\01", /* 2Fh */
+ "SEARCH DATA HIGH(10)\0\01", /* 30h */
+ "SEARCH DATA EQUAL(10)\0\02"
+ "OBJECT POSITION", /* 31h */
+ "SEARCH DATA LOW(10)\0\01", /* 32h */
+ "SET LIMITS(10)\0\01", /* 33h */
+ "PRE-FETCH(10)\0\03"
+ "READ POSITION\0"
+ "GET DATA BUFFER STATUS", /* 34h */
+ "SYNCHRONIZE CACHE(10)\0\01", /* 35h */
+ "LOCK UNLOCK CACHE(10)\0\01", /* 36h */
+ "READ DEFECT DATA(10)\0\01", /* 37h */
+ "MEDIUM SCAN\0\01", /* 38h */
+ "COMPARE\0\01", /* 39h */
+ "COPY AND VERIFY\0\01", /* 3Ah */
+ "WRITE BUFFER\0\01", /* 3Bh */
+ "READ BUFFER\0\01", /* 3Ch */
+ "UPDATE BLOCK\0\01", /* 3Dh */
+ "READ LONG\0\01", /* 3Eh */
+ "WRITE LONG\0\01", /* 3Fh */
+ "CHANGE DEFINITION\0\01", /* 40h */
+ "WRITE SAME(10)\0\01", /* 41h */
+ "READ SUB-CHANNEL\0\01", /* 42h */
+ "READ TOC/PMA/ATIP\0\01", /* 43h */
+ "REPORT DENSITY SUPPORT\0\01", /* 44h */
+ "READ HEADER\0\01", /* 44h */
+ "PLAY AUDIO(10)\0\01", /* 45h */
+ "GET CONFIGURATION\0\01", /* 46h */
+ "PLAY AUDIO MSF\0\01", /* 47h */
+ "PLAY AUDIO TRACK INDEX\0\01", /* 48h */
+ "PLAY TRACK RELATIVE(10)\0\01", /* 49h */
+ "GET EVENT STATUS NOTIFICATION\0\01", /* 4Ah */
+ "PAUSE/RESUME\0\01", /* 4Bh */
+ "LOG SELECT\0\01", /* 4Ch */
+ "LOG SENSE\0\01", /* 4Dh */
+ "STOP PLAY/SCAN\0\01", /* 4Eh */
+ "\0\0", /* 4Fh */
+ "XDWRITE(10)\0\01", /* 50h */
+ "XPWRITE(10)\0\02"
+ "READ DISC INFORMATION", /* 51h */
+ "XDREAD(10)\0\01"
+ "READ TRACK INFORMATION", /* 52h */
+ "RESERVE TRACK\0\01", /* 53h */
+ "SEND OPC INFORMATION\0\01", /* 54h */
+ "MODE SELECT(10)\0\01", /* 55h */
+ "RESERVE(10)\0\02"
+ "RESERVE ELEMENT(10)", /* 56h */
+ "RELEASE(10)\0\02"
+ "RELEASE ELEMENT(10)", /* 57h */
+ "REPAIR TRACK\0\01", /* 58h */
+ "READ MASTER CUE\0\01", /* 59h */
+ "MODE SENSE(10)\0\01", /* 5Ah */
+ "CLOSE TRACK/SESSION\0\01", /* 5Bh */
+ "READ BUFFER CAPACITY\0\01", /* 5Ch */
+ "SEND CUE SHEET\0\01", /* 5Dh */
+ "PERSISTENT RESERVE IN\0\01", /* 5Eh */
+ "PERSISTENT RESERVE OUT\0\01", /* 5Fh */
+ "\0\0", /* 60h */
+ "\0\0", /* 61h */
+ "\0\0", /* 62h */
+ "\0\0", /* 63h */
+ "\0\0", /* 64h */
+ "\0\0", /* 65h */
+ "\0\0", /* 66h */
+ "\0\0", /* 67h */
+ "\0\0", /* 68h */
+ "\0\0", /* 69h */
+ "\0\0", /* 6Ah */
+ "\0\0", /* 6Bh */
+ "\0\0", /* 6Ch */
+ "\0\0", /* 6Dh */
+ "\0\0", /* 6Eh */
+ "\0\0", /* 6Fh */
+ "\0\0", /* 70h */
+ "\0\0", /* 71h */
+ "\0\0", /* 72h */
+ "\0\0", /* 73h */
+ "\0\0", /* 74h */
+ "\0\0", /* 75h */
+ "\0\0", /* 76h */
+ "\0\0", /* 77h */
+ "\0\0", /* 78h */
+ "\0\0", /* 79h */
+ "\0\0", /* 7Ah */
+ "\0\0", /* 7Bh */
+ "\0\0", /* 7Ch */
+ "\0\0", /* 7Eh */
+ "\0\0", /* 7Eh */
+ "\0\0", /* 7Fh */
+ "XDWRITE EXTENDED(16)\0\01", /* 80h */
+ "REBUILD(16)\0\01", /* 81h */
+ "REGENERATE(16)\0\01", /* 82h */
+ "EXTENDED COPY\0\01", /* 83h */
+ "RECEIVE COPY RESULTS\0\01", /* 84h */
+ "ACCESS CONTROL IN [proposed]\0\01", /* 86h */
+ "ACCESS CONTROL OUT [proposed]\0\01", /* 87h */
+ "READ(16)\0\01", /* 88h */
+ "DEVICE LOCKS [proposed]\0\01", /* 89h */
+ "WRITE(16)\0\01", /* 8Ah */
+ "\0\0", /* 8Bh */
+ "READ ATTRIBUTES [proposed]\0\01", /* 8Ch */
+ "WRITE ATTRIBUTES [proposed]\0\01", /* 8Dh */
+ "WRITE AND VERIFY(16)\0\01", /* 8Eh */
+ "VERIFY(16)\0\01", /* 8Fh */
+ "PRE-FETCH(16)\0\01", /* 90h */
+ "SYNCHRONIZE CACHE(16)\0\02"
+ "SPACE(16) [1]", /* 91h */
+ "LOCK UNLOCK CACHE(16)\0\02"
+ "LOCATE(16) [1]", /* 92h */
+ "WRITE SAME(16)\0\01", /* 93h */
+ "[usage proposed by SCSI Socket Services project]\0\01", /* 94h */
+ "[usage proposed by SCSI Socket Services project]\0\01", /* 95h */
+ "[usage proposed by SCSI Socket Services project]\0\01", /* 96h */
+ "[usage proposed by SCSI Socket Services project]\0\01", /* 97h */
+ "MARGIN CONTROL [proposed]\0\01", /* 98h */
+ "\0\0", /* 99h */
+ "\0\0", /* 9Ah */
+ "\0\0", /* 9Bh */
+ "\0\0", /* 9Ch */
+ "\0\0", /* 9Dh */
+ "SERVICE ACTION IN [proposed]\0\01", /* 9Eh */
+ "SERVICE ACTION OUT [proposed]\0\01", /* 9Fh */
+ "REPORT LUNS\0\01", /* A0h */
+ "BLANK\0\01", /* A1h */
+ "SEND EVENT\0\01", /* A2h */
+ "MAINTENANCE (IN)\0\02"
+ "SEND KEY", /* A3h */
+ "MAINTENANCE (OUT)\0\02"
+ "REPORT KEY", /* A4h */
+ "MOVE MEDIUM\0\02"
+ "PLAY AUDIO(12)", /* A5h */
+ "EXCHANGE MEDIUM\0\02"
+ "LOAD/UNLOAD C/DVD", /* A6h */
+ "MOVE MEDIUM ATTACHED\0\02"
+ "SET READ AHEAD\0\01", /* A7h */
+ "READ(12)\0\02"
+ "GET MESSAGE(12)", /* A8h */
+ "PLAY TRACK RELATIVE(12)\0\01", /* A9h */
+ "WRITE(12)\0\02"
+ "SEND MESSAGE(12)", /* AAh */
+ "\0\0", /* ABh */
+ "ERASE(12)\0\02"
+ "GET PERFORMANCE", /* ACh */
+ "READ DVD STRUCTURE\0\01", /* ADh */
+ "WRITE AND VERIFY(12)\0\01", /* AEh */
+ "VERIFY(12)\0\01", /* AFh */
+ "SEARCH DATA HIGH(12)\0\01", /* B0h */
+ "SEARCH DATA EQUAL(12)\0\01", /* B1h */
+ "SEARCH DATA LOW(12)\0\01", /* B2h */
+ "SET LIMITS(12)\0\01", /* B3h */
+ "READ ELEMENT STATUS ATTACHED\0\01", /* B4h */
+ "REQUEST VOLUME ELEMENT ADDRESS\0\01", /* B5h */
+ "SEND VOLUME TAG\0\02"
+ "SET STREAMING", /* B6h */
+ "READ DEFECT DATA(12)\0\01", /* B7h */
+ "READ ELEMENT STATUS\0\01", /* B8h */
+ "READ CD MSF\0\01", /* B9h */
+ "REDUNDANCY GROUP (IN)\0\02"
+ "SCAN", /* BAh */
+ "REDUNDANCY GROUP (OUT)\0\02"
+ "SET CD-ROM SPEED", /* BBh */
+ "SPARE (IN)\0\02"
+ "PLAY CD", /* BCh */
+ "SPARE (OUT)\0\02"
+ "MECHANISM STATUS", /* BDh */
+ "VOLUME SET (IN)\0\02"
+ "READ CD", /* BEh */
+ "VOLUME SET (OUT)\0\0\02"
+ "SEND DVD STRUCTURE", /* BFh */
+ "\0\0", /* C0h */
+ "\0\0", /* C1h */
+ "\0\0", /* C2h */
+ "\0\0", /* C3h */
+ "\0\0", /* C4h */
+ "\0\0", /* C5h */
+ "\0\0", /* C6h */
+ "\0\0", /* C7h */
+ "\0\0", /* C8h */
+ "\0\0", /* C9h */
+ "\0\0", /* CAh */
+ "\0\0", /* CBh */
+ "\0\0", /* CCh */
+ "\0\0", /* CDh */
+ "\0\0", /* CEh */
+ "\0\0", /* CFh */
+ "\0\0", /* D0h */
+ "\0\0", /* D1h */
+ "\0\0", /* D2h */
+ "\0\0", /* D3h */
+ "\0\0", /* D4h */
+ "\0\0", /* D5h */
+ "\0\0", /* D6h */
+ "\0\0", /* D7h */
+ "\0\0", /* D8h */
+ "\0\0", /* D9h */
+ "\0\0", /* DAh */
+ "\0\0", /* DBh */
+ "\0\0", /* DCh */
+ "\0\0", /* DEh */
+ "\0\0", /* DEh */
+ "\0\0", /* DFh */
+ "\0\0", /* E0h */
+ "\0\0", /* E1h */
+ "\0\0", /* E2h */
+ "\0\0", /* E3h */
+ "\0\0", /* E4h */
+ "\0\0", /* E5h */
+ "\0\0", /* E6h */
+ "\0\0", /* E7h */
+ "\0\0", /* E8h */
+ "\0\0", /* E9h */
+ "\0\0", /* EAh */
+ "\0\0", /* EBh */
+ "\0\0", /* ECh */
+ "\0\0", /* EDh */
+ "\0\0", /* EEh */
+ "\0\0", /* EFh */
+ "\0\0", /* F0h */
+ "\0\0", /* F1h */
+ "\0\0", /* F2h */
+ "\0\0", /* F3h */
+ "\0\0", /* F4h */
+ "\0\0", /* F5h */
+ "\0\0", /* F6h */
+ "\0\0", /* F7h */
+ "\0\0", /* F8h */
+ "\0\0", /* F9h */
+ "\0\0", /* FAh */
+ "\0\0", /* FBh */
+ "\0\0", /* FEh */
+ "\0\0", /* FEh */
+ "\0\0", /* FEh */
+ "\0\0" /* FFh */
+};
+
};
#endif /* CONFIG_MCA */
-#ifdef CONFIG_ISAPNP
+#if defined(CONFIG_ISAPNP) || defined(CONFIG_ISAPNP_MODULE)
static struct isapnp_device_id el3_isapnp_adapters[] __initdata = {
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,
ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5090),
MODULE_DEVICE_TABLE(isapnp, el3_isapnp_adapters);
static u16 el3_isapnp_phys_addr[8][3];
+#endif /* CONFIG_ISAPNP || CONFIG_ISAPNP_MODULE */
static int nopnp;
-#endif /* CONFIG_ISAPNP */
int __init el3_probe(struct net_device *dev)
{
u16 phys_addr[3];
static int current_tag;
int mca_slot = -1;
-#ifdef CONFIG_ISAPNP
+#if defined(CONFIG_ISAPNP) || defined(CONFIG_ISAPNP_MODULE)
static int pnp_cards;
-#endif /* CONFIG_ISAPNP */
+#endif /* CONFIG_ISAPNP || CONFIG_ISAPNP_MODULE */
if (dev) SET_MODULE_OWNER(dev);
}
#endif /* CONFIG_MCA */
-#ifdef CONFIG_ISAPNP
+#if defined(CONFIG_ISAPNP) || defined(CONFIG_ISAPNP_MODULE)
if (nopnp == 1)
goto no_pnp;
}
}
no_pnp:
-#endif /* CONFIG_ISAPNP */
+#endif /* CONFIG_ISAPNP || CONFIG_ISAPNP_MODULE */
/* Select an open I/O location at 0x1*0 to do contention select. */
for ( ; id_port < 0x200; id_port += 0x10) {
phys_addr[i] = htons(id_read_eeprom(i));
}
-#ifdef CONFIG_ISAPNP
+#if defined(CONFIG_ISAPNP) || defined(CONFIG_ISAPNP_MODULE)
if (nopnp == 0) {
/* The ISA PnP 3c509 cards respond to the ID sequence.
This check is needed in order not to register them twice. */
}
}
}
-#endif /* CONFIG_ISAPNP */
+#endif /* CONFIG_ISAPNP || CONFIG_ISAPNP_MODULE */
{
unsigned int iobase = id_read_eeprom(8);
*/
#define DRV_NAME "8139too"
-#define DRV_VERSION "0.9.18-pre4"
+#define DRV_VERSION "0.9.18"
#include <linux/config.h>
#define RX_BUF_PAD 16
#define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */
#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD)
-#define RX_EARLY_THRESH 2
+#define RX_EARLY_THRESH 14
/* Number of Tx descriptor registers. */
#define NUM_TX_DESC 4
dep_tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC $CONFIG_PCI
dep_mbool ' Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I $CONFIG_ACENIC
+dep_tristate 'D-Link 2000-based Gigabit Ethernet support' CONFIG_DL2K $CONFIG_PCI
dep_tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS $CONFIG_SBUS
dep_tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI $CONFIG_PCI
dep_tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN $CONFIG_PCI $CONFIG_EXPERIMENTAL
obj-$(CONFIG_MACMACE) += macmace.o
obj-$(CONFIG_MAC89x0) += mac89x0.o
obj-$(CONFIG_TUN) += tun.o
+obj-$(CONFIG_DL2K) += dl2k.o
ifeq ($(CONFIG_ARCH_ACORN),y)
mod-subdirs += ../acorn/net
--- /dev/null
+/* D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
+/*
+ Copyright (c) 2001 by D-Link Corporation
+ Written by Edward Peng.<edward_peng@dlink.com.tw>
+ Created 03-May-2001, base on Linux' sundance.c.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+*/
+/*
+ Rev Date Description
+ ==========================================================================
+ 0.01 2001/05/03 Create DL2000-based linux driver
+ 0.02 2001/05/21 Add VLAN and hardware checksum support.
+ 1.00 2001/06/26 Add jumbo frame support.
+*/
+
+#include "dl2k.h"
+
+
+static char version[] __devinitdata =
+KERN_INFO "D-Link DL2000-based linux driver v1.00 2001/06/26\n";
+
+
+
+#define MAX_UNITS 8
+static int mtu[MAX_UNITS];
+static int vlan[MAX_UNITS];
+static int jumbo[MAX_UNITS];
+static char *media[MAX_UNITS];
+static int copy_thresh;
+
+MODULE_AUTHOR ("Edward Peng");
+MODULE_DESCRIPTION ("D-Link DL2000-based Gigabit Ethernet Adapter");
+MODULE_PARM (mtu, "1-" __MODULE_STRING (MAX_UNITS) "i");
+MODULE_PARM (media, "1-" __MODULE_STRING (MAX_UNITS) "s");
+MODULE_PARM (vlan, "1-" __MODULE_STRING (MAX_UNITS) "i");
+MODULE_PARM (jumbo, "1-" __MODULE_STRING (MAX_UNITS) "i");
+MODULE_PARM (copy_thresh, "i");
+
+/* Enable the default interrupts */
+#define EnableInt() \
+writew(RxComplete| RxDMAComplete | HostError | IntRequested | TxComplete| \
+ TxDMAComplete| UpdateStats | LinkEvent, ioaddr + IntEnable)
+static int max_intrloop = 25;
+static int multicast_filter_limit = 0x40;
+
+static int rio_open (struct net_device *dev);
+static void tx_timeout (struct net_device *dev);
+static void alloc_list (struct net_device *dev);
+static int start_xmit (struct sk_buff *skb, struct net_device *dev);
+static void rio_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+static void tx_error (struct net_device *dev, int tx_status);
+static int receive_packet (struct net_device *dev);
+static void rio_error (struct net_device *dev, int int_status);
+static int change_mtu (struct net_device *dev, int new_mtu);
+static void set_multicast (struct net_device *dev);
+static struct net_device_stats *get_stats (struct net_device *dev);
+static int rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+static int rio_close (struct net_device *dev);
+static int find_miiphy (struct net_device *dev);
+static int parse_eeprom (struct net_device *dev);
+static int read_eeprom (long ioaddr, int eep_addr);
+static unsigned get_crc (unsigned char *p, int len);
+static int mii_wait_link (struct net_device *dev, int wait);
+static int mii_set_media (struct net_device *dev);
+static int mii_get_media (struct net_device *dev);
+static int mii_read (struct net_device *dev, int phy_addr, int reg_num);
+static int mii_write (struct net_device *dev, int phy_addr, int reg_num,
+ u16 data);
+#ifdef RIO_DEBUG
+static int rio_ioctl_ext (struct net_device *dev, struct ioctl_data *iodata);
+#endif
+
+static int __devinit
+rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct net_device *dev;
+ struct netdev_private *np;
+ static int card_idx;
+ int chip_idx = ent->driver_data;
+ int err, irq = pdev->irq;
+ long ioaddr;
+ static int version_printed;
+
+ if (!version_printed++)
+ printk ("%s", version);
+
+ err = pci_enable_device (pdev);
+ if (err)
+ return err;
+
+ err = pci_request_regions (pdev, "dl2k");
+ if (err)
+ goto err_out_disable;
+
+ pci_set_master (pdev);
+
+ dev = alloc_etherdev (sizeof (*np));
+ if (!dev) {
+ err = -ENOMEM;
+ goto err_out_res;
+ }
+ SET_MODULE_OWNER (dev);
+
+#ifdef USE_IO_OPS
+ ioaddr = pci_resource_start (pdev, 0);
+#else
+ ioaddr = pci_resource_start (pdev, 1);
+ ioaddr = (long) ioremap (ioaddr, RIO_IO_SIZE);
+ if (!ioaddr) {
+ err = -ENOMEM;
+ goto err_out_dev;
+ }
+#endif
+ dev->base_addr = ioaddr;
+ dev->irq = irq;
+ np = dev->priv;
+ np->chip_id = chip_idx;
+ spin_lock_init (&np->lock);
+
+ /* Parse manual configuration */
+ np->an_enable = 1;
+ if (card_idx < MAX_UNITS) {
+ if (media[card_idx] != NULL) {
+ np->an_enable = 0;
+ if (strcmp (media[card_idx], "100mbps_fd") == 0 ||
+ strcmp (media[card_idx], "4") == 0) {
+ np->speed = 100;
+ np->full_duplex = 1;
+ } else if (strcmp (media[card_idx], "100mbps_hd") == 0
+ || strcmp (media[card_idx], "3") == 0) {
+ np->speed = 100;
+ np->full_duplex = 0;
+ } else if (strcmp (media[card_idx], "10mbps_fd") == 0 ||
+ strcmp (media[card_idx], "2") == 0) {
+ np->speed = 10;
+ np->full_duplex = 1;
+ } else if (strcmp (media[card_idx], "10mbps_hd") == 0 ||
+ strcmp (media[card_idx], "1") == 0) {
+ np->speed = 10;
+ np->full_duplex = 0;
+ }
+ /* Auto-Negotiation is mandatory for 1000BASE-T,
+ IEEE 802.3ab Annex 28D page 14 */
+ else if (strcmp (media[card_idx], "1000mbps_fd") == 0 ||
+ strcmp (media[card_idx], "5") == 0 ||
+ strcmp (media[card_idx], "1000mbps_hd") == 0 ||
+ strcmp (media[card_idx], "6") == 0) {
+ np->speed = 1000;
+ np->full_duplex = 1;
+ np->an_enable = 1;
+ } else {
+ np->an_enable = 1;
+ }
+ }
+ if (jumbo[card_idx] != 0) {
+ np->jumbo = 1;
+ dev->mtu = 9000;
+ } else {
+ np->jumbo = 0;
+ if (mtu[card_idx] > 0 && mtu[card_idx] < PACKET_SIZE)
+ dev->mtu = mtu[card_idx];
+ }
+ np->vlan = (vlan[card_idx] > 0 && vlan[card_idx] < 4096) ?
+ vlan[card_idx] : 0;
+ }
+ dev->open = &rio_open;
+ dev->hard_start_xmit = &start_xmit;
+ dev->stop = &rio_close;
+ dev->get_stats = &get_stats;
+ dev->set_multicast_list = &set_multicast;
+ dev->do_ioctl = &rio_ioctl;
+ dev->tx_timeout = &tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+ dev->change_mtu = &change_mtu;
+#ifdef TX_HW_CHECKSUM
+ dev->features = NETIF_F_SG | NETIF_F_HW_CSUM;
+#endif
+ pci_set_drvdata (pdev, dev);
+
+ /* Parse eeprom data */
+ parse_eeprom (dev);
+
+ /* Find PHY address */
+ err = find_miiphy (dev);
+ if (err)
+ goto err_out_unmap;
+
+ /* Set media and reset PHY */
+ mii_set_media (dev);
+
+ /* Reset all logic functions */
+ writew (GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset,
+ ioaddr + ASICCtrl + 2);
+
+ err = register_netdev (dev);
+ if (err)
+ goto err_out_unmap;
+
+ card_idx++;
+
+ printk (KERN_INFO "%s: %s, %2x:%2x:%2x:%2x:%2x:%2x, IRQ %d\n",
+ dev->name, np->name,
+ dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5],
+ irq);
+ return 0;
+
+err_out_unmap:
+#ifndef USE_IO_OPS
+ iounmap ((void *) ioaddr);
+
+err_out_dev:
+#endif
+ kfree (dev);
+
+err_out_res:
+ pci_release_regions (pdev);
+
+err_out_disable:
+ pci_disable_device (pdev);
+ return err;
+}
+
+int
+find_miiphy (struct net_device *dev)
+{
+ int i, phy_found = 0;
+ struct netdev_private *np;
+ long ioaddr;
+ np = dev->priv;
+ ioaddr = dev->base_addr;
+ np->phy_addr = 1;
+
+ for (i = 31; i >= 0; i--) {
+ int mii_status = mii_read (dev, i, 1);
+ if (mii_status != 0xffff && mii_status != 0x0000) {
+ np->phy_addr = i;
+ phy_found++;
+ }
+ }
+ if (!phy_found) {
+ printk (KERN_ERR "%s: No MII PHY found!\n", dev->name);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+int
+parse_eeprom (struct net_device *dev)
+{
+ int i, j;
+ int ioaddr = dev->base_addr;
+ u8 sromdata[256];
+ u8 *psib;
+ u32 crc;
+ PSROM_t psrom = (PSROM_t) sromdata;
+ struct netdev_private *np = dev->priv;
+
+ int cid, next;
+
+ /* Read eeprom */
+ for (i = 0; i < 128; i++) {
+ ((u16 *) sromdata)[i] = le16_to_cpu (read_eeprom (ioaddr, i));
+ }
+
+ /* Check CRC */
+ crc = ~get_crc (sromdata, 256 - 4);
+ if (psrom->crc != ~get_crc (sromdata, 256 - 4)) {
+ printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name);
+ return -1;
+ }
+
+ /* Set MAC address */
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = psrom->mac_addr[i];
+
+ /* Parse Software Infomation Block */
+ i = 0x30;
+ psib = (u8 *) sromdata;
+ do {
+ cid = psib[i++];
+ next = psib[i++];
+ if ((cid == 0 && next == 0) || (cid == 0xff && next == 0xff)) {
+ printk (KERN_ERR "Cell data error\n");
+ return -1;
+ }
+ switch (cid) {
+ case 0: /* Format version */
+ break;
+ case 1: /* End of cell */
+ return 0;
+ case 2: /* Duplex Polarity */
+ np->duplex_polarity = psib[i];
+ writeb (readb (ioaddr + PhyCtrl) | psib[i],
+ ioaddr + PhyCtrl);
+ break;
+ case 3: /* Wake Polarity */
+ np->wake_polarity = psib[i];
+ break;
+ case 9: /* Adapter description */
+ j = (next - i > 255) ? 255 : next - i;
+ memcpy (np->name, &(psib[i]), j);
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8: /* Reversed */
+ break;
+ default: /* Unknown cell */
+ return -1;
+ }
+ i = next;
+ } while (1);
+
+ return 0;
+}
+
+static int
+rio_open (struct net_device *dev)
+{
+ struct netdev_private *np = dev->priv;
+ long ioaddr = dev->base_addr;
+ int i;
+
+ i = request_irq (dev->irq, &rio_interrupt, SA_SHIRQ, dev->name, dev);
+ if (i)
+ return i;
+
+ /* DebugCtrl bit 4, 5, 9 must set */
+ writel (readl (ioaddr + DebugCtrl) | 0x0230, ioaddr + DebugCtrl);
+
+ /* Jumbo frame */
+ if (jumbo != 0)
+ writew (9014, ioaddr + MaxFrameSize);
+
+ alloc_list (dev);
+
+ /* Get station address */
+ for (i = 0; i < 6; i++)
+ writeb (dev->dev_addr[i], ioaddr + StationAddr0 + i);
+
+ set_multicast (dev);
+
+ /* Set RIO to poll every N*320nsec. */
+ writeb (0xff, ioaddr + RxDMAPollPeriod);
+ writeb (0xff, ioaddr + TxDMAPollPeriod);
+ netif_start_queue (dev);
+ writel (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl);
+
+ /* VLAN supported */
+ if (np->vlan) {
+ /* priority field in RxDMAIntCtrl */
+ writel (0x7 << 10, ioaddr + RxDMAIntCtrl);
+ /* VLANId */
+ writew (np->vlan, ioaddr + VLANId);
+ /* Length/Type should be 0x8100 */
+ writel (0x8100 << 16 | np->vlan, ioaddr + VLANTag);
+ /* Enable AutoVLANuntagging, but disable AutoVLANtagging.
+ VLAN information tagged by TFC' VID, CFI fields. */
+ writel (readl (ioaddr + MACCtrl) | AutoVLANuntagging,
+ ioaddr + MACCtrl);
+ }
+
+ /* Enable default interrupts */
+ EnableInt ();
+
+ /* clear statistics */
+ get_stats (dev);
+ return 0;
+}
+
+static void
+tx_timeout (struct net_device *dev)
+{
+ struct netdev_private *np = dev->priv;
+ long ioaddr = dev->base_addr;
+
+ printk (KERN_WARNING "%s: Transmit timed out, TxStatus %4.4x.\n",
+ dev->name, readl (ioaddr + TxStatus));
+ dev->if_port = 0;
+ dev->trans_start = jiffies;
+ np->stats.tx_errors++;
+ if (!np->tx_full)
+ netif_wake_queue (dev);
+}
+
+ /* allocate and initialize Tx and Rx descriptors */
+static void
+alloc_list (struct net_device *dev)
+{
+ struct netdev_private *np = dev->priv;
+ int i;
+
+ np->tx_full = 0;
+ np->cur_rx = np->cur_tx = 0;
+ np->old_rx = np->old_tx = 0;
+ np->rx_buf_sz = (dev->mtu <= 1500 ? PACKET_SIZE : dev->mtu + 32);
+ np->rx_head_desc = &np->rx_ring[0];
+
+ /* Initialize Tx descriptors, TFDListPtr leaves in start_xmit(). */
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ np->tx_skbuff[i] = 0;
+ np->tx_ring[i].status = 0;
+ }
+
+ /* Initialize Rx descriptors */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ np->rx_ring[i].next_desc =
+ virt_to_le64desc (&np->rx_ring[i + 1]);
+ np->rx_ring[i].status = 0;
+ np->rx_ring[i].fraginfo = 0;
+ np->rx_skbuff[i] = 0;
+ }
+
+ /* Chain the next pointer to the top */
+ np->rx_ring[i - 1].next_desc = virt_to_le64desc (&np->rx_ring[0]);
+
+ /* Allocate the rx buffers */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ /* Allocated fixed size of skbuff */
+ struct sk_buff *skb = dev_alloc_skb (np->rx_buf_sz);
+ np->rx_skbuff[i] = skb;
+ if (skb == NULL) {
+ printk (KERN_ERR
+ "%s: alloc_list: allocate Rx buffer error! ",
+ dev->name);
+ break;
+ }
+ skb->dev = dev; /* Mark as being used by this device. */
+ skb_reserve (skb, 2); /* 16 byte align the IP header. */
+ /* Rubicon now supports 40 bits of addressing space. */
+ np->rx_ring[i].fraginfo = virt_to_le64desc (skb->tail);
+ np->rx_ring[i].fraginfo |= cpu_to_le64 (np->rx_buf_sz) << 48;
+ }
+
+ /* Set RFDListPtr */
+ writel (cpu_to_le32 (virt_to_bus (&np->rx_ring[0])),
+ dev->base_addr + RFDListPtr0);
+ writel (0, dev->base_addr + RFDListPtr1);
+
+ return;
+}
+
+static int
+start_xmit (struct sk_buff *skb, struct net_device *dev)
+{
+ struct netdev_private *np = dev->priv;
+ struct netdev_desc *txdesc;
+ unsigned entry;
+ u32 ioaddr;
+
+ ioaddr = dev->base_addr;
+ entry = np->cur_tx % TX_RING_SIZE;
+ np->tx_skbuff[entry] = skb;
+ txdesc = &np->tx_ring[entry];
+ txdesc->next_desc = 0;
+
+ /* Set TFDDone to avoid TxDMA gather this descriptor */
+ txdesc->status = cpu_to_le64 (TFDDone);
+ txdesc->status |=
+ cpu_to_le64 (entry | WordAlignDisable | (1 << FragCountShift));
+#ifdef TX_HW_CHECKSUM
+ if (skb->ip_summed == CHECKSUM_HW) {
+ txdesc->status |=
+ cpu_to_le64 (TCPChecksumEnable | UDPChecksumEnable |
+ IPChecksumEnable);
+ }
+#endif
+ if (np->vlan) {
+ txdesc->status |= cpu_to_le64 (VLANTagInsert |
+ cpu_to_le64 (vlan) << 32 |
+ cpu_to_le64 (skb->
+ priority) << 45);
+ }
+
+ /* Send one packet each time at 10Mbps mode */
+ if (entry % 0x08 == 0 || np->speed == 10)
+ txdesc->status |= cpu_to_le64 (TxIndicate);
+ txdesc->fraginfo = virt_to_le64desc (skb->data);
+ txdesc->fraginfo |= cpu_to_le64 (skb->len) << 48;
+
+ /* Chain the last descriptor's pointer to this one */
+ if (np->last_tx)
+ np->last_tx->next_desc = virt_to_le64desc (txdesc);
+ np->last_tx = txdesc;
+
+ /* Clear TFDDone, then TxDMA start to send this descriptor */
+ txdesc->status &= ~cpu_to_le64 (TFDDone);
+
+ DEBUG_TFD_DUMP (np);
+
+ /* TxDMAPollNow */
+ writel (readl (ioaddr + DMACtrl) | 0x00001000, ioaddr + DMACtrl);
+ np->cur_tx++;
+
+ if (np->cur_tx - np->old_tx < TX_QUEUE_LEN - 1 && np->speed != 10) {
+ /* do nothing */
+ } else {
+ np->tx_full = 1;
+ netif_stop_queue (dev);
+ }
+
+ /* The first TFDListPtr */
+ if (readl (dev->base_addr + TFDListPtr0) == 0) {
+ writel (virt_to_bus (&np->tx_ring[entry]),
+ dev->base_addr + TFDListPtr0);
+ writel (0, dev->base_addr + TFDListPtr1);
+ }
+
+ /* NETDEV WATCHDOG timer */
+ dev->trans_start = jiffies;
+ return 0;
+}
+
+static void
+rio_interrupt (int irq, void *dev_instance, struct pt_regs *rgs)
+{
+ struct net_device *dev = dev_instance;
+ struct netdev_private *np;
+ unsigned int_status;
+ long ioaddr;
+ int cnt = max_intrloop;
+
+ ioaddr = dev->base_addr;
+ np = dev->priv;
+ spin_lock (&np->lock);
+ while (1) {
+ int_status = readw (ioaddr + IntStatus);
+ writew (int_status & (HostError | TxComplete | RxComplete |
+ IntRequested | UpdateStats | LinkEvent |
+ TxDMAComplete | RxDMAComplete | RFDListEnd
+ | RxDMAPriority), ioaddr + IntStatus);
+ if (int_status == 0)
+ break;
+ /* Processing received packets */
+ receive_packet (dev);
+ /* TxComplete interrupt */
+ if (int_status & TxComplete) {
+ int cnt = 20;
+ int tx_status = readl (ioaddr + TxStatus);
+ while (tx_status & 0x80) { /* TxComplete */
+ /* Handle TxError */
+ if (tx_status & 0x01)
+ tx_error (dev, tx_status);
+ tx_status = readl (ioaddr + TxStatus);
+ /* too much TxError */
+ if (--cnt < 0)
+ break;
+ }
+ /* Send one packet each time at 10Mbps mode */
+ if (np->speed == 10) {
+ np->tx_full = 0;
+ netif_wake_queue (dev);
+ }
+ }
+ /* Free used tx skbuffs */
+ for (; np->cur_tx - np->old_tx > 0; np->old_tx++) {
+ int entry = np->old_tx % TX_RING_SIZE;
+ if (!(np->tx_ring[entry].status & TFDDone))
+ break;
+ dev_kfree_skb_irq (np->tx_skbuff[entry]);
+ np->tx_skbuff[entry] = 0;
+ }
+ /* If the ring is no longer full, clear tx_full and
+ call netif_wake_queue() */
+ if (np->tx_full && np->cur_tx - np->old_tx < TX_QUEUE_LEN - 1) {
+ np->tx_full = 0;
+ netif_wake_queue (dev);
+ }
+
+ /* Handle uncommon events */
+ if (int_status &
+ (IntRequested | HostError | LinkEvent | UpdateStats))
+ rio_error (dev, int_status);
+ /* If too much interrupts here, disable all interrupts except
+ IntRequest. When CountDown down to 0, IntRequest will
+ be caught by rio_error() to recovery the interrupts */
+ if (--cnt < 0) {
+ get_stats (dev);
+ writel (1000, ioaddr + CountDown);
+ writew (IntRequested, ioaddr + IntEnable);
+ break;
+ }
+ }
+ spin_unlock (&np->lock);
+}
+
+static void
+tx_error (struct net_device *dev, int tx_status)
+{
+ struct netdev_private *np;
+ long ioaddr = dev->base_addr;
+ int frame_id;
+ int i;
+
+ np = dev->priv;
+
+ frame_id = (tx_status & 0xffff0000) >> 16;
+ printk (KERN_ERR "%s: Transmit error, TxStatus %4.4x, FrameId %d.\n",
+ dev->name, tx_status, frame_id);
+ np->stats.tx_errors++;
+ np->stats.tx_dropped++;
+ /* Ttransmit Underrun */
+ if (tx_status & 0x10) {
+ np->stats.tx_fifo_errors++;
+ /* Transmit Underrun need to set TxReset, DMARest, FIFOReset */
+ writew (TxReset | DMAReset | FIFOReset, ioaddr + ASICCtrl + 2);
+ /* Wait for ResetBusy bit clear */
+ for (i = 50; i > 0; i--) {
+ if ((readw (ioaddr + ASICCtrl + 2) & ResetBusy) == 0)
+ break;
+ mdelay (1);
+ }
+ /* Reset TFDListPtr */
+ writel (virt_to_bus (&np->tx_ring[frame_id]),
+ dev->base_addr + TFDListPtr0);
+ writel (0, dev->base_addr + TFDListPtr1);
+
+ /* Let TxStartThresh stay default value */
+ }
+ /* Late Collision */
+ if (tx_status & 0x04) {
+ np->stats.tx_fifo_errors++;
+ /* TxReset and clear FIFO */
+ writew (TxReset | FIFOReset, ioaddr + ASICCtrl + 2);
+ /* Wait reset done */
+ for (i = 50; i > 0; i--) {
+ if ((readw (ioaddr + ASICCtrl + 2) & ResetBusy) == 0)
+ break;
+ mdelay (1);
+ }
+ /* Let TxStartThresh stay default value */
+ }
+ /* Maximum Collisions */
+#ifdef ETHER_STATS
+ if (tx_status & 0x08)
+ np->stats.collisions16++;
+#else
+ if (tx_status & 0x08)
+ np->stats.collisions++;
+#endif
+
+ /* Restart the Tx. */
+ writel (readw (dev->base_addr + MACCtrl) | TxEnable, ioaddr + MACCtrl);
+}
+
+/* Every interrupts go into here to see if any packet need to process, this
+ ensure Rx rings keep full in a critical cases of Rx rings ran out */
+static int
+receive_packet (struct net_device *dev)
+{
+ struct netdev_private *np = (struct netdev_private *) dev->priv;
+ int entry = np->cur_rx % RX_RING_SIZE;
+ int cnt = np->old_rx + RX_RING_SIZE - np->cur_rx;
+
+ DEBUG_RFD_DUMP (np, 1);
+ /* If RFDDone, FrameStart and FrameEnd set, there is a new packet in. */
+ while (np->rx_head_desc->status & RFDDone &&
+ np->rx_head_desc->status & FrameStart &&
+ np->rx_head_desc->status & FrameEnd) {
+ struct netdev_desc *desc = np->rx_head_desc;
+ u64 frame_status = le64_to_cpu (desc->status);
+ int pkt_len = le64_to_cpu (desc->status & 0xffff); /* Chip omits the CRC. */
+
+ if (--cnt < 0)
+ break;
+ DEBUG_PKT_DUMP (np, pkt_len);
+ /* Update rx error statistics, drop packet. */
+ if (frame_status & 0x003f0000) {
+ np->stats.rx_errors++;
+ if (frame_status & 0x00100000)
+ np->stats.rx_length_errors++;
+ if (frame_status & 0x00010000)
+ np->stats.rx_fifo_errors++;
+ if (frame_status & 0x00060000)
+ np->stats.rx_frame_errors++;
+ if (frame_status & 0x00080000)
+ np->stats.rx_crc_errors++;
+ } else {
+ struct sk_buff *skb;
+ /* Small skbuffs for short packets */
+ if (pkt_len > copy_thresh) {
+ skb_put (skb = np->rx_skbuff[entry], pkt_len);
+ np->rx_skbuff[entry] = NULL;
+ } else if ((skb = dev_alloc_skb (pkt_len + 2)) != NULL) {
+ skb->dev = dev;
+ skb_reserve (skb, 2); /* 16 byte align the IP header */
+ eth_copy_and_sum (skb,
+ np->rx_skbuff[entry]->tail,
+ pkt_len, 0);
+ skb_put (skb, pkt_len);
+ }
+ skb->protocol = eth_type_trans (skb, dev);
+#ifdef RX_HW_CHECKSUM
+ /* Checksum done by hw, but csum value unavailable. */
+ if (!(frame_status & (TCPError | UDPError | IPError))) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ }
+#endif
+ netif_rx (skb);
+ dev->last_rx = jiffies;
+ }
+ entry = (++np->cur_rx) % RX_RING_SIZE;
+ np->rx_head_desc = &np->rx_ring[entry];
+ }
+
+ /* Re-allocate skbuffs to fill the descriptor ring */
+ for (; np->cur_rx - np->old_rx > 0; np->old_rx++) {
+ struct sk_buff *skb;
+ entry = np->old_rx % RX_RING_SIZE;
+ /* Dropped packets don't need to re-allocate */
+ if (np->rx_skbuff[entry] == NULL) {
+ skb = dev_alloc_skb (np->rx_buf_sz);
+ if (skb == NULL) {
+ np->rx_ring[entry].fraginfo = 0;
+ printk (KERN_ERR
+ "%s: Allocate Rx buffer error!",
+ dev->name);
+ break;
+ }
+ np->rx_skbuff[entry] = skb;
+ skb->dev = dev;
+ skb_reserve (skb, 2); /* 16 byte align the IP header */
+ np->rx_ring[entry].fraginfo =
+ virt_to_le64desc (skb->tail);
+ }
+ np->rx_ring[entry].fraginfo |=
+ cpu_to_le64 (np->rx_buf_sz) << 48;
+ np->rx_ring[entry].status = 0;
+ }
+ /* RxDMAPollNow */
+ writel (readl (dev->base_addr + DMACtrl) | 0x00000010,
+ dev->base_addr + DMACtrl);
+
+ DEBUG_RFD_DUMP (np, 2);
+ return 0;
+}
+
+static void
+rio_error (struct net_device *dev, int int_status)
+{
+ long ioaddr = dev->base_addr;
+ struct netdev_private *np = dev->priv;
+
+ /* Stop the down counter and recovery the interrupt */
+ if (int_status & IntRequested) {
+
+ writew (0, ioaddr + IntEnable);
+ writel (0, ioaddr + CountDown);
+ /* Enable default interrupts */
+ EnableInt ();
+ }
+
+ /* Link change event */
+ if (int_status & LinkEvent) {
+ if (mii_wait_link (dev, 10) == 0) {
+ printk (KERN_INFO "%s: Link up\n", dev->name);
+ if (np->an_enable) {
+ /* Auto-Negotiation mode */
+ mii_get_media (dev);
+ if (np->full_duplex) {
+ writew (readw (dev->base_addr + MACCtrl)
+ | DuplexSelect,
+ ioaddr + MACCtrl);
+ }
+ }
+ } else {
+ printk (KERN_INFO "%s: Link off\n", dev->name);
+ }
+ }
+
+ /* UpdateStats statistics registers */
+ if (int_status & UpdateStats) {
+ get_stats (dev);
+ }
+
+ /* PCI Error, a catastronphic error related to the bus interface
+ occurs, set GlobalReset and HostReset to reset. */
+ if (int_status & HostError) {
+ printk (KERN_ERR "%s: PCI Error! IntStatus %4.4x.\n",
+ dev->name, int_status);
+ writew (GlobalReset | HostReset, ioaddr + ASICCtrl + 2);
+ mdelay (500);
+ }
+}
+
+static struct net_device_stats *
+get_stats (struct net_device *dev)
+{
+ long ioaddr = dev->base_addr;
+ struct netdev_private *np = dev->priv;
+ u16 temp1;
+ u16 temp2;
+ int i;
+ /* All statistics registers need to acknowledge,
+ else overflow could cause some problem */
+ np->stats.rx_packets += readl (ioaddr + FramesRcvOk);
+ np->stats.tx_packets += readl (ioaddr + FramesXmtOk);
+ np->stats.rx_bytes += readl (ioaddr + OctetRcvOk);
+ np->stats.tx_bytes += readl (ioaddr + OctetXmtOk);
+ temp1 = readw (ioaddr + FrameLostRxError);
+ np->stats.rx_errors += temp1;
+ np->stats.rx_missed_errors += temp1;
+ np->stats.tx_dropped += readw (ioaddr + FramesAbortXSColls);
+ temp1 = readl (ioaddr + SingleColFrames) +
+ readl (ioaddr + MultiColFrames) + readl (ioaddr + LateCollisions);
+ temp2 = readw (ioaddr + CarrierSenseErrors);
+ np->stats.tx_carrier_errors += temp2;
+ np->stats.tx_errors += readw (ioaddr + FramesWEXDeferal) +
+ readl (ioaddr + FramesWDeferredXmt) + temp2;
+
+ /* detailed rx_error */
+ np->stats.rx_length_errors += readw (ioaddr + InRangeLengthErrors) +
+ readw (ioaddr + FrameTooLongErrors);
+ np->stats.rx_crc_errors += readw (ioaddr + FrameCheckSeqError);
+
+ /* Clear all other statistic register. */
+ readw (ioaddr + MacControlFramesXmtd);
+ readw (ioaddr + BcstFramesXmtdOk);
+ readl (ioaddr + McstFramesXmtdOk);
+ readl (ioaddr + BcstOctetXmtOk);
+ readl (ioaddr + McstOctetXmtOk);
+ readw (ioaddr + MacControlFramesRcvd);
+ readw (ioaddr + BcstFramesRcvOk);
+ readl (ioaddr + McstFramesRcvOk);
+ readl (ioaddr + BcstOctetRcvOk);
+
+ for (i = 0x100; i <= 0x150; i += 4)
+ readl (ioaddr + i);
+ readw (ioaddr + TxJumboFrames);
+ readw (ioaddr + RxJumboFrames);
+ readw (ioaddr + TCPCheckSumErrors);
+ readw (ioaddr + UDPCheckSumErrors);
+ readw (ioaddr + IPCheckSumErrors);
+ return &np->stats;
+}
+
+int
+change_mtu (struct net_device *dev, int new_mtu)
+{
+ int max = (jumbo) ? 9000 : 1536;
+
+ if ((new_mtu < 68) || (new_mtu > max)) {
+ return -EINVAL;
+ }
+
+ dev->mtu = new_mtu;
+
+ return 0;
+}
+
+#define CRC_POLY 0xedb88320
+static unsigned
+get_crc (unsigned char *p, int len)
+{
+ int bit;
+ unsigned char byte;
+ unsigned crc = 0xffffffff;
+
+ while (--len >= 0) {
+ byte = *p++;
+ for (bit = 0; bit < 8; bit++, byte >>= 1) {
+ crc = (crc >> 1) ^ (((crc ^ byte) & 1) ? CRC_POLY : 0);
+ }
+ }
+ return crc;
+}
+
+static void
+set_multicast (struct net_device *dev)
+{
+ long ioaddr = dev->base_addr;
+ u32 hash_table[2];
+ u16 rx_mode = 0;
+ int i;
+ struct dev_mc_list *mclist;
+ struct netdev_private *np = dev->priv;
+
+ /* Default: receive broadcast and unicast */
+ rx_mode = ReceiveBroadcast | ReceiveUnicast;
+ if (dev->flags & IFF_PROMISC) {
+ /* Receive all frames promiscuously. */
+ rx_mode |= ReceiveAllFrames;
+ } else
+ if (((dev->flags & IFF_MULTICAST)
+ && (dev->mc_count > multicast_filter_limit))
+ || (dev->flags & IFF_ALLMULTI)) {
+ /* Receive broadcast and multicast frames */
+ rx_mode |= ReceiveBroadcast | ReceiveMulticast | ReceiveUnicast;
+ } else if ((dev->flags & IFF_MULTICAST) & (dev->mc_count > 0)) {
+ /* Receive broadcast frames and multicast frames filtering by Hashtable */
+ rx_mode |=
+ ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast;
+ }
+ if (np->vlan) {
+ /* ReceiveVLANMatch field in ReceiveMode */
+ rx_mode |= ReceiveVLANMatch;
+ }
+ hash_table[0] = 0x00000000;
+ hash_table[1] = 0x00000000;
+
+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+ i++, mclist = mclist->next) {
+ set_bit (get_crc (mclist->dmi_addr, ETH_ALEN) & 0x3f,
+ hash_table);
+ }
+ writel (hash_table[0], ioaddr + HashTable0);
+ writel (hash_table[1], ioaddr + HashTable1);
+ writew (rx_mode, ioaddr + ReceiveMode);
+}
+
+static int
+rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ int phy_addr;
+ struct netdev_private *np = dev->priv;
+ struct mii_data *miidata = (struct mii_data *) &rq->ifr_data;
+#ifdef RIO_DEBUG
+ struct ioctl_data *iodata = (struct ioctl_data *) (rq->ifr_data);
+#endif
+ u16 *data = (u16 *) & rq->ifr_data;
+ struct netdev_desc *desc;
+ int i;
+
+ phy_addr = np->phy_addr;
+ switch (cmd) {
+ case SIOCDEVPRIVATE:
+#ifdef RIO_DEBUG
+ if (rio_ioctl_ext (dev, iodata) != 0)
+ return -EOPNOTSUPP;
+ break;
+#else
+ return -EOPNOTSUPP;
+#endif
+ case SIOCDEVPRIVATE + 1:
+ miidata->out_value = mii_read (dev, phy_addr, miidata->reg_num);
+ break;
+ case SIOCDEVPRIVATE + 2:
+ mii_write (dev, phy_addr, miidata->reg_num, miidata->in_value);
+ break;
+ case SIOCDEVPRIVATE + 3:
+ np->rx_debug = (data[0] <= 7) ? data[0] : 0;
+ printk ("rx_debug = %d\n", np->rx_debug);
+ break;
+ case SIOCDEVPRIVATE + 4:
+ np->tx_debug = (data[0] <= 7) ? data[0] : 0;
+ printk ("tx_debug = %d\n", np->tx_debug);
+ break;
+ case SIOCDEVPRIVATE + 5:
+ np->tx_full = 1;
+ netif_stop_queue (dev);
+ break;
+ case SIOCDEVPRIVATE + 6:
+ np->tx_full = 0;
+ netif_wake_queue (dev);
+ break;
+ case SIOCDEVPRIVATE + 7:
+ printk ("tx_full=%x cur_tx=%x old_tx=%x cur_rx=%x old_rx=%x\n",
+ (u32) np->tx_full, (u32) np->cur_tx, (u32) np->old_tx,
+ (u32) np->cur_rx, (u32) np->old_rx);
+ break;
+ case SIOCDEVPRIVATE + 8:
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ desc = &np->tx_ring[i];
+ printk
+ ("cur:%08x next:%08x status:%08x frag1:%08x frag0:%08x",
+ (u32) virt_to_bus (desc), (u32) desc->next_desc,
+ (u32) desc->status, (u32) (desc->fraginfo >> 32),
+ (u32) desc->fraginfo);
+ printk ("\n");
+ }
+ printk ("\n");
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+#ifdef RIO_DEBUG
+int
+rio_ioctl_ext (struct net_device *dev, struct ioctl_data *iodata)
+{
+ struct netdev_private *np = dev->priv;
+ int phy_addr = np->phy_addr;
+ u32 hi, lo;
+ int i;
+ BMCR_t bmcr;
+ BMSR_t bmsr;
+
+ if (iodata == NULL)
+ goto invalid_cmd;
+ if (strcmp (iodata->signature, "rio") != 0)
+ goto invalid_cmd;
+
+ switch (iodata->cmd) {
+ case 0:
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ hi = np->tx_ring[i].status >> 32;
+ lo = np->tx_ring[i].status;
+ printk ("TFC=%08x %08x \n", hi, lo);
+
+ }
+ break;
+ case 1:
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ hi = np->rx_ring[i].status >> 32;
+ lo = np->rx_ring[i].status;
+ printk ("RFS=%08x %08x \n", hi, lo);
+ }
+ break;
+ case 2:
+ break;
+ case 3:
+ if (iodata->data != NULL)
+ np->tx_debug = iodata->data[0];
+ break;
+ case 4:
+ /* Soft reset PHY */
+ mii_write (dev, phy_addr, MII_BMCR, MII_BMCR_RESET);
+ bmcr.image = 0;
+ bmcr.bits.an_enable = 1;
+ bmcr.bits.reset = 1;
+ mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+ break;
+ case 5:
+ mii_write (dev, phy_addr, MII_BMCR, 0x1940);
+ mdelay (10);
+ mii_write (dev, phy_addr, MII_BMCR, 0x1940);
+ mdelay (100); /* wait a certain time */
+ break;
+ case 6:
+ /* 5) Set media and Power Up */
+ bmcr.image = 0;
+ bmcr.bits.power_down = 1;
+ if (np->an_enable) {
+ bmcr.bits.an_enable = 1;
+ } else {
+ if (np->speed == 100) {
+ bmcr.bits.speed100 = 1;
+ bmcr.bits.speed1000 = 0;
+ printk ("Manual 100 Mbps, ");
+ } else if (np->speed == 10) {
+ bmcr.bits.speed100 = 0;
+ bmcr.bits.speed1000 = 0;
+ printk ("Manual 10 Mbps, ");
+ }
+ if (np->full_duplex) {
+ bmcr.bits.duplex_mode = 1;
+ printk ("Full duplex. \n");
+ } else {
+ bmcr.bits.duplex_mode = 0;
+ printk ("Half duplex.\n");
+ }
+ }
+ mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+ break;
+ case 7:
+ bmcr.image = mii_read (dev, phy_addr, MII_BMCR);
+ bmsr.image = mii_read (dev, phy_addr, MII_BMSR);
+ printk ("BMCR=%x BMSR=%x LinkUp=%d\n",
+ bmcr.image, bmsr.image, bmsr.bits.link_status);
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+
+invalid_cmd:
+ return -1;
+}
+#endif
+#define EEP_READ 0x0200
+#define EEP_BUSY 0x8000
+/* Read the EEPROM word */
+int
+read_eeprom (long ioaddr, int eep_addr)
+{
+ int i = 1000;
+ writew (EEP_READ | (eep_addr & 0xff), ioaddr + EepromCtrl);
+ while (i-- > 0) {
+ if (!(readw (ioaddr + EepromCtrl) & EEP_BUSY)) {
+ return readw (ioaddr + EepromData);
+ }
+ }
+ return 0;
+}
+
+enum phy_ctrl_bits {
+ MII_READ = 0x00, MII_CLK = 0x01, MII_DATA1 = 0x02, MII_WRITE = 0x04,
+ MII_DUPLEX = 0x08,
+};
+
+#define mii_delay() readb(ioaddr)
+static void
+mii_sendbit (struct net_device *dev, u32 data)
+{
+ int ioaddr = dev->base_addr + PhyCtrl;
+ data = (data) ? MII_DATA1 : 0;
+ data |= MII_WRITE;
+ data |= (readb (ioaddr) & 0xf8) | MII_WRITE;
+ writeb (data, ioaddr);
+ mii_delay ();
+ writeb (data | MII_CLK, ioaddr);
+ mii_delay ();
+}
+
+static int
+mii_getbit (struct net_device *dev)
+{
+ int ioaddr = dev->base_addr + PhyCtrl;
+ u8 data;
+
+ data = (readb (ioaddr) & 0xf8) | MII_READ;
+ writeb (data, ioaddr);
+ mii_delay ();
+ writeb (data | MII_CLK, ioaddr);
+ mii_delay ();
+ return ((readb (ioaddr) >> 1) & 1);
+}
+
+static void
+mii_send_bits (struct net_device *dev, u32 data, int len)
+{
+ int i;
+ for (i = len - 1; i >= 0; i--) {
+ mii_sendbit (dev, data & (1 << i));
+ }
+}
+
+static int
+mii_read (struct net_device *dev, int phy_addr, int reg_num)
+{
+ u32 cmd;
+ int i;
+ u32 retval = 0;
+
+ /* Preamble */
+ mii_send_bits (dev, 0xffffffff, 32);
+ /* ST(2), OP(2), ADDR(5), REG#(5), TA(2), Data(16) total 32 bits */
+ /* ST,OP = 0110'b for read operation */
+ cmd = (0x06 << 10 | phy_addr << 5 | reg_num);
+ mii_send_bits (dev, cmd, 14);
+ /* Turnaround */
+ if (mii_getbit (dev))
+ goto err_out;
+ /* Read data */
+ for (i = 0; i < 16; i++) {
+ retval |= mii_getbit (dev);
+ retval <<= 1;
+ }
+ /* End cycle */
+ mii_getbit (dev);
+ return (retval >> 1) & 0xffff;
+
+err_out:
+ return 0;
+}
+static int
+mii_write (struct net_device *dev, int phy_addr, int reg_num, u16 data)
+{
+ u32 cmd;
+
+ /* Preamble */
+ mii_send_bits (dev, 0xffffffff, 32);
+ /* ST(2), OP(2), ADDR(5), REG#(5), TA(2), Data(16) total 32 bits */
+ /* ST,OP,AAAAA,RRRRR,TA = 0101xxxxxxxxxx10'b = 0x0502 for write */
+ cmd = (0x5002 << 16) | (phy_addr << 23) | (reg_num << 18) | data;
+ mii_send_bits (dev, cmd, 32);
+ /* End cycle */
+ mii_getbit (dev);
+ return 0;
+}
+static int
+mii_wait_link (struct net_device *dev, int wait)
+{
+ BMSR_t bmsr;
+ int phy_addr;
+ struct netdev_private *np;
+
+ np = dev->priv;
+ phy_addr = np->phy_addr;
+
+ do {
+ bmsr.image = mii_read (dev, phy_addr, MII_BMSR);
+ if (bmsr.bits.link_status)
+ return 0;
+ mdelay (1);
+ } while (--wait > 0);
+ return -1;
+}
+static int
+mii_get_media (struct net_device *dev)
+{
+ ANAR_t negotiate;
+ BMSR_t bmsr;
+ BMCR_t bmcr;
+ MSCR_t mscr;
+ MSSR_t mssr;
+ int phy_addr;
+ struct netdev_private *np;
+
+ np = dev->priv;
+ phy_addr = np->phy_addr;
+
+ bmsr.image = mii_read (dev, phy_addr, MII_BMSR);
+ if (np->an_enable) {
+ if (!bmsr.bits.an_complete) {
+ /* Auto-Negotiation not completed */
+ return -1;
+ }
+ negotiate.image = mii_read (dev, phy_addr, MII_ANAR) &
+ mii_read (dev, phy_addr, MII_ANLPAR);
+ mscr.image = mii_read (dev, phy_addr, MII_MSCR);
+ mssr.image = mii_read (dev, phy_addr, MII_MSSR);
+ if (mscr.bits.media_1000BT_FD & mssr.bits.lp_1000BT_FD) {
+ np->speed = 1000;
+ np->full_duplex = 1;
+ printk (KERN_INFO "Auto 1000BaseT, Full duplex.\n");
+ } else if (mscr.bits.media_1000BT_HD & mssr.bits.lp_1000BT_HD) {
+ np->speed = 1000;
+ np->full_duplex = 0;
+ printk (KERN_INFO "Auto 1000BaseT, Half duplex.\n");
+ } else if (negotiate.bits.media_100BX_FD) {
+ np->speed = 100;
+ np->full_duplex = 1;
+ printk (KERN_INFO "Auto 100BaseT, Full duplex.\n");
+ } else if (negotiate.bits.media_100BX_HD) {
+ np->speed = 100;
+ np->full_duplex = 0;
+ printk (KERN_INFO "Auto 100BaseT, Half duplex.\n");
+ } else if (negotiate.bits.media_10BT_FD) {
+ np->speed = 10;
+ np->full_duplex = 1;
+ printk (KERN_INFO "Auto 10BaseT, Full duplex.\n");
+ } else if (negotiate.bits.media_10BT_HD) {
+ np->speed = 10;
+ np->full_duplex = 0;
+ printk (KERN_INFO "Auto 10BaseT, Half duplex.\n");
+ }
+ } else {
+ bmcr.image = mii_read (dev, phy_addr, MII_BMCR);
+ if (bmcr.bits.speed100 == 1 && bmcr.bits.speed1000 == 0) {
+ printk (KERN_INFO "Operating at 100 Mbps, ");
+ } else if (bmcr.bits.speed100 == 0 && bmcr.bits.speed1000 == 0) {
+ printk (KERN_INFO "Operating at 10 Mbps, ");
+ } else if (bmcr.bits.speed100 == 0 && bmcr.bits.speed1000 == 1) {
+ printk (KERN_INFO "Operating at 1000 Mbps, ");
+ }
+ if (bmcr.bits.duplex_mode) {
+ printk ("Full duplex.\n");
+ } else {
+ printk ("Half duplex.\n");
+ }
+ }
+ return 0;
+}
+
+static int
+mii_set_media (struct net_device *dev)
+{
+ PHY_SCR_t pscr;
+ BMCR_t bmcr;
+ BMSR_t bmsr;
+ ANAR_t anar;
+ int phy_addr;
+ struct netdev_private *np;
+ np = dev->priv;
+ phy_addr = np->phy_addr;
+
+ /* Does user set speed? */
+ if (np->an_enable) {
+ /* Reset to enable Auto-Negotiation */
+ bmsr.image = mii_read (dev, phy_addr, MII_BMSR);
+ anar.image = mii_read (dev, phy_addr, MII_ANAR);
+ anar.bits.media_100BX_FD = bmsr.bits.media_100BX_FD;
+ anar.bits.media_100BX_HD = bmsr.bits.media_100BX_HD;
+ anar.bits.media_100BT4 = bmsr.bits.media_100BT4;
+ anar.bits.media_10BT_FD = bmsr.bits.media_10BT_FD;
+ anar.bits.media_10BT_HD = bmsr.bits.media_10BT_HD;
+ mii_write (dev, phy_addr, MII_ANAR, anar.image);
+
+ /* Enable Auto crossover */
+ pscr.image = mii_read (dev, phy_addr, MII_PHY_SCR);
+ pscr.bits.mdi_crossover_mode = 3; /* 11'b */
+ mii_write (dev, phy_addr, MII_PHY_SCR, pscr.image);
+ /* Soft reset PHY */
+ mii_write (dev, phy_addr, MII_BMCR, MII_BMCR_RESET);
+ bmcr.image = 0;
+ bmcr.bits.an_enable = 1;
+ bmcr.bits.reset = 1;
+ mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+ /* Wait for Link up, link up need a certain time */
+ if (mii_wait_link (dev, 3200) != 0) {
+ printk (KERN_INFO "Link time out\n");
+ }
+ mdelay (1);
+ mii_get_media (dev);
+ } else {
+ /* Force speed setting */
+ /* 1) Disable Auto crossover */
+ pscr.image = mii_read (dev, phy_addr, MII_PHY_SCR);
+ pscr.bits.mdi_crossover_mode = 0;
+ mii_write (dev, phy_addr, MII_PHY_SCR, pscr.image);
+
+ /* 2) PHY Reset */
+ bmcr.image = mii_read (dev, phy_addr, MII_BMCR);
+ bmcr.bits.reset = 1;
+ mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+
+ /* 3) Power Down */
+ bmcr.image = 0x1940; /* must be 0x1940 */
+ mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+ mdelay (10); /* wait a certain time */
+
+ /* 4) Advertise nothing */
+ mii_write (dev, phy_addr, MII_ANAR, 0);
+
+ /* 5) Set media and Power Up */
+ bmcr.image = 0;
+ bmcr.bits.power_down = 1;
+ if (np->speed == 100) {
+ bmcr.bits.speed100 = 1;
+ bmcr.bits.speed1000 = 0;
+ printk (KERN_INFO "Manual 100 Mbps, ");
+ } else if (np->speed == 10) {
+ bmcr.bits.speed100 = 0;
+ bmcr.bits.speed1000 = 0;
+ printk (KERN_INFO "Manual 10 Mbps, ");
+ }
+ if (np->full_duplex) {
+ bmcr.bits.duplex_mode = 1;
+ printk ("Full duplex. \n");
+ } else {
+ bmcr.bits.duplex_mode = 0;
+ printk ("Half duplex.\n");
+ }
+#if 0
+ /* Set 1000BaseT Master/Slave setting */
+ mscr.image = mii_read (dev, phy_addr, MII_MSCR);
+ mscr.bits.cfg_enable = 1;
+ mscr.bits.cfg_value = 0;
+#endif
+ mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+
+ /* Wait for Link up, link up need a certain time */
+ if (mii_wait_link (dev, 3200) != 0) {
+ printk (KERN_INFO "Link time out\n");
+ }
+ mii_get_media (dev);
+ }
+ return 0;
+}
+
+static int
+rio_close (struct net_device *dev)
+{
+ long ioaddr = dev->base_addr;
+ struct netdev_private *np = dev->priv;
+ int i;
+
+ netif_stop_queue (dev);
+
+ /* Disable interrupts */
+ writew (0, ioaddr + IntEnable);
+
+ /* Stop Tx and Rx logics */
+ writel (TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl);
+ synchronize_irq ();
+ free_irq (dev->irq, dev);
+
+ /* Free all the skbuffs in the queue. */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ np->rx_ring[i].status = 0;
+ np->rx_ring[i].fraginfo = 0;
+ if (np->rx_skbuff[i]) {
+ dev_kfree_skb (np->rx_skbuff[i]);
+ }
+ np->rx_skbuff[i] = 0;
+ }
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ if (np->tx_skbuff[i])
+ dev_kfree_skb (np->tx_skbuff[i]);
+ np->tx_skbuff[i] = 0;
+ }
+ return 0;
+}
+
+static void __devexit
+rio_remove1 (struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata (pdev);
+ if (dev) {
+ unregister_netdev (dev);
+#ifndef USE_IO_OPS
+ iounmap ((char *) (dev->base_addr));
+#endif
+ kfree (dev);
+ pci_release_regions (pdev);
+ pci_disable_device (pdev);
+ }
+ pci_set_drvdata (pdev, NULL);
+}
+
+static struct pci_driver rio_driver = {
+ name: "dl2k",
+ id_table: rio_pci_tbl,
+ probe: rio_probe1,
+ remove: rio_remove1,
+};
+
+static int __init
+rio_init (void)
+{
+#ifdef MODULE
+ printk ("%s", version);
+#endif
+
+ return pci_module_init (&rio_driver);
+}
+
+static void __exit
+rio_exit (void)
+{
+ pci_unregister_driver (&rio_driver);
+}
+
+module_init (rio_init);
+module_exit (rio_exit);
+
+/*
+
+Compile command:
+
+gcc -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -c dl2x.c
+
+*/
--- /dev/null
+/* D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
+/*
+ Copyright (c) 2001 by D-Link Corporation
+ Written by Edward Peng.<edward_peng@dlink.com.tw>
+ Created 03-May-2001, base on Linux' sundance.c.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+*/
+
+#ifndef __DL2K_H__
+#define __DL2K_H__
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <asm/processor.h> /* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+
+#define TX_RING_SIZE 16
+#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */
+#define RX_RING_SIZE 16
+
+#define virt_to_le64desc(addr) cpu_to_le64(virt_to_bus(addr))
+#define le64desc_to_virt(addr) bus_to_virt(le64_to_cpu(addr))
+/* This driver was written to use PCI memory space, however x86-oriented
+ hardware often uses I/O space accesses. */
+#ifdef USE_IO_OPS
+#undef readb
+#undef readw
+#undef readl
+#undef writeb
+#undef writew
+#undef writel
+#define readb inb
+#define readw inw
+#define readl inl
+#define writeb outb
+#define writew outw
+#define writel outl
+#endif
+
+/* Offsets to the device registers.
+ Unlike software-only systems, device drivers interact with complex hardware.
+ It's not useful to define symbolic names for every register bit in the
+ device. The name can only partially document the semantics and make
+ the driver longer and more difficult to read.
+ In general, only the important configuration values or bits changed
+ multiple times should be defined symbolically.
+*/
+enum dl2x_offsets {
+ /* I/O register offsets */
+ DMACtrl = 0x00,
+ RxDMAStatus = 0x08,
+ TFDListPtr0 = 0x10,
+ TFDListPtr1 = 0x14,
+ TxDMABurstThresh = 0x18,
+ TxDMAUrgentThresh = 0x19,
+ TxDMAPollPeriod = 0x1a,
+ RFDListPtr0 = 0x1c,
+ RFDListPtr1 = 0x20,
+ RxDMABurstThresh = 0x24,
+ RxDMAUrgentThresh = 0x25,
+ RxDMAPollPeriod = 0x26,
+ RxDMAIntCtrl = 0x28,
+ DebugCtrl = 0x2c,
+ ASICCtrl = 0x30,
+ FifoCtrl = 0x38,
+ RxEarlyThresh = 0x3a,
+ FlowOffThresh = 0x3c,
+ FlowOnThresh = 0x3e,
+ TxStartThresh = 0x44,
+ EepromData = 0x48,
+ EepromCtrl = 0x4a,
+ ExpromAddr = 0x4c,
+ Exprodata = 0x50,
+ WakeEvent0x51,
+ CountDown = 0x54,
+ IntStatusAck = 0x5a,
+ IntEnable = 0x5c,
+ IntStatus = 0x5e,
+ TxStatus = 0x60,
+ MACCtrl = 0x6c,
+ VLANTag = 0x70,
+ PhyCtrl = 0x76,
+ StationAddr0 = 0x78,
+ StationAddr1 = 0x7a,
+ StationAddr2 = 0x7c,
+ VLANId = 0x80,
+ MaxFrameSize = 0x86,
+ ReceiveMode = 0x88,
+ HashTable0 = 0x8c,
+ HashTable1 = 0x90,
+ RmonStatMask = 0x98,
+ StatMask = 0x9c,
+ RxJumboFrames = 0xbc,
+ TCPCheckSumErrors = 0xc0,
+ IPCheckSumErrors = 0xc2,
+ UDPCheckSumErrors = 0xc4,
+ TxJumboFrames = 0xf4,
+ /* Ethernet MIB statistic register offsets */
+ OctetRcvOk = 0xa8,
+ McstOctetRcvOk = 0xac,
+ BcstOctetRcvOk = 0xb0,
+ FramesRcvOk = 0xb4,
+ McstFramesRcvOk = 0xb8,
+ BcstFramesRcvOk = 0xbe,
+ MacControlFramesRcvd = 0xc6,
+ FrameTooLongErrors = 0xc8,
+ InRangeLengthErrors = 0xca,
+ FrameCheckSeqError = 0xcc,
+ FrameLostRxError = 0xce,
+ OctetXmtOk = 0xd0,
+ McstOctetXmtOk = 0xd4,
+ BcstOctetXmtOk = 0xd8,
+ FramesXmtOk = 0xdc,
+ McstFramesXmtdOk = 0xe0,
+ FramesWDeferredXmt = 0xe4,
+ LateCollisions = 0xe8,
+ MultiColFrames = 0xec,
+ SingleColFrames = 0xf0,
+ BcstFramesXmtdOk = 0xf6,
+ CarrierSenseErrors = 0xf8,
+ MacControlFramesXmtd = 0xfa,
+ FramesAbortXSColls = 0xfc,
+ FramesWEXDeferal = 0xfe,
+ /* RMON statistic register offsets */
+ EtherStatsCollisions = 0x100,
+ EtherStatsOctetsTransmit = 0x104,
+ EtherStatsPktsTransmit = 0x108,
+ EtherStatsPkts64OctetTransmit = 0x10c,
+ EtherStats65to127OctetsTransmit = 0x110,
+ EtherStatsPkts128to255OctetsTransmit = 0x114,
+ EtherStatsPkts256to511OctetsTransmit = 0x118,
+ EtherStatsPkts512to1023OctetsTransmit = 0x11c,
+ EtherStatsPkts1024to1518OctetsTransmit = 0x120,
+ EtherStatsCRCAlignErrors = 0x124,
+ EtherStatsUndersizePkts = 0x128,
+ EtherStatsFragments = 0x12c,
+ EtherStatsJabbers = 0x130,
+ EtherStatsOctets = 0x134,
+ EtherStatsPkts = 0x138,
+ EtherStats64Octets = 0x13c,
+ EtherStatsPkts65to127Octets = 0x140,
+ EtherStatsPkts128to255Octets = 0x144,
+ EtherStatsPkts256to511Octets = 0x148,
+ EtherStatsPkts512to1023Octets = 0x14c,
+ EtherStatsPkts1024to1518Octets = 0x150,
+};
+
+/* Bits in the interrupt status/mask registers. */
+enum IntStatus_bits {
+ InterruptStatus = 0x0001,
+ HostError = 0x0002,
+ MACCtrlFrame = 0x0008,
+ TxComplete = 0x0004,
+ RxComplete = 0x0010,
+ RxEarly = 0x0020,
+ IntRequested = 0x0040,
+ UpdateStats = 0x0080,
+ LinkEvent = 0x0100,
+ TxDMAComplete = 0x0200,
+ RxDMAComplete = 0x0400,
+ RFDListEnd = 0x0800,
+ RxDMAPriority = 0x1000,
+};
+
+/* Bits in the ReceiveMode register. */
+enum ReceiveMode_bits {
+ ReceiveIPMulticast = 0x0020,
+ ReceiveMulticastHash = 0x0010,
+ ReceiveAllFrames = 0x0008,
+ ReceiveBroadcast = 0x0004,
+ ReceiveMulticast = 0x0002,
+ ReceiveUnicast = 0x0001,
+ ReceiveVLANMatch = 0x0100,
+ ReceiveVLANHash = 0x0200,
+};
+/* Bits in MACCtrl. */
+enum MACCtrl_bits {
+ DuplexSelect = 0x20,
+ RcvFCS = 0x200,
+ AutoVLANtagging = 0x1000,
+ AutoVLANuntagging = 0x2000,
+ StatsEnable = 0x00200000,
+ StatsDisable = 0x00400000,
+ StatsEnabled = 0x00800000,
+ TxEnable = 0x01000000,
+ TxDisable = 0x02000000,
+ TxEnabled = 0x04000000,
+ RxEnable = 0x08000000,
+ RxDisable = 0x10000000,
+ RxEnabled = 0x20000000,
+};
+enum ASICCtrl_HiWord_bits {
+ GlobalReset = 0x0001,
+ RxReset = 0x0002,
+ TxReset = 0x0004,
+ DMAReset = 0x0008,
+ FIFOReset = 0x0010,
+ NetworkReset = 0x0020,
+ HostReset = 0x0040,
+ ResetBusy = 0x0400,
+};
+
+/* Transmit Frame Control bits */
+enum TFC_bits {
+ DwordAlign = 0x00000000,
+ WordAlignDisable = 0x00030000,
+ WordAlign = 0x00020000,
+ TCPChecksumEnable = 0x00040000,
+ UDPChecksumEnable = 0x00080000,
+ IPChecksumEnable = 0x00100000,
+ FCSAppendDisable = 0x00200000,
+ TxIndicate = 0x00400000,
+ TxDMAIndicate = 0x00800000,
+ FragCountShift = 24,
+ VLANTagInsert = 0x0000000010000000,
+ TFDDone = 0x80000000,
+ VIDShift = 32,
+ CFI = 0x0000100000000000,
+ UsePriorityShift = 48,
+};
+
+/* Receive Frames Status bits */
+enum RFS_bits {
+ RxFIFOOverrun = 0x00010000,
+ RxRuntFrame = 0x00020000,
+ RxAlignmentError = 0x00040000,
+ RxFCSError = 0x00080000,
+ RxOverSizedFrame = 0x00100000,
+ RxLengthError = 0x00200000,
+ VLANDetected = 0x00400000,
+ TCPDetected = 0x00800000,
+ TCPError = 0x01000000,
+ UDPDetected = 0x02000000,
+ UDPError = 0x04000000,
+ IPDetected = 0x08000000,
+ IPError = 0x10000000,
+ FrameStart = 0x20000000,
+ FrameEnd = 0x40000000,
+ RFDDone = 0x80000000,
+ TCIShift = 32,
+};
+
+#define MII_RESET_TIME_OUT 10000
+/* MII register */
+enum _mii_reg {
+ MII_BMCR = 0,
+ MII_BMSR = 1,
+ MII_PHY_ID1 = 2,
+ MII_PHY_ID2 = 3,
+ MII_ANAR = 4,
+ MII_ANLPAR = 5,
+ MII_ANER = 6,
+ MII_ANNPT = 7,
+ MII_ANLPRNP = 8,
+ MII_MSCR = 9,
+ MII_MSSR = 10,
+ MII_ESR = 15,
+ MII_PHY_SCR = 16,
+};
+
+/* Basic Mode Control Register */
+typedef union t_MII_BMCR {
+ u16 image;
+ struct {
+ u16 _bit_5_0:6; // bit 5:0
+ u16 speed1000:1; // bit 6
+ u16 col_test_enable:1; // bit 7
+ u16 duplex_mode:1; // bit 8
+ u16 restart_an:1; // bit 9
+ u16 isolate:1; // bit 10
+ u16 power_down:1; // bit 11
+ u16 an_enable:1; // bit 12
+ u16 speed100:1; // bit 13
+ u16 loopback:1; // bit 14
+ u16 reset:1; // bit 15
+ } bits;
+} BMCR_t, *PBMCR_t;
+
+enum _mii_bmcr {
+ MII_BMCR_RESET = 0x8000,
+ MII_BMCR_LOOP_BACK = 0x4000,
+ MII_BMCR_SPEED_LSB = 0x2000,
+ MII_BMCR_AN_ENABLE = 0x1000,
+ MII_BMCR_POWER_DOWN = 0x0800,
+ MII_BMCR_ISOLATE = 0x0400,
+ MII_BMCR_RESTART_AN = 0x0200,
+ MII_BMCR_DUPLEX_MODE = 0x0100,
+ MII_BMCR_COL_TEST = 0x0080,
+ MII_BMCR_SPEED_MSB = 0x0040,
+ MII_BMCR_SPEED_RESERVED = 0x003f,
+ MII_BMCR_SPEED_10 = 0,
+ MII_BMCR_SPEED_100 = MII_BMCR_SPEED_LSB,
+ MII_BMCR_SPEED_1000 = MII_BMCR_SPEED_MSB,
+};
+
+/* Basic Mode Status Register */
+typedef union t_MII_BMSR {
+ u16 image;
+ struct {
+ u16 ext_capability:1; // bit 0
+ u16 japper_detect:1; // bit 1
+ u16 link_status:1; // bit 2
+ u16 an_ability:1; // bit 3
+ u16 remote_fault:1; // bit 4
+ u16 an_complete:1; // bit 5
+ u16 preamble_supp:1; // bit 6
+ u16 _bit_7:1; // bit 7
+ u16 ext_status:1; // bit 8
+ u16 media_100BT2_HD:1; // bit 9
+ u16 media_100BT2_FD:1; // bit 10
+ u16 media_10BT_HD:1; // bit 11
+ u16 media_10BT_FD:1; // bit 12
+ u16 media_100BX_HD:1; // bit 13
+ u16 media_100BX_FD:1; // bit 14
+ u16 media_100BT4:1; // bit 15
+ } bits;
+} BMSR_t, *PBMSR_t;
+
+enum _mii_bmsr {
+ MII_BMSR_100BT4 = 0x8000,
+ MII_BMSR_100BX_FD = 0x4000,
+ MII_BMSR_100BX_HD = 0x2000,
+ MII_BMSR_10BT_FD = 0x1000,
+ MII_BMSR_10BT_HD = 0x0800,
+ MII_BMSR_100BT2_FD = 0x0400,
+ MII_BMSR_100BT2_HD = 0x0200,
+ MII_BMSR_EXT_STATUS = 0x0100,
+ MII_BMSR_PREAMBLE_SUPP = 0x0040,
+ MII_BMSR_AN_COMPLETE = 0x0020,
+ MII_BMSR_REMOTE_FAULT = 0x0010,
+ MII_BMSR_AN_ABILITY = 0x0008,
+ MII_BMSR_LINK_STATUS = 0x0004,
+ MII_BMSR_JABBER_DETECT = 0x0002,
+ MII_BMSR_EXT_CAP = 0x0001,
+};
+
+/* ANAR */
+typedef union t_MII_ANAR {
+ u16 image;
+ struct {
+ u16 selector:5; // bit 4:0
+ u16 media_10BT_HD:1; // bit 5
+ u16 media_10BT_FD:1; // bit 6
+ u16 media_100BX_HD:1; // bit 7
+ u16 media_100BX_FD:1; // bit 8
+ u16 media_100BT4:1; // bit 9
+ u16 pause:1; // bit 10
+ u16 asymmetric:1; // bit 11
+ u16 _bit12:1; // bit 12
+ u16 remote_fault:1; // bit 13
+ u16 _bit14:1; // bit 14
+ u16 next_page:1; // bit 15
+ } bits;
+} ANAR_t, *PANAR_t;
+
+enum _mii_anar {
+ MII_ANAR_NEXT_PAGE = 0x8000,
+ MII_ANAR_REMOTE_FAULT = 0x4000,
+ MII_ANAR_ASYMMETRIC = 0x0800,
+ MII_ANAR_PAUSE = 0x0400,
+ MII_ANAR_100BT4 = 0x0200,
+ MII_ANAR_100BX_FD = 0x0100,
+ MII_ANAR_100BX_HD = 0x0080,
+ MII_ANAR_10BT_FD = 0x0020,
+ MII_ANAR_10BT_HD = 0x0010,
+ MII_ANAR_SELECTOR = 0x001f,
+ MII_IEEE8023_CSMACD = 0x0001,
+};
+
+/* ANLPAR */
+typedef union t_MII_ANLPAR {
+ u16 image;
+ struct {
+ u16 selector:5; // bit 4:0
+ u16 media_10BT_HD:1; // bit 5
+ u16 media_10BT_FD:1; // bit 6
+ u16 media_100BX_HD:1; // bit 7
+ u16 media_100BX_FD:1; // bit 8
+ u16 media_100BT4:1; // bit 9
+ u16 pause:1; // bit 10
+ u16 asymmetric:1; // bit 11
+ u16 _bit12:1; // bit 12
+ u16 remote_fault:1; // bit 13
+ u16 _bit14:1; // bit 14
+ u16 next_page:1; // bit 15
+ } bits;
+} ANLPAR_t, *PANLPAR_t;
+
+enum _mii_anlpar {
+ MII_ANLPAR_NEXT_PAGE = MII_ANAR_NEXT_PAGE,
+ MII_ANLPAR_REMOTE_FAULT = MII_ANAR_REMOTE_FAULT,
+ MII_ANLPAR_ASYMMETRIC = MII_ANAR_ASYMMETRIC,
+ MII_ANLPAR_PAUSE = MII_ANAR_PAUSE,
+ MII_ANLPAR_100BT4 = MII_ANAR_100BT4,
+ MII_ANLPAR_100BX_FD = MII_ANAR_100BX_FD,
+ MII_ANLPAR_100BX_HD = MII_ANAR_100BX_HD,
+ MII_ANLPAR_10BT_FD = MII_ANAR_10BT_FD,
+ MII_ANLPAR_10BT_HD = MII_ANAR_10BT_HD,
+ MII_ANLPAR_SELECTOR = MII_ANAR_SELECTOR,
+};
+
+/* Auto-Negotiation Expansion Register */
+typedef union t_MII_ANER {
+ u16 image;
+ struct {
+ u16 lp_negotiable:1; // bit 0
+ u16 page_received:1; // bit 1
+ u16 nextpagable:1; // bit 2
+ u16 lp_nextpagable:1; // bit 3
+ u16 pdetect_fault:1; // bit 4
+ u16 _bit15_5:11; // bit 15:5
+ } bits;
+} ANER_t, *PANER_t;
+
+enum _mii_aner {
+ MII_ANER_PAR_DETECT_FAULT = 0x0010,
+ MII_ANER_LP_NEXTPAGABLE = 0x0008,
+ MII_ANER_NETXTPAGABLE = 0x0004,
+ MII_ANER_PAGE_RECEIVED = 0x0002,
+ MII_ANER_LP_NEGOTIABLE = 0x0001,
+};
+
+/* MASTER-SLAVE Control Register */
+typedef union t_MII_MSCR {
+ u16 image;
+ struct {
+ u16 _bit_7_0:8; // bit 7:0
+ u16 media_1000BT_HD:1; // bit 8
+ u16 media_1000BT_FD:1; // bit 9
+ u16 port_type:1; // bit 10
+ u16 cfg_value:1; // bit 11
+ u16 cfg_enable:1; // bit 12
+ u16 test_mode:3; // bit 15:13
+ } bits;
+} MSCR_t, *PMSCR_t;
+
+enum _mii_mscr {
+ MII_MSCR_TEST_MODE = 0xe000,
+ MII_MSCR_CFG_ENABLE = 0x1000,
+ MII_MSCR_CFG_VALUE = 0x0800,
+ MII_MSCR_PORT_VALUE = 0x0400,
+ MII_MSCR_1000BT_FD = 0x0200,
+ MII_MSCR_1000BT_HD = 0X0100,
+};
+
+/* MASTER-SLAVE Status Register */
+typedef union t_MII_MSSR {
+ u16 image;
+ struct {
+ u16 idle_err_count:8; // bit 7:0
+ u16 _bit_9_8:2; // bit 9:8
+ u16 lp_1000BT_HD:1; // bit 10
+ u16 lp_1000BT_FD:1; // bit 11
+ u16 remote_rcv_status:1; // bit 12
+ u16 local_rcv_status:1; // bit 13
+ u16 cfg_resolution:1; // bit 14
+ u16 cfg_fault:1; // bit 15
+ } bits;
+} MSSR_t, *PMSSR_t;
+
+enum _mii_mssr {
+ MII_MSSR_CFG_FAULT = 0x8000,
+ MII_MSSR_CFG_RES = 0x4000,
+ MII_MSSR_LOCAL_RCV_STATUS = 0x2000,
+ MII_MSSR_REMOTE_RCVR = 0x1000,
+ MII_MSSR_LP_1000BT_HD = 0x0800,
+ MII_MSSR_LP_1000BT_FD = 0x0400,
+ MII_MSSR_IDLE_ERR_COUNT = 0x00ff,
+};
+
+/* IEEE Extened Status Register */
+typedef union t_MII_ESR {
+ u16 image;
+ struct {
+ u16 _bit_11_0:12; // bit 11:0
+ u16 media_1000BT_HD:2; // bit 12
+ u16 media_1000BT_FD:1; // bit 13
+ u16 media_1000BX_HD:1; // bit 14
+ u16 media_1000BX_FD:1; // bit 15
+ } bits;
+} ESR_t, *PESR_t;
+
+enum _mii_esr {
+ MII_ESR_1000BX_FD = 0x8000,
+ MII_ESR_1000BX_HD = 0x4000,
+ MII_ESR_1000BT_FD = 0x2000,
+ MII_ESR_1000BT_HD = 0x1000,
+};
+/* PHY Specific Control Register */
+typedef union t_MII_PHY_SCR {
+ u16 image;
+ struct {
+ u16 disable_jabber:1; // bit 0
+ u16 polarity_reversal:1; // bit 1
+ u16 SEQ_test:1; // bit 2
+ u16 _bit_3:1; // bit 3
+ u16 disable_CLK125:1; // bit 4
+ u16 mdi_crossover_mode:2; // bit 6:5
+ u16 enable_ext_dist:1; // bit 7
+ u16 _bit_8_9:2; // bit 9:8
+ u16 force_link:1; // bit 10
+ u16 assert_CRS:1; // bit 11
+ u16 rcv_fifo_depth:2; // bit 13:12
+ u16 xmit_fifo_depth:2; // bit 15:14
+ } bits;
+} PHY_SCR_t, *PPHY_SCR_t;
+
+typedef enum t_MII_ADMIN_STATUS {
+ adm_reset,
+ adm_operational,
+ adm_loopback,
+ adm_power_down,
+ adm_isolate
+} MII_ADMIN_t, *PMII_ADMIN_t;
+
+typedef struct t_SROM {
+ u16 config_param; /* 0x00 */
+ u16 asic_ctrl; /* 0x02 */
+ u16 sub_vendor_id; /* 0x04 */
+ u16 sub_system_id; /* 0x06 */
+ u16 reserved1[12]; /* 0x08-0x1f */
+ u8 mac_addr[6]; /* 0x20-0x25 */
+ u8 reserved2[10]; /* 0x26-0x2f */
+ u8 sib[204]; /* 0x30-0xfb */
+ u32 crc; /* 0xfc-0xff */
+} SROM_t, *PSROM_t;
+
+/* Ioctl custom data */
+struct ioctl_data {
+ char signature[10];
+ int cmd;
+ int len;
+ char *data;
+};
+
+struct mii_data {
+ __u16 reserved;
+ __u16 reg_num;
+ __u16 in_value;
+ __u16 out_value;
+};
+
+/* The Rx and Tx buffer descriptors. */
+struct netdev_desc {
+ u64 next_desc;
+ u64 status;
+ u64 fraginfo;
+};
+
+#define PRIV_ALIGN 15 /* Required alignment mask */
+/* Use __attribute__((aligned (L1_CACHE_BYTES))) to maintain alignment
+ within the structure. */
+struct netdev_private {
+ /* Descriptor rings first for alignment. */
+ struct netdev_desc rx_ring[RX_RING_SIZE];
+ struct netdev_desc tx_ring[TX_RING_SIZE];
+ /* The addresses of receive-in-place skbuffs. */
+ struct sk_buff *rx_skbuff[RX_RING_SIZE];
+ /* The saved address of a sent-in-place packet/buffer, for later free(). */
+ struct sk_buff *tx_skbuff[TX_RING_SIZE];
+ struct net_device_stats stats;
+ spinlock_t lock;
+ struct netdev_desc *rx_head_desc;
+ unsigned int rx_buf_sz; /* Based on MTU+slack. */
+ unsigned int tx_full:1; /* The Tx queue is full. */
+ unsigned int full_duplex:1; /* Full-duplex operation requested. */
+ unsigned int speed; /* Operating speed */
+ unsigned int vlan; /* VLAN Id */
+ unsigned int an_enable; /* Auto-Negotiated Enable */
+ unsigned int chip_id; /* PCI table chip id */
+ unsigned int jumbo;
+ struct netdev_desc *last_tx; /* Last Tx descriptor used. */
+ u64 cur_rx, old_rx; /* Producer/consumer ring indices */
+ u64 cur_tx, old_tx;
+ int wake_polarity;
+ char name[256]; /* net device description */
+ u8 duplex_polarity;
+ u16 mcast_filter[4];
+ u16 advertising; /* NWay media advertisement */
+ u16 negotiate; /* Negotiated media */
+ int phy_addr; /* PHY addresses. */
+ int tx_debug;
+ int rx_debug;
+};
+
+/* The station address location in the EEPROM. */
+#ifdef USE_IO_OPS
+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0)
+#else
+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
+#endif
+/* The struct pci_device_id consist of:
+ vendor, device Vendor and device ID to match (or PCI_ANY_ID)
+ subvendor, subdevice Subsystem vendor and device ID to match (or PCI_ANY_ID)
+ class Device class to match. The class_mask tells which bits
+ class_mask of the class are honored during the comparison.
+ driver_data Data private to the driver.
+*/
+static struct pci_device_id rio_pci_tbl[] __devinitdata = {
+ {0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0,}
+};
+MODULE_DEVICE_TABLE (pci, rio_pci_tbl);
+#define TX_TIMEOUT (4*HZ)
+#define PACKET_SIZE 1536
+#define RIO_IO_SIZE 340
+#ifdef RIO_DEBUG
+#define DEBUG_TFD_DUMP(x) debug_tfd_dump(x)
+#define DEBUG_RFD_DUMP(x,flag) debug_rfd_dump(x,flag)
+#define DEBUG_PKT_DUMP(x,len) debug_pkt_dump(x,len)
+#define DEBUG_PRINT printk
+
+static inline void
+debug_tfd_dump (struct netdev_private *np)
+{
+ int i;
+ struct netdev_desc *desc;
+
+ if (np->tx_debug == 6) {
+ printk ("TFDone Dump: ");
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ desc = &np->tx_ring[i];
+ if ((desc->fraginfo & 0xffffffffff) == 0)
+ printk ("X");
+ else
+ printk ("%d", (desc->status & TFDDone) ? 1 : 0);
+ }
+ printk ("\n");
+ }
+ if (np->tx_debug == 5) {
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ desc = &np->tx_ring[i];
+ printk
+ ("cur:%08x next:%08x status:%08x frag1:%08x frag0:%08x",
+ (u32) virt_to_bus (desc), (u32) desc->next_desc,
+ (u32) desc->status, (u32) (desc->fraginfo >> 32),
+ (u32) desc->fraginfo);
+ printk ("\n");
+ }
+ printk ("\n");
+ }
+}
+static inline void
+debug_rfd_dump (struct netdev_private *np, int flag)
+{
+ int i;
+ struct netdev_desc *desc;
+ int entry = np->cur_rx % RX_RING_SIZE;
+
+ if (np->rx_debug == 5) {
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ desc = &np->rx_ring[i];
+ printk
+ ("cur:%08x next:%08x status:%08x frag1:%08x frag0:%08x",
+ (u32) virt_to_bus (desc), (u32) desc->next_desc,
+ (u32) desc->status, (u32) (desc->fraginfo >> 32),
+ (u32) desc->fraginfo);
+ printk ("\n");
+ }
+ printk ("\n");
+ }
+
+ if (np->rx_debug == 6) {
+ if (flag == 1)
+ printk ("RFDone Dump: ");
+ else if (flag == 2)
+ printk ("Re-Filling: ");
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ desc = &np->rx_ring[i];
+ printk ("%d", (desc->status & RFDDone) ? 1 : 0);
+ }
+ printk ("\n");
+ }
+ if (np->rx_debug == 7) {
+ printk (" In rcv_pkt(), entry %d status %4.4x %4.4x.\n",
+ entry, (u32) (np->rx_ring[entry].status >> 32),
+ (u32) np->rx_ring[entry].status);
+ }
+
+}
+
+static inline void
+debug_pkt_dump (struct netdev_private *np, int pkt_len)
+{
+ int i;
+ struct netdev_desc *desc = np->rx_head_desc;
+ unsigned char *pchar;
+ unsigned char *phead;
+ u64 frame_status = le64_to_cpu (desc->status);
+
+ if (np->rx_debug == 4) {
+ printk (" rcv_pkt: status was %4.4x %4.4x.\n",
+ (u32) (frame_status >> 32), (u32) frame_status);
+ }
+ if (np->rx_debug == 7) {
+ phead = le64desc_to_virt ((desc->fraginfo & 0xffffffffff));
+ for (pchar = phead, i = 0; i < pkt_len; i++, pchar++) {
+ printk ("%02x ", *pchar);
+ if ((i + 1) % 20 == 0)
+ printk ("\n");
+ }
+ }
+}
+#else
+#define DEBUG_TFD_DUMP(x) {}
+#define DEBUG_RFD_DUMP(x,flag) {}
+#define DEBUG_PKT_DUMP(x,len) {}
+#define DEBUG_PRINT() {}
+#endif
+
+#endif /* __DL2K_H__ */
pci_dma_sync_single(ep->pci_dev, ep->rx_ring[entry].bufaddr,
ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
- pci_unmap_single(ep->pci_dev, ep->rx_ring[entry].bufaddr,
- ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
if (pkt_len > PKT_BUF_SZ - 4) {
printk(KERN_ERR "%s: Oversized Ethernet frame, status %x "
"%d bytes.\n",
pkt_len);
#endif
} else {
+ pci_unmap_single(ep->pci_dev,
+ ep->rx_ring[entry].bufaddr,
+ ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
skb_put(skb = ep->rx_skbuff[entry], pkt_len);
ep->rx_skbuff[entry] = NULL;
}
-/* $Id: aurora.c,v 1.13 2001/05/10 01:45:38 davem Exp $
+/* $Id: aurora.c,v 1.14 2001/06/29 23:07:37 davem Exp $
* linux/drivers/sbus/char/aurora.c -- Aurora multiport driver
*
* Copyright (c) 1999 by Oliver Aldulea (oli@bv.ro)
static int aurora_set_modem_info(struct Aurora_port * port, unsigned int cmd,
unsigned int *value)
{
- int error;
unsigned int arg;
unsigned long flags;
struct Aurora_board *bp = port_Board(port);
#ifdef AURORA_DEBUG
printk("aurora_set_modem_info: start\n");
#endif
- error = get_user(arg, value);
- if (error)
- return error;
+ if (get_user(arg, value))
+ return -EFAULT;
chip = AURORA_CD180(port_No(port));
switch (cmd) {
case TIOCMBIS:
struct Aurora_board *bp = port_Board(port);
int change_speed;
unsigned long flags;
- int error;
#ifdef AURORA_DEBUG
printk("aurora_set_serial_info: start\n");
#endif
- error = verify_area(VERIFY_READ, (void *) newinfo, sizeof(tmp));
- if (error)
- return error;
- copy_from_user(&tmp, newinfo, sizeof(tmp));
-
+ if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
+ return -EFAULT;
#if 0
if ((tmp.irq != bp->irq) ||
(tmp.port != bp->base) ||
{
struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- int error;
int retval;
#ifdef AURORA_DEBUG
aurora_send_break(port, arg ? arg*(HZ/10) : HZ/4);
return 0;
case TIOCGSOFTCAR:
- error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
- if (error)
- return error;
- put_user(C_CLOCAL(tty) ? 1 : 0,
- (unsigned long *) arg);
- return 0;
+ return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg);
case TIOCSSOFTCAR:
- retval = get_user(arg,(unsigned long *) arg);
- if (retval)
- return retval;
+ if (get_user(arg,(unsigned long *)arg))
+ return -EFAULT;
tty->termios->c_cflag =
((tty->termios->c_cflag & ~CLOCAL) |
(arg ? CLOCAL : 0));
return 0;
case TIOCMGET:
- error = verify_area(VERIFY_WRITE, (void *) arg,
+ retval = verify_area(VERIFY_WRITE, (void *) arg,
sizeof(unsigned int));
- if (error)
- return error;
+ if (retval)
+ return retval;
return aurora_get_modem_info(port, (unsigned int *) arg);
case TIOCMBIS:
case TIOCMBIC:
* v0.6 - never time out
* v0.7 - fixed bulk-IN read and poll (David Paschal, paschal@rcsis.com)
* v0.8 - add devfs support
+ * v0.9 - fix unplug-while-open paths
*/
/*
struct usblp {
struct usb_device *dev; /* USB device */
devfs_handle_t devfs; /* devfs device */
+ struct semaphore sem; /* locks this struct, especially "dev" */
struct urb readurb, writeurb; /* The urbs */
wait_queue_head_t wait; /* Zzzzz ... */
int readcount; /* Counter for reads */
static int usblp_check_status(struct usblp *usblp, int err)
{
unsigned char status, newerr = 0;
+ int error;
- if (usblp_read_status(usblp, &status)) {
- err("usblp%d: failed reading printer status", usblp->minor);
+ error = usblp_read_status (usblp, &status);
+ if (error < 0) {
+ err("usblp%d: error %d reading printer status",
+ usblp->minor, error);
return 0;
}
return retval;
}
+static void usblp_cleanup (struct usblp *usblp)
+{
+ devfs_unregister (usblp->devfs);
+ usblp_table [usblp->minor] = NULL;
+ info ("usblp%d: removed", usblp->minor);
+
+ kfree (usblp->writeurb.transfer_buffer);
+ kfree (usblp->device_id_string);
+ kfree (usblp);
+}
+
static int usblp_release(struct inode *inode, struct file *file)
{
struct usblp *usblp = file->private_data;
+ down (&usblp->sem);
usblp->used = 0;
-
if (usblp->dev) {
if (usblp->bidir)
usb_unlink_urb(&usblp->readurb);
usb_unlink_urb(&usblp->writeurb);
- return 0;
- }
-
- devfs_unregister(usblp->devfs);
- usblp_table[usblp->minor] = NULL;
- kfree(usblp->device_id_string);
- kfree(usblp);
-
+ up(&usblp->sem);
+ } else /* finish cleanup from disconnect */
+ usblp_cleanup (usblp);
return 0;
}
struct usblp *usblp = file->private_data;
int length, err;
unsigned char status;
+ int retval = 0;
+
+ down (&usblp->sem);
+ if (!usblp->dev) {
+ retval = -ENODEV;
+ goto done;
+ }
if (_IOC_TYPE(cmd) == 'P') /* new-style ioctl number */
switch (_IOC_NR(cmd)) {
case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */
- if (_IOC_DIR(cmd) != _IOC_READ)
- return -EINVAL;
+ if (_IOC_DIR(cmd) != _IOC_READ) {
+ retval = -EINVAL;
+ goto done;
+ }
err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1);
if (err < 0) {
dbg ("usblp%d: error = %d reading IEEE-1284 Device ID string",
usblp->minor, err);
usblp->device_id_string[0] = usblp->device_id_string[1] = '\0';
- return -EIO;
+ retval = -EIO;
+ goto done;
}
length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */
if (length > _IOC_SIZE(cmd)) length = _IOC_SIZE(cmd); /* truncate */
- if (copy_to_user((unsigned char *) arg, usblp->device_id_string, (unsigned long) length))
- return -EFAULT;
+ if (copy_to_user((unsigned char *) arg,
+ usblp->device_id_string, (unsigned long) length)) {
+ retval = -EFAULT;
+ goto done;
+ }
break;
default:
- return -EINVAL;
+ retval = -EINVAL;
}
else /* old-style ioctl value */
switch (cmd) {
case LPGETSTATUS:
if (usblp_read_status(usblp, &status)) {
err("usblp%d: failed reading printer status", usblp->minor);
- return -EIO;
+ retval = -EIO;
+ goto done;
}
if (copy_to_user ((unsigned char *)arg, &status, 1))
- return -EFAULT;
+ retval = -EFAULT;
break;
default:
- return -EINVAL;
+ retval = -EINVAL;
}
- return 0;
+done:
+ up (&usblp->sem);
+ return retval;
}
static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
while (writecount < count) {
+ // FIXME: only use urb->status inside completion
+ // callbacks; this way is racey...
if (usblp->writeurb.status == -EINPROGRESS) {
if (file->f_flags & O_NONBLOCK)
}
}
- if (!usblp->dev)
+ down (&usblp->sem);
+ if (!usblp->dev) {
+ up (&usblp->sem);
return -ENODEV;
+ }
- if (usblp->writeurb.status) {
+ if (usblp->writeurb.status != 0) {
if (usblp->quirks & USBLP_QUIRK_BIDIR) {
if (usblp->writeurb.status != -EINPROGRESS)
err("usblp%d: error %d writing to printer",
usblp->minor, usblp->writeurb.status);
err = usblp->writeurb.status;
- continue;
- }
- else {
+ } else
err = usblp_check_status(usblp, err);
- continue;
- }
+ up (&usblp->sem);
+
+ /* if the fault was due to disconnect, let khubd's
+ * call to usblp_disconnect() grab usblp->sem ...
+ */
+ schedule ();
+ continue;
}
writecount += usblp->writeurb.transfer_buffer_length;
usblp->writeurb.transfer_buffer_length = 0;
- if (writecount == count)
- continue;
+ if (writecount == count) {
+ up (&usblp->sem);
+ break;
+ }
usblp->writeurb.transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ?
(count - writecount) : USBLP_BUF_SIZE;
usblp->writeurb.dev = usblp->dev;
usb_submit_urb(&usblp->writeurb);
+ up (&usblp->sem);
}
return count;
if (!usblp->bidir)
return -EINVAL;
+ down (&usblp->sem);
+ if (!usblp->dev) {
+ count = -ENODEV;
+ goto done;
+ }
+
if (usblp->readurb.status == -EINPROGRESS) {
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
+ if (file->f_flags & O_NONBLOCK) {
+ count = -EAGAIN;
+ goto done;
+ }
+ // FIXME: only use urb->status inside completion
+ // callbacks; this way is racey...
while (usblp->readurb.status == -EINPROGRESS) {
- if (signal_pending(current))
- return -EINTR;
+ if (signal_pending(current)) {
+ count = -EINTR;
+ goto done;
+ }
+ up (&usblp->sem);
interruptible_sleep_on(&usblp->wait);
+ down (&usblp->sem);
}
}
- if (!usblp->dev)
- return -ENODEV;
+ if (!usblp->dev) {
+ count = -ENODEV;
+ goto done;
+ }
if (usblp->readurb.status) {
err("usblp%d: error %d reading from printer",
usblp->readurb.dev = usblp->dev;
usblp->readcount = 0;
usb_submit_urb(&usblp->readurb);
- return -EIO;
+ count = -EIO;
+ goto done;
}
count = count < usblp->readurb.actual_length - usblp->readcount ?
count : usblp->readurb.actual_length - usblp->readcount;
- if (copy_to_user(buffer, usblp->readurb.transfer_buffer + usblp->readcount, count))
- return -EFAULT;
+ if (copy_to_user(buffer, usblp->readurb.transfer_buffer + usblp->readcount, count)) {
+ count = -EFAULT;
+ goto done;
+ }
if ((usblp->readcount += count) == usblp->readurb.actual_length) {
usblp->readcount = 0;
usb_submit_urb(&usblp->readurb);
}
+done:
+ up (&usblp->sem);
return count;
}
return NULL;
}
memset(usblp, 0, sizeof(struct usblp));
+ init_MUTEX (&usblp->sem);
/* lookup quirks for this printer */
quirks = usblp_quirks(dev->descriptor.idVendor, dev->descriptor.idProduct);
sprintf(name, "lp%d", minor);
- /* Create with perms=664 */
+ /* if we have devfs, create with perms=660 */
usblp->devfs = devfs_register(usb_devfs_handle, name,
DEVFS_FL_DEFAULT, USB_MAJOR,
USBLP_MINOR_BASE + minor,
S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
S_IWGRP, &usblp_fops, NULL);
- if (usblp->devfs == NULL)
- err("usblp%d: device node registration failed", minor);
info("usblp%d: USB %sdirectional printer dev %d if %d alt %d",
minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts);
struct usblp *usblp = ptr;
if (!usblp || !usblp->dev) {
- err("disconnect on nonexisting interface");
- return;
+ err("bogus disconnect");
+ BUG ();
}
+ down (&usblp->sem);
usblp->dev = NULL;
usb_unlink_urb(&usblp->writeurb);
if (usblp->bidir)
usb_unlink_urb(&usblp->readurb);
- kfree(usblp->writeurb.transfer_buffer);
-
- if (usblp->used) return;
-
- kfree(usblp->device_id_string);
-
- devfs_unregister(usblp->devfs);
- usblp_table[usblp->minor] = NULL;
- kfree(usblp);
+ if (!usblp->used)
+ usblp_cleanup (usblp);
+ else /* cleanup later, on close */
+ up (&usblp->sem);
}
static struct usb_device_id usblp_ids [] = {
return result;
}
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
}
static void empeg_close (struct usb_serial_port *port, struct file * filp)
{
struct usb_serial *serial;
- unsigned char *transfer_buffer;
if (port_paranoia_check (port, __FUNCTION__))
return;
--port->open_count;
if (port->open_count <= 0) {
- transfer_buffer = kmalloc (0x12, GFP_KERNEL);
-
- if (!transfer_buffer) {
- err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12);
- } else {
- kfree (transfer_buffer);
- }
-
/* shutdown our bulk read */
usb_unlink_urb (port->read_urb);
port->active = 0;
case TIOCMSET: /* Turns on and off the lines as specified by the mask */
dbg(__FUNCTION__ " TIOCMSET");
- if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+ if (get_user(mask, (unsigned long *) arg))
+ return -EFAULT;
urb_value = ((mask & TIOCM_DTR) ? HIGH : LOW);
if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),urb_value) < 0){
err("Error from DTR set urb (TIOCMSET)");
case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
dbg(__FUNCTION__ " TIOCMBIS");
- if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+ if (get_user(mask, (unsigned long *) arg))
+ return -EFAULT;
if (mask & TIOCM_DTR){
if ((ret = set_dtr(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
dbg(__FUNCTION__ " TIOCMBIC");
- if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+ if (get_user(mask, (unsigned long *) arg))
+ return -EFAULT;
if (mask & TIOCM_DTR){
if ((ret = set_dtr(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (07/03/2001) gkh
+ * Fixed module paramater size. Thanks to John Brockmeyer for the pointer.
+ * Fixed vendor and product getting defined through the MODULE_PARM macro
+ * if the Generic driver wasn't compiled in.
+ * Fixed problem with generic_shutdown() not being called for drivers that
+ * don't have a shutdown() function.
+ *
* (06/06/2001) gkh
* added evil hack that is needed for the prolific pl2303 device due to the
* crazy way its endpoints are set up.
/*
* Version Information
*/
-#define DRIVER_VERSION "v1.2"
+#define DRIVER_VERSION "v1.3"
#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/"
#define DRIVER_DESC "USB Serial Driver core"
static void serial_unthrottle (struct tty_struct * tty);
static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg);
static void serial_set_termios (struct tty_struct *tty, struct termios * old);
+static void serial_shutdown (struct usb_serial *serial);
static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id);
}
+static void serial_shutdown (struct usb_serial *serial)
+{
+ if (serial->type->shutdown) {
+ serial->type->shutdown(serial);
+ } else {
+ generic_shutdown(serial);
+ }
+}
+
+
/*****************************************************************************
* generic devices specific driver functions
serial->port[i].tty->driver_data = NULL;
}
- if (serial->type->shutdown)
- serial->type->shutdown(serial);
+ serial_shutdown (serial);
for (i = 0; i < serial->num_ports; ++i)
serial->port[i].active = 0;
return -1;
}
- info(DRIVER_VERSION ":" DRIVER_DESC);
+ info(DRIVER_DESC " " DRIVER_VERSION);
return 0;
}
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "Debug enabled or not");
-MODULE_PARM(vendor, "i");
+#ifdef CONFIG_USB_SERIAL_GENERIC
+MODULE_PARM(vendor, "h");
MODULE_PARM_DESC(vendor, "User specified USB idVendor");
-MODULE_PARM(product, "i");
+MODULE_PARM(product, "h");
MODULE_PARM_DESC(product, "User specified USB idProduct");
+#endif
switch (when) {
case PBOOK_SLEEP_NOW:
- ohci_pci_suspend (ohci->ohci_dev);
+ ohci_pci_suspend (ohci->ohci_dev, 3);
break;
case PBOOK_WAKE:
ohci_pci_resume (ohci->ohci_dev);
#ifdef MODULE
-#define INCLUDE_LINUX_LOGOBW
+#define INCLUDE_LINUX_LOGO_DATA
#include <linux/linux_logo.h>
#endif /* MODULE */
break;
#endif
#ifdef FBCON_HAS_CFB32
- case 32:
- i = (regno << 8) | regno;
+ case 32: {
+ int i = (regno << 8) | regno;
p->fbcon_cmap.cfb32[regno] = (i << 16) | i;
break;
+ }
#endif
}
#define BH_ENTRY(list) list_entry((list), struct buffer_head, b_inode_buffers)
+#define get_bh(bh) atomic_inc(&(bh)->b_count)
+#define put_bh(bh) atomic_dec(&(bh)->b_count)
+
/*
* Hash table gook..
*/
int bdflush_min[N_PARAM] = { 0, 10, 5, 25, 0, 1*HZ, 0, 0, 0};
int bdflush_max[N_PARAM] = {100,50000, 20000, 20000,600*HZ, 6000*HZ, 100, 0, 0};
+static inline void __unlock_buffer(struct buffer_head *bh)
+{
+ clear_bit(BH_Lock, &bh->b_state);
+ smp_mb__after_clear_bit();
+ if (waitqueue_active(&bh->b_wait))
+ wake_up(&bh->b_wait);
+}
+
+void unlock_buffer(struct buffer_head *bh)
+{
+ get_bh(bh);
+ __unlock_buffer(bh);
+ put_bh(bh);
+}
+
/*
* Rewrote the wait-routines to use the "new" wait-queue functionality,
* and getting rid of the cli-sti pairs. The wait-queue routines still
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
- atomic_inc(&bh->b_count);
+ get_bh(bh);
add_wait_queue(&bh->b_wait, &wait);
do {
run_task_queue(&tq_disk);
} while (buffer_locked(bh));
tsk->state = TASK_RUNNING;
remove_wait_queue(&bh->b_wait, &wait);
- atomic_dec(&bh->b_count);
+ put_bh(bh);
}
/* End-of-write handler.. Just mark it up-to-date and unlock the buffer. */
static void end_buffer_write(struct buffer_head *bh, int uptodate)
{
mark_buffer_uptodate(bh, uptodate);
- unlock_buffer(bh);
+ __unlock_buffer(bh);
+ put_bh(bh);
}
/*
static void write_locked_buffers(struct buffer_head **array, unsigned int count)
{
struct buffer_head *wait = *array;
- atomic_inc(&wait->b_count);
+ get_bh(wait);
do {
struct buffer_head * bh = *array++;
bh->b_end_io = end_buffer_write;
submit_bh(WRITE, bh);
} while (--count);
wait_on_buffer(wait);
- atomic_dec(&wait->b_count);
+ put_bh(wait);
}
#define NRSYNC (32)
continue;
if (test_and_set_bit(BH_Lock, &bh->b_state))
continue;
+ get_bh(bh);
if (atomic_set_buffer_clean(bh)) {
__refile_buffer(bh);
array[count++] = bh;
write_locked_buffers(array, count);
goto repeat;
}
- unlock_buffer(bh);
+ __unlock_buffer(bh);
+ put_bh(bh);
}
spin_unlock(&lru_list_lock);
if (dev && bh->b_dev != dev)
continue;
- atomic_inc(&bh->b_count);
+ get_bh(bh);
spin_unlock(&lru_list_lock);
wait_on_buffer (bh);
- atomic_dec(&bh->b_count);
+ put_bh(bh);
goto repeat;
}
spin_unlock(&lru_list_lock);
bh->b_dev == dev)
break;
if (bh)
- atomic_inc(&bh->b_count);
+ get_bh(bh);
return bh;
}
if (!bh->b_pprev)
continue;
if (buffer_locked(bh)) {
- atomic_inc(&bh->b_count);
+ get_bh(bh);
spin_unlock(&lru_list_lock);
wait_on_buffer(bh);
slept = 1;
spin_lock(&lru_list_lock);
- atomic_dec(&bh->b_count);
+ put_bh(bh);
}
write_lock(&hash_table_lock);
if (!bh->b_pprev)
continue;
if (buffer_locked(bh)) {
- atomic_inc(&bh->b_count);
+ get_bh(bh);
spin_unlock(&lru_list_lock);
wait_on_buffer(bh);
slept = 1;
spin_lock(&lru_list_lock);
- atomic_dec(&bh->b_count);
+ put_bh(bh);
}
write_lock(&hash_table_lock);
* that unlock the page..
*/
spin_lock_irqsave(&page_uptodate_lock, flags);
- unlock_buffer(bh);
- atomic_dec(&bh->b_count);
+ __unlock_buffer(bh);
tmp = bh->b_this_page;
while (tmp != bh) {
if (tmp->b_end_io == end_buffer_io_async && buffer_locked(tmp))
/* OK, the async IO on this page is complete. */
spin_unlock_irqrestore(&page_uptodate_lock, flags);
+ put_bh(bh);
/*
* if none of the buffers had errors then we can set the
return;
still_busy:
+ put_bh(bh);
spin_unlock_irqrestore(&page_uptodate_lock, flags);
return;
}
bh->b_inode = &tmp;
list_add(&bh->b_inode_buffers, &tmp.i_dirty_buffers);
if (buffer_dirty(bh)) {
- atomic_inc(&bh->b_count);
+ get_bh(bh);
spin_unlock(&lru_list_lock);
ll_rw_block(WRITE, 1, &bh);
brelse(bh);
while (!list_empty(&tmp.i_dirty_buffers)) {
bh = BH_ENTRY(tmp.i_dirty_buffers.prev);
remove_inode_queue(bh);
- atomic_inc(&bh->b_count);
+ get_bh(bh);
spin_unlock(&lru_list_lock);
wait_on_buffer(bh);
if (!buffer_uptodate(bh))
bh = BH_ENTRY(list), list != &inode->i_dirty_buffers;
list = bh->b_inode_buffers.prev) {
if (buffer_locked(bh)) {
- atomic_inc(&bh->b_count);
+ get_bh(bh);
spin_unlock(&lru_list_lock);
wait_on_buffer(bh);
if (!buffer_uptodate(bh))
void __brelse(struct buffer_head * buf)
{
if (atomic_read(&buf->b_count)) {
- atomic_dec(&buf->b_count);
+ put_bh(buf);
return;
}
printk("VFS: brelse: Trying to free free buffer\n");
do {
lock_buffer(bh);
bh->b_end_io = end_buffer_io_async;
- atomic_inc(&bh->b_count);
+ get_bh(bh);
set_bit(BH_Uptodate, &bh->b_state);
clear_bit(BH_Dirty, &bh->b_state);
bh = bh->b_this_page;
/* Stage 3: submit the IO */
do {
+ struct buffer_head *next = bh->b_this_page;
submit_bh(WRITE, bh);
- bh = bh->b_this_page;
+ bh = next;
} while (bh != head);
/* Done - end_buffer_io_async will unlock */
struct buffer_head * bh = arr[i];
lock_buffer(bh);
bh->b_end_io = end_buffer_io_async;
- atomic_inc(&bh->b_count);
+ get_bh(bh);
}
/* Stage 3: start the IO */
mark_buffer_uptodate(bh, uptodate);
kiobuf = bh->b_private;
- unlock_buffer(bh);
+ __unlock_buffer(bh);
+ put_bh(bh);
end_kio_request(kiobuf, uptodate);
}
offset += size;
atomic_inc(&iobuf->io_count);
-
+ get_bh(tmp);
submit_bh(rw, tmp);
/*
* Wait for IO if we have got too much
bh->b_blocknr = *(b++);
set_bit(BH_Mapped, &bh->b_state);
bh->b_end_io = end_buffer_io_async;
- atomic_inc(&bh->b_count);
+ get_bh(bh);
bh = bh->b_this_page;
} while (bh != head);
/* Stage 2: start the IO */
do {
+ struct buffer_head *next = bh->b_this_page;
submit_bh(rw, bh);
- bh = bh->b_this_page;
+ bh = next;
} while (bh != head);
return 0;
}
}
/* OK, now we are committed to write it out. */
- atomic_inc(&bh->b_count);
+ get_bh(bh);
spin_unlock(&lru_list_lock);
ll_rw_block(WRITE, 1, &bh);
- atomic_dec(&bh->b_count);
+ put_bh(bh);
if (current->need_resched)
schedule();
*/
#define K(x) ((x) << (PAGE_SHIFT - 10))
#define B(x) ((x) << PAGE_SHIFT)
- si_meminfo(&i);
- si_swapinfo(&i);
- len = sprintf(page, " total: used: free: shared: buffers: cached:\n"
- "Mem: %8lu %8lu %8lu %8lu %8lu %8u\n"
- "Swap: %8lu %8lu %8lu\n",
- B(i.totalram), B(i.totalram-i.freeram), B(i.freeram),
- B(i.sharedram), B(i.bufferram),
- B(atomic_read(&page_cache_size)), B(i.totalswap),
- B(i.totalswap-i.freeswap), B(i.freeswap));
- /*
- * Tagged format, for easy grepping and expansion.
- * The above will go away eventually, once the tools
- * have been updated.
- */
- len += sprintf(page+len,
- "MemTotal: %8lu kB\n"
- "MemFree: %8lu kB\n"
- "MemShared: %8lu kB\n"
- "Buffers: %8lu kB\n"
- "Cached: %8u kB\n"
+ si_meminfo(&i);
+ si_swapinfo(&i);
+ len = sprintf(page, " total: used: free: shared: buffers: cached:\n"
+ "Mem: %8lu %8lu %8lu %8lu %8lu %8u\n"
+ "Swap: %8lu %8lu %8lu\n",
+ B(i.totalram), B(i.totalram-i.freeram), B(i.freeram),
+ B(i.sharedram), B(i.bufferram),
+ B(atomic_read(&page_cache_size)), B(i.totalswap),
+ B(i.totalswap-i.freeswap), B(i.freeswap));
+ /*
+ * Tagged format, for easy grepping and expansion.
+ * The above will go away eventually, once the tools
+ * have been updated.
+ */
+ len += sprintf(page+len,
+ "MemTotal: %8lu kB\n"
+ "MemFree: %8lu kB\n"
+ "MemShared: %8lu kB\n"
+ "Buffers: %8lu kB\n"
+ "Cached: %8lu kB\n"
+ "SwapCached: %8lu kB\n"
"Active: %8u kB\n"
"Inact_dirty: %8u kB\n"
"Inact_clean: %8u kB\n"
"Inact_target: %8lu kB\n"
- "HighTotal: %8lu kB\n"
- "HighFree: %8lu kB\n"
- "LowTotal: %8lu kB\n"
- "LowFree: %8lu kB\n"
- "SwapTotal: %8lu kB\n"
- "SwapFree: %8lu kB\n",
- K(i.totalram),
- K(i.freeram),
- K(i.sharedram),
- K(i.bufferram),
- K(atomic_read(&page_cache_size)),
+ "HighTotal: %8lu kB\n"
+ "HighFree: %8lu kB\n"
+ "LowTotal: %8lu kB\n"
+ "LowFree: %8lu kB\n"
+ "SwapTotal: %8lu kB\n"
+ "SwapFree: %8lu kB\n",
+ K(i.totalram),
+ K(i.freeram),
+ K(i.sharedram),
+ K(i.bufferram),
+ K(atomic_read(&page_cache_size) - swapper_space.nrpages),
+ K(swapper_space.nrpages),
K(nr_active_pages),
K(nr_inactive_dirty_pages),
K(nr_inactive_clean_pages()),
K(inactive_target),
- K(i.totalhigh),
- K(i.freehigh),
- K(i.totalram-i.totalhigh),
- K(i.freeram-i.freehigh),
- K(i.totalswap),
- K(i.freeswap));
+ K(i.totalhigh),
+ K(i.freehigh),
+ K(i.totalram-i.totalhigh),
+ K(i.freeram-i.freehigh),
+ K(i.totalswap),
+ K(i.freeswap));
return proc_calc_metrics(page, start, off, count, eof, len);
#undef B
kstat.per_cpu_nice[cpu_logical_map(i)],
kstat.per_cpu_system[cpu_logical_map(i)],
jif - ( kstat.per_cpu_user[cpu_logical_map(i)] \
- + kstat.per_cpu_nice[cpu_logical_map(i)] \
- + kstat.per_cpu_system[cpu_logical_map(i)]));
+ + kstat.per_cpu_nice[cpu_logical_map(i)] \
+ + kstat.per_cpu_system[cpu_logical_map(i)]));
len += sprintf(page + len,
"page %u %u\n"
- "swap %u %u\n"
+ "swap %u %u\n"
"intr %u",
kstat.pgpgin >> 1,
kstat.pgpgout >> 1,
if (err)
goto out_unlock;
memcpy (de->name, name, namelen);
- memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen);
+ memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen - 2);
de->inode = cpu_to_fs16(inode->i_sb, inode->i_ino);
err = dir_commit_chunk(page, from, to);
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
-/* $Id: vaddrs.h,v 1.26 2000/08/01 04:53:58 anton Exp $ */
+/* $Id: vaddrs.h,v 1.27 2001/07/04 00:18:18 davem Exp $ */
#ifndef _SPARC_VADDRS_H
#define _SPARC_VADDRS_H
-/* $Id: starfire.h,v 1.1 2000/09/21 06:18:53 anton Exp $
+/* $Id: starfire.h,v 1.2 2001/07/04 00:18:18 davem Exp $
* starfire.h: Group all starfire specific code together.
*
* Copyright (C) 2000 Anton Blanchard (anton@samba.org)
#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet/TR/TB */
#define ARPHRD_ARCNET 7 /* ARCnet */
#define ARPHRD_APPLETLK 8 /* APPLEtalk */
+#define ARPHRD_IEEE1394 9 /* IEEE 1394 IPv4 - RFC 2734 */
#define ARPHRD_DLCI 15 /* Frame Relay DLCI */
#define ARPHRD_ATM 19 /* ATM */
#define ARPHRD_METRICOM 23 /* Metricom STRIP (new IANA id) */
-/* $Id: isdnif.h,v 1.37.6.4 2001/06/09 15:14:19 kai Exp $
+/* $Id: isdnif.h,v 1.37.6.5 2001/06/11 22:08:38 kai Exp $
* Linux ISDN subsystem
*
__wait_on_buffer(bh);
}
-extern inline void unlock_buffer(struct buffer_head *bh)
-{
- clear_bit(BH_Lock, &bh->b_state);
- smp_mb__after_clear_bit();
- if (waitqueue_active(&bh->b_wait))
- wake_up(&bh->b_wait);
-}
+extern void unlock_buffer(struct buffer_head *bh);
/*
* super-block locking. Again, interrupts may only unlock
EXPORT_SYMBOL(__bforget);
EXPORT_SYMBOL(ll_rw_block);
EXPORT_SYMBOL(submit_bh);
+EXPORT_SYMBOL(unlock_buffer);
EXPORT_SYMBOL(__wait_on_buffer);
EXPORT_SYMBOL(___wait_on_page);
EXPORT_SYMBOL(block_write_full_page);
{
pte_t pte = *ptep;
- if (pte_present(pte) && ptep_test_and_clear_dirty(ptep)) {
+ if (pte_present(pte)) {
struct page *page = pte_page(pte);
- flush_tlb_page(vma, address);
- set_page_dirty(page);
+ if (VALID_PAGE(page) && !PageReserved(page) && ptep_test_and_clear_dirty(ptep)) {
+ flush_tlb_page(vma, address);
+ if (page->mapping)
+ set_page_dirty(page);
+ }
}
return 0;
}
spin_lock(&mm->page_table_lock);
return -1;
}
- wait_on_page(page);
- flush_page_to_ram(page);
- flush_icache_page(vma, page);
}
/*
pte = pte_mkwrite(pte_mkdirty(pte));
UnlockPage(page);
+ flush_page_to_ram(page);
+ flush_icache_page(vma, page);
set_pte(page_table, pte);
/* No need to invalidate - it was non-present before */
*/
int out_of_memory(void)
{
+ long cache_mem, limit;
+
/* Enough free memory? Not OOM. */
if (nr_free_pages() > freepages.min)
return 0;
if (nr_free_pages() + nr_inactive_clean_pages() > freepages.low)
return 0;
+ /*
+ * If the buffer and page cache (excluding swap cache) are over
+ * their (/proc tunable) minimum, we're still not OOM. We test
+ * this to make sure we don't return OOM when the system simply
+ * has a hard time with the cache.
+ */
+ cache_mem = atomic_read(&page_cache_size);
+ cache_mem += atomic_read(&buffermem_pages);
+ cache_mem -= swapper_space.nrpages;
+ limit = (page_cache.min_percent + buffer_mem.min_percent);
+ limit *= num_physpages / 100;
+
+ if (cache_mem > limit)
+ return 0;
+
/* Enough swap space left? Not OOM. */
if (nr_swap_pages > 0)
return 0;
*/
static int shmem_writepage(struct page * page)
{
- int error = 0;
+ int error;
struct shmem_inode_info *info;
swp_entry_t *entry, swap;
struct inode *inode;
if (!PageLocked(page))
BUG();
- /* Only move to the swap cache if there are no other users of
- * the page. */
- if (atomic_read(&page->count) > 2)
- goto out;
-
inode = page->mapping->host;
info = &inode->u.shmem_i;
swap = __get_swap_page(2);
error = -ENOMEM;
- if (!swap.val)
+ if (!swap.val) {
+ activate_page(page);
goto out;
+ }
spin_lock(&info->lock);
entry = shmem_swp_entry(info, page->index);
BUG();
flags = page->flags & ~((1 << PG_error) | (1 << PG_arch_1));
page->flags = flags | (1 << PG_uptodate);
+ page->age = PAGE_AGE_START;
add_to_page_cache_locked(page, &swapper_space, entry.val);
}
static struct dn_dev_parms dn_dev_list[] = {
{
- ARPHRD_ETHER, /* Ethernet */
- DN_DEV_BCAST,
- DN_DEV_S_RU,
- 0,
- 1498,
- 1,
- 10,
- 0,
- "ethernet",
- NET_DECNET_CONF_ETHER,
- dn_eth_up,
- NULL,
- dn_send_brd_hello,
- NULL
+ type: ARPHRD_ETHER, /* Ethernet */
+ mode: DN_DEV_BCAST,
+ state: DN_DEV_S_RU,
+ blksize: 1498,
+ t2: 1,
+ t3: 10,
+ name: "ethernet",
+ ctl_name: NET_DECNET_CONF_ETHER,
+ up: dn_eth_up,
+ timer3: dn_send_brd_hello,
},
{
- ARPHRD_IPGRE, /* DECnet tunneled over GRE in IP */
- DN_DEV_BCAST,
- DN_DEV_S_RU,
- 0,
- 1400,
- 1,
- 10,
- 0,
- "ipgre",
- NET_DECNET_CONF_GRE,
- NULL,
- NULL,
- dn_send_brd_hello,
- NULL
+ type: ARPHRD_IPGRE, /* DECnet tunneled over GRE in IP */
+ mode: DN_DEV_BCAST,
+ state: DN_DEV_S_RU,
+ blksize: 1400,
+ t2: 1,
+ t3: 10,
+ name: "ipgre",
+ ctl_name: NET_DECNET_CONF_GRE,
+ timer3: dn_send_brd_hello,
},
#if 0
{
- ARPHRD_X25, /* Bog standard X.25 */
- DN_DEV_UCAST,
- DN_DEV_S_DS,
- 0,
- 230,
- 1,
- 120,
- 0,
- "x25",
- NET_DECNET_CONF_X25,
- NULL,
- NULL,
- dn_send_ptp_hello,
- NULL
+ type: ARPHRD_X25, /* Bog standard X.25 */
+ mode: DN_DEV_UCAST,
+ state: DN_DEV_S_DS,
+ blksize: 230,
+ t2: 1,
+ t3: 120,
+ name: "x25",
+ ctl_name: NET_DECNET_CONF_X25,
+ timer3: dn_send_ptp_hello,
},
#endif
#if 0
{
- ARPHRD_PPP, /* DECnet over PPP */
- DN_DEV_BCAST,
- DN_DEV_S_RU,
- 0,
- 230,
- 1,
- 10,
- 0,
- "ppp",
- NET_DECNET_CONF_PPP,
- NULL,
- NULL,
- dn_send_brd_hello,
- NULL
+ type: ARPHRD_PPP, /* DECnet over PPP */
+ mode: DN_DEV_BCAST,
+ state: DN_DEV_S_RU,
+ blksize: 230,
+ t2: 1,
+ t3: 10,
+ name: "ppp",
+ ctl_name: NET_DECNET_CONF_PPP,
+ timer3: dn_send_brd_hello,
},
#endif
#if 0
{
- ARPHRD_DDCMP, /* DECnet over DDCMP */
- DN_DEV_UCAST,
- DN_DEV_S_DS,
- 0,
- 230,
- 1,
- 120,
- 0,
- "ddcmp",
- NET_DECNET_CONF_DDCMP,
- NULL,
- NULL,
- dn_send_ptp_hello,
- NULL
+ type: ARPHRD_DDCMP, /* DECnet over DDCMP */
+ mode: DN_DEV_UCAST,
+ state: DN_DEV_S_DS,
+ blksize: 230,
+ t2: 1,
+ t3: 120,
+ name: "ddcmp",
+ ctl_name: NET_DECNET_CONF_DDCMP,
+ timer3: dn_send_ptp_hello,
},
#endif
{
- ARPHRD_LOOPBACK, /* Loopback interface - always last */
- DN_DEV_BCAST,
- DN_DEV_S_RU,
- 0,
- 1498,
- 1,
- 10,
- 0,
- "loopback",
- NET_DECNET_CONF_LOOPBACK,
- NULL,
- NULL,
- dn_send_brd_hello,
- NULL
+ type: ARPHRD_LOOPBACK, /* Loopback interface - always last */
+ mode: DN_DEV_BCAST,
+ state: DN_DEV_S_RU,
+ blksize: 1498,
+ t2: 1,
+ t3: 10,
+ name: "loopback",
+ ctl_name: NET_DECNET_CONF_LOOPBACK,
+ timer3: dn_send_brd_hello,
}
};
static int min_t3[] = { 1 };
static int max_t3[] = { 8191 }; /* Must fit in 16 bits when multiplied by BCT3MULT or T3MULT */
-static int min_priority[] = { 0 };
+static int min_priority[1];
static int max_priority[] = { 127 }; /* From DECnet spec */
static int dn_forwarding_proc(ctl_table *, int, struct file *,
if (newlen != sizeof(int))
return -EINVAL;
- get_user(value, (int *)newval);
+ if (get_user(value, (int *)newval))
+ return -EFAULT;
if (value < 0)
return -EINVAL;
if (value > 2)
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <net/sock.h>
+#include <net/route.h>
#include <linux/netfilter_ipv4/ip_queue.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
#define IPQ_QMAX_DEFAULT 1024
#define IPQ_PROC_FS_NAME "ip_queue"
#define NET_IPQ_QMAX 2088
#define NET_IPQ_QMAX_NAME "ip_queue_maxlen"
+typedef struct ipq_rt_info {
+ __u8 tos;
+ __u32 daddr;
+ __u32 saddr;
+} ipq_rt_info_t;
+
typedef struct ipq_queue_element {
struct list_head list; /* Links element into queue */
int verdict; /* Current verdict */
struct nf_info *info; /* Extra info from netfilter */
struct sk_buff *skb; /* Packet inside */
+ ipq_rt_info_t rt_info; /* May need post-mangle routing */
} ipq_queue_element_t;
typedef int (*ipq_send_cb_t)(ipq_queue_element_t *e);
* Packet queue
*
****************************************************************************/
-
/* Dequeue a packet if matched by cmp, or the next available if cmp is NULL */
static ipq_queue_element_t *
ipq_dequeue(ipq_queue_t *q,
printk(KERN_ERR "ip_queue: OOM in enqueue\n");
return -ENOMEM;
}
+
e->verdict = NF_DROP;
e->info = info;
e->skb = skb;
+
+ if (e->info->hook == NF_IP_LOCAL_OUT) {
+ struct iphdr *iph = skb->nh.iph;
+
+ e->rt_info.tos = iph->tos;
+ e->rt_info.daddr = iph->daddr;
+ e->rt_info.saddr = iph->saddr;
+ }
+
spin_lock_bh(&q->lock);
if (q->len >= *q->maxlen) {
spin_unlock_bh(&q->lock);
kfree(q);
}
+/* With a chainsaw... */
+static int route_me_harder(struct sk_buff *skb)
+{
+ struct iphdr *iph = skb->nh.iph;
+ struct rtable *rt;
+
+ struct rt_key key = {
+ dst:iph->daddr, src:iph->saddr,
+ oif:skb->sk ? skb->sk->bound_dev_if : 0,
+ tos:RT_TOS(iph->tos)|RTO_CONN,
+#ifdef CONFIG_IP_ROUTE_FWMARK
+ fwmark:skb->nfmark
+#endif
+ };
+
+ if (ip_route_output_key(&rt, &key) != 0) {
+ printk("route_me_harder: No more route.\n");
+ return -EINVAL;
+ }
+
+ /* Drop old route. */
+ dst_release(skb->dst);
+ skb->dst = &rt->u.dst;
+ return 0;
+}
+
static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, ipq_queue_element_t *e)
{
int diff;
"in mangle, dropping packet\n");
return -ENOMEM;
}
+ if (e->skb->sk)
+ skb_set_owner_w(newskb, e->skb->sk);
kfree_skb(e->skb);
e->skb = newskb;
}
}
memcpy(e->skb->data, v->payload, v->data_len);
e->skb->nfcache |= NFC_ALTERED;
+
+ /*
+ * Extra routing may needed on local out, as the QUEUE target never
+ * returns control to the table.
+ */
+ if (e->info->hook == NF_IP_LOCAL_OUT) {
+ struct iphdr *iph = e->skb->nh.iph;
+
+ if (!(iph->tos == e->rt_info.tos
+ && iph->daddr == e->rt_info.daddr
+ && iph->saddr == e->rt_info.saddr))
+ return route_me_harder(e->skb);
+ }
return 0;
}
if (e->info->outdev) strcpy(pm->outdev_name, e->info->outdev->name);
else pm->outdev_name[0] = '\0';
pm->hw_protocol = e->skb->protocol;
+ if (e->info->indev && e->skb->dev) {
+ pm->hw_type = e->skb->dev->type;
+ if (e->skb->dev->hard_header_parse)
+ pm->hw_addrlen =
+ e->skb->dev->hard_header_parse(e->skb,
+ pm->hw_addr);
+ }
if (data_len)
memcpy(pm->payload, e->skb->data, data_len);
nlh->nlmsg_len = skb->tail - old_tail;
int status, type;
struct nlmsghdr *nlh;
+ if (skb->len < sizeof(struct nlmsghdr))
+ return;
+
nlh = (struct nlmsghdr *)skb->data;
- if (nlh->nlmsg_len < sizeof(*nlh)
- || skb->len < nlh->nlmsg_len
- || nlh->nlmsg_pid <= 0
+ if (nlh->nlmsg_len < sizeof(struct nlmsghdr)
+ || skb->len < nlh->nlmsg_len)
+ return;
+
+ if(nlh->nlmsg_pid <= 0
|| !(nlh->nlmsg_flags & NLM_F_REQUEST)
|| nlh->nlmsg_flags & NLM_F_MULTI)
RCV_SKB_FAIL(-EINVAL);
int embedded)
{
u_int8_t *opt = (u_int8_t *)tcph;
+ u_int8_t *endhdr = (u_int8_t *)tcph + tcph->doff * 4;
u_int8_t tcpflags;
int end_of_options = 0;
size_t i;
return 0;
}
/* CHECK: oversize options. */
- else if (opt[i+1] + i >= tcph->doff * 4) {
+ else if (&opt[i] + opt[i+1] > endhdr) {
limpk("TCP option %u at %Zu too long\n",
(unsigned int) opt[i], i);
return 0;
check_ip(struct iphdr *iph, size_t length, int embedded)
{
u_int8_t *opt = (u_int8_t *)iph;
+ u_int8_t *endhdr = (u_int8_t *)iph + iph->ihl * 4;
int end_of_options = 0;
void *protoh;
size_t datalen;
return 0;
}
/* CHECK: oversize options. */
- else if (opt[i+1] + i > iph->ihl * 4) {
+ else if (&opt[i] + opt[i+1] > endhdr) {
limpk("IP option %u at %u too long\n",
opt[i], i);
return 0;
ret = ipt_do_table(pskb, hook, in, out, &packet_mangler, NULL);
/* Reroute for ANY change. */
- if (ret != NF_DROP && ret != NF_STOLEN
+ if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE
&& ((*pskb)->nh.iph->saddr != saddr
|| (*pskb)->nh.iph->daddr != daddr
|| (*pskb)->nfmark != nfmark