From: Linus Torvalds Date: Tue, 5 Feb 2002 03:10:48 +0000 (-0800) Subject: v2.4.6.3 -> v2.4.6.4 X-Git-Tag: v2.5.0~75 X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=ccb6dd87174f4f71a0d15838a70a2b97bed6e203;p=history.git v2.4.6.3 -> v2.4.6.4 - David Miller: sparc and networking updates - Al Viro: SysV FS add_link off-by-two bogosity. - Jeff Garzik: merge D-Link DL2k GigE driver, other network driver cleanups - Kai Germaschewski: ISDN update - Alan Cox: more merging (MPT fusion core) - Johannes Erdfelt: USB updates - Stas Sergeev: make sure we return out of vm86 mode when interrupts get re.enabled - Rusty Russell: netfilter fixes for ipt_unclean and ip_queue - me: initialize page->age when adding it to the swap cache - Paul Mackerras: PPC updates - some subtle fs/buffer.c race conditions (Andrew Morton, me) --- diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 799e354d230b..932e50efc2f2 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -8842,6 +8842,18 @@ CONFIG_MYRI_SBUS 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 diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index d2b63417e0b9..9729d2b08552 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -1,7 +1,7 @@ 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)) @@ -62,6 +62,9 @@ via-audio.sgml: via-audio.tmpl $(TOPDIR)/drivers/sound/via82cxxx_audio.c $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/sound/via82cxxx_audio.c \ 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.sgml diff --git a/Documentation/DocBook/via-audio.tmpl b/Documentation/DocBook/via-audio.tmpl index 039eff979d32..768031ccba95 100644 --- a/Documentation/DocBook/via-audio.tmpl +++ b/Documentation/DocBook/via-audio.tmpl @@ -17,7 +17,7 @@ - 2000 + 1999-2001 Jeff Garzik @@ -149,23 +149,6 @@ Known Bugs And Assumptions - MMAP support - - - MMAP support is currently missing. Make sure to - test with Quake. - - - - AC97 codec timeout during init - - - A warning message "via82cxxx: timeout while reading AC97 - codec" is printed during driver initialization. This - message can safely be ignored. - - - Low volume @@ -198,6 +181,16 @@ AC97 mixer interface fixes and debugging by Ron Cemer roncemer@gte.net. + + Rui Sousa rui.sousa@conexant.com, for bugfixing + MMAP support, and several other notable fixes that resulted from + his hard work and testing. + + + Adrian Cox adrian@humboldt.co.uk, for bugfixing + MMAP support, and several other notable fixes that resulted from + his hard work and testing. + @@ -219,7 +212,10 @@ and device ids are not examined. - GNU indent formatting options: -kr -i8 -pcs + GNU indent formatting options: + +-kr -i8 -ts8 -br -ce -bap -sob -l80 -pcs -cs -ss -bs -di1 -nbc -lp -psl + Via has graciously donated e-mail support and source code to help further @@ -238,6 +234,79 @@ Driver ChangeLog + +Version 1.1.15 + + + + + Support for variable fragment size and variable fragment number (Rui + Sousa) + + + + + + Fixes for the SPEED, STEREO, CHANNELS, FMT ioctls when in read & + write mode (Rui Sousa) + + + + + + Mmaped sound is now fully functional. (Rui Sousa) + + + + + + Make sure to enable PCI device before reading any of its PCI + config information. (fixes potential hotplug problems) + + + + + + Clean up code a bit and add more internal function documentation. + + + + + + AC97 codec access fixes (Adrian Cox) + + + + + + Big endian fixes (Adrian Cox) + + + + + + MIDI support (Adrian Cox) + + + + + + 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. + + + + + + Use new pci_request_regions and pci_disable_device functions in + kernel 2.4.6. + + + + + + Version 1.1.14 diff --git a/Documentation/networking/8139too.txt b/Documentation/networking/8139too.txt index b9a3da3f93cf..34f239c1a310 100644 --- a/Documentation/networking/8139too.txt +++ b/Documentation/networking/8139too.txt @@ -185,6 +185,20 @@ suggestions welcome) (WIP) 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 diff --git a/Documentation/networking/dl2k.txt b/Documentation/networking/dl2k.txt new file mode 100644 index 000000000000..6cf2316856d9 --- /dev/null +++ b/Documentation/networking/dl2k.txt @@ -0,0 +1,236 @@ + + 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 ; 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 + + 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. + diff --git a/MAINTAINERS b/MAINTAINERS index 8b3de51297b8..76a54c9f31b3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -106,6 +106,12 @@ M: p_gortmaker@yahoo.com 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 @@ -566,8 +572,8 @@ S: Maintained 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 @@ -812,7 +818,7 @@ S: Maintained 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 diff --git a/arch/i386/defconfig b/arch/i386/defconfig index 822ae7407f64..fde5dbf42fb4 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -414,6 +414,7 @@ CONFIG_EEPRO100=y # # 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 diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c index 15b20d6956f7..0ba8589d4d04 100644 --- a/arch/i386/kernel/vm86.c +++ b/arch/i386/kernel/vm86.c @@ -456,7 +456,7 @@ void handle_vm86_fault(struct kernel_vm86_regs * regs, long error_code) 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; diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c index 5ea759857a2c..aaca7e2edd83 100644 --- a/arch/ppc/kernel/prom.c +++ b/arch/ppc/kernel/prom.c @@ -116,8 +116,11 @@ unsigned int rtas_entry; /* physical pointer */ 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; @@ -1153,7 +1156,19 @@ inspect_node(phandle node, struct device_node *dad, *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, @@ -1186,19 +1201,46 @@ void 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; @@ -1240,9 +1282,8 @@ finish_node(struct device_node *np, unsigned long mem_start, 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); @@ -1298,141 +1339,210 @@ finish_node(struct device_node *np, unsigned long mem_start, 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; jfull_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=regpsize) || ((mask & *map) != (mask & reg[i]))) - found = 0; - map++; - map_size--; - } - for (i=0; iparent; - } 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 @@ -1475,7 +1585,7 @@ prom_n_addr_cells(struct device_node* np) 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; } @@ -1490,7 +1600,7 @@ prom_n_size_cells(struct device_node* np) 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; } @@ -1502,8 +1612,7 @@ interpret_pci_props(struct device_node *np, unsigned long mem_start, { 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); @@ -1525,44 +1634,6 @@ interpret_pci_props(struct device_node *np, unsigned long mem_start, 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); @@ -1677,26 +1748,10 @@ interpret_macio_props(struct device_node *np, unsigned long mem_start, 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); } @@ -1978,13 +2033,12 @@ get_property(struct device_node *np, const char *name, int *lenp) { 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; } diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 52472167fcf1..a57c0b96f06c 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -967,6 +967,7 @@ static void end_buffer_io_sync(struct buffer_head *bh, int uptodate) { mark_buffer_uptodate(bh, uptodate); unlock_buffer(bh); + atomic_dec(&bh->b_count); } /** @@ -1055,6 +1056,7 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]) continue; /* We have the buffer lock */ + atomic_inc(&bh->b_count); bh->b_end_io = end_buffer_io_sync; switch(rw) { diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c index ce15a467cc35..a0ca8e94dc9d 100644 --- a/drivers/block/ps2esdi.c +++ b/drivers/block/ps2esdi.c @@ -117,6 +117,7 @@ static int access_count[MAX_HD]; 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; diff --git a/drivers/char/serial.c b/drivers/char/serial.c index 646cfb103bf8..f36e7334cc63 100644 --- a/drivers/char/serial.c +++ b/drivers/char/serial.c @@ -59,8 +59,8 @@ * */ -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: @@ -3512,7 +3512,7 @@ static void autoconfig_startech_uarts(struct async_struct *info, 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. @@ -3556,17 +3556,32 @@ static void autoconfig_startech_uarts(struct async_struct *info, * 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, @@ -3979,10 +3994,7 @@ static void __devinit start_pci_pnp_board(struct pci_dev *dev, * 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; @@ -4046,10 +4058,7 @@ pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable) #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; @@ -4078,10 +4087,7 @@ pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable) #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; @@ -4102,10 +4108,7 @@ pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable) } /* 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) @@ -4163,10 +4166,7 @@ static struct timedia_struct { { 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; @@ -4187,10 +4187,7 @@ pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable) 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); diff --git a/drivers/isdn/eicon/eicon.h b/drivers/isdn/eicon/eicon.h index fee003d6eecc..23d772561660 100644 --- a/drivers/isdn/eicon/eicon.h +++ b/drivers/isdn/eicon/eicon.h @@ -1,4 +1,4 @@ -/* $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. * diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index b1a79f166734..ea3185b2c4ab 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -56,8 +56,8 @@ * 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) @@ -73,16 +73,18 @@ * */ -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); @@ -90,9 +92,9 @@ 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 @@ -106,9 +108,9 @@ EXPORT_SYMBOL(elsa_init_pcmcia); #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 @@ -178,9 +180,9 @@ EXPORT_SYMBOL(avm_a1_init_pcmcia); #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 @@ -222,7 +224,7 @@ EXPORT_SYMBOL(sedl_init_pcmcia); #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 @@ -255,7 +257,7 @@ EXPORT_SYMBOL(hfc_init_pcmcia); #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 @@ -327,8 +329,7 @@ EXPORT_SYMBOL(HiSax_closecard); #define EMPTY_CARD {0, DEFAULT_PROTO, {0, 0, 0, 0}, NULL} -struct IsdnCard cards[] = -{ +struct IsdnCard cards[] = { FIRST_CARD, EMPTY_CARD, EMPTY_CARD, @@ -373,7 +374,7 @@ MODULE_PARM(id, "s"); #ifdef IO0_IO1 MODULE_PARM(io0, "1-8i"); MODULE_PARM(io1, "1-8i"); -#endif /* IO0_IO1 */ +#endif #endif /* MODULE */ int nrcards; @@ -384,8 +385,7 @@ extern char *l3_revision; extern char *lli_revision; extern char *tei_revision; -char * -HiSax_getrev(const char *revision) +char *HiSax_getrev(const char *revision) { char *rev; char *p; @@ -399,8 +399,7 @@ HiSax_getrev(const char *revision) return rev; } -void __init -HiSaxVersion(void) +void __init HiSaxVersion(void) { char tmp[64]; @@ -419,26 +418,24 @@ HiSaxVersion(void) 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]; @@ -446,7 +443,7 @@ HiSax_setup(char *line) 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)) { @@ -484,7 +481,7 @@ HiSax_setup(char *line) strcpy(HiSaxID, "HiSax"); HiSax_id = HiSaxID; } - return(1); + return 1; } __setup("hisax=", HiSax_setup); @@ -527,7 +524,7 @@ extern int setup_ix1micro(struct IsdnCard *card); #endif #if CARD_DIEHLDIVA -extern int setup_diva(struct IsdnCard *card); +extern int setup_diva(struct IsdnCard *card); #endif #if CARD_ASUSCOM @@ -609,43 +606,41 @@ extern int setup_netjet_u(struct IsdnCard *card); /* * 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) @@ -673,13 +668,12 @@ HiSax_readstatus(u_char * buf, int len, int user, int id, int channel) 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; @@ -697,15 +691,15 @@ jiftime(char *s, long mark) *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; @@ -729,18 +723,19 @@ VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args) 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; @@ -754,7 +749,7 @@ VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args) 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); @@ -774,8 +769,7 @@ VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args) } } -void -HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...) +void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...) { va_list args; @@ -784,8 +778,7 @@ HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...) va_end(args); } -int -ll_run(struct IsdnCardState *cs, int addfeatures) +int ll_run(struct IsdnCardState *cs, int addfeatures) { long flags; isdn_ctrl ic; @@ -800,19 +793,17 @@ ll_run(struct IsdnCardState *cs, int addfeatures) 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; @@ -827,8 +818,7 @@ ll_unload(struct IsdnCardState *cs) kfree(cs->dlog); } -static void -closecard(int cardnr) +static void closecard(int cardnr) { struct IsdnCardState *csta = cards[cardnr].cs; @@ -856,56 +846,54 @@ closecard(int cardnr) 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; @@ -923,8 +911,8 @@ checkcard(int cardnr, char *id, int *busy_flag) } 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; @@ -940,14 +928,12 @@ checkcard(int cardnr, char *id, int *busy_flag) 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))) { @@ -981,7 +967,7 @@ checkcard(int cardnr, char *id, int *busy_flag) ISDN_FEATURE_P_NI1 | #endif 0; - + cs->iif.command = HiSax_command; cs->iif.writecmd = NULL; cs->iif.writebuf_skb = HiSax_writebuf_skb; @@ -1092,12 +1078,12 @@ checkcard(int cardnr, char *id, int *busy_flag) 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 @@ -1126,7 +1112,7 @@ checkcard(int cardnr, char *id, int *busy_flag) 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; @@ -1163,8 +1149,7 @@ checkcard(int cardnr, char *id, int *busy_flag) 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; } @@ -1210,8 +1195,7 @@ checkcard(int cardnr, char *id, int *busy_flag) return ret; } -void __devinit -HiSax_shiftcards(int idx) +void __devinit HiSax_shiftcards(int idx) { int i; @@ -1219,8 +1203,7 @@ HiSax_shiftcards(int idx) 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; @@ -1254,7 +1237,8 @@ HiSax_inithardware(int *busy_flag) 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--; @@ -1263,19 +1247,17 @@ HiSax_inithardware(int *busy_flag) 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); @@ -1283,15 +1265,14 @@ HiSax_closecard(int cardnr) 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; @@ -1299,21 +1280,25 @@ HiSax_reportcard(int cardnr, int sel) 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; @@ -1333,7 +1318,7 @@ HiSax_reportcard(int cardnr, int sel) static int __init HiSax_init(void) { int i, retval; -#ifdef MODULE +#ifdef MODULE int j; int nzproto = 0; #endif @@ -1357,7 +1342,7 @@ static int __init HiSax_init(void) #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 @@ -1396,98 +1381,100 @@ static int __init HiSax_init(void) 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) @@ -1505,7 +1492,7 @@ static int __init HiSax_init(void) retval = -EIO; goto out_isdnl1; } - + return 0; out_isdnl1: @@ -1524,12 +1511,12 @@ static int __init HiSax_init(void) 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(); @@ -1549,7 +1536,7 @@ int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) 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]; @@ -1559,7 +1546,7 @@ int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) } } 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; @@ -1576,7 +1563,7 @@ int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) HiSax_inithardware(busy_flag); printk(KERN_NOTICE "HiSax: module installed\n"); #endif - return (0); + return 0; } #endif @@ -1590,7 +1577,7 @@ int hfc_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) 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]; @@ -1601,7 +1588,7 @@ int hfc_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) } } 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; @@ -1619,7 +1606,7 @@ int hfc_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) HiSax_inithardware(busy_flag); printk(KERN_NOTICE "HiSax: module installed\n"); #endif - return (0); + return 0; } #endif @@ -1633,7 +1620,7 @@ int sedl_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) 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]; @@ -1644,7 +1631,7 @@ int sedl_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) } } 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; @@ -1662,7 +1649,7 @@ int sedl_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) HiSax_inithardware(busy_flag); printk(KERN_NOTICE "HiSax: module installed\n"); #endif - return (0); + return 0; } #endif @@ -1676,7 +1663,7 @@ int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) 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]; @@ -1687,7 +1674,7 @@ int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) } } 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; @@ -1705,11 +1692,12 @@ int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) 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; @@ -1720,11 +1708,11 @@ int __devinit hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard * else sprintf(ids, "HiSax"); if (!checkcard(nrcards, ids, busy_flag)) { - return(-1); + return -1; } ret = nrcards; nrcards++; - return (ret); + return ret; } #include diff --git a/drivers/isdn/hisax/md b/drivers/isdn/hisax/md deleted file mode 100644 index 5efa612cfe71..000000000000 --- a/drivers/isdn/hisax/md +++ /dev/null @@ -1,12 +0,0 @@ -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 diff --git a/drivers/isdn/isdn_tty.c b/drivers/isdn/isdn_tty.c index e95beb90ba60..df3645e9d8d6 100644 --- a/drivers/isdn/isdn_tty.c +++ b/drivers/isdn/isdn_tty.c @@ -1,4 +1,4 @@ -/* $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). * @@ -66,7 +66,7 @@ static int bit2si[8] = 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() @@ -1420,8 +1420,7 @@ isdn_tty_get_lsr_info(modem_info * info, uint * value) 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); } @@ -1444,8 +1443,7 @@ isdn_tty_get_modem_info(modem_info * info, 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 @@ -1454,7 +1452,8 @@ isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value) 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 @@ -1522,7 +1521,6 @@ isdn_tty_ioctl(struct tty_struct *tty, struct file *file, 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")) @@ -1552,19 +1550,13 @@ isdn_tty_ioctl(struct tty_struct *tty, struct file *file, #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)); @@ -1573,26 +1565,16 @@ isdn_tty_ioctl(struct tty_struct *tty, struct file *file, #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); diff --git a/drivers/message/fusion/Config.in b/drivers/message/fusion/Config.in new file mode 100644 index 000000000000..4d04055d83fa --- /dev/null +++ b/drivers/message/fusion/Config.in @@ -0,0 +1,39 @@ +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 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 diff --git a/drivers/message/fusion/Makefile b/drivers/message/fusion/Makefile new file mode 100644 index 000000000000..46df6571dfc5 --- /dev/null +++ b/drivers/message/fusion/Makefile @@ -0,0 +1,72 @@ +# +# 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) diff --git a/drivers/message/fusion/ascq_tbl.c b/drivers/message/fusion/ascq_tbl.c new file mode 100644 index 000000000000..210c4e74b628 --- /dev/null +++ b/drivers/message/fusion/ascq_tbl.c @@ -0,0 +1,2416 @@ +#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 diff --git a/drivers/message/fusion/ascq_tbl.sh b/drivers/message/fusion/ascq_tbl.sh new file mode 100644 index 000000000000..76ba95458d17 --- /dev/null +++ b/drivers/message/fusion/ascq_tbl.sh @@ -0,0 +1,109 @@ +#!/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 diff --git a/drivers/message/fusion/isense.c b/drivers/message/fusion/isense.c new file mode 100644 index 000000000000..553c8db6a37d --- /dev/null +++ b/drivers/message/fusion/isense.c @@ -0,0 +1,122 @@ +/* + * 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 +#include +#include +#include +#include + +/* Hmmm, avoid undefined spinlock_t on lk-2.2.14-5.0 */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) +#include +#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); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + diff --git a/drivers/message/fusion/isense.h b/drivers/message/fusion/isense.h new file mode 100644 index 000000000000..e1ce503fef3c --- /dev/null +++ b/drivers/message/fusion/isense.h @@ -0,0 +1,95 @@ +#ifndef ISENSE_H_INCLUDED +#define ISENSE_H_INCLUDED +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#ifdef __KERNEL__ +#include /* needed for u8, etc. */ +#include /* needed for strcat */ +#include /* 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 + diff --git a/drivers/message/fusion/linux_compat.h b/drivers/message/fusion/linux_compat.h new file mode 100644 index 000000000000..21d651007d7d --- /dev/null +++ b/drivers/message/fusion/linux_compat.h @@ -0,0 +1,199 @@ +/* drivers/message/fusion/linux_compat.h */ + +#ifndef FUSION_LINUX_COMPAT_H +#define FUSION_LINUX_COMPAT_H +/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#include +#include +#include +#include + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#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 +/* 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 */ + diff --git a/drivers/message/fusion/lsi/fc_log.h b/drivers/message/fusion/lsi/fc_log.h new file mode 100644 index 000000000000..57597172ee31 --- /dev/null +++ b/drivers/message/fusion/lsi/fc_log.h @@ -0,0 +1,83 @@ +/* + * 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; diff --git a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h new file mode 100644 index 000000000000..bf0a662e50f5 --- /dev/null +++ b/drivers/message/fusion/lsi/mpi.h @@ -0,0 +1,643 @@ +/* + * 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 diff --git a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h new file mode 100644 index 000000000000..dd81a65e25b5 --- /dev/null +++ b/drivers/message/fusion/lsi/mpi_cnfg.h @@ -0,0 +1,971 @@ +/* + * 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 + diff --git a/drivers/message/fusion/lsi/mpi_fc.h b/drivers/message/fusion/lsi/mpi_fc.h new file mode 100644 index 000000000000..73d17d2217ba --- /dev/null +++ b/drivers/message/fusion/lsi/mpi_fc.h @@ -0,0 +1,350 @@ +/* + * 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 + diff --git a/drivers/message/fusion/lsi/mpi_history.txt b/drivers/message/fusion/lsi/mpi_history.txt new file mode 100644 index 000000000000..5ac3e0622f52 --- /dev/null +++ b/drivers/message/fusion/lsi/mpi_history.txt @@ -0,0 +1,237 @@ + + ============================== + 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 + + + * -------------------------------------------------------------------------- + diff --git a/drivers/message/fusion/lsi/mpi_init.h b/drivers/message/fusion/lsi/mpi_init.h new file mode 100644 index 000000000000..4f3c8dc705c5 --- /dev/null +++ b/drivers/message/fusion/lsi/mpi_init.h @@ -0,0 +1,215 @@ +/* + * 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 diff --git a/drivers/message/fusion/lsi/mpi_ioc.h b/drivers/message/fusion/lsi/mpi_ioc.h new file mode 100644 index 000000000000..0411671dc9a9 --- /dev/null +++ b/drivers/message/fusion/lsi/mpi_ioc.h @@ -0,0 +1,583 @@ +/* + * 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 diff --git a/drivers/message/fusion/lsi/mpi_lan.h b/drivers/message/fusion/lsi/mpi_lan.h new file mode 100644 index 000000000000..86d15dc25996 --- /dev/null +++ b/drivers/message/fusion/lsi/mpi_lan.h @@ -0,0 +1,204 @@ +/* + * 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 + diff --git a/drivers/message/fusion/lsi/mpi_targ.h b/drivers/message/fusion/lsi/mpi_targ.h new file mode 100644 index 000000000000..8b0d74a2b64c --- /dev/null +++ b/drivers/message/fusion/lsi/mpi_targ.h @@ -0,0 +1,328 @@ +/* + * 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 + diff --git a/drivers/message/fusion/lsi/mpi_type.h b/drivers/message/fusion/lsi/mpi_type.h new file mode 100644 index 000000000000..733dec74c6d8 --- /dev/null +++ b/drivers/message/fusion/lsi/mpi_type.h @@ -0,0 +1,90 @@ +/* + * 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 + diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c new file mode 100644 index 000000000000..0ada7fe6e632 --- /dev/null +++ b/drivers/message/fusion/mptbase.c @@ -0,0 +1,3360 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_MTRR +#include +#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<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; cntname, 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<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<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; ichip->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); diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h new file mode 100644 index 000000000000..68fc7acff022 --- /dev/null +++ b/drivers/message/fusion/mptbase.h @@ -0,0 +1,581 @@ +/* + * 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 (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 + diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c new file mode 100644 index 000000000000..7bcb3757c8ef --- /dev/null +++ b/drivers/message/fusion/mptctl.c @@ -0,0 +1,1296 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#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= 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); diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c new file mode 100644 index 000000000000..f619f2f12588 --- /dev/null +++ b/drivers/message/fusion/mptlan.c @@ -0,0 +1,1462 @@ +/* + * 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 +#include +#include + +#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); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff --git a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h new file mode 100644 index 000000000000..c32cfa01f2c1 --- /dev/null +++ b/drivers/message/fusion/mptlan.h @@ -0,0 +1,72 @@ +/* mptlan.h */ + +#ifndef LINUX_MPTLAN_H_INCLUDED +#define LINUX_MPTLAN_H_INCLUDED +/*****************************************************************************/ + +#if !defined(__GENKSYMS__) +#include +#endif + +#include +#include +// #include +#include +// #include +#include +#include +#include +#include +#include +#include +#include +#include +// #include + +#include +#include + + /* 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 + diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c new file mode 100644 index 000000000000..d1a21e1e0c43 --- /dev/null +++ b/drivers/message/fusion/mptscsih.c @@ -0,0 +1,2508 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include /* 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; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h new file mode 100644 index 000000000000..ba144600dcc3 --- /dev/null +++ b/drivers/message/fusion/mptscsih.h @@ -0,0 +1,247 @@ +/* + * 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 +# 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 newly defined TQ_ACTIVE) + */ +#define HAVE_TQ_SCHED 1 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +# include +# 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 + diff --git a/drivers/message/fusion/scsi3.h b/drivers/message/fusion/scsi3.h new file mode 100644 index 000000000000..fbb4e37154bf --- /dev/null +++ b/drivers/message/fusion/scsi3.h @@ -0,0 +1,700 @@ +/* + * 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 +#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 diff --git a/drivers/message/fusion/scsiops.c b/drivers/message/fusion/scsiops.c new file mode 100644 index 000000000000..2143e42ab508 --- /dev/null +++ b/drivers/message/fusion/scsiops.c @@ -0,0 +1,309 @@ + +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 */ +}; + diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index ece6677f0ae7..c2584037ce1f 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -174,7 +174,7 @@ static struct el3_mca_adapters_struct el3_mca_adapters[] __initdata = { }; #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), @@ -203,8 +203,8 @@ static struct isapnp_device_id el3_isapnp_adapters[] __initdata = { 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) { @@ -214,9 +214,9 @@ 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); @@ -320,7 +320,7 @@ int __init el3_probe(struct net_device *dev) } #endif /* CONFIG_MCA */ -#ifdef CONFIG_ISAPNP +#if defined(CONFIG_ISAPNP) || defined(CONFIG_ISAPNP_MODULE) if (nopnp == 1) goto no_pnp; @@ -356,7 +356,7 @@ int __init el3_probe(struct net_device *dev) } } 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) { @@ -402,7 +402,7 @@ no_pnp: 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. */ @@ -422,7 +422,7 @@ no_pnp: } } } -#endif /* CONFIG_ISAPNP */ +#endif /* CONFIG_ISAPNP || CONFIG_ISAPNP_MODULE */ { unsigned int iobase = id_read_eeprom(8); diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index f06e5bb34708..680659a92eb8 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -137,7 +137,7 @@ an MMIO register read. */ #define DRV_NAME "8139too" -#define DRV_VERSION "0.9.18-pre4" +#define DRV_VERSION "0.9.18" #include @@ -209,7 +209,7 @@ static int multicast_filter_limit = 32; #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 diff --git a/drivers/net/Config.in b/drivers/net/Config.in index c8d15d27ec87..e433d8fb47c6 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -207,6 +207,7 @@ comment 'Ethernet (1000 Mbit)' 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 diff --git a/drivers/net/Makefile b/drivers/net/Makefile index d9db1063c04e..23074af321f0 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -207,6 +207,7 @@ obj-$(CONFIG_MACSONIC) += macsonic.o 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 diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c new file mode 100644 index 000000000000..d9a747234d5c --- /dev/null +++ b/drivers/net/dl2k.c @@ -0,0 +1,1443 @@ +/* D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */ +/* + Copyright (c) 2001 by D-Link Corporation + Written by Edward Peng. + 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 + +*/ diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h new file mode 100644 index 000000000000..1482072269a2 --- /dev/null +++ b/drivers/net/dl2k.h @@ -0,0 +1,729 @@ +/* D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */ +/* + Copyright (c) 2001 by D-Link Corporation + Written by Edward Peng. + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include +#include +#include + +#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__ */ diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index e9cab7c10399..e581850c3696 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -1174,8 +1174,6 @@ static int epic_rx(struct net_device *dev) 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", @@ -1196,6 +1194,9 @@ static int epic_rx(struct net_device *dev) 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; } diff --git a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c index ed9abb541e51..fc73604f3f8b 100644 --- a/drivers/sbus/char/aurora.c +++ b/drivers/sbus/char/aurora.c @@ -1,4 +1,4 @@ -/* $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) @@ -1851,7 +1851,6 @@ static int aurora_get_modem_info(struct Aurora_port * port, unsigned int *value) 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); @@ -1860,9 +1859,8 @@ static int aurora_set_modem_info(struct Aurora_port * port, unsigned int cmd, #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: @@ -1940,16 +1938,12 @@ static int aurora_set_serial_info(struct Aurora_port * port, 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) || @@ -2025,7 +2019,6 @@ static int aurora_ioctl(struct tty_struct * tty, struct file * filp, { struct Aurora_port *port = (struct Aurora_port *) tty->driver_data; - int error; int retval; #ifdef AURORA_DEBUG @@ -2051,25 +2044,19 @@ static int aurora_ioctl(struct tty_struct * tty, struct file * filp, 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: diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c index 80b9b15bd090..d552c56affa4 100644 --- a/drivers/usb/printer.c +++ b/drivers/usb/printer.c @@ -19,6 +19,7 @@ * 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 */ /* @@ -88,6 +89,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H 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 */ @@ -172,9 +174,12 @@ static char *usblp_messages[] = { "ok", "out of paper", "off-line", "on fire" }; 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; } @@ -244,24 +249,30 @@ out: 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; } @@ -279,21 +290,31 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 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 */ @@ -307,13 +328,16 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 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) { @@ -321,17 +345,20 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int 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) @@ -341,6 +368,8 @@ static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, 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) @@ -356,28 +385,36 @@ static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, } } - 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; @@ -387,6 +424,7 @@ static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, usblp->writeurb.dev = usblp->dev; usb_submit_urb(&usblp->writeurb); + up (&usblp->sem); } return count; @@ -399,20 +437,36 @@ static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t 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", @@ -420,14 +474,17 @@ static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t 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; @@ -435,6 +492,8 @@ static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t usb_submit_urb(&usblp->readurb); } +done: + up (&usblp->sem); return count; } @@ -537,6 +596,7 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum, 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); @@ -599,14 +659,12 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum, 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); @@ -619,25 +677,21 @@ static void usblp_disconnect(struct usb_device *dev, void *ptr) 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 [] = { diff --git a/drivers/usb/scanner.c b/drivers/usb/scanner.c index bafcbeb869b5..95f36da88159 100644 --- a/drivers/usb/scanner.c +++ b/drivers/usb/scanner.c @@ -909,7 +909,7 @@ ioctl_scanner(struct inode *inode, struct file *file, return result; } default: - return -ENOIOCTLCMD; + return -ENOTTY; } return 0; } diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 50fb149452fe..de9c744d14f7 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -247,7 +247,6 @@ static int empeg_open (struct usb_serial_port *port, struct file *filp) 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; @@ -263,14 +262,6 @@ static void empeg_close (struct usb_serial_port *port, struct file * filp) --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; diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 44794a9dc1cc..98bbd1e4654d 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -902,7 +902,8 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns 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)"); @@ -915,7 +916,8 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns 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), @@ -936,7 +938,8 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns 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), diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c index a22b0f770408..8fe8a374b3ec 100644 --- a/drivers/usb/serial/usbserial.c +++ b/drivers/usb/serial/usbserial.c @@ -15,6 +15,13 @@ * * 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. @@ -296,7 +303,7 @@ /* * 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" @@ -347,6 +354,7 @@ static void serial_throttle (struct tty_struct * tty); 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); @@ -736,6 +744,16 @@ static void serial_break (struct tty_struct *tty, int break_state) } +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 @@ -1311,8 +1329,7 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr) 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; @@ -1426,7 +1443,7 @@ int usb_serial_init(void) return -1; } - info(DRIVER_VERSION ":" DRIVER_DESC); + info(DRIVER_DESC " " DRIVER_VERSION); return 0; } @@ -1500,9 +1517,11 @@ MODULE_DESCRIPTION( DRIVER_DESC ); 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 diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c index 7d1cd90f2d40..76576dae0dbf 100644 --- a/drivers/usb/usb-ohci.c +++ b/drivers/usb/usb-ohci.c @@ -2749,7 +2749,7 @@ static int ohci_sleep_notify (struct pmu_sleep_notifier * self, int when) 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); diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c index 5bcdf0d8aeb1..4f41cc9c678d 100644 --- a/drivers/video/hgafb.c +++ b/drivers/video/hgafb.c @@ -49,7 +49,7 @@ #ifdef MODULE -#define INCLUDE_LINUX_LOGOBW +#define INCLUDE_LINUX_LOGO_DATA #include #endif /* MODULE */ diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c index 3604e88d7f07..8dbfd1b70589 100644 --- a/drivers/video/imsttfb.c +++ b/drivers/video/imsttfb.c @@ -1278,10 +1278,11 @@ imsttfb_setcolreg (u_int regno, u_int red, u_int green, u_int blue, 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 } diff --git a/fs/buffer.c b/fs/buffer.c index 89c3c6d9d60d..264babd758e0 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -71,6 +71,9 @@ static char buffersize_index[65] = #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.. */ @@ -133,6 +136,21 @@ union bdflush_param { 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 @@ -147,7 +165,7 @@ void __wait_on_buffer(struct buffer_head * bh) 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); @@ -158,14 +176,15 @@ void __wait_on_buffer(struct buffer_head * bh) } 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); } /* @@ -179,14 +198,14 @@ static void end_buffer_write(struct buffer_head *bh, int uptodate) 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) @@ -210,6 +229,7 @@ repeat: 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; @@ -220,7 +240,8 @@ repeat: write_locked_buffers(array, count); goto repeat; } - unlock_buffer(bh); + __unlock_buffer(bh); + put_bh(bh); } spin_unlock(&lru_list_lock); @@ -249,10 +270,10 @@ repeat: 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); @@ -552,7 +573,7 @@ static inline struct buffer_head * __get_hash_table(kdev_t dev, int block, int s bh->b_dev == dev) break; if (bh) - atomic_inc(&bh->b_count); + get_bh(bh); return bh; } @@ -646,12 +667,12 @@ void __invalidate_buffers(kdev_t dev, int destroy_dirty_buffers) 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); @@ -711,12 +732,12 @@ void set_blocksize(kdev_t dev, int size) 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); @@ -802,8 +823,7 @@ static void end_buffer_io_async(struct buffer_head * bh, int uptodate) * 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)) @@ -813,6 +833,7 @@ static void end_buffer_io_async(struct buffer_head * bh, int uptodate) /* 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 @@ -832,6 +853,7 @@ static void end_buffer_io_async(struct buffer_head * bh, int uptodate) return; still_busy: + put_bh(bh); spin_unlock_irqrestore(&page_uptodate_lock, flags); return; } @@ -879,7 +901,7 @@ int fsync_inode_buffers(struct inode *inode) 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); @@ -891,7 +913,7 @@ int fsync_inode_buffers(struct inode *inode) 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)) @@ -935,7 +957,7 @@ int osync_inode_buffers(struct inode *inode) 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)) @@ -1130,7 +1152,7 @@ void refile_buffer(struct buffer_head *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"); @@ -1528,7 +1550,7 @@ static int __block_write_full_page(struct inode *inode, struct page *page, get_b 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; @@ -1536,8 +1558,9 @@ static int __block_write_full_page(struct inode *inode, struct page *page, get_b /* 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 */ @@ -1729,7 +1752,7 @@ int block_read_full_page(struct page *page, get_block_t *get_block) 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 */ @@ -1982,7 +2005,8 @@ static void end_buffer_io_kiobuf(struct buffer_head *bh, int uptodate) mark_buffer_uptodate(bh, uptodate); kiobuf = bh->b_private; - unlock_buffer(bh); + __unlock_buffer(bh); + put_bh(bh); end_kio_request(kiobuf, uptodate); } @@ -2107,7 +2131,7 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[], offset += size; atomic_inc(&iobuf->io_count); - + get_bh(tmp); submit_bh(rw, tmp); /* * Wait for IO if we have got too much @@ -2175,14 +2199,15 @@ int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size) 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; } @@ -2554,10 +2579,10 @@ static int flush_dirty_buffers(int check_flushtime) } /* 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(); diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index d61d6b9df29c..b067f3f1bfdf 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -146,51 +146,53 @@ static int meminfo_read_proc(char *page, char **start, off_t off, */ #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 @@ -289,11 +291,11 @@ static int kstat_read_proc(char *page, char **start, off_t off, 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, diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c index 5bff91f6c83b..3265d150be1a 100644 --- a/fs/sysv/dir.c +++ b/fs/sysv/dir.c @@ -211,7 +211,7 @@ got_it: 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; diff --git a/include/asm-sparc/vaddrs.h b/include/asm-sparc/vaddrs.h index e2f6fbe91fc8..0470ea55e6a9 100644 --- a/include/asm-sparc/vaddrs.h +++ b/include/asm-sparc/vaddrs.h @@ -1,4 +1,4 @@ -/* $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 diff --git a/include/asm-sparc64/starfire.h b/include/asm-sparc64/starfire.h index a738fb363a40..b606cb2b32a8 100644 --- a/include/asm-sparc64/starfire.h +++ b/include/asm-sparc64/starfire.h @@ -1,4 +1,4 @@ -/* $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) diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h index b43c299448df..9843b91077d2 100644 --- a/include/linux/if_arp.h +++ b/include/linux/if_arp.h @@ -35,6 +35,7 @@ #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) */ diff --git a/include/linux/isdnif.h b/include/linux/isdnif.h index cca81b6b50a5..e09c9cccee02 100644 --- a/include/linux/isdnif.h +++ b/include/linux/isdnif.h @@ -1,4 +1,4 @@ -/* $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 * diff --git a/include/linux/locks.h b/include/linux/locks.h index 1c1f2bbb19eb..1c3fa10b9270 100644 --- a/include/linux/locks.h +++ b/include/linux/locks.h @@ -26,13 +26,7 @@ extern inline void lock_buffer(struct buffer_head * bh) __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 diff --git a/kernel/ksyms.c b/kernel/ksyms.c index c79ab58b0d55..9702fda030d5 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -194,6 +194,7 @@ EXPORT_SYMBOL(__brelse); 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); diff --git a/mm/filemap.c b/mm/filemap.c index 86b9354a2424..d7794cff7716 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1649,10 +1649,13 @@ static inline int filemap_sync_pte(pte_t * ptep, struct vm_area_struct *vma, { 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; } diff --git a/mm/memory.c b/mm/memory.c index cd6d4896522e..f99c7367ab2c 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1108,9 +1108,6 @@ static int do_swap_page(struct mm_struct * mm, spin_lock(&mm->page_table_lock); return -1; } - wait_on_page(page); - flush_page_to_ram(page); - flush_icache_page(vma, page); } /* @@ -1140,6 +1137,8 @@ static int do_swap_page(struct mm_struct * mm, 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 */ diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 3617a5585af4..74b7121ddf1c 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -191,6 +191,8 @@ void oom_kill(void) */ int out_of_memory(void) { + long cache_mem, limit; + /* Enough free memory? Not OOM. */ if (nr_free_pages() > freepages.min) return 0; @@ -198,6 +200,21 @@ int out_of_memory(void) 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; diff --git a/mm/shmem.c b/mm/shmem.c index 71f868e3cc4c..d19bf7e794cc 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -223,7 +223,7 @@ static void shmem_delete_inode(struct inode * inode) */ 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; @@ -231,17 +231,14 @@ static int shmem_writepage(struct page * page) 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); diff --git a/mm/swap_state.c b/mm/swap_state.c index 142c7df7c121..c5ae51446c57 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -81,6 +81,7 @@ void add_to_swap_cache(struct page *page, swp_entry_t entry) 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); } diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 056eaa043b64..4d96bf2d9fd5 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -68,106 +68,77 @@ static void dn_send_ptp_hello(struct net_device *dev); 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, } }; @@ -182,7 +153,7 @@ static int max_t2[] = { 60 }; /* No max specified, but this seems sensible */ 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 *, @@ -344,7 +315,8 @@ static int dn_forwarding_sysctl(ctl_table *table, int *name, int nlen, 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) diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 9c8d493b5917..9fee820f6d0e 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -24,19 +24,28 @@ #include #include #include +#include #include +#include #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); @@ -64,7 +73,6 @@ typedef struct ipq_queue { * 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, @@ -150,9 +158,19 @@ static int ipq_enqueue(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); @@ -198,6 +216,32 @@ static void ipq_destroy_queue(ipq_queue_t *q) 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; @@ -223,6 +267,8 @@ static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, ipq_queue_element_t *e) "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; } @@ -230,6 +276,19 @@ static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, ipq_queue_element_t *e) } 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; } @@ -400,6 +459,13 @@ static struct sk_buff *netlink_build_message(ipq_queue_element_t *e, int *errp) 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; @@ -431,10 +497,15 @@ extern __inline__ void netlink_receive_user_skb(struct sk_buff *skb) 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); diff --git a/net/ipv4/netfilter/ipt_unclean.c b/net/ipv4/netfilter/ipt_unclean.c index 8779c6bb9ede..69d18834df3b 100644 --- a/net/ipv4/netfilter/ipt_unclean.c +++ b/net/ipv4/netfilter/ipt_unclean.c @@ -268,6 +268,7 @@ check_tcp(const struct iphdr *iph, 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; @@ -373,7 +374,7 @@ check_tcp(const struct iphdr *iph, 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; @@ -392,6 +393,7 @@ static int 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; @@ -444,7 +446,7 @@ check_ip(struct iphdr *iph, size_t length, int embedded) 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; diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index 60d4698fb74e..cefcd79e6f0d 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -148,7 +148,7 @@ ipt_local_out_hook(unsigned int hook, 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